简介:
蒙皮动画:通过模拟人的运动来模拟3D物体的动画,游戏中也经常使用。
制作蒙皮动画的主要过程和注意点:
1. 制作蒙皮骨骼:
var material = new THREE.MeshBasicMaterial({color: 0xfff000,wireframe:true,skinning : true});
mesh = new THREE.SkinnedMesh(geometry,material);
mesh.position.y = 15;
注意这里的material中的 skinning: true 必须设置为true,否则蒙皮骨骼不随骨骼运动。
2. 制作骨头:
var bones =[];
var arm = new THREE.Bone();
arm.position.y = - 15;
bones.push(arm);
for(var i = 0 ;i<3;i++){
var bone = new THREE.Bone();
bone.position.y = 10;
arm.add(bone);
arm = bone;
bones.push(bone);
}
注意:这里的思路是先创建一个骨头arm ,然后循环创建n块骨头,分别添加到前一块骨头里。也就是 bone[0] 添加到arm中,bone[1] 添加到bone[0]中,最终实现一个骨头以此连接的整体骨头arm,后面用到。
注意2:骨头arm添加到mesh中的起始位置在mesh的中心点,所以这里可以设置position.y = - mesh的高度的一半,其他bone的位置以次相对添加它的bone。
3.制作骨架:
var skeleton = new THREE.Skeleton(bones);
4.mesh添加骨头并且骨架附体:
mesh.add(bones[0]);
mesh.bind(skeleton);
5.最后一步设置geometry每个顶点受哪些骨头的影响以及影响程度:
for ( var i = 0; i < geometry.vertices.length; i ++ ) {
var vertex = geometry.vertices[ i ];
var y = ( vertex.y + 15 );
var skinIndex = Math.floor( y / 10 );
var skinWeight = ( y % 10 ) / 10;
geometry.skinIndices.push( new THREE.Vector4( skinIndex, skinIndex + 1, 0, 0 ) );
geometry.skinWeights.push( new THREE.Vector4( 1 - skinWeight, skinWeight, 0, 0 ) );
}
注意:这里var y = ( vertex.y + 15 ); 是因为我们位移mesh时,geometry的vertices的值没有变化,所以每个值加了mesh的偏移值,geometry的vertices的值没有变化的解决方法可以设置geometry.verricesNeedUpdate = true;
注意:这里的意思每一层的节点受到该层对应的骨头的影响程度:
案例如下:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>蒙皮</title>
<style>
body{
margin:0;
}
</style>
</head>
<script src="../build/three.js"></script>
<script src="../js/controls/OrbitControls.js"></script>
<script>
function init() {
createScene();
buildAuxSystem();
addBox();
loop();
}
var scene,camera,renderer,width = window.innerWidth,height = window.innerHeight,controls;
var mesh;
function createScene() {
scene = new THREE.Scene;
camera = new THREE.PerspectiveCamera(45,width/height,1,1000);
camera.position.set(0,0,200);
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(new THREE.Color(0x333333),1);
renderer.setSize(width,height);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize",handleWindowResize,false)
}
function loop() {
renderer.render(scene,camera);
requestAnimationFrame(loop);
var time = Date.now() * 0.001;
for ( var i = 0; i < mesh.skeleton.bones.length; i ++ ) {
mesh.skeleton.bones[ i ].rotation.z = Math.sin( time ) * 2 / mesh.skeleton.bones.length;
}
}
function handleWindowResize() {
width = window.innerWidth;
height = window.innerHeight;
renderer.setSize(width,height);
camera.aspect = width/height;
camera.updateProjectionMatrix();
}
// 建立辅助设备系统
function buildAuxSystem(){
var gridHelper = new THREE.GridHelper(320,32);
scene.add(gridHelper);
// var axesHelper = new THREE.AxesHelper(320);
// scene.add(axesHelper);
controls = new THREE.OrbitControls(camera,renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.3;
controls.rotateSpeed = 0.35;
controls.enableKeys = false;
controls.update();
}
function addBox() {
var geometry = new THREE.BoxGeometry(10,30,10,1,9,1);
for ( var i = 0; i < geometry.vertices.length; i ++ ) {
var vertex = geometry.vertices[ i ];
var y = ( vertex.y + 15 );
var skinIndex = Math.floor( y / 10 );
var skinWeight = ( y % 10 ) / 10;
geometry.skinIndices.push( new THREE.Vector4( skinIndex, skinIndex + 1, 0, 0 ) );
geometry.skinWeights.push( new THREE.Vector4( 1 - skinWeight, skinWeight, 0, 0 ) );
}
var material = new THREE.MeshBasicMaterial({color: 0xfff000,wireframe:true,skinning : true});
mesh = new THREE.SkinnedMesh(geometry,material);
mesh.position.y = 15;
var bones =[];
var arm = new THREE.Bone();
arm.position.y = - 15;
bones.push(arm);
for(var i = 0 ;i<3;i++){
var bone = new THREE.Bone();
bone.position.y = 10;
arm.add(bone);
arm = bone;
bones.push(bone);
}
mesh.add(bones[0]);
var skeleton = new THREE.Skeleton(bones);
mesh.bind(skeleton);
var skeletonHelper = new THREE.SkeletonHelper(mesh);
scene.add(skeletonHelper);
scene.add(mesh);
}
</script>
<body onload ="init()">
</body>
</html>