效果预览
准备所需资源
搭建场景环境
const container = document.querySelector("#box_bim");// 创建摄像机camera = new THREE.PerspectiveCamera(50,window.innerWidth / window.innerHeight,0.1,1000);// camera.position.set(500, 500, 500);// 调整近裁减值camera.near = 0.1; // 根据需要调整这个值// 调整远裁减值camera.far = 100000; // 根据需要调整这个值// 更新相机投影矩阵(如果使用了透视投影)camera.updateProjectionMatrix();// 创建场景scene = new THREE.Scene();renderer = new THREE.WebGLRenderer({ antialias: true });renderer.setPixelRatio(window.devicePixelRatio);renderer.setSize(window.innerWidth, window.innerHeight);renderer.shadowMap.enabled = truecontainer.appendChild(renderer.domElement);//辅助观察的坐标系const axesHelper = new THREE.AxesHelper(100);scene.add(axesHelper);const environment = new RoomEnvironment();
const pmremGenerator = new THREE.PMREMGenerator(renderer);scene.background = new THREE.Color(0x000000); //背景色scene.environment = pmremGenerator.fromScene(environment).texture;// 如果你使用的是 THREE.SpotLight(光束光源),可以通过以下方式设置光束的范围:const spotLight = new THREE.SpotLight(0xFFFFFF, 1, 100);spotLight.position.set(50, 50, 50);spotLight.angle = Math.PI / 4; // 光束的角度spotLight.penumbra = 0.05; // 光束边缘的模糊度spotLight.decay = 2; // 光强随距离的减少速度scene.add(spotLight);labelRenderer = new CSS2DRenderer();labelRenderer.setSize(window.innerWidth, window.innerHeight);labelRenderer.domElement.style.position = "absolute";labelRenderer.domElement.style.top = "0px";container.appendChild(labelRenderer.domElement);controls = new OrbitControls(camera, labelRenderer.domElement); //控制图层,添加相机控件controls.enableDamping = true;// controls.minDistance = 1;// controls.maxDistance = 10;controls.target.set(0, 0.5, 0);controls.autoRotate = falsecontrols.autoRotateSpeed =0.5controls.update();
添加模型
使用的是gltf类型的模型
// 实例化加载器g1tfconst gltfLoader = new GLTFLoader();// 实例化加较器draco -- 为了解决大型模型经过压缩无法直接加载的问题const dracoloader = new DRACOLoader();dracoloader.setDecoderPath("./draco/");// 加载第一个模型 - 人gltfLoader.setDRACOLoader(dracoloader);gltfLoader.load("./model/people.gltf",(gltf) =>{// 设置模型大小gltf.scene.scale.set(0.2, 0.2, 0.2);gltf.scene.position.set(200,0,0)//调整人位置,使得车模型在小区模型的地面上people = gltf.scenescene.add(gltf.scene);})// 加载第二个模型 - 车辆gltfLoader.load("./model/car.gltf",(gltf) =>{gltf.scene.scale.set(0.2,0.2,0.2);gltf.scene.position.set(100,0,0)//调整车辆位置,使得车模型在小区模型的地面上car = gltf.scenescene.add(gltf.scene); })// 加载第三个模型 - 小区gltfLoader.load("./model/district.gltf",(gltf) =>{gltf.scene.scale.set(0.08, 0.08, 0.08); // 小区模型太大,需要缩小gltf.scene.position.set(100,238,500)//调整车辆位置,使得车模型在小区模型的地面上gltf.scene.rotation.y = -Math.PI / 13;//旋转模型,使得坐标轴与小区的房屋平行便于计算轨迹向量scene.add(gltf.scene);})
增加运动轨迹
// 创建轨迹 - 车辆的移动轨迹spline = new THREE.CatmullRomCurve3([new THREE.Vector3(100,0,0), new THREE.Vector3(100,0,30), new THREE.Vector3(100,0,60), new THREE.Vector3(100,0,90), new THREE.Vector3(100,0,120), new THREE.Vector3(100,0,150), new THREE.Vector3(100,0,180), new THREE.Vector3(100,0,210), new THREE.Vector3(100,0,240), new THREE.Vector3(100,0,270), new THREE.Vector3(100,0,300), new THREE.Vector3(110,0,300), new THREE.Vector3(130,0,300), new THREE.Vector3(150,0,300), new THREE.Vector3(170,0,300), new THREE.Vector3(190,0,300), new THREE.Vector3(210,0,300), new THREE.Vector3(290,0,300), new THREE.Vector3(500,0,300), new THREE.Vector3(800,0,300), new THREE.Vector3(900,0,300), new THREE.Vector3(900,0,290), new THREE.Vector3(900,0,280), new THREE.Vector3(900,0,270), new THREE.Vector3(900,0,260), new THREE.Vector3(900,0,250), new THREE.Vector3(900,0,170), new THREE.Vector3(900,0,120), new THREE.Vector3(900,0,90), new THREE.Vector3(900,0,60), new THREE.Vector3(900,0,30), new THREE.Vector3(900,0,-30), new THREE.Vector3(900,0,-60), new THREE.Vector3(900,0,-90), new THREE.Vector3(800,0,-90), new THREE.Vector3(100,0,-90), ]);spline.curveType = 'catmullrom'spline.closed = true //设置是否闭环spline.tension = 0.5 //设置线的张力,0为无弧度折线// 为曲线添加材质在场景中显示出来,方便看到轨迹线const points = spline.getPoints(50) // 50等分获取曲线点const geometry = new THREE.BufferGeometry().setFromPoints(points);const material = new THREE.LineBasicMaterial({ color: 0x000000 });// Create the final object to add to the sceneconst curveObject = new THREE.Line(geometry, material);scene.add(curveObject) // 添加到场景中
使物体沿着轨迹移动
// 创建渲染函数let progress = 0; // 物体运动时在运动路径的初始位置,范围0~1const velocity = 0.0008; // 影响运动速率的一个值,范围0~1,需要和渲染频率结合计算才能得到真正的速率// 物体沿线移动方法function moveOnCurve() {if (spline == null || car == null) {console.log("Loading")} else {if (progress <= 1 - velocity) {const point = spline.getPointAt(progress); //获取样条曲线指定点坐标const pointBox = spline.getPointAt(progress + velocity); //获取样条曲线指定点坐标if (point && pointBox) {car.position.set(point.x, point.y, point.z);var targetPos = pointBox //目标位置点var offsetAngle = 0 //目标移动时的朝向偏移// //以下代码在多段路径时可重复执行var mtx = new THREE.Matrix4() //创建一个4维矩阵// .lookAt ( eye : Vector3, target : Vector3, up : Vector3 ) : this,构造一个旋转矩阵,从eye 指向 target,由向量 up 定向。mtx.lookAt(car.position, targetPos, car.up) //设置朝向mtx.multiply(new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(0, offsetAngle, 0)))var toRot = new THREE.Quaternion().setFromRotationMatrix(mtx) //计算出需要进行旋转的四元数值car.quaternion.slerp(toRot, 0.2)}progress += velocity;} else {progress = 0;}}};
参考链接
Three.js学习