Frage

ich zur Zeit das Lesen aus einer Tiefe Textur in einem nachbearbeiten Schärfentiefe Shader den folgenden GLSL Code verwendet:

vec4 depthSample = texture2D(sDepthTexture, tcScreen);
float depth = depthSample.x * 255.0 / 256.0 +
              depthSample.y * 255.0 / 65536.0 +
              depthSample.z * 255.0 / 16777216.0;

Und dann den Tiefenwert auf einen Abstand Ansicht Raum basierend Umwandlung auf den nahen und fernen Ebene Entfernungen:

float zDistance = (zNear * zFar) / (zFar - depth * (zFar - zNear));

Dies scheint alles recht gut zu funktionieren, aber sie ist daran interessiert zu wissen, wie die obige Berechnung nur auf der aktuellen Projektionsmatrix auf Basis zu tun, ohne gesonderte zNear und zFar Werte zu benötigen.

Mein erster Versuch beteiligt (vec4(tcscreen.x, tcScreen.y, depth, 1.0) * 2.0 - 1.0) Multiplikation mit dem Kehrwert der Projektionsmatrix, wobei das Ergebnis durch durch w teilt, dann den resultierenden z Wert als den Abstand nehmen, aber das schien nicht zu funktionieren. Was ist der richtige Ansatz hier?

Auch wenn schräge Stumpfes Verwendung Abschneiden die nahe Ebene auf eine gewählte Schnittebene zu verschieben, ist die in der Nähe Ebenenabstand jetzt möglicherweise unterschiedlich für jedes Pixel? Und wenn ja, dann bedeutet das, dass alle Shadern, die einen Abstand von einer Tiefen Textur berechnen müssen von diesem Fall zu beachten und keine konstanten nahe Ebene Abstand annehmen?

Danke!

War es hilfreich?

Lösung

Es stellt sich heraus, dass ich vergessen hatte, den endgültige Z-Wert zu negieren einen positiven Abstand vor der nahen Ebene zu bekommen (OpenGL Kamera schaut nach unten -Z). Für zukünftige Referenz für den GLSL-Code, den Abstand vor der nahen Ebene bekommen ist:

float depth = /* sampled from depth texture as in the original question */ ;

vec4 screenPos = vec4(tcScreen.x, tcScreen.y, depth, 1.0) * 2.0 - 1.0;
vec4 viewPosition = projectionMatrixInverse * screenPos;

float z = -(viewPosition.z / viewPosition.w);

Wenn Sie eine Weltraumposition stattdessen wollen (wie SuperPro wurde mit), dann kann das durch die Kombination der Ansicht und Projektionsmatrizen und dann unter Verwendung der inversen diese Matrix nicht nur die Projektionsmatrix inverse Verwendung finden.

Da nur die Z- und W-Komponenten von viewPosition die oben GLSL zur Berechnung viewPosition benötigt werden, können etwas vereinfacht werden. Zwei Punktprodukte werden anstelle einer Vollmatrixmultiplikation genügen, und es gibt keine Notwendigkeit, die volle inverse Projektionsmatrix in den Shader als nur die beiden unteren Reihen nötig sind, um zu füttern:

vec2 viewPositionZW = vec2(
    dot(projectionMatrixInverseRow2, screenPos),
    dot(projectionMatrixInverseRow3, screenPos)
);

float z = -(viewPositionZW.x / viewPositionZW.y);

Die Leistung dieser ist ein wenig schlechter als die nahen und fernen Entfernungen verwenden, vermutlich wegen der zusätzlichen Punktprodukte, bekam ich einen ~ 5% Ermäßigung. Die in der Nähe und Ferne Mathe kann auch durch Fütterung (zNear * zFar) und (zFar - zNear) in als Konstanten optimiert werden, aber ich habe keine messbare Verbesserung durch dies zu tun.

Interessanterweise, wenn Sie kombinieren die oben mit einer Projektionsmatrix, die schräg Stumpfes Clipping verwendet ich nichts vernünftig aus ihn heraus bekommen, aber ich vernünftigen Ausgang tun bekommen, wenn das in der Nähe und Ferne Gleichung mit derselben Projektionsmatrix , wenn auch mit dem, was offenbar einem gewissen Verzerrung der Tiefenwerte sein (obwohl dies nur durch den Verlust von Tiefengenauigkeit inhärent in schrägem Stumpfes clipping sein könnte). Wenn jemand etwas Licht auf vergießen kann, was genau mathematisch hier los ich es schätzen würde, wenn auch vielleicht das soll in einer anderen Frage sein.

Andere Tipps

Ich verwende den folgenden Code in einem Blitz-Shader, um die Blitzrichtung zu berechnen. Wold Position auch durch die Multiplikation der Bildschirmposition mit dem Kehrwert der Projektionsmatrix berechnet wird.

Leider HLSL:

float depth = tex2D(DepthMapSampler, PSIn.TexCoord).r;

float4 screenPos;
screenPos.x = PSIn.TexCoord.x*2.0f-1.0f;
screenPos.y = -(PSIn.TexCoord.y*2.0f-1.0f);
screenPos.z = depth;
screenPos.w = 1.0f; 

float4 worldPos = mul(screenPos, xViewProjectionInv);
worldPos /= worldPos.w;

funktioniert gut, so nehme ich an Worldposition korrekt ist!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top