three.js:如何使用骨骼动画获取更新后的顶点?

3
与此堆栈溢出问题中的问题Three.js: Get updated vertices with morph targets类似,我对如何获取具有骨骼动画的网格的“实际”顶点位置感兴趣。
我尝试打印出位置值,但它们从未实际更新(据我所理解,这是因为它们是在GPU上计算的,而不是CPU)。上面问题的答案提到了在CPU上执行与GPU相同的计算以获取形态目标动画的最新顶点位置,但是否有一种方法可以针对骨骼动画执行相同的方法?如果有的话,怎么做?
另外,对于形态目标,有人指出该代码已经存在于Mesh.raycast函数中(https://github.com/mrdoob/three.js/blob/master/src/objects/Mesh.js#L115)。但是,我不知道raycast如何处理骨骼动画网格-它如何知道面的更新位置?
谢谢!
1个回答

5

一段时间前,three.js论坛上曾经讨论过类似的话题。我在那里展示了一个计算蒙皮网格每帧AABB的代码片段。该代码实际上通过JavaScript执行了与顶点着色器中相同的顶点位移。该程序如下:

function updateAABB( skinnedMesh, aabb ) {

    var skeleton = skinnedMesh.skeleton;
    var boneMatrices = skeleton.boneMatrices;
    var geometry = skinnedMesh.geometry;

    var index = geometry.index;
    var position = geometry.attributes.position;
    var skinIndex = geometry.attributes.skinIndex;
    var skinWeigth = geometry.attributes.skinWeight;

    var bindMatrix = skinnedMesh.bindMatrix;
    var bindMatrixInverse = skinnedMesh.bindMatrixInverse;

    var i, j, si, sw;

    aabb.makeEmpty();

    // 

    if ( index !== null ) {

        // indexed geometry

        for ( i = 0; i < index.count; i ++ ) {

            vertex.fromBufferAttribute( position, index[ i ] );
            skinIndices.fromBufferAttribute( skinIndex, index[ i ] );
            skinWeights.fromBufferAttribute( skinWeigth, index[ i ] );

            // the following code section is normally implemented in the vertex shader

            vertex.applyMatrix4( bindMatrix ); // transform to bind space
            skinned.set( 0, 0, 0 );

            for ( j = 0; j < 4; j ++ ) {

                si = skinIndices.getComponent( j );
                sw = skinWeights.getComponent( j );
                boneMatrix.fromArray( boneMatrices, si * 16 );

                // weighted vertex transformation

                temp.copy( vertex ).applyMatrix4( boneMatrix ).multiplyScalar( sw );
                skinned.add( temp );

            }

            skinned.applyMatrix4( bindMatrixInverse ); // back to local space

            // expand aabb

            aabb.expandByPoint( skinned );

        }

    } else {

        // non-indexed geometry

        for ( i = 0; i < position.count; i ++ ) {

            vertex.fromBufferAttribute( position, i );
            skinIndices.fromBufferAttribute( skinIndex, i );
            skinWeights.fromBufferAttribute( skinWeigth, i );

            // the following code section is normally implemented in the vertex shader

            vertex.applyMatrix4( bindMatrix ); // transform to bind space
            skinned.set( 0, 0, 0 );

            for ( j = 0; j < 4; j ++ ) {

                si = skinIndices.getComponent( j );
                sw = skinWeights.getComponent( j );
                boneMatrix.fromArray( boneMatrices, si * 16 );

                // weighted vertex transformation

                temp.copy( vertex ).applyMatrix4( boneMatrix ).multiplyScalar( sw );
                skinned.add( temp );

            }

            skinned.applyMatrix4( bindMatrixInverse ); // back to local space

            // expand aabb

            aabb.expandByPoint( skinned );

        }

    }

    aabb.applyMatrix4( skinnedMesh.matrixWorld );

}

同时,对于morph目标,有人指出此代码已经存在于Mesh.raycast函数中。可以使用射线投射到形变的网格上,但不能对蒙皮网格进行射线投射。Mesh.raycast()中的代码已经非常复杂,我认为在进一步增强之前需要进行严格的重构。同时你可以使用提供的代码片段自行构建解决方案。顶点位移逻辑实际上是最复杂的部分。
实时演示:https://jsfiddle.net/fnjkeg9x/1/ three.js R107

2
更新:在 https://github.com/mrdoob/three.js/pull/19178 - r116 中添加了对蒙皮网格的光线投射。 - Suma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接