문제

나는 현재 다음 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;

그런 다음 깊이 값을 가까운 평면 거리 및 원거리 거리에 기초하여 뷰 공간 거리로 변환합니다.

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

이 모든 것이 상당히 잘 작동하는 것처럼 보이지만, 분리 할 필요없이 현재 프로젝션 매트릭스를 기반으로 위의 계산을 수행하는 방법을 알고 싶습니다. zNear 그리고 zFar 가치.

나의 초기 시도에는 곱하는 것이 포함되었습니다 (vec4(tcscreen.x, tcScreen.y, depth, 1.0) * 2.0 - 1.0) 투영 행렬의 역수로 결과를 w, 결과를 가져옵니다 z 거리로 가치가 있지만 이것은 작동하지 않는 것 같습니다. 여기에 올바른 접근법은 무엇입니까?

또한, 비스듬한 Frustum 클리핑을 사용하여 가까운 평면을 선택된 클리핑 평면으로 이동할 때, 모든 픽셀마다 잠재적으로 다른 평면 거리가 다른가? 그렇다면 이렇게하면 깊이 텍스처로부터 거리를 계산하는 셰이더 가이 경우를 인식해야하고 평면 거리 근처의 일정한 상수를 가정하지 않아야한다는 것을 의미합니까?

감사!

도움이 되었습니까?

해결책

최종 z 값을 부정하는 것을 잊어 버렸다는 것이 밝혀졌습니다. 근처 평면 앞에서 양수 거리를 얻는 (OpenGL 카메라가 -z를 아래로 봅니다). 향후 참조를 위해 가까운 비행기 앞에서 거리를 얻기위한 GLSL 코드는 다음과 같습니다.

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

대신 월드 우주 위치를 원한다면 (SuperPro가 사용중인 것과 같은)보기와 투영 행렬을 결합한 다음 투영 행렬 역수를 사용하지 않고 해당 매트릭스의 역수를 사용하여 찾을 수 있습니다.

z 및 w 구성 요소 만 있기 때문입니다 viewPosition 컴퓨팅을 위해서는 위의 GLSL이 필요합니다 viewPosition 다소 단순화 될 수 있습니다. 전체 행렬 곱셈 대신 두 개의 도트 제품으로 충분하며, 하단 두 행만 필요하므로 전체 역 프로젝션 매트릭스를 셰이더에 공급할 필요가 없습니다.

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

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

이것의 성능은 가까운 거리와 멀리 떨어진 거리를 사용하는 것보다 조금 더 나쁩니다. 아마도 여분의 도트 제품으로 인해 ~ 5% 감소했습니다. 가까운 거리 및 원거리 수학은 피드를 통해 최적화 할 수 있습니다. (zNear * zFar) 그리고 (zFar - zNear) 상수에서, 그러나 나는 이것을함으로써 측정 가능한 개선을 보지 못했습니다.

흥미롭게도, 위를 비스듬한 Frustum 클리핑을 사용하는 프로젝션 매트릭스와 결합하면 현명한 것을 얻을 수는 없지만 동일한 투영 행렬과 함께 가까운 거리 및 원거리 방정식을 사용할 때는 합리적인 출력을 얻을 수 없습니다. 깊이 값의 일부 왜곡으로 보이는 것 (이것은 비스듬한 뇌성 클리핑에 내재 된 깊이 정밀도의 손실로 인한 것일 수 있습니다). 누군가가 수학적으로 정확히 무슨 일이 일어나고 있는지에 대해 약간의 빛을 발할 수 있다면, 다른 질문에 있어야 할지도 모른다.

다른 팁

번개 방향을 계산하기 위해 Lightning Shader에서 다음 코드를 사용합니다. Wold 위치는 또한 화면 위치에 돌출 행렬 매트릭스의 역을 곱하여 계산됩니다.

불행히도 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;

잘 작동하므로 WorldPosition이 정확하다고 생각합니다!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top