初入公司,因为公司主要业务是three 3D,所以需要学习three.js,主要学习以视频为主,这里推荐老陈打码的视频,讲的不错,还免费
demo的环境搭建
1、创建文件夹后,npm init 初始化 一路回车
2、下载依赖
2.1、安装parcel www.parceljs.cn/getting_sta…
parcel 是 Web 应用打包工具,适用于经验不同的开发者。它利用多核处理提供了极快的速度,并且不需要任何配置。
首先通过 Yarn 或者 npm 安装 Parcel :
Yarn:
yarn global add parcel-bundler
npm:
npm install -g parcel-bundler
2.2 three依赖安装 github.com/mrdoob/thre…
npm install three
3、创建文件
这样,我们可以index.html中模块化引入main.js
<body>
<script src="./main/main.js" type="module"></script>
</body>
4、配置package.json
接着,通过修改你的package.json来添加这些任务脚本
{
"scripts": {
"dev": "parcel src/index.html",
"build": "parcel src/index.html"
},
}
配置完成后,我们可以通过命令 npm run dev
启动项目或者npm run build
进行打包
three初次尝试
我们的主要逻辑写在main.js文件中
1、所需依赖
import * as THREE from 'three'; // three.js
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; // 轨道控制器
const TWEEN = require('@tweenjs/tween.js') // 补间动画
其中tween tweenjs.github.io/tween.js/需要下载,后面需要tween.js控制相机聚焦
npm i @tweenjs/tween.js@^18
2、基础功能:相机、场景、光源、渲染器、控制器
2.1 相机
// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, .1, 10000);
camera.position.set(1000, 520, 760); // 设置相机的坐标
2.2 创建场景
// 创建场景
const scene = new THREE.Scene();
2.3 创建光源
// 环境光
let light = new THREE.AmbientLight(0xadadad); // soft white light
scene.add(light);
// 平行光源
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(1000, 1000, 0);
scene.add(directionalLight);
2.4 创建地板
// 创建地板
const planeGeo = new THREE.PlaneGeometry(900, 900);
const planeMaterial = new THREE.MeshLambertMaterial({
color: new THREE.Color('#333333'),
side: THREE.DoubleSide
});
const planeMesh = new THREE.Mesh(planeGeo, planeMaterial);
planeMesh.rotation.x = -Math.PI / 2;
scene.add(planeMesh);
2.5 创建坐标系(可要可不要)
const helper = new THREE.AxesHelper(100);
scene.add(helper);
2.6 渲染器
// 渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
2.7 控制器
// 轨道查看器
const controls = new OrbitControls(camera, renderer.domElement);
2.8
function render() {
requestAnimationFrame(render);
TWEEN.update();
renderer.render(scene, camera);
}
render();
3、制作建筑
以上步骤,已经做好了环境和基础功能,现在我们需要做一些方块表示建筑
// 随机生产大于10的数
function randWidth (width) {
return Math.random() * width + 10;
}
// 创建若干个建筑物
const buildCount = 50;
const group = new THREE.Group();
for (let i=0; i < buildCount; i++) {
const x = randWidth(20);
const y = randWidth(100);
const z = randWidth(10);
const boxGeometry = new THREE.BoxBufferGeometry(x, y ,z);
const positionX = 300 - randWidth(600);
const positionZ = 300 - randWidth(600);
boxGeometry.translate(positionX, y / 2 ,positionZ);
// 建筑颜色
const material = new THREE.MeshBasicMaterial( { color: 0x5588aa } );
const mesh = new THREE.Mesh(boxGeometry, material);
mesh.isBuild = true;
group.add(mesh);
}
scene.add(group);
4、用tween.js控制相机实现聚焦效果
聚焦实际上是相机的运动,所以我们只需要控制相机的位置就可以了
/************ tween动画 **************/
// 当前相机所在点位置
const p1 = {
x: camera.position.x,
y: camera.position.y,
z: camera.position.z,
}
// 相机目标位置点
const p2 = {x:-400, y:520, z:760};
function cameraMove(position, time) {
const tween1 = new TWEEN.Tween(p1).to(position, time).easing(TWEEN.Easing.Quadratic.InOut)
tween1.onUpdate(() => {
camera.position.set(p1.x, p1.y, p1.z)
camera.lookAt(0, 0, 0)
});
return tween1;
}
function action() {
const tweena = cameraMove({ x: 20, y: 100, z: 100 }, 4000);
tweena.start();
}
5、模型拾取
这里只展示代码和实现,具体参考请看 Three.js的物体点击选中拾取原理剖析
请注意这里是three.js全屏模式下的点击选中拾取原理
addClick();
function addClick () {
var raycaster = new THREE.Raycaster();//光线投射,用于确定鼠标点击位置
var mouse = new THREE.Vector2();//创建二维平面
window.addEventListener("mousedown",mousedown);//页面绑定鼠标点击事件
//点击方法
function mousedown(e){
//将html坐标系转化为webgl坐标系,并确定鼠标点击位置
mouse.x = e.clientX / renderer.domElement.clientWidth*2-1;
mouse.y = -(e.clientY / renderer.domElement.clientHeight*2)+1;
//以camera为z坐标,确定所点击物体的3D空间位置
raycaster.setFromCamera(mouse,camera);
//确定所点击位置上的物体数量
var intersects = raycaster.intersectObjects(scene.children);
//选中后进行的操作
if(intersects.length){
console.log(intersects[0].object);
}
}
}
点击建筑打印
我们也可以通过isBuild判断是否是建筑物,监听mousemove更改鼠标样式,
function mousemove(e){
//将html坐标系转化为webgl坐标系,并确定鼠标点击位置
mouse.x = e.clientX / renderer.domElement.clientWidth*2-1;
mouse.y = -(e.clientY / renderer.domElement.clientHeight*2)+1;
//以camera为z坐标,确定所点击物体的3D空间位置
raycaster.setFromCamera(mouse,camera);
//确定所点击位置上的物体数量
var intersects = raycaster.intersectObjects(scene.children);
//选中后进行的操作
var body = document.querySelector("body")
if(intersects.length){
if (intersects[0].object.isBuild) {
console.log(intersects[0].object.isBuil)
body.style.cursor= "move"
} else {
body.style.cursor= "auto"
}
} else {
body.style.cursor= "auto"
}
}
6、点击模型颜色变更
在上述mousedown监听的方法中,执行setSelected
if(intersects.length){
if (intersects[0].object.isBuild) {
intersects[0].object.material.color.set(0xffffff); // 将建筑设置为白色
}
}
效果展示
我正在参加「创意开发 投稿大赛」详情请看:掘金创意开发大赛来了!