I am trying to do some work with the GPU for a cloth simulation and I am having some problems with different hardware. I am using threejs as the framework, but I believe that isn't relevant for the problem I am having.
Basically what I do is I upload a matrix and an inverse of that matrix in order to transform points from local coords to world, do some math in world coords (like collision detection), and then transform them back to local. This works great on my laptop when I am using floating point textures, however I noticed on my phone there are some bizarre artifacts:
correct:
incorrect:
After doing some debugging I have narrowed it down to two problems. Both of them are related to decimal precision. The collapsing of the vertices due to constraints (and precision problems during the constraints) and losing precision when using the matrix multiplication and the inverse.
The reason I believe the problem is related to precision is because if I use a floating point texture it works on my computer, but if I use a half float I have the same problems. My phone supports floating point textures which is one reason I am confused about why this would be happening on my phone. I narrowed the problem down so all of the cloth simulation is disabled and if I run the application with half float textures on my computer, without any gravity but with the transformation and inverse the plane sort of flickers in weird ways
while if the transformation and inverse are disabled then it looks normal.
I am out of ideas for how to handle this problem though or if I am even going down the right path. I believe that half float textures have limited decimal precision but I don't understand why this would be causing my problems since it should only affect the output of the shader, not the math going on in the shader.
The code for the shader looks like the following:
' vec2 cellSize = 1.0 / res;',
' vec4 pos = texture2D(vertexPositions, vuv.xy );',
' vec2 newUV;',
' if(type == 0.0){',
' float px = floor(vuv.x * res.x );',
' float spacingx = px- (2.0 * floor(px/2.0));',
' float py = floor(vuv.y * res.y );',
' float spacingy = py- (2.0 * floor(py/2.0));',
' float total = spacingx + spacingy;',
' total = total- (2.0 * floor(total/2.0));',
' if(total == 0.0){',
' newUV = vuv + (direction * cellSize);',
' }',
' else{',
' newUV = vuv - (direction * cellSize);',
' }',
' }',
' if(type == 1.0){',
' float px = floor(vuv.x * res.x );',
' float spacingx = px- (2.0 * floor(px/2.0));',
' float total = spacingx;',
' if(total == 0.0){',
' newUV = vuv + (direction * cellSize);',
' }',
' else{',
' newUV = vuv - (direction * cellSize);',
' }',
' }',
' vec4 totalDisplacement = vec4(0.0);',
' if(newUV.x > 0.0 && newUV.x < 1.0 && newUV.y > 0.0 && newUV.y < 1.0){ ',
' vec4 posOld = texture2D(vertexPositionsStart, vuv);' ,
' vec4 posOld2 = texture2D(vertexPositionsStart, newUV);' ,
' float targetDistance = length(posOld - posOld2);',
' vec4 newPos = texture2D(vertexPositions, newUV);',
' float dx = pos.x - newPos.x;',
' float dy = pos.y - newPos.y;',
' float dz = pos.z - newPos.z;',
' float distance = sqrt(dx * dx + dy * dy + dz * dz);',
' float difference = targetDistance- distance;',
' float percent = difference / distance / 2.0;',
' float offsetX = dx * percent * rigid;',
' float offsetY = dy * percent * rigid;',
' float offsetZ = dz * percent * rigid;',
' totalDisplacement.x += offsetX;',
' totalDisplacement.y += offsetY;',
' totalDisplacement.z += offsetZ;',
' }',
' }',
' }',
' pos += totalDisplacement;',
' if( vuv.x > 1.0 - cellSize.x && topConstrain == 1 ){',
' pos =transformation * texture2D(vertexPositionsStart, vuv.xy );',
' }',
' if( vuv.x < cellSize.x && bottomConstrain == 1 ){',
' pos =transformation * texture2D(vertexPositionsStart, vuv.xy );',
' }',
' if( vuv.y < cellSize.y && leftConstrain == 1 ){',
' pos =transformation * texture2D(vertexPositionsStart, vuv.xy );',
' }',
' if( vuv.y > 1.0 - cellSize.y && rightConstrain == 1 ){',
' pos =transformation * texture2D(vertexPositionsStart, vuv.xy );',
' }',
' gl_FragColor = vec4( pos.xyz , 1.0 );',