Three.js Verlet Cloth Simulation на GPU: не могу следовать моей логике при поиске ошибки

1

У меня возникла проблема в понимании логики, которую я пытаюсь реализовать с помощью Three.js и GPUComputationRenderer по yomboprime.

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

Я хочу сделать простой симулятор Verlet-Cloth. Вот логика, которую я уже смог реализовать (короткая версия):

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) Old-Position-Shader Этот шейдер просто сохраняет текущее положение и сохраняет его для следующего шага.

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

Это работает отлично, но с этим шаблоном невозможно вычислить ограничения более одного раза за один шаг, поскольку каждая вершина наблюдается отдельно и не может видеть изменение положения, которое другие пиксели сделали бы на первой итерации.

Я пытаюсь отделить ограничения от верба. На данный момент это выглядит так:

1) Position-Shader (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);

Эта логика не работает, даже если я вообще не вычисляю ограничений и просто передаю значения, как раньше. Как только некоторое ускорение добавляется в положение-шейдер, значения позиции взрываются в никуда.

Что я делаю неправильно?

Теги:
three.js
shader
webgl
gpgpu

1 ответ

2
Лучший ответ

Этот пример не является верлекой, но я думаю, что основная посылка может вам помочь. У меня есть скрипка, которая использует GPUComputationRender для выполнения некоторой весенней физики в облаке точек. Я думаю, вы могли бы приспособить его к вашим потребностям.

Вам нужна дополнительная информация. Вам понадобятся фиксированные ссылки на оригинальную форму ткани (как будто это плоская доска), а также сила, действующая в настоящее время на любую из этих точек (под действием силы тяжести + ветер + структурная целостность или что-то еще), которое затем дает вам это текущее положение. Эти точечные ссылки на его первоначальную форму в сочетании с силами - вот что даст вашей ткани память вместо того, чтобы раскалываться, как было.

Вот, например, мой шейдер весенней физики, который GPUComputationRenderer использует для вычисления позиций точки в моей визуализации. В этом случае tOffsets - это координаты, которые дают облаку постоянную память о его первоначальной форме - они никогда не меняются. Это DataTexture, который я добавляю к униформам в начале программы. Различные силы, такие как mass, springConstant, gravity и damping также остаются неизменными и живут в шейдере. 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 law: F = M * A
       float mass = 24.0;
       vec2 acceleration = vec2(0.0, 0.0);

       // 1. apply gravity 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 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>

Ещё вопросы

Сообщество Overcoder
Наверх
Меню