GPU上的Three.js Verlet布料模拟:无法通过我的逻辑来查找错误

时间:2018-02-05 13:36:34

标签: javascript three.js webgl shader gpgpu

我在使用yomboprime了解我试图用Three.js和GPUComputationRenderer实现的逻辑时遇到了问题。

https://github.com/yomboprime/GPGPU-threejs-demos/blob/gh-pages/js/GPUComputationRenderer.js

我想做一个简单的Verlet-Cloth-Simulation。这是我已经能够实现的逻辑(简短版本):

1)Position-Fragment-Shader:此着色器采用旧的和当前位置纹理并计算新位置,如下所示:

vec3 position = texture2D( texturePosition, uv ).xyz;
vec3 oldPosition = texture2D( textureOldPosition, uv ).xyz;
position =  (position * 2.0 - oldPosition + acceleration * delta *delta )

t = checkConstraints(position);
position += t;
gl_FragColor = vec4(position,1);

2)旧位置着色器此着色器只保存当前位置并将其保存以供下一步使用。

vec3 position = texture2D( texturePosition, uv ).xyz;
gl_FragColor = vec4(position,1);

这样可以正常工作,但是使用该模式不可能在一个步骤中多次计算约束,因为每个顶点都是单独观察的,并且无法看到其他像素在其中完成的位置变化。第一次迭代。

我想要做的是将约束与verlet分开。目前它看起来像这样:

1)位置着色器(texturePosition)

vec3 position = texture2D( textureConstraints, uv ).xyz;
vec3 oldPosition = texture2D( textureOldPosition, uv ).xyz;

position =  (position * 2.0 - oldPosition + acceleration * delta *delta );
gl_FragColor = vec4(position, 1 );

2)Constraint-Shader(textureConstraints)

vec3 position = texture2D( texturePosition, uv ).xyz;

t = checkConstraints(position);
    position += t;
gl_FragColor = vec4(position,1);

3)旧位置着色器(textureOldPosition)

vec3 position = texture2D( textureConstraints, uv ).xyz;

gl_FragColor = vec4(position,1);

这个逻辑不起作用,即使我根本不计算约束,只是像以前那样传递值。一旦在位置着色器中添加了一些加速度,位置值就会爆炸到任何地方。

我做错了什么?

1 个答案:

答案 0 :(得分:2)

这个例子不是verlet布,但我认为基本前提可能对你有所帮助。我有fiddle使用GPUComputationRender在点云上完成一些弹簧物理。我认为你可以根据自己的需要调整它。

您需要的是更多信息。你需要固定参考布料的原始形状(就好像它是一块平板)以及当前施加在任何这些点上的力(通过重力+风+结构完整性或其他任何东西),然后给你那一点的当前位置。那些指向其原始形状与力量相结合的点将会给你的布料留下记忆而不是像往常那样突然分开。

例如,这是我的弹簧物理着色器,GPUComputationRenderer用来计算我的可视化中的点位置。在这种情况下,tOffsets是为云提供其原始形状的永久记忆的坐标 - 它们永远不会改变。这是我在程序开始时添加到制服中的DataTexture。 massspringConstantgravitydamping等各种力量也保持一致并生活在着色器中。 tPositions是改变的vec4坐标(两个坐标记录当前位置,另外两个记录当前速度):

<script id="position_fragment_shader" type="x-shader/x-fragment">   
  // This shader handles only the math to move the various points. Adding the sprites and point opacity comes in the following shader.      
  uniform sampler2D tOffsets; 
  uniform float uTime;

  varying vec2 vUv;

  float hash(float n) { return fract(sin(n) * 1e4); }

  float noise(float x) {
      float i = floor(x);
      float f = fract(x);
      float u = f * f * (3.0 - 2.0 * f);
      return mix(hash(i), hash(i + 1.0), u);
  }

  void main() {
      vec2 uv = gl_FragCoord.xy / resolution.xy;

       float damping = 0.98;

       vec4 nowPos = texture2D( tPositions, uv ).xyzw;
       vec4 offsets = texture2D( tOffsets, uv ).xyzw;
       vec2 velocity = vec2(nowPos.z, nowPos.w);

       float anchorHeight = 100.0;
       float yAnchor = anchorHeight;
       vec2 anchor = vec2( -(uTime * 50.0) + offsets.x, yAnchor + (noise(uTime) * 30.0) );

       // Newton's law: F = M * A
       float mass = 24.0;
       vec2 acceleration = vec2(0.0, 0.0);

       // 1. apply gravity's force:
       vec2 gravity = vec2(0.0, 2.0);
       gravity /= mass;
     acceleration += gravity;


       // 2. apply the spring force
       float restLength = yAnchor - offsets.y;
       float springConstant = 0.2;

       // Vector pointing from anchor to point position
       vec2 springForce = vec2(nowPos.x - anchor.x, nowPos.y - anchor.y);
       // length of the vector
       float distance = length( springForce );
       // stretch is the difference between the current distance and restLength
       float stretch =  distance - restLength;

       // Calculate springForce according to Hooke's Law
       springForce = normalize(springForce);
       springForce *= (springConstant * stretch);

       springForce /= mass;
       acceleration += springForce;

       velocity += acceleration;
       velocity *= damping;
       vec2 newPosition = vec2(nowPos.x - velocity.x, nowPos.y - velocity.y);
       // Write new position out
       gl_FragColor = vec4(newPosition.x, newPosition.y, velocity.x, velocity.y);
   }
</script>