我有渲染的Three.js场景,我想导出动画渲染后的外观。例如,在动画大约100帧后,用户点击导出,场景应该像当时那样导出到STL。
根据我的尝试(使用STLExporter.js,即),似乎只使用初始位置导出模型。
如果已经有办法做到这一点,或者做一个简单的工作,我会很感激在那个方向上轻推。
更新:在进一步深入了解内部结构之后,我已经想出(至少表面上看)STLExporter无法正常工作的原因。 STLExporter查找所有对象并询问它们Geometry
对象的顶点和面。我的模型有一堆被剥皮的骨头。在动画步骤期间,骨骼会更新,但这些更新不会传播到原始Geometry
对象。我知道这些变换顶点正在计算并存在于某处(它们会在画布上显示)。
问题是哪里这些变换的顶点和面存储了,我可以访问它们以将它们导出为STL吗?
答案 0 :(得分:8)
问题是这些转换的顶点和面存储在哪里,我可以访问它们以将它们导出为STL吗?
遗憾的是,答案是无处可去的。这些都是通过传入几个大型数组来调用WebGL函数在GPU上计算的。
为了解释如何计算这一点,让我们首先回顾动画的工作原理,使用this knight example作为参考。 SkinnedMesh对象包含一个骨架(由许多Bone s组成)和一堆顶点。他们开始安排在所谓的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文件:
答案 1 :(得分:3)
经过一周的脱发后,我设法修改代码,在最终的stl文件中包含morphTarget数据。你可以在https://gist.github.com/jcarletto27/e271bbb7639c4bed2427
找到凯文改变的修改后的代码由于JS不是我喜欢的语言,它并不漂亮,但是它可以毫不费力地工作。希望除了我之外,有人可以使用它!