我在理解我尝试使用 Three.js 和 yomboprime 的 GPUComputationRenderer 实现的逻辑时遇到问题。
( https://github.com/yomboprime/GPGPU-threejs-demos/blob/gh-pages/js/GPUComputationRenderer.js )
我想做一个简单的 Verlet 布料模拟。这是我已经能够实现的逻辑(简短版本):
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);
这工作正常,但使用该模式,不可能在一个步骤中多次计算约束,因为每个顶点都是单独观察的,并且无法看到其他像素在第一次迭代中所做的位置变化。
我想做的是将约束与 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)约束着色器(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);
这个逻辑不起作用,即使我根本不计算约束并且只是像以前一样传递值。一旦在位置着色器中添加一些加速度,位置值就会爆炸到无处可去。
我做错了什么?
最佳答案
这个例子不是verlet布料,但我认为基本前提可能对你有帮助。我有一个fiddle它使用 GPUComputationRender 在点云上完成一些 Spring 物理。我认为您可以根据您的需要进行调整。
您需要的是更多信息。您需要对布料的原始形状(就好像它是一 block 平板)以及当前施加在任何这些点上的力(通过重力+风+结构完整性或其他)的固定引用,然后为您提供该点的当前位置。这些对其原始形状的引用点与力的结合将为您的布料带来内存,而不是像以前那样被甩开。
例如,这是我的 Spring 物理着色器,GPUComputationRenderer
使用它来计算可视化中的点位置。在这种情况下,tOffsets 是使云永久内存其原始形状的坐标 - 它们永远不会改变。这是我在程序开始时添加到制服中的 DataTexture。质量、 Spring 常数、重力和阻尼等各种力也保持一致并存在于着色器中。 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>
关于javascript - Three.js GPU 上的 Verlet 布料模拟 : Can't follow my logic for finding bug,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48623830/