Three.js骨骼笔记
程序员文章站
2022-03-26 14:40:31
...
Three.js骨骼笔记
版权声明:本文为CSDN博主「郭隆邦技术博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u014291990/article/details/103353337
郭隆邦老师提供的代码,相信也有小伙伴没运行出来
稍作修改,能运行出个样子,但是还有报错
用代码的小伙伴记得修改js的url
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="/three.js/three.js"></script>
<script src="/three.js/OrbitControls.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<script>
/**
* 创建场景对象
*/
var scene = new THREE.Scene();
/**
* 创建网格模型
*/
//var geometry=new THREE.OctahedronGeometry(60);//创建一个立方体几何对象
/**
* 创建骨骼网格模型SkinnedMesh
*/
// 创建一个圆柱几何体,高度120,顶点坐标y分量范围[-60,60]
var geometry = new THREE.CylinderGeometry(5, 10, 120, 50, 300);
geometry.translate(0, 60, 0); //平移后,y分量范围[0,120]
console.log("name", geometry.vertices); //控制台查看顶点坐标
//
/**
* 设置几何体对象Geometry的蒙皮索引skinIndices、权重skinWeights属性
* 实现一个模拟腿部骨骼运动的效果
*/
//遍历几何体顶点,为每一个顶点设置蒙皮索引、权重属性
//根据y来分段,0~60一段、60~100一段、100~120一段
for (var i = 0; i < geometry.vertices.length; i++) {
var vertex = geometry.vertices[i]; //第i个顶点
if (vertex.y <= 60) {
// 设置每个顶点蒙皮索引属性 受根关节Bone1影响
geometry.skinIndices.push(new THREE.Vector4(0, 0, 0, 0));
// 设置每个顶点蒙皮权重属性
// 影响该顶点关节Bone1对应权重是1-vertex.y/60
geometry.skinWeights.push(new THREE.Vector4(1 - vertex.y / 1000, 0, 0, 0));
} else if (60 < vertex.y && vertex.y <= 60 + 40) {
// Vector4(1, 0, 0, 0)表示对应顶点受关节Bone2影响
geometry.skinIndices.push(new THREE.Vector4(1, 0, 0, 0));
// 影响该顶点关节Bone2对应权重是1-(vertex.y-60)/40
geometry.skinWeights.push(new THREE.Vector4(1 - (vertex.y - 60) / 1000, 0, 0, 0));
} else if (60 + 40 < vertex.y && vertex.y <= 60 + 40 + 20) {
// Vector4(2, 0, 0, 0)表示对应顶点受关节Bone3影响
geometry.skinIndices.push(new THREE.Vector4(2, 0, 0, 0));
// 影响该顶点关节Bone3对应权重是1-(vertex.y-100)/20
geometry.skinWeights.push(new THREE.Vector4(1 - (vertex.y - 100) / 1000, 0, 0, 0));
}
}
// 材质对象
var material = new THREE.MeshPhongMaterial({
skinning: true, //允许蒙皮动画
// wireframe:true,
});
// 创建骨骼网格模型
var SkinnedMesh = new THREE.SkinnedMesh(geometry, material);
SkinnedMesh.position.set(50, 120, 50); //设置网格模型位置
SkinnedMesh.rotateX(Math.PI); //旋转网格模型
scene.add(SkinnedMesh); //网格模型添加到场景中
/**
* 骨骼系统
*/
var Bone1 = new THREE.Bone(); //关节1,用来作为根关节
var Bone2 = new THREE.Bone(); //关节2
var Bone3 = new THREE.Bone(); //关节3
// 设置关节父子关系 多个骨头关节构成一个树结构
Bone1.add(Bone2);
Bone2.add(Bone3);
// 设置关节之间的相对位置
//根关节Bone1默认位置是(0,0,0)
Bone2.position.y = 60; //Bone2相对父对象Bone1位置
Bone3.position.y = 40; //Bone3相对父对象Bone2位置
// 所有Bone对象插入到Skeleton中,全部设置为.bones属性的元素
var skeleton = new THREE.Skeleton([Bone1, Bone2, Bone3]); //创建骨骼系统
// console.log(skeleton.bones);
// 返回所有关节的世界坐标
// skeleton.bones.forEach(elem => {
// console.log(elem.getWorldPosition(new THREE.Vector3()));
// });
//骨骼关联网格模型
SkinnedMesh.add(Bone1); //根骨头关节添加到网格模型
SkinnedMesh.bind(skeleton); //网格模型绑定到骨骼系统
console.log(SkinnedMesh);
/**
* 骨骼辅助显示
*/
var skeletonHelper = new THREE.SkeletonHelper(SkinnedMesh);
scene.add(skeletonHelper);
// 转动关节带动骨骼网格模型出现弯曲效果 好像腿弯曲一样
skeleton.bones[1].rotation.x = 0.1;
skeleton.bones[2].rotation.x = 0.1;
/**
* 光源设置
*/
//点光源
var point = new THREE.PointLight(0xFDFEFF);
point.position.set(200, 800, 300);//点光源位置
scene.add(point);//点光源添加到场景中
//点光源2
//var point2=new THREE.PointLight(0xff0000);
//point2.position.set(-400,-200,-300);//点光源位置
//scene.add(point2);//点光源添加到场景中
//环境光
var ambient = new THREE.AmbientLight(0x444444);
scene.add(ambient);
/**
* 相机设置
*/
var width = window.innerWidth;//窗口宽度
var height = window.innerHeight;//窗口高度
var k = width / height;//窗口宽高比
var s = 200;//三维场景缩放系数
//创建相机对象
var camera = new THREE.PerspectiveCamera(60, width / height, 1, 1000);
camera.position.set(292, 109, 268);//设置相机位置
camera.lookAt(scene.position);//设置相机方向(指向的场景对象)
/**
* 创建渲染器对象
*/
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
renderer.setClearColor(0xb9d3ff, 1);//设置背景颜色
document.body.appendChild(renderer.domElement);//body元素中插入canvas对象
var n = 0;
var T = 50;
var step = 0.01;
// 渲染函数
function render() {
renderer.render(scene, camera);
requestAnimationFrame(render);
n += 1;
if (n < T) {
// 改变骨关节角度
skeleton.bones[0].rotation.x = skeleton.bones[0].rotation.x - step;
skeleton.bones[1].rotation.x = skeleton.bones[1].rotation.x + step;
skeleton.bones[2].rotation.x = skeleton.bones[2].rotation.x + 2 * step;
}
if (n < 2 * T && n > T) {
skeleton.bones[0].rotation.x = skeleton.bones[0].rotation.x + step;
skeleton.bones[1].rotation.x = skeleton.bones[1].rotation.x - step;
skeleton.bones[2].rotation.x = skeleton.bones[2].rotation.x - 2 * step;
}
if (n === 2 * T) {
n = 0;
}
}
render();
</script>
</body>
</html>