我的目标是拥有一个像3骨骼骨架的东西,每个关节上只有一个球体,例如,肩膀上有一个球体的手臂,一个在肘部,一个在手腕上。
我找到的所有东西都使用了一些JSON加载器,它可以完成构建骨架的所有工作。复制Three.js的文档,我制作了这段代码,它似乎在(0,0,0)点显示3个球体。
//all this lies in my init() function
var bones = [];
var shoulder = new THREE.Bone();
var elbow = new THREE.Bone();
var wrist = new THREE.Bone();
//link the bones
shoulder.add(elbow);
elbow.add(wrist);
//set the default position of the bones
shoulder.position.set(1, 1, 1);
elbow.position.set(1, 1, 2);
wrist.position.set(1, 1, 3);
//put all the bones in an array for the skeleton
bones.push(shoulder);
bones.push(elbow);
bones.push(wrist);
//this one is a global variable in my script
skel = new THREE.Skeleton(bones);
var m = new THREE.MeshPhongMaterial( { color: 0xffff00, emissive: 0x072534, shading: THREE.SmoothShading} );
//create the geometry for the spheres
var g1 = new THREE.SphereGeometry(0.2, 100, 100);
var g2 = new THREE.SphereGeometry(0.2, 100, 100);
var g3 = new THREE.SphereGeometry(0.2, 100, 100);
for (var i = 0; i < g1.vertices.length; i++){
// put the indices of the bones and the associated weights
//on each vertex of the geometry
g1.skinIndices[i] = new THREE.Vector4(0, 0, 0, 0);
g1.skinWeights[i] = new THREE.Vector4(1, 0, 0, 0);
g2.skinIndices[i] = new THREE.Vector4(1, 0, 0, 0);
g2.skinWeights[i] = new THREE.Vector4(1, 0, 0, 0);
g3.skinIndices[i] = new THREE.Vector4(2, 0, 0, 0);
g3.skinWeights[i] = new THREE.Vector4(1, 0, 0, 0);
}
//create the meshes
var s1 = new THREE.SkinnedMesh(g1, m);
var s2 = new THREE.SkinnedMesh(g2, m);
var s3 = new THREE.SkinnedMesh(g3, m);
//bind the meshes with the bones.
//I guesse this is the problematic part
s1.add(skel.bones[0]);
s1.bind(skel);
s2.add(skel.bones[1]);
s2.bind(skel);
s3.add(skel.bones[2]);
s3.bind(skel);
scene.add(s1);
scene.add(s2);
scene.add(s3);
我有一个render()
和一个animate()
函数,可以显示一些简单的几何体。 (我没有把它们放在这里以避免显示太多不相关的代码)
实际上,我不知道s1.add(skel.bones[0])
和s1.bind(skel)
到底做了什么:我在一个例子中看到了这个并尝试复制我看到的内容,但它没有做我想要的事情去做。我只是希望将每个球体放在不同的位置,并且能够将骨架用于动画目的。
答案 0 :(得分:1)
注意,英语不是我的自然语言!
我同意,我找不到任何真正的基础教程!这就是我为什么要进行实验的原因。事情有点困难。有一些必要的步骤,“s1.add(skel.bones [0])和s1.bind(skel)真正做什么”只是其中之一。
首先,您必须创建彼此依赖的骨骼。然后,您必须根据特定几何计算顶点对骨骼的依赖关系。每个顶点最多可以包含四个骨骼。在示例中,我只计算了两个骨骼。
现在从骨骼创建一个骨架。下一步是骨骼,骨架和网格的连接:
skeleton = new THREE.Skeleton( bones );
mesh.add( bones[ 0 ] ); // add the first bone to the mesh
mesh.bind( skeleton ); // connect the skeleton
要查看骨架使用情况:
skeletonHelper = new THREE.SkeletonHelper( mesh );
示例中的骨骼是使用函数createBones(positionY, height, boneCount)
查找不同的函数skinIndexWeigtLatheBody()
和skinIndexWeightCylinder(geometry)
。气缸和车床比球体更容易计算,因为顶点更系统,更简单。
最后用骨头制作动画。 mesh.skeleton.bones.rotation.x = ...
剧本:
document.getElementById('move').checked = false;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 20000 );
camera.position.set(-200,100,200);
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xeeeeee, 1 );
container = document.createElement('div');
document.body.appendChild(container);
container.appendChild(renderer.domElement);
orbit = new THREE.OrbitControls( camera, renderer.domElement );
orbit.enableZoom = true;
light1 = new THREE.PointLight(0xffffff,1,0);
light1.position.set( -100, 300, 1000 );
scene.add(light1);
clock = new THREE.Clock(true);
geometryNeck = new THREE.SphereGeometry(10, 6, 6);
rSegmentCount = 8; // radial segments
bodyHeight = 80; // body: LatheGeometry
boneBodyCount = 3;
boneBodySegCount = 3;
bodySegHeightCount = boneBodySegCount * boneBodyCount; // segments total
boneBodyHeight = bodyHeight / boneBodyCount ;
outlineBody = [
[0.01,-bodyHeight ],[20,-78],[35,-74],[42,-65],[45,-55],[44,-45],[30,-27],[10,0] // from -bodyHeight to 0
];
pointsBody = []; // Vector2 points x,y
for ( var i = 0; i < outlineBody.length ; i++ ) {
pointsBody.push(new THREE.Vector2(outlineBody[i][0], outlineBody[i][1]))
}
geometryBody = new THREE.LatheGeometry( pointsBody, rSegmentCount );
skinIndexWeigtLatheBody(); // function
//---
limbRadius = 4;
limbHeight = 60;
boneLimbCount = 3;
boneLimbSegCount = 1;
limbRadSegCount = 6; // or 0.5*rSegmentCount;
limbHeightSegCount = boneLimbSegCount*boneLimbCount;
boneLimbHeight = limbHeight/ boneLimbCount ;
limbHalfHeight = limbHeight * 0.5;
openEnded = false;
geometryLimbs = [];
for (var i=0; i<2;i++){ // 2 limbs
geometryLimbs[i] = new THREE.CylinderGeometry(limbRadius,limbRadius,limbHeight,limbRadSegCount,limbHeightSegCount,openEnded);
}
bonesBody = createBones( 0 , -boneBodyHeight, boneBodyCount); // function
bonesLimbs = [];
for (var i=0; i<2; i++){
// function
bonesLimbs[i] = createBones(-limbHalfHeight, boneLimbHeight, boneLimbCount);
}
material = new THREE.MeshPhongMaterial({ color: 0x896215, emissive: 0xa96415, wireframe: true, skinning: true});
meshNeck = new THREE.Mesh(geometryNeck, material);
meshBody = new THREE.SkinnedMesh(geometryBody, material );
meshBody.add( meshNeck );
geometrysLimbs = [];
meshesLimbs = [];
for (var i=0; i<2; i++){
skinIndexWeightCylinder(geometryLimbs[i]); // function
meshesLimbs[i] = new THREE.SkinnedMesh(geometryLimbs[i], material);
}
meshesLimbs[0].rotation.z = 1.57; // arm right
meshesLimbs[0].position.x = -limbHalfHeight;
meshesLimbs[1].rotation.z = -1.57; // arm left
meshesLimbs[1].position.x = limbHalfHeight;
skeletonBody = new THREE.Skeleton( bonesBody );
meshBody.add( bonesBody[ 0 ] );
meshBody.bind( skeletonBody );
scene.add( meshBody );
skeletonHelperBody = new THREE.SkeletonHelper( meshBody );
scene.add( skeletonHelperBody );
skeletonsLimbs = [];
skeletonHelperLimbs = [];
for (var i=0; i<2; i++){
skeletonsLimbs[i] = new THREE.Skeleton( bonesLimbs[i] );
meshesLimbs[i].add( bonesLimbs[i][0] );
meshesLimbs[i].bind( skeletonsLimbs[i] );
meshBody.add( meshesLimbs[i] );
skeletonHelperLimbs[i] = new THREE.SkeletonHelper( meshesLimbs[i] );
scene.add( skeletonHelperLimbs[i] );
}
//........................................................................
animate();
//........................................................................
function skinIndexWeigtLatheBody(){
for ( var i =0; i<geometryBody.vertices.length; i++ ) {
vertexY = geometryBody.vertices[ i ].y ; // only y dependet
skinIndex = boneBodyCount-1 - Math.floor((i % bodySegHeightCount)/ boneBodySegCount) ; // skin-index, bone 0 top
skinWeight = ( (bodyHeight - vertexY) % boneBodyHeight ) / boneBodyHeight ; // weight
geometryBody.skinIndices.push( new THREE.Vector4( skinIndex, skinIndex+1, 0, 0 ) ); // allocation (2 from max. 4 bones)
geometryBody.skinWeights.push( new THREE.Vector4( 1-skinWeight, skinWeight , 0, 0 ) );
}
}
function skinIndexWeightCylinder(geometry){
for ( var i = 0; i < geometry.vertices.length; i ++ ) {
vertexY = geometry.vertices[ i ].y + limbHalfHeight; // only y dependet
skinIndex = Math.floor( vertexY / boneLimbHeight ); // bone 0: bottom
skinWeight = ( vertexY % boneLimbHeight) / boneLimbHeight; // weight
geometry.skinIndices.push( new THREE.Vector4( skinIndex, skinIndex+1, 0, 0 ) ); // allocation (2 from max. 4 bones)
geometry.skinWeights.push( new THREE.Vector4( 1-skinWeight, skinWeight , 0, 0 ) );
}
}
function createBones(positionY, height, boneCount){
bones = []; // base: bone 0
basicBone = new THREE.Bone(); // base bone, length 0, not visible
bones.push( basicBone );
basicBone.position.y = positionY;
prevBone = basicBone; // previous bone for further
for ( var i = 1; i < boneCount+1 ; i ++ ) {
bone = prevBone.clone();
bone.position.y = height; // at the right distance ...
bones.push( bone ); // lay down
prevBone.add( bone ); // ... each to the previous bone
prevBone = bone; // new previous bone
}
return bones;
}
function animate() {
requestAnimationFrame( animate );
var time = clock.getElapsedTime();
if ( document.getElementById("move").checked) { // HTML: <input type="checkbox" id="move"> move
for ( var i = 1; i < meshBody.skeleton.bones.length - 2; i ++ ) {
meshBody.skeleton.bones[ i ].rotation.z = 0.5*Math.sin( 1.8*time ) / meshBody.skeleton.bones.length;
}
for ( var i = 1; i < boneLimbCount+1; i++ ) {
meshesLimbs[0].skeleton.bones[ i ].rotation.x = 0.6*Math.cos( 1.2*time ) / boneLimbCount;
meshesLimbs[0].skeleton.bones[ i ].rotation.z = 0.6*Math.sin( 1.2*time ) / boneLimbCount;
meshesLimbs[1].skeleton.bones[ i ].rotation.x = 0.6*Math.cos( 1.2*time ) / boneLimbCount;
meshesLimbs[1].skeleton.bones[ i ].rotation.z = 0.6*Math.sin( 3.14+1.2*time ) / boneLimbCount;
}
meshNeck.rotation.x = -0.20*(0.8+Math.sin( -1.57+1.2*time ));
meshNeck.rotation.y = -0.15*(0.6+Math.sin( -1.57+1.9*time ));
meshBody.rotation.x = 0.2;
skeletonHelperBody.update();
for ( var j = 0; j < 2; j++ ){
skeletonHelperLimbs[j].update();
}
}
renderer.render( scene, camera );
}
<input type="checkbox" id="move"> move
<script src="../js/three.min.84.js"></script>
<script src="../js/OrbitControls.js"></script>
示例位于http://threejs.hofk.de/ Skeleton Basic。
“Hummel Mara”(大黄蜂玛拉)展示了一个扩展的例子。一个带骨头的大黄蜂!它基于之前的骨架例子。 //评论是用德语写的,但是用英语命名的变量。
Knochen - bone,Skelet - skeleton,Knoten - vertex,( - node ...),Ziffer - number,Tafel - table,bewegen - move ...带翻译德语/英语,如dict.cc或google tanslater - 我也是。
顺便说一下,不要在开头使用100个球段。