THREE.js中的变形目标动画,用于自定义网格

时间:2014-10-30 20:18:25

标签: javascript three.js

我正在制作动画,该动画显示围绕轴的2D功能的旋转,以创建3D表面。我已经能够成功渲染表面,现在我正在尝试使用MorphTargets创建动画部分。

不幸的是,虽然我已成功将所有变形帧推入我的几何体中,但我无法让动画播放。我发现的所有动画示例都使用blender来导入模型,因此并不完全有用(许多也已过时)。

我看着变形马作为一个例子(http://threejs.org/examples/#webgl_morphtargets_horse),并试图尽可能地复制代码,但我没有成功。

这是我的代码初始化morphVerticeHolder,它是一个2D数组来保存每个动画帧的顶点

 //First indices of multiarray corresponds to morph frame, second to the vertice
 var morphVerticeHolder = [];
 for(var i = 0; i < 20; i++) {
   morphVerticeHolder[i] = [];
 }

这是我的代码沿着轴推动顶点。请注意,我同时也推动了我的变形顶点。 mI代表网格间隔。

for(var i = xstart; i <= xend; i+= mI) {
  geo.vertices.push(new THREE.Vector3(i,0,0));
  for(var j = 0; j < 20; j++) { //20 Frames of the morph animation
    morphVerticeHolder[j].push(new THREE.Vector3(i,0,0));
  }
}

此代码推送所有顶点。 i沿x轴范围,而j沿着theta范围,填充网格的顶点。

//Push the vertices
  var tmesh = 2*Math.PI/meshPoints; //Theta mesh interval
  verticeCounter = 0;
  for(var i = xstart; i <= xend; i+=mI) {
    var rMain = solveEquation(i);
    var rSecond = solveEquation(i+mI);
    var counter = 0;
    for(var j = 0; j < 2*Math.PI; j += tmesh) {
      geo.vertices.push(new THREE.Vector3(i, rMain*Math.cos(j/1000),rMain*Math.sin(j/1000)));
      for(var k = 0; k < 20; k++) {
        morphVerticeHolder[k].push(new THREE.Vector3(i, rMain*Math.cos(j*(k+1)/20),rMain*Math.sin(j*(k+1)/20)));
      }
    }
  }

除以1000是为了使原始网格开始接近0,然后使用变形顶点(从期望值的1/20到20/20范围内)将其旋转动画。

然后我推脸。您可以尝试解释我的算法,但基本上我想出了如何跟踪哪个顶点在哪里。

for(var i = 0; i < meshPoints; i++) {
    var sI = meshPoints*(i+1);
    var sI2 = meshPoints*(i+2);
    for(var j = 0; j < meshPoints-1; j ++) {
      if(i === 0) {
        //First Point, Fill end
        geo.faces.push(new THREE.Face3(sI+j, sI+j+1, 0));
        geo.faces.push(new THREE.Face3(sI+j+1, sI+j, 0));
        //Filll Body
        geo.faces.push(new THREE.Face3(sI+j, sI+j+1, sI2+j));
        geo.faces.push(new THREE.Face3(sI+j+1, sI+j, sI2+j));
        geo.faces.push(new THREE.Face3(sI+j+1, sI2+j, sI2+j+1));
        geo.faces.push(new THREE.Face3(sI2+j, sI+j+1, sI2+j+1));
      } else if(i === meshPoints-1) {
        //Last Point, Fill end
        geo.faces.push(new THREE.Face3(sI+j, sI+j+1, meshPoints-1));
        geo.faces.push(new THREE.Face3(sI+j+1, sI+j, meshPoints-1));
      } else {
        geo.faces.push(new THREE.Face3(sI+j, sI+j+1, sI2+j));
        geo.faces.push(new THREE.Face3(sI+j+1, sI+j, sI2+j));
        geo.faces.push(new THREE.Face3(sI+j+1, sI2+j, sI2+j+1));
        geo.faces.push(new THREE.Face3(sI2+j, sI+j+1, sI2+j+1));
      }
    }
  }

这是剩下的,初始化等等。

for(var k = 0; k < 20; k++) {
    geo.morphTargets.push( { name: "target" + k, vertices: morphVerticeHolder[k]} );
  }

  var uniforms = {
    resolution: { type: "v2", value: new THREE.Vector2 },
    zmax: { type: "f", value: maxz},
    zmin: { type: "f", value: minz}
  };
  var mat = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: document.getElementById('cubeVertexShader').innerHTML,
    fragmentShader: document.getElementById('cubeFragmentShader').innerHTML
  });
  functionObject = new THREE.Mesh( geo, mat);
  this.scene.add(functionObject);
  functionObject.name = 'current';

  this.animation = new THREE.MorphAnimation( functionObject, 'Revolution' );
  this.animation.play();

  this.setWithinRender(function() {
    this.animation.update(.1);
  });

this.setWitinRender将匿名函数放入THREE.js的渲染循环中(这是一个与THREE设置分开调用的函数。

正如我上面提到的,网格呈现,如果我在推动原始顶点时摆脱/ 1000,我得到整个表面。但是,如上所述设置的动画不会播放。有没有人对此有任何见解?

谢谢!

1 个答案:

答案 0 :(得分:3)

经过一些研究,深入研究源代码,我发现使用的材料必须将morphTargets属性设置为true。我曾尝试使用我正在使用的着色器材质,但是必须在顶点着色器中手动应用morphTargetInfluences。

因此,我将材料转换为

var mat = new THREE.MeshNormalMaterial( { color: 0x990000, morphTargets: true } );

一切都很好!