目录
流程
基本流程
1、添加模型
2、增加运动轨迹
3、让模型沿轨迹运动
工程文件结构如下图:
static:存放静态资源文件
three.js-master:为官网下载的代码包,包含所有需要用到的资源包,链接:https://github.com/mrdoob/three.js/archive/master.zip
index.html:页面代码
模型使用的是官方示例中的Soldier模型,文件位置:three.js-master\examples\models\gltf\Soldier.glb
为了方便操作我们将文件拷出来放在上图static\3dmod\gltf文件夹下,static与three.js-master同级
index.html单页代码组成
<!DOCTYPE html><html><head><meta charset="utf-8"><title>My first three.js app</title><style>
body {margin:0;}</style></head><body><script type="importmap">{"imports":{"three":"./three.js-master/build/three.module.js"}}</script><script type="module">// 下文JS代码位置// ...</script></body></html>
参照官网例子:https://threejs.org/examples/#webgl_animation_skinning_blending中的场景和模型
搭建场景环境
import*asTHREEfrom"three";import{ OrbitControls }from"./three.js-master/examples/jsm/controls/OrbitControls.js";let scene, camera, renderer;// 渲染器开启阴影渲染:renderer.shadowMapEnabled = true;// 灯光需要开启“引起阴影”:light.castShadow = true;// 物体需要开启“引起阴影”和“接收阴影”:mesh.castShadow = mesh.receiveShadow = true;functioninit(){
scene =newTHREE.Scene();
camera =newTHREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight,0.1,1000);
renderer =newTHREE.WebGLRenderer();// position and point the camera to the center of the scene
camera.position.set(5,5,5);
camera.lookAt(scene.position);// 增加坐标系红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.// 添加坐标系到场景中const axes =newTHREE.AxesHelper(20);
scene.add(axes);// 调整背景颜色,边界雾化
scene.background =newTHREE.Color(0xa0a0a0);
scene.fog =newTHREE.Fog(0xa0a0a0,10,30);// 半球形光源const hemiLight =newTHREE.HemisphereLight(0xffffff,0x444444);
hemiLight.position.set(0,10,0);
scene.add(hemiLight);// 创建一个虚拟的球形网格 Mesh 的辅助对象来模拟 半球形光源 HemisphereLight.const hemiLighthelper =newTHREE.HemisphereLightHelper(hemiLight,5);
scene.add(hemiLighthelper);// 地面const mesh =newTHREE.Mesh(newTHREE.PlaneGeometry(100,100),newTHREE.MeshPhongMaterial({color:0x999999,depthWrite:false}));
mesh.rotation.x =- Math.PI/2;
mesh.receiveShadow =true;
scene.add(mesh);// 平行光const directionalLight =newTHREE.DirectionalLight(0xFFFFFF);
directionalLight.castShadow =true;
directionalLight.shadow.camera.near =0.5;
directionalLight.shadow.camera.far =50;
directionalLight.shadow.camera.left =-10;
directionalLight.shadow.camera.right =10;
directionalLight.shadow.camera.top =10;
directionalLight.shadow.camera.bottom =-10;
directionalLight.position.set(0,5,5);
scene.add(directionalLight);// 用于模拟场景中平行光 DirectionalLight 的辅助对象. 其中包含了表示光位置的平面和表示光方向的线段.const directionalLightHelper =newTHREE.DirectionalLightHelper(directionalLight,5);
scene.add(directionalLightHelper);
renderer.shadowMap.enabled =true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);// 控制器const controls =newOrbitControls(camera, renderer.domElement);}// 渲染functionanimate(){requestAnimationFrame(animate);
renderer.render(scene, camera);};
这里是添加了几个辅助对象,方便找到光照和场景坐标位置
添加模型
这里我们直接导入模型,在《Three.js学习四——模型导入》中有相对详细的介绍
let model =null;functionloadModel(){// 加载模型并开启阴影和接受阴影const gltfLoader =newGLTFLoader();
gltfLoader.setPath('./static/3dmod/gltf/').load('Soldier.glb',function(gltf){// gltf.scene.rotation.y = Math.PI;// console.log("gltf", gltf)
gltf.scene.scale.set(1,1,1)
gltf.scene.traverse(function(object){if(object.isMesh){
object.castShadow =true;//阴影
object.receiveShadow =true;//接受别人投的阴影}});
scene.add(gltf.scene);
model = gltf.scene;},function(res){// console.log(res.total, res.loaded)});}
增加运动轨迹
用到了Three.js提供的CatmullRomCurve3:使用Catmull-Rom算法, 从一系列的点创建一条平滑的三维样条曲线。
let curve =null;functionmakeCurve(){//Create a closed wavey loop
curve =newTHREE.CatmullRomCurve3([newTHREE.Vector3(0,0,0),newTHREE.Vector3(5,0,0),newTHREE.Vector3(0,0,5)]);
curve.curveType ="catmullrom";
curve.closed =true;//设置是否闭环
curve.tension =0.5![请添加图片描述](https://img-blog.csdnimg.cn/12a2fa45062d44a58bb7cbf719e4b20f.gif);//设置线的张力,0为无弧度折线// 为曲线添加材质在场景中显示出来,不显示也不会影响运动轨迹,相当于一个Helperconst points = curve.getPoints(50);const geometry =newTHREE.BufferGeometry().setFromPoints(points);const material =newTHREE.LineBasicMaterial({color:0x000000});// Create the final object to add to the sceneconst curveObject =newTHREE.Line(geometry, material);
scene.add(curveObject)}
让模型沿轨迹运动
let progress =0;// 物体运动时在运动路径的初始位置,范围0~1const velocity =0.001;// 影响运动速率的一个值,范围0~1,需要和渲染频率结合计算才能得到真正的速率// 物体沿线移动方法functionmoveOnCurve(){if(curve ==null|| model ==null){
console.log("Loading")}else{if(progress <=1- velocity){const point = curve.getPointAt(progress);//获取样条曲线指定点坐标const pointBox = curve.getPointAt(progress + velocity);//获取样条曲线指定点坐标if(point && pointBox){
model.position.set(point.x, point.y, point.z);// model.lookAt(pointBox.x, pointBox.y, pointBox.z); //因为这个模型加载进来默认面部是正对Z轴负方向的,所以直接lookAt会导致出现倒着跑的现象,这里用重新设置朝向的方法来解决。var targetPos = pointBox //目标位置点var offsetAngle =0//目标移动时的朝向偏移// //以下代码在多段路径时可重复执行var mtx =newTHREE.Matrix4()//创建一个4维矩阵// .lookAt ( eye : Vector3, target : Vector3, up : Vector3 ) : this,构造一个旋转矩阵,从eye 指向 target,由向量 up 定向。
mtx.lookAt(model.position, targetPos, model.up)//设置朝向
mtx.multiply(newTHREE.Matrix4().makeRotationFromEuler(newTHREE.Euler(0, offsetAngle,0)))var toRot =newTHREE.Quaternion().setFromRotationMatrix(mtx)//计算出需要进行旋转的四元数值
model.quaternion.slerp(toRot,0.2)}
progress += velocity;}else{
progress =0;}}};// moveOnCurve()需要在渲染中一直调用更新,以达到物体移动效果functionanimate(){requestAnimationFrame(animate);moveOnCurve();
renderer.render(scene, camera);};
完整代码和效果
完整代码
<!DOCTYPE html><html><head><meta charset="utf-8"><title>My first three.js app</title><style>
body {margin:0;}</style></head><body><script type="importmap">{"imports":{"three":"./three.js-master/build/three.module.js"}}</script><script type="module">import*asTHREEfrom"three";import{ OrbitControls }from"./three.js-master/examples/jsm/controls/OrbitControls.js";import{ GLTFLoader }from"./three.js-master/examples/jsm/loaders/GLTFLoader.js";let scene, camera, renderer;let curve =null, model =null;let progress =0;// 物体运动时在运动路径的初始位置,范围0~1const velocity =0.001;// 影响运动速率的一个值,范围0~1,需要和渲染频率结合计算才能得到真正的速率// 渲染器开启阴影渲染:renderer.shadowMapEnabled = true;// 灯光需要开启“引起阴影”:light.castShadow = true;// 物体需要开启“引起阴影”和“接收阴影”:mesh.castShadow = mesh.receiveShadow = true;functioninit(){
scene =newTHREE.Scene();
camera =newTHREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight,0.1,1000);
renderer =newTHREE.WebGLRenderer();// position and point the camera to the center of the scene
camera.position.set(5,5,5);
camera.lookAt(scene.position);// 增加坐标系红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.// 添加坐标系到场景中const axes =newTHREE.AxesHelper(20);
scene.add(axes);// 调整背景颜色,边界雾化
scene.background =newTHREE.Color(0xa0a0a0);
scene.fog =newTHREE.Fog(0xa0a0a0,10,30);// 半球形光源const hemiLight =newTHREE.HemisphereLight(0xffffff,0x444444);
hemiLight.position.set(0,10,0);
scene.add(hemiLight);// 创建一个虚拟的球形网格 Mesh 的辅助对象来模拟 半球形光源 HemisphereLight.const hemiLighthelper =newTHREE.HemisphereLightHelper(hemiLight,5);
scene.add(hemiLighthelper);// 地面const mesh =newTHREE.Mesh(newTHREE.PlaneGeometry(100,100),newTHREE.MeshPhongMaterial({color:0x999999,depthWrite:false}));
mesh.rotation.x =- Math.PI/2;
mesh.receiveShadow =true;
scene.add(mesh);// 平行光const directionalLight =newTHREE.DirectionalLight(0xFFFFFF);
directionalLight.castShadow =true;
directionalLight.shadow.camera.near =0.5;
directionalLight.shadow.camera.far =50;
directionalLight.shadow.camera.left =-10;
directionalLight.shadow.camera.right =10;
directionalLight.shadow.camera.top =10;
directionalLight.shadow.camera.bottom =-10;
directionalLight.position.set(0,5,5);
scene.add(directionalLight);// 用于模拟场景中平行光 DirectionalLight 的辅助对象. 其中包含了表示光位置的平面和表示光方向的线段.const directionalLightHelper =newTHREE.DirectionalLightHelper(directionalLight,5);
scene.add(directionalLightHelper);
renderer.shadowMap.enabled =true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);// 控制器const controls =newOrbitControls(camera, renderer.domElement);}functionloadModel(){// 加载模型并开启阴影和接受阴影const gltfLoader =newGLTFLoader();
gltfLoader.setPath('./static/3dmod/gltf/').load('Soldier.glb',function(gltf){// gltf.scene.rotation.y = Math.PI;// console.log("gltf", gltf)
gltf.scene.scale.set(1,1,1)
gltf.scene.traverse(function(object){if(object.isMesh){
object.castShadow =true;//阴影
object.receiveShadow =true;//接受别人投的阴影}});
scene.add(gltf.scene);
model = gltf.scene;},function(res){// console.log(res.total, res.loaded)});}functionmakeCurve(){//Create a closed wavey loop
curve =newTHREE.CatmullRomCurve3([newTHREE.Vector3(0,0,0),newTHREE.Vector3(5,0,0),newTHREE.Vector3(0,0,5)]);
curve.curveType ="catmullrom";
curve.closed =true;//设置是否闭环
curve.tension =0.5;//设置线的张力,0为无弧度折线// 为曲线添加材质在场景中显示出来,不显示也不会影响运动轨迹,相当于一个Helperconst points = curve.getPoints(50);const geometry =newTHREE.BufferGeometry().setFromPoints(points);const material =newTHREE.LineBasicMaterial({color:0x000000});// Create the final object to add to the sceneconst curveObject =newTHREE.Line(geometry, material);
scene.add(curveObject)}// 物体沿线移动方法functionmoveOnCurve(){if(curve ==null|| model ==null){
console.log("Loading")}else{if(progress <=1- velocity){const point = curve.getPointAt(progress);//获取样条曲线指定点坐标const pointBox = curve.getPointAt(progress + velocity);//获取样条曲线指定点坐标if(point && pointBox){
model.position.set(point.x, point.y, point.z);// model.lookAt(pointBox.x, pointBox.y, pointBox.z);//因为这个模型加载进来默认面部是正对Z轴负方向的,所以直接lookAt会导致出现倒着跑的现象,这里用重新设置朝向的方法来解决。var targetPos = pointBox //目标位置点var offsetAngle =0//目标移动时的朝向偏移// //以下代码在多段路径时可重复执行var mtx =newTHREE.Matrix4()//创建一个4维矩阵// .lookAt ( eye : Vector3, target : Vector3, up : Vector3 ) : this,构造一个旋转矩阵,从eye 指向 target,由向量 up 定向。
mtx.lookAt(model.position, targetPos, model.up)//设置朝向
mtx.multiply(newTHREE.Matrix4().makeRotationFromEuler(newTHREE.Euler(0, offsetAngle,0)))var toRot =newTHREE.Quaternion().setFromRotationMatrix(mtx)//计算出需要进行旋转的四元数值
model.quaternion.slerp(toRot,0.2)}
progress += velocity;}else{
progress =0;}}};functionanimate(){requestAnimationFrame(animate);moveOnCurve();
renderer.render(scene, camera);};init();loadModel();makeCurve();animate();</script></body></html>
效果:
版权归原作者 Mr_Bobcp 所有, 如有侵权,请联系我们删除。