使用three.js在三维模型之间转换顶点

使用three.js在三维模型之间转换顶点,three.js,glsl,shader,buffer-geometry,Three.js,Glsl,Shader,Buffer Geometry,我试图实现多边形吹扫和重组效果,类似于: 在这两个示例中,您可以看到它们如何将顶点从一个三维模型变形/转换到另一个三维模型,从而产生非常酷的效果。我有一些类似的工作,但我无法理解它们如何使用速度偏移来转换顶点(请参考第一个链接,了解粒子如何不简单地映射并轻松移动到新位置,而是使用一些角度偏移): 因此,我在Three.js中导入我的两个模型,取一个具有较大顶点数的模型并复制其几何体,同时将第二个模型的模型数据作为属性附加: class CustomGeometry extends TH

我试图实现多边形吹扫和重组效果,类似于:

在这两个示例中,您可以看到它们如何将顶点从一个三维模型变形/转换到另一个三维模型,从而产生非常酷的效果。我有一些类似的工作,但我无法理解它们如何使用速度偏移来转换顶点(请参考第一个链接,了解粒子如何不简单地映射并轻松移动到新位置,而是使用一些角度偏移):

因此,我在Three.js中导入我的两个模型,取一个具有较大顶点数的模型并复制其几何体,同时将第二个模型的模型数据作为属性附加:

class CustomGeometry extends THREE.BufferGeometry {
  constructor (geometry1, geometry2) {
    super()

    let { count } = geometry1.attributes.position

    // this will hold
    let targetArr = new Float32Array(count * 3)
    let morphFactorArr = new Float32Array(count)

    for (let i = 0; i < count; i += 3) {
      targetArr[i + 0] = geometry2.attributes.position.array[i + 0] || 0
      targetArr[i + 1] = geometry2.attributes.position.array[i + 1] || 0
      targetArr[i + 2] = geometry2.attributes.position.array[i + 2] || 0

      let rand = Math.random()
      morphFactorArr[i + 0] = rand
      morphFactorArr[i + 1] = rand
      morphFactorArr[i + 2] = rand
    }
    this.addAttribute('a_target',      new THREE.BufferAttribute(targetArr, 3))
    this.addAttribute('a_morphFactor', new THREE.BufferAttribute(morphFactorArr, 1))
    this.addAttribute('position', geometry1.attributes.position)
  }
}
这是可行的,但真的很无聊。顶点只是从一个模型映射到另一个模型,没有任何偏移,没有重力或任何你想加入混合的东西

此外,由于如果顶点数不匹配,我会将0附加到一个位置,因此未使用的位置只会缩放到vec4(0.0、0.0、0.0、1.0),这同样会导致单调乏味的效果(这里是兔子和大象模型之间的变形)

(请注意,未使用的兔子顶点如何简单地缩小到0)

如何处理这样的问题

另外,在未来,他们是如何做到这一点的

  • 当模型在屏幕上处于活动状态时,在模型内部设置顶点动画

  • 将粒子映射到下一个模型时(单击箭头并过渡时),是否对粒子应用不同的速度和重力

  • 是通过传递布尔属性来实现的吗?他们是否正在更改targetPositions阵列?任何帮助都是非常感谢的

    这很有效,但真的很无聊。顶点只是从一个模型映射到另一个模型,没有任何偏移,没有重力或任何你想加入混合的东西

    因此,您可以应用任何可以想象和编码的效果。 这不是您问题的确切答案,但这是最简单的激励示例,说明了可以使用着色器执行哪些操作。扰流板:链接到一个工作示例在这个答案的末尾

    让我们来改变这个

    进入这个

    在过渡过程中使用有趣的群集粒子

    我们将使用带有一些自定义属性的
    THREE.BoxBufferGeometry()

    var sideLenght = 10;
    var sideDivision = 50;
    var cubeGeom = new THREE.BoxBufferGeometry(sideLenght, sideLenght, sideLenght, sideDivision, sideDivision, sideDivision);
    var attrPhi = new Float32Array( cubeGeom.attributes.position.count );
    var attrTheta = new Float32Array( cubeGeom.attributes.position.count );
    var attrSpeed = new Float32Array( cubeGeom.attributes.position.count );
    var attrAmplitude = new Float32Array( cubeGeom.attributes.position.count );
    var attrFrequency = new Float32Array( cubeGeom.attributes.position.count );
    for (var attr = 0; attr < cubeGeom.attributes.position.count; attr++){
        attrPhi[attr] = Math.random() * Math.PI * 2;
      attrTheta[attr] = Math.random() * Math.PI * 2;
      attrSpeed[attr] = THREE.Math.randFloatSpread(6);  
      attrAmplitude[attr] = Math.random() * 5;
      attrFrequency[attr] = Math.random() * 5;
    }
    cubeGeom.addAttribute( 'phi', new THREE.BufferAttribute( attrPhi, 1 ) );
    cubeGeom.addAttribute( 'theta', new THREE.BufferAttribute( attrTheta, 1 ) );
    cubeGeom.addAttribute( 'speed', new THREE.BufferAttribute( attrSpeed, 1 ) );
    cubeGeom.addAttribute( 'amplitude', new THREE.BufferAttribute( attrAmplitude, 1 ) );
    cubeGeom.addAttribute( 'frequency', new THREE.BufferAttribute( attrFrequency, 1 ) );
    
    如您所见,所有的魔法都发生在顶点着色器及其
    rtp2xyz()
    函数中

    最后,动画功能的代码:

    var clock = new THREE.Clock();
    var timeVal = 0;
    
    render();
    function render(){
        timeVal += clock.getDelta();
        requestAnimationFrame(render);
      uniforms.time.value = timeVal;
      uniforms.interpolation.value = slider.value;
      renderer.render(scene, camera);
    }
    
    哦,是的,我们的页面中有一个滑块控件:

    <input id="slider" type="range" min="0" max="1" step="0.01" value="0.5" style="position:absolute;width:300px;">
    
    
    
    FYI:适用于所有支持WebGLhey的浏览器,非常感谢您提供的详细答案!我的大脑在思考如何做
    new\u position=vec3(某物)
    ,然后在下一行为它添加另一个值。。。因为我在上面的一行用
    =
    符号设置它。然后,我看到您实际上也在
    rtp2xyz()
    中使用了插值值,它开始变得有意义了。。。。基本上,只要我使用
    插值
    值作为偏移量,我就可以对位置做任何事情,添加柏林噪声、向量场等等。。正确吗?另外,请您详细说明一下:
    sin(a_=factor*3.1415926)*2.0
    ?为什么我们要乘以π?因为
    sin(0)
    sin(PI)
    等于0(当
    a_变形因子从0到1时),当
    a_变形因子
    为0.5时,sin处的半径最大(PI*0.5)。谢谢你的帮助,我想我现在真的得到了!已经有东西在运行了
    var clock = new THREE.Clock();
    var timeVal = 0;
    
    render();
    function render(){
        timeVal += clock.getDelta();
        requestAnimationFrame(render);
      uniforms.time.value = timeVal;
      uniforms.interpolation.value = slider.value;
      renderer.render(scene, camera);
    }
    
    <input id="slider" type="range" min="0" max="1" step="0.01" value="0.5" style="position:absolute;width:300px;">