Ich versuche, etwas Arbeit mit der GPU für eine Tuch-Simulation zu tun, und ich habe einige Probleme mit unterschiedlicher Hardware. Ich benutze Threejs als Rahmen, aber ich glaube, das ist nicht relevant für das Problem, das ich habe.GLSL Matrix/Umkehr Multiplikation Präzision
Im Grunde lade ich eine Matrix und eine Umkehrung dieser Matrix hoch, um Punkte von lokalen Koordinaten in Welt zu transformieren, mache einige Berechnungen in Weltkoordinaten (wie Kollisionserkennung) und transformiere sie dann zurück in Lokal. Dies funktioniert gut auf meinem Laptop, wenn ich mit Punkt Texturen schwimmen, aber bemerkte ich auf meinem Handy gibt es einige bizarre Artefakte:
richtig:
falsch:
Nachdem einige Debug tun Ich habe verengte es auf zwei Probleme. Beide beziehen sich auf die Dezimalgenauigkeit. Das Kollabieren der Vertices aufgrund von Constraints (und Präzisionsproblemen während der Constraints) und das Verlieren der Genauigkeit bei Verwendung der Matrixmultiplikation und der Inversen.
Der Grund, warum ich glaube, dass das Problem mit der Genauigkeit zusammenhängt, ist, weil wenn ich eine Fließkomma-Textur verwende, funktioniert es auf meinem Computer, aber wenn ich einen halben Schwimmer verwende, habe ich die gleichen Probleme. Mein Telefon unterstützt Floating-Point-Texturen. Das ist einer der Gründe, warum ich verwirrt bin, warum das auf meinem Handy passiert. Ich habe das Problem eingegrenzt, so dass die gesamte Stoffsimulation deaktiviert ist und wenn ich die Anwendung mit halben Float-Texturen auf meinem Computer ohne Gravitation, aber mit der Transformation und umgekehrt die flare-Art von Flackern auf seltsame Weise flackert, während if Die Transformation und Inverse sind deaktiviert, dann sieht es normal aus.
Ich habe keine Ideen, wie ich mit diesem Problem umgehen soll oder ob ich sogar den richtigen Weg eingeschlagen habe. Ich glaube, dass Halb-Float-Texturen eine begrenzte Dezimal-Genauigkeit haben, aber ich verstehe nicht, warum dies meine Probleme verursachen würde, da es nur die Ausgabe des Shaders beeinflussen sollte, nicht die Mathe, die im Shader läuft.
Der Code für den Shader sieht wie folgt aus:
' 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);',
Die Genauigkeitsanforderungen für GLES sind viel niedriger als für Desktop-GL (besonders wenn Sie mit GLES2 arbeiten). Es hilft nicht, wenn Sie volle fp32-Texturen verwenden, wenn Ihre Shader-ALUs immer noch eine viel geringere Präzision verwenden. – derhass
Ich sehe. Sie denken also, das Problem ist, dass die Shader-ALUs meines Telefons nicht genug Präzision unterstützen. Ich verstehe nicht, warum dieses Problem immer noch auftritt, wenn ich auf meinem Computer Halb-Float-Texturen verwende. Das scheint jedoch eine vernünftige Erklärung zu sein, obwohl –
versuchen, das ** relative Koordinatensystem ** zu verwenden, damit die transformierten Eckpunkte nicht zu weit von Ihren [Matrizenursprüngen] entfernt sind (https://stackoverflow.com/questions/28075743/how-do- i-compose-a-rotation-matrix-mit-menschenlesbaren-winkel-von-scratch/28084380? s = 1 | 64.0697 # 28084380).Nach der Berechnung zurück in das ursprüngliche Koordinatensystem übersetzen. Auf diese Weise vermeiden Sie, Vektoren mit hoher Magnitude mit Matrizen zu multiplizieren, was zu Genauigkeitsproblemen führt. Weitere Informationen finden Sie unter [Verbesserung der Genauigkeit der Ray- und Ellipsoid-Schnittpunkte] (https://stackoverflow.com/q/25470493/2521214) – Spektre