Vertex Shader World 변환, 왜 4차원 벡터를 사용합니까?
문제
이 사이트에서: http://www.toymaker.info/Games/html/vertex_shaders.html
다음과 같은 코드 조각이 있습니다.
// transformations provided by the app, constant Uniform data
float4x4 matWorldViewProj: WORLDVIEWPROJECTION;
// the format of our vertex data
struct VS_OUTPUT
{
float4 Pos : POSITION;
};
// Simple Vertex Shader - carry out transformation
VS_OUTPUT VS(float4 Pos : POSITION)
{
VS_OUTPUT Out = (VS_OUTPUT)0;
Out.Pos = mul(Pos,matWorldViewProj);
return Out;
}
내 질문은 다음과 같습니다VS_OUTPUT 구조체의 위치가 4차원 벡터인 이유는 무엇입니까?위치는 단지 x, y, z가 아닌가요?
해결책
원근 계산을 위해서는 w 좌표가 필요하기 때문입니다. Directx보다 정점 셰이더에서 출력 한 후에는 w로 나누어 관점을 분할합니다.
본질적으로 출력 정점 위치로 32768, -32768, 32768, 65536이있는 경우 W 분할 후 0.5, -0.5, 0.5, 1이됩니다.이 시점에서 W는 더 이상 필요하지 않기 때문에 폐기 할 수 있습니다. 그런 다음이 정보는 뷰포트 매트릭스를 통해 전달되어 사용 가능한 2D 좌표로 변환합니다.
편집 : 투영 행렬을 사용하여 매트릭스 곱셈을 수행하는 방법을 살펴보면 값이 올바른 위치에 어떻게 배치되는지 확인할 수 있습니다.
d3dxmatrixperspectivelh에 지정된 투영 행렬을 취합니다
2*zn/w 0 0 0
0 2*zn/h 0 0
0 0 zf/(zf-zn) 1
0 0 zn*zf/(zn-zf) 0
그리고 임의의 x, y, z, 1에 적용하면 (정점 위치 w는 항상 1) 정점 입력 값을 얻을 수 있습니다.
x' = ((2*zn/w) * x) + (0 * y) + (0 * z) + (0 * w)
y' = (0 * x) + ((2*zn/h) * y) + (0 * z) + (0 * w)
z' = (0 * x) + (0 * y) + ((zf/(zf-zn)) * z) + ((zn*zf/(zn-zf)) * w)
w' = (0 * x) + (0 * y) + (1 * z) + (0 * w)
즉시 W와 Z가 다르다는 것을 알 수 있습니다. w 코드는 이제 전달 된 z 좌표가 투사 행렬에 전달됩니다. Z에는 훨씬 더 복잡한 것을 포함합니다.
그래서 .. 우리는 (2, 1, 5, 1)의 입력 위치가 1과 zf (z-far 10)와 1 및 ah의 aw (너비)가 있다고 가정합니다. 높이) 1.
우리는이 값을 통과시킵니다
x' = (((2 * 1)/1) * 2
y' = (((2 * 1)/1) * 1
z' = ((10/(10-1) * 5 + ((10 * 1/(1-10)) * 1)
w' = 5
우리가 얻는 확장
x' = 4
y' = 2
z' = 4.4
w' = 5
그런 다음 최종 관점 분할을 수행하면 얻습니다
x'' = 0.8
y'' = 0.4
z'' = 0.88
w'' = 1
그리고 이제 우리는 최종 좌표 위치를 가지고 있습니다. 이것은 x와 y 범위가 -1에서 1 사이이며 z는 0에서 1 사이의 범위를 가정합니다.
기괴한 보너스로 | x '| 또는 | y '| 또는 | z '| | w '|보다 큽니다 또는 z '는 정점이 화면 오프 스크린 인 것보다 0보다 작습니다. 이 정보는 삼각형을 화면에 클리핑하는 데 사용됩니다.
어쨌든 나는 그것이 꽤 포괄적 인 대답이라고 생각합니다 : D
edit2 : 행 메이저 매트릭스를 사용하고 있다는 경고를받습니다. 열 메이저 매트릭스가 바뀌 었습니다.
다른 팁
회전은 3차원 행렬로 지정되고 변환은 벡터로 지정됩니다.두 가지 변환을 단일 4 x 3 행렬로 결합하여 "단일" 작업으로 수행할 수 있습니다.
rx1 rx2 rx3 tx1
ry1 ry2 ry3 ty1
rz1 rz2 rz3 tz1
그러나 이것은 정사각형이 아니기 때문에 수행할 수 없는 다양한 작업이 있습니다(하나의 반전).추가 행을 추가하면(아무 작업도 수행되지 않음):
0 0 0 1
이러한 모든 작업이 가능해집니다(쉽지는 않더라도).
Goz가 설명했듯이 그의 대답 "1"을 동일하지 않은 값으로 만들면 행렬이 원근 변환이 됩니다.
클리핑은이 프로세스에서 중요한 부분입니다. 기하학에 발생하는 일을 시각화하는 데 도움이됩니다. 클리핑 스테이지는 본질적으로 원점을 중심으로하는 2 단위 큐브 외부에있는 원시의 모든 지점을 버립니다 (OK, 부분적으로 클리핑되었지만 여기서는 중요하지 않은 프리미티브를 재구성해야합니다).
세계 공간 좌표를 직접 큐브에 매핑하는 매트릭스를 구성하는 것이 가능하지만, 먼 비행기에서 가까운 비행기로 점진적인 움직임은 선형입니다. 즉, 시청자에서 1 마일 떨어진 곳에서 한 발의 움직임은 카메라에서 몇 피트에서 한 발의 움직임과 동일한 크기를 증가시킬 수 있습니다.
그러나 벡터 (W)에 또 다른 좌표가있는 경우 벡터 구성 요소를 W로 나눌 수 있으며 프리미티브는 위의 동작을 나타내지 않지만 여전히 2 단위 큐브 내부에서 끝날 수 있습니다. 위에.
자세한 설명은 참조하십시오 http://www.opengl.org/resources/faq/technical/depthbuffer.htm#0060 그리고 http://en.wikipedia.org/wiki/transformation_matrix#perspection_projection.
간단한 대답은 파이프 라인에 W가 무엇인지 말하지 않으면 투영에 대한 충분한 정보를 제공하지 않았다고 말하는 것입니다. 파이프 라인이 무엇을하는지 이해하지 않고 직접 확인할 수 있습니다 ...
아시다시피, 4x4 매트릭스는 각 부품이하는 일에 따라 부품으로 분할 될 수 있습니다. 왼쪽 상단의 3x3 행렬은 회전 또는 스케일 작업을 수행 할 때 변경됩니다. 네 번째 열은 번역을 할 때 변경됩니다. 원근 행렬을 검사하면 행렬의 하단 행을 변경합니다. 그런 다음 매트릭스 벡터 곱셈이 어떻게 수행되는지 살펴보면 행렬의 하단 행이 벡터의 결과 W 구성 요소에만 영향을 미친다는 것을 알 수 있습니다. 따라서 파이프 라인에 w에 대해 말하지 않으면 모든 정보가 없습니다.