three.js NDC空间转视图空间
NDC空间转视图空间, 比较常用。很多效果依赖于此。
包括:
- GTAOShader
- ReflectorForSSRPass
- SSRShader
下面看一下它的庐山真面目。
1、计算clipW
视图空间(view) 应用投影矩阵后转换到 剪裁空间(clip)。
[
A
0
B
0
0
C
D
0
0
0
E
F
0
0
−
1
0
]
[
v
i
e
w
x
v
i
e
w
y
v
i
e
w
z
1
]
=
[
c
l
i
p
x
c
l
i
p
y
c
l
i
p
z
c
l
i
p
w
]
\left[ \begin{matrix} A & 0 & B & 0 \\ 0 & C & D & 0 \\ 0 & 0 & E & F \\ 0 & 0 & -1 & 0 \end{matrix} \right] \left[ \begin{matrix} view_{x} \\ view_{y} \\ view_{z} \\ 1 \\ \end{matrix} \right] = \left[ \begin{matrix} clip_{x} \\ clip_{y} \\ clip_{z} \\ clip_{w} \\ \end{matrix} \right]
A0000C00BDE−100F0
viewxviewyviewz1
=
clipxclipyclipzclipw
投影矩阵按列存储在glsl中。那么就会存储为:
[
A
0
0
0
0
C
0
0
B
D
E
−
1
0
0
F
0
]
\left[ \begin{matrix} A & 0 & 0 & 0 \\ 0 & C & 0 & 0 \\ B & D & E & -1 \\ 0 & 0 & F & 0 \end{matrix} \right]
A0B00CD000EF00−10
于是:
// clipZ = E * viewZ + F
clipZ = (viewZ * cameraProjectionMatrix[2][2]) + cameraProjectionMatrix[2][3]
// clipW = -1 * viewZ + 0
clipW = (viewZ * cameraProjectionMatrix[3][2]) + cameraProjectionMatrix[3][3] = -viewZ
2、计算viewZ
原理见: three.js 中的 perspectiveDepthToViewZ
float getDepth( const in vec2 uv ) {
return texture2D( tDepth, uv ).x;
}
float getViewZ( const in float depth ) {
return perspectiveDepthToViewZ( depth, cameraNear, cameraFar );
}
float depth = getDepth( vUv );
float viewZ = getViewZ( depth );
3、计算 viewPos
vec3 getViewPosition(
const in vec2 uv,
const in float depth,
const in float clipW
) {
// ndc
vec4 clipPosition = vec4( ( vec3(uv, depth) - 0.5 ) * 2.0, 1.0 );
// clip
clipPosition *= clipW;
// view
return ( cameraInverseProjectionMatrix * clipPosition ).xyz;
}
vec3 viewPosition = getViewPosition( vUv, depth, clipW );