Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第八章 8.1节 为什么要关闭深度写入? 我测试后与书中描述的“无法透过半透明表面看到后面的物体”不符 #153

Closed
FzuLiWei opened this issue Aug 18, 2017 · 3 comments

Comments

@FzuLiWei
Copy link

commented Aug 18, 2017

1
2
3

@FzuLiWei

This comment has been minimized.

Copy link
Author

commented Aug 18, 2017

图2为蓝色方块shader

@candycat1992

This comment has been minimized.

Copy link
Owner

commented Aug 22, 2017

书里的意思是,如果半透明物体开启了深度写入的话,就无法看到在该fragment处后面渲染的fragment,这个主要是为了在半透明物体互相交叉、无法得到正确渲染效果时,我们折中的一种方式。

举个例子,我们来创造一个半透明物体互相交叉的例子:

qq 20170822191617

这两个方块使用的Shader是一样的,但使用了两个各自的材质。为了让效果明显我故意把它们材质的透明度调成不同的值,摄像机靠后的方块透明度较低,靠前的较高。

在不采用其他方法的前提下,如果我们使用书里这种传统的透明混合的方式(指关闭深度写入进行混合)会得到下面的效果:

qq 20170822190453

实际上,这种效果是有问题的。错误的地方在于中间两个方块互相重叠的地方,这个混合效果有问题。我们可以在脑海里重现这个渲染过程:首先Unity会基于物体中心对两个方块进行排序,来实现半透明物体的从后往前渲染的目的。所以,Unity会先渲染方块B、再渲染方块A(参见第一张图里面两个方块在摄像机空间下的位置)。然而在重叠区域,正确的渲染顺序应该是先渲染方块A,因为在这部分区域内,它被方块B覆盖住了,它位于后面。出现错误的本质原因是因为我们的排序都是基于object level的,而不是基于pixel level的排序。

如果此时我们把深度打开,则会得到下面的效果:

qq 20170822190454

你可以一眼就看出来这里面的错误,那就是方块A的重叠部分别完全剔除掉了,这部分完全没有渲染!它被剔除掉的 原因就是因为Unity会先渲染方块B,由于方块B进行了深度写入,所以等到方块A渲染的时候,重叠部分A的像素根本无法通过depth test,会直接被剔除掉。

除了半透明物体之间的问题,尽管理论上来说,理想情况下半透明物体应该在所有不透明物体渲染完之后再渲染,但如果一个不透明物体因为某些原因在某个半透明物体后面被渲染了,也可能会因为半透明物体开启了深度写入而出现非常明显的渲染错误(不透明物体被半透明物体完全遮挡掉没有渲染)。

我觉得看到这里你应该知道我们为什么要关闭深度写入。总结一下的话,可以参考知乎上Milo Yip的回答

对于不透明(opaque)的 fragment,最后只需要看到最接近视点的 fragment。在实时渲染一般是通过深度缓冲来取得这个最近的 fragment。

但对于半透明的 fragment,每一个都会影响最终的结果,需要从远至近地渲染。由于深度缓冲不能用于排序多个 fragment,所以只能用于保存最接近视点的不透明 fragment 深度,远于该深度的透明 fragment 不用渲染,所以仍需要深度测试(depth test)。

由于需要手动排序半透明的物体,写入深度已没有意义。如果能完美地手工排序不透明 fragment,写入深度也没有影响;但若物体在深度方向有重叠,有些 fragment 的顺序会有误,如果开启深度写入,会令到渲染错误很明显,而关掉的话影响较小一点。

当然理想的话,应该用顺序无关透明(order independent transparency, OIT)技术,例如用逐像素链表存储多个 fragment,以像素为单位排序渲染。

简而言之,就是因为,传统的半透明混合总是会在物体交叉、渲染重叠的情况下,出现错误的混合效果。如果开启深度写入,会令到渲染错误很明显,而关掉的话影响较小一点。

回到你的图里,由于你的两个方块摆放规则不存在相互重叠,所以Unity对于两个物体的排序在pixel level也是正确的排序,即每个像素也都是满足从后往前渲染的,所以你不会发现问题。

@FzuLiWei

This comment has been minimized.

Copy link
Author

commented Aug 25, 2017

OK明白了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.