如何在aframe中实现复杂模型

时间:2017-04-26 22:16:07

标签: three.js aframe

我对aframe和ECS建模技术很陌生,所以我可能还没有完全掌握应该如何使用这种架构。

我想模拟像机器人手臂这样的东西:在一个简化版本中,它是一个基础,在旋转器和手臂本身之上。该模型从单个json文件加载,并由不同部分的几个嵌套对象组成。

如果我希望能够独立控制不同的自由度(这意味着设置object.rotation - 对象本身的不同子项上的值),那么如何在aframe中实现这样的事情?

我想到的一件事是将模型文件的加载实现为一个组件,并将每个自由度作为一个单独的组件。所以基本上是这样的:

<a-entity robot-model="..." base-rotation="123" arm-pitch="10" />

或者,对于像这样的事情,使用registerPrimitive会更好吗?

我的第一次看法是这样的:

registerComponent('robot', {
  schema: {type: 'asset'},
  update() {
    // - load and parse model using THREE.ObjectLoader
    // - once ready, assign property this.parts with the various
    //   parts of the robot-arm
  }
});

registerComponent('dof-1', {
  schema: {type: 'number'},
  dependencies: ['robot'],
  init() {
    this.robot = this.el.components.robot;
  },
  tick(t, dt) {
    if (!this.robot.parts) { return; } // not ready yet
    // update values (left out here: acceleration etc)
    this.robot.parts.dof1.rotation.x = this.data;
  }
});

// more parts / dof implemented likewise

1 个答案:

答案 0 :(得分:3)

我假设您已经使用Blender,Maya或Cinema4D等软件创建并装配了3D模型。如果没有,文章Animation from Blender to three.js是一个很好的起点。

完成上述操作后,您可以使用支持蒙皮/装配的任何格式将模型导入A-Frame。 THREE.ObjectLoader(.json)或THREE.GLTFLoader(.gltf)是很好的选择,并且已经存在包装这些加载器的A-Frame组件。假设你正在使用JSON和object-model component from A-Frame Extras,你可以这样做:

<a-entity object-model="src: url(my-model.json)"></a-entity>

此时你应该在场景中看到一个模型,没有编写任何JavaScript,但它还没有动画。如果您知道自己想要的动画,可以使用相同的建模软件在关键帧或变形目标中创建动画:Blender,Maya或Cinema4D。假设您在导出模型时包含动画,可以使用animation-mixer组件(也来自A-Frame Extras),如下所示:

<a-entity object-model="src: url(my-model.json)"
          animation-mixer="clip: *;"></a-entity>

这将立即播放所有动画。您可以使用剪辑名称而不是*来播放特定的动画。

如果您的动画需要在运行时计算,并且无法融入模型中,则您需要编写自定义组件。这很快变得复杂,但基础知识并不太糟糕:

<a-entity object-model="src: url(my-model.json)"
          custom-animation></a-entity>

和JS:

AFRAME.registerComponent('custom-animation', {
  tick: function (t, dt) {
    var mesh = this.el.getObject3D('mesh');

    // With complex models, you may need to loop over `mesh.children`
    // in case the mesh you want to animate is a child of another 
    // object in your model file.
    if (!mesh || !mesh.isSkinnedMesh) { return; }

    mesh.traverse(function (node) {
      if (node.isBone && node.name === 'arm') {
        node.rotation.x += dt * Math.PI / 1000;
      }
    });
  }
});