Domanda

Al momento sto leggendo da una texture di profondità in una profondità di campo postprocess dello shader utilizzando il seguente codice GLSL:

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;

E poi convertire il valore di profondità ad una distanza vista dello spazio in base alle distanze aereo vicino e lontano:

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

Questo sembra tutto funzionare abbastanza bene, però io sono interessato a sapere come fare il calcolo di cui sopra basato solo sulla matrice di proiezione corrente senza bisogno di valori zNear e zFar separati.

Il mio primo tentativo coinvolto moltiplicando (vec4(tcscreen.x, tcScreen.y, depth, 1.0) * 2.0 - 1.0) per l'inverso della matrice di proiezione, dividendo il risultato attraverso da w, poi prendendo il valore z risultante come la distanza, ma questo non sembra funzionare. Qual è l'approccio corretto qui?

Inoltre, quando si utilizza tronco obliquo clipping per spostare il piano vicino su un piano clipping scelto è la distanza aereo vicino ora potenzialmente diverso per ogni pixel? E se è così, allora questo significa che qualsiasi shader che calcolano una distanza da una texture di profondità devono essere consapevoli di questo caso e non assumere una distanza aereo vicino costante?

Grazie!

È stato utile?

Soluzione

Si scopre che avevo dimenticato di negare il valore Z finale per ottenere una distanza positiva davanti al aereo vicino (OpenGL fotocamera guarda in basso Z). Per riferimento futuro il codice GLSL per ottenere la distanza davanti al aereo vicino è:

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);

Se si voleva una posizione spaziale mondiale invece (come SuperPro stava usando) allora che possono essere trovati combinando la vista e proiezione matrici e quindi utilizzando l'inversa di quella matrice piuttosto che usando l'inversa della matrice di proiezione.

Poiché sono necessari solo Z e componenti W del viewPosition del GLSL sopra per viewPosition calcolo può essere semplificata piuttosto. Due prodotti dot basteranno invece di una moltiplicazione matrice completa, e non c'è necessità di alimentare la matrice di proiezione inversa pieno nella Shader sono necessari come solo le due righe inferiori:

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

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

Le prestazioni di questo è un po 'peggio rispetto all'utilizzo dei vicini e lontani distanze, presumibilmente a causa dei prodotti dot in più, ho ottenuto una riduzione del ~ 5%. La matematica vicino e lontano distanza può anche essere ottimizzato alimentando (zNear * zFar) e (zFar - zNear) come costanti, ma non ho visto alcun miglioramento misurabile in questo modo.

È interessante notare che, quando si combinano il sopra con una matrice di proiezione che utilizza tronco di cono obliquo clipping non riesco a ottenere nulla sensato fuori di esso, ma io capisco uscita ragionevole quando si utilizza l'equazione vicino e lontano lontano con la stessa matrice di proiezione , anche se con quello che sembra essere qualche distorsione dei valori di profondità (se questo potrebbe essere proprio a causa della perdita di profondità precisione inerente obliquo troncoconico clipping). Se qualcuno può far luce su cosa esattamente sta succedendo qui matematicamente sarei grato, anche se forse che dovrebbe essere in una questione diversa.

Altri suggerimenti

Io uso il seguente codice in uno shader fulmine, al fine di calcolare la direzione di un fulmine. posizione wold è anche calcolato moltiplicando la posizione dello schermo con l'inversa della matrice di proiezione.

Purtroppo 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;

funziona bene, quindi suppongo Worldposition è corretta!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top