将Three.js场景导出到STL,保持动画完整 [英] Exporting Three.js scene to STL keeping animations intact

查看:111
本文介绍了将Three.js场景导出到STL,保持动画完整的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我渲染了Three.js场景,我想导出动画渲染后的外观.例如,动画播放了约100帧后,用户单击了export(导出),并且应该将场景照原样导出到STL.

I have a Three.js scene rendered and I would like to export how it looks after the animations have rendered. For example, after the animation has gone ~100 frames, the user hits export and the scene should be exported to STL just as it is at that moment.

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

From what I've tried (using STLExporter.js, that is), it seems to export the model using the initial positions only.

如果已经有解决方法,或者可以直接解决,那么我很乐意朝这个方向努力.

If there's already a way to do this, or a straightforward work around, I would appreciate a nudge in that direction.

更新:在深入研究内部结构之后,我(至少从表面上)弄清楚了为什么STLExporter无法正常工作. STLExporter查找所有对象,并要求它们提供Geometry对象的顶点和面.我的模型有一堆被蒙皮的骨头.在动画步骤中,骨骼将被更新,但是这些更新不会传播到原始的Geometry对象.我知道这些变换的顶点正在计算中,并且存在于某个位置(它们显示在画布上).

Update: After a bit more digging into the internals, I've figured out (at least superficially) why STLExporter did not work. STLExporter finds all objects and asks them for the vertices and faces of the Geometry object. My model has a bunch of bones that are skinned. During the animation step, the bones get updated, but these updates does not propagate to the original Geometry object. I know these transformed vertices are being calculated and exist somewhere (they get displayed on the canvas).

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

The question is where are these transformed vertices and faces stored and can I access them to export them as an STL?

推荐答案

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

The question is where are these transformed vertices and faces stored and can I access them to export them as an STL?

不幸的是,答案无处可寻.这些都是通过传入多个大型数组通过调用WebGL函数在GPU上计算得出的.

The answer to this, unfortunately, is nowhere. These are all computed on the GPU through calls to WebGL functions by passing in several large arrays.

要解释如何计算该值,我们首先使用此骑士示例,回顾一下动画的工作原理.以供参考. SkinnedMesh 对象除其他外还包含一个骨架(由许多骨骼)和一堆顶点.它们开始以称为绑定姿势.每个顶点都绑定到0-4根骨骼,如果这些骨骼移动,则顶点将移动,从而创建动画.

To explain how to calculate this, let's first review how animation works, using this knight example for reference. The SkinnedMesh object contains, among other things, a skeleton (made of many Bones) and a bunch of vertices. They start out arranged in what's known as a bind pose. Each vertex is bound to 0-4 bones and if those bones move, the vertexes will move, creating animation.

如果要以我们的骑士为例,请在半摆期间暂停动画,然后尝试

If you were to take our knight example, pause the animation mid-swing, and try the standard STL exporter, the STL file generated would be exactly this pose, not the animated one. Why? Because it simply looks at mesh.geometry.vertices, which are not changed from the original bind pose during animation. Only the bones experience change and the GPU does some math to move the vertices corresponding to each bone.

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

That math to move each vertex is pretty straight forward - transform the bind-pose vertex position into bone-space and then from bone-space to global-space before exporting.
Adapting the code from here, we add this to the original exporter:

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文件:

This yields STL files that look like:

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

这篇关于将Three.js场景导出到STL,保持动画完整的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆