0

我有一个搅拌机模型,上面有一些形状键。我导出这个模型并在threejs中使用它。可以说这是一个立方体。然后我创建了 Three.Points,在这个模型(即立方体)的顶点上绘制小球体。

var cube = loadGLTFFromBlender(gltfFile); // This loads the model
var points = new THREE.Points(cube.geometry, pointMaterial); //got my points

现在使用 morphTargets,我为立方体设置了动画。到目前为止,一切都很好。

//Some code that uses the shapee keys 
cube.morphTargetInfluences[0] = 0.2; // <-- I animate this value

但我期待这些点也会变形/动画,因为这些点使用相同的几何图形。但似乎不能开箱即用。

一些谷歌搜索表明,变形发生在 GPU 级别,并且对象中的几何数据并未真正修改。在 StackOverflow 的其中一个问题(Three.js: Get updated vertices with morph targets)中,@WestLangley 建议在 CPU 上进行相同的几何更新,然后使用它。

我的问题:

  1. 在解决这个问题时还有其他选择吗?
  2. CPU 变形计算似乎更慢,我想看看是否有任何其他方法可以让我的 Three.Points 与变形立方体保持同步?立方体用 morphtargets 动画,我期待 Three.Points 做同样的事情。

如果搅拌机中的形状键动画涉及更多,我想#1不是一个真正的选择?

理想情况下,以下内容会有所帮助:

cube.morphTargetInfluences[0] = 0.2; // <-- I animate this value
var morphedGeometry = getMorphedGeometry(cube);
syncPointsGeometry(morphedGeometry); 
4

1 回答 1

1

回答我自己的问题,以防将来对其他人有帮助。

我能够找到几个解决方案:

  1. 基于 CPU(慢) - 使用函数将变形复制到位置

        function updatePointsGeometry(points,weight) {
            if (!points.geometry.attributes.morphTarget0) {
                return;
            }
            for (var i = 0; i < points.geometry.attributes.position.count; i++) {
                points.geometry.attributes.position.array[i+0] =  weight * points.geometry.attributes.morphTarget0.array[i+0];
                points.geometry.attributes.position.array[i+1] =  weight * points.geometry.attributes.morphTarget0.array[i+1];
                points.geometry.attributes.position.array[i+2] =  weight * points.geometry.attributes.morphTarget0.array[i+2];
            }
            points.geometry.attributes.position.needsUpdate = true;
        }
    
  2. 基于 GPU(推荐)- 使用自定义着色器,该着色器使用 morphtargets 和 morphinfluence 来更改点

            var shaderPoint = THREE.ShaderLib.points;
            var uniforms = THREE.UniformsUtils.clone(shaderPoint.uniforms);
            uniforms.map.value = imageTexture;
            uniforms.size.value = 10;
            //Custom Shader
            customPointMaterial = new THREE.ShaderMaterial({
                uniforms: uniforms,
                morphTargets: true,
                defines: {
                    USE_MAP: ""
                },
                transparent: false,
                opacity: 1,
                alphaTest: 0.5,
                fog: false,
                vertexShader: document.getElementById( 'vertexShader' ).textContent,
                fragmentShader: shaderPoint.fragmentShader
            });
            //copy over the morph data from original geometry to the points
            myPoints = new THREE.Points(mesh.geometry, customPointMaterial);
            myPoints.morphTargetInfluences = mesh.morphTargetInfluences;
            myPoints.morphTargetDictionary = mesh.morphTargetDictionary;
    

这是顶点着色器

    uniform float size;
    uniform float scale;
    uniform float morphTargetInfluences[ 4 ];

    #include <common>
    #include <color_pars_vertex>
    #include <fog_pars_vertex>
    #include <shadowmap_pars_vertex>
    #include <logdepthbuf_pars_vertex>
    #include <clipping_planes_pars_vertex>
    void main() {
        #include <color_vertex>
        #include <begin_vertex>
        #include <project_vertex>
        #ifdef USE_SIZEATTENUATION
            gl_PointSize = size * ( scale / - mvPosition.z );
        #else
            gl_PointSize = size;
        #endif
        vec3 morphed = vec3( 0.0 , 0.0 , 0.0 );
        morphed += ( morphTarget0 - position ) * morphTargetInfluences[0];
        morphed += position;
        gl_Position = projectionMatrix * modelViewMatrix * vec4( morphed, 1.0 );
        #include <logdepthbuf_vertex>
        #include <clipping_planes_vertex>
        #include <worldpos_vertex>
        #include <shadowmap_vertex>
        #include <fog_vertex>
    }
于 2018-05-18T03:37:39.393 回答