使用统一变量移动具有不同转换延迟的顶点

时间:2017-08-02 08:20:58

标签: three.js glsl

我想使用不同的持续时间和各个顶点的延迟,将顶点从一个3D模型变形到下一个三维模型。

首先,我加载我的两个模型,采用具有更大顶点数的模型并复制它的顶点位置。然后,我采用第二个模型并将其顶点位置指定为targetPosition属性:

class CustomGeometry extends THREE.BufferGeometry {
   constructor (refGeo1, refGeo2) {
      super()
      let count = refGeo1.attributes.position.count

      let targets = new Float32Array(count * 3)
      for (let i = 0; i < count; i += 3) {
        // if there is no corresponding vertex, simply assign 0
        targets[i + 0] = refGeo2.attributes.position.array[i + 0] || 0
        targets[i + 1] = refGeo2.attributes.position.array[i + 1] || 0
        targets[i + 2] = refGeo2.attributes.position.array[i + 2] || 0
      }

      this.addAttribute('position', refGeo1.attributes.position)
      this.addAttribute('targetPosition', new THREE.BufferAttribute(targets, 3))
   }
}

然后我可以传递一个统一变量mixFactor并在我的顶点着色器中执行此操作:

vec3 newPosition = mix(position, targetPosition, mixFactor)

这是一个实时example

这很好,除了当mixFactor变量改变时顶点均匀地通过空间(具有相同的定时持续时间)。如何为混音添加延迟和不同的时间?

我知道我可以attribute float mixFactor穿上制服,然后在CPU上补间,但这会导致我的表现失败......我怀疑我必须添加transitionTiming和{{1将属性浮动到我的顶点,但我失去了如何在着色器中进行数学运算......

1 个答案:

答案 0 :(得分:1)

您为每个顶点添加了另一个属性,可以称之为mixAmountOffset。在着色器中的mixAmount计算中使用它。

attribute float mixAmountOffset;
uniform float mixAmount;

....

    float realMixAmount = clamp(mixAmount + mixAmountOffset, 0., 1.);

然后在混合中使用realMixmount

vec4 position = mix(position1, position2, realMixAmount);

您只需在JavaScript中更新mixAmount

为了更清楚你需要realMixAmount为每个顶点传递0到1之间的值。因此,我们假设您将mixAmountOffset设置为从顶点

的0到-1的负值
for (let i = 0; i < vertexCount ++i) {
   mixAmountOffset[i] = -i / vertexCount;
}

现在mixAmount + mixAmountOffset的数学需要将所有点从0传递到1. mixAmountOffset的范围现在为0到-1,这意味着当mixAmount为0时mixAmount + mixAmountOffset将来自所有顶点都为0到-1。因为clamp在所有顶点上都是0到0。

mixAmount1时,mixAmount + mixAmountOffset将从1变为0.意味着只有第一个顶点使用第二个模型的位置,最后一个顶点仍在使用第一个模特的位置。

你需要将mixAmount从0变为2.那么当mixAmount为2时,mixAmount + mixAmountOffset将在所有顶点之间从2变为1,并且钳位将使1变为1所有顶点都有1个。换句话说,所有顶点都将使用model2

您使用mixAmountOffsets以及如何计算realMixeAmount的算法取决于您自己。关键是你需要在事情开始之前进行数学运算所有顶点得到realMixAmount为0并且事情结束之后所有顶点得到realMixAmount为1.有无数种方法可以做到这一点。

查看您的代码,您传递了mixAmountOffset的顶点索引,例如,您可以传递另一个制服vertexCount并执行scaledMixAmountOffset = mixAmountOffset / vertexCount

或者,您可以将mixAmountOffset缓冲区中的正值从0添加到1,将mixAmount从-1添加到1.

或......等......

您可能想要做的其他事情:

当你lerp时,你可以在mixAmount上使用某种平滑功能,但在这种情况下,因为每个顶点都有效地单独渲染你可能想要将平滑函数放在着色器中

示例:

 ... 

 float smooth(float pos) {
    pos *= 2.;
    if (pos < 1.) {
      return 0.5 * pow(2., 10. * (pos - 1.));
    }
    return 0.5 * (-pow(2., -10. * --pos) + 2.);
  }

  void main () {
    float realFactorOffset = clamp(mixFactor + mixFactorOffset, 0.0, 1.0);
    realFactorOffset = smooth(realFactorOffset);
    vec3 newPosition = mix(position, targetPosition, realFactorOffset);


 ...

请参阅:cross-site scripting (XSS)