翻译:
Real depth in OpenGL / GLSL - Before I Forget…
有一个需求:用openGL做球形贴图。需要前后移动相机观测球体,当相机位置超出球体时看到的内容从球体内表面变成球体外表面。
方案一:超出时,计算哪些片段属于前半球,不要渲染这些片段;
方案二:在片段着色器用深度值判断;
首先看一下这个公式.
A = -(zFar + zNear) / (zFar - zNear);
B = -2*zFar*zNear / (zFar - zNear);
A 和B分别是视锥体透视投影(perspective)的投影矩阵的3行3列(3,3)和4列(3,4)。
通常线性照相机模型最后Project矩阵左乘顶点向量后gl_position值变成:
[...,..., Az+B, -z]
然后顶点shader跑完,openGL自动做透视划分:
g
l
_
p
o
s
i
t
i
o
n
=
v
e
c
4
(
x
,
y
,
z
,
w
)
;
o
u
t
=
(
x
/
w
y
/
w
z
/
w
)
gl\_position =vec4(x,y,z,w); \\ out = \begin{pmatrix} x /w \\ y / w \\ z / w \end{pmatrix}
gl_position=vec4(x,y,z,w);out=⎝⎛x/wy/wz/w⎠⎞
那么
z
n
=
z
/
w
z_n=z/w
zn=z/w 就是点在vertex Shader最终输出的gl_position 做透视划分后的向量的z值.
所以
z
n
z_n
zn的计算公式为:
z_n = -(Az_e + B) / z_e; // z_n in [-1, 1]
z_b = 0.5z_n + 0.5; // z_b in [0, 1]
z_b 是把透视划分后的点从[-1,1]映射到[0,1](深度缓存值范围).
以上是片段着色器每个点的深度值计算原理。在片段着色器clip一下透明值,就可以解决绘制一个物体时被遮挡的问题。例如我只要视野内球体内部.其截面法线垂直于我的视线: