【问题标题】:Exporting Three.js scene to STL keeping animations intact将 Three.js 场景导出到 STL,保持动画不变
【发布时间】:2016-01-19 19:25:16
【问题描述】:

我渲染了一个 Three.js 场景,我想导出它在动画渲染后的样子。例如,在动画播放了大约 100 帧之后,用户点击导出,场景应该被导出为 STL,就像当时一样。

根据我的尝试(即使用STLExporter.js),它似乎只使用初始位置导出模型。

如果已经有办法做到这一点,或者有一个简单的解决方法,我会很感激朝那个方向轻推。

更新:在深入了解内部结构之后,我已经(至少在表面上)弄清楚了 STLExporter 不起作用的原因。 STLExporter 查找所有对象并询问他们Geometry 对象的顶点和面。我的模型有一堆被剥皮的骨头。在动画步骤中,骨骼得到更新,但这些更新不会传播到原始的Geometry 对象。我知道这些转换后的顶点正在计算并存在于某处(它们显示在画布上)。

问题是这些转换后的顶点和面存储在哪里,我可以访问它们以将它们导出为 STL?

【问题讨论】:

  • 请参阅this SO 问题,解释不同类型的 3D 矩阵。
  • STL 标签用于 C++ 标准模板库,这是您的意图吗?
  • 不。现在修复标签。

标签: javascript three.js export


【解决方案1】:

问题是这些转换后的顶点和面存储在哪里,我可以访问它们以将它们导出为 STL?

不幸的是,这个问题的答案无处可寻。这些都是在 GPU 上通过传入几个大数组调用 WebGL 函数来计算的。

为了解释如何计算这个,让我们首先回顾一下动画是如何工作的,使用this knight example作为参考。 SkinnedMesh 对象包括一个骨架(由许多 Bones 组成)和一堆顶点。他们开始以所谓的bind pose 排列。每个顶点绑定到 0-4 个骨骼,如果这些骨骼移动,顶点也会移动,从而创建动画。

如果您以我们的骑士为例,在挥杆中暂停动画,并尝试standard STL exporter,生成的 STL 文件将正是这个姿势,而不是动画姿势。为什么?因为它只是查看mesh.geometry.vertices,它们在动画期间不会从原始绑定姿势发生变化。只有骨骼会发生变化,GPU 会做一些数学运算来移动每个骨骼对应的顶点。

移动每个顶点的数学非常简单 - 将绑定姿势顶点位置转换为骨骼空间,然后在导出之前从骨骼空间转换为全局空间。
改编 here 的代码,我们将其添加到原始导出器中:

vector.copy( vertices[ vertexIndex ] );
boneIndices = [];   //which bones we need
boneIndices[0] = mesh.geometry.skinIndices[vertexIndex].x;
boneIndices[1] = mesh.geometry.skinIndices[vertexIndex].y;
boneIndices[2] = mesh.geometry.skinIndices[vertexIndex].z;
boneIndices[3] = mesh.geometry.skinIndices[vertexIndex].w;

weights = [];   //some bones impact the vertex more than others
weights[0] = mesh.geometry.skinWeights[vertexIndex].x;
weights[1] = mesh.geometry.skinWeights[vertexIndex].y;
weights[2] = mesh.geometry.skinWeights[vertexIndex].z;
weights[3] = mesh.geometry.skinWeights[vertexIndex].w;

inverses = [];  //boneInverses are the transform from bind-pose to some "bone space"
inverses[0] = mesh.skeleton.boneInverses[ boneIndices[0] ];
inverses[1] = mesh.skeleton.boneInverses[ boneIndices[1] ];
inverses[2] = mesh.skeleton.boneInverses[ boneIndices[2] ];
inverses[3] = mesh.skeleton.boneInverses[ boneIndices[3] ];

skinMatrices = [];  //each bone's matrix world is the transform from "bone space" to the "global space"
skinMatrices[0] = mesh.skeleton.bones[ boneIndices[0] ].matrixWorld;
skinMatrices[1] = mesh.skeleton.bones[ boneIndices[1] ].matrixWorld;
skinMatrices[2] = mesh.skeleton.bones[ boneIndices[2] ].matrixWorld;
skinMatrices[3] = mesh.skeleton.bones[ boneIndices[3] ].matrixWorld;

var finalVector = new THREE.Vector4();
for(var k = 0; k<4; k++) {
    var tempVector = new THREE.Vector4(vector.x, vector.y, vector.z);
    //weight the transformation
    tempVector.multiplyScalar(weights[k]);
    //the inverse takes the vector into local bone space
    tempVector.applyMatrix4(inverses[k])
    //which is then transformed to the appropriate world space
    .applyMatrix4(skinMatrices[k]);
    finalVector.add(tempVector);
}

output += '\t\t\tvertex ' + finalVector.x + ' ' + finalVector.y + ' ' + finalVector.z + '\n';

这会生成如下所示的 STL 文件:

完整代码可在https://gist.github.com/kjlubick/fb6ba9c51df63ba0951f获取

【讨论】:

  • 您如何对link 进行同样的更改?
  • 似乎那个导出器不再工作了,因为我有一个空文件。知道如何在新的version 中处理动画吗?我试图复制代码,但几何结构不同,我没有足够的知识来适应它
【解决方案2】:

经过一周的努力,我设法修改了代码,将 morphTarget 数据包含在最终的 stl 文件中。您可以在https://gist.github.com/jcarletto27/e271bbb7639c4bed2427找到 Kevin 更改的修改代码

由于 JS 不是我最喜欢的语言,它并不漂亮,但它可以轻松地工作。希望除了我之外有人能从中得到一些用处!

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2014-06-09
  • 2019-08-09
  • 2015-08-16
  • 2016-09-12
  • 2018-11-23
  • 1970-01-01
  • 1970-01-01
  • 2013-04-18
相关资源
最近更新 更多