先说个题外话, 本来我想解答一下最近Creators Club论坛上经常出现的一个问题, 意外的是在网上竟然找不到什么全面的答案..
这是个有着复杂答案的简单问题:
“为什么我的透明物体的绘制顺序不对, 或者有些不见了?”
当绘制一个3D场景时, 对图形进行深度排序是非常重要的, 这样离镜头近才画在远处物体的前面. 我们不会希望看到远处的山把近在眼前的建筑给挡住了!
如今有三种深度排序方法得到了广泛的应用:
- 深度缓冲 (也叫做 z-buffering)
- 油画家算法
- 背面剔除
不幸的是, 每种都有其局限性. 为了达到好的结果, 大多数游戏是把三种方法结合起来使用的.
深度缓冲
深度缓冲简单而有效, 结果也很完美. 但是对于透明的物体它就无能为力了!
这是因为深度缓冲只记录了当前已经绘制的最近像素. 对于不透明的物体, 这已经能够满足我们的需要了. 看一下这个绘制两个三角形的例子, A和B:

如果我们先画B再画A, 深度缓冲会看到新的像素(A的)比之前的(B的)要近, 那么它就画在了前面.
如果我们用相反的顺序画(先A后B), 深度缓冲会看到B的像素比之前A已经画的要远, 所以就把它们给丢弃掉了.
无论哪种情况我们都会得到正确的结果: A在前面, B隐藏在后面.
但是当这些几何图形是透明的, 即B透过A是部分可见的时会怎样呢? 如果我们先画B再画A的话是没有问题的, 但反过来就不行了.
在这种情况下, 深度缓冲会从B取一个像素, 同时注意到已经绘制了一个更近的像素(A的), 然后它就没辙了!
唯一的选择是绘制B(这会得到一个错误的结果, B会画在A前面, 但A的alpha 混合却没有起作用), 或者完全抛弃B. 不爽!
结论
深度缓冲对于不透明的物体是很完美的, 但对于透明的物体却不实用.
油画家算法
深度缓冲没法应付以错误的顺序来绘制透明物体的情况, 这很好解决, 对吧? 保证它们按正确的顺序绘制就可以了! 如果对场景中的所有物体进行排序, 那我们就可以先画远处的, 再画近处的, 这样就可以确保前面例子中的B可以在A之前绘制.
不幸的是, 这说起来容易做起来难. 对物体进行排序在很多情况下并不适用, 如A和B相交的情况该怎么办?

如果A是个玻璃杯而B是它里面的一个玻璃球时就是这样. 现在我们就没法对它们进行排序了, 因为A的一部分比B近, 而另一部分又比B远.
甚至我们不需要两个不同的物体来复现这个问题. 组成玻璃杯的那些三角形会怎样? 要让它们显示正确, 需要在前面的绘制之前先绘制后面的. 所以, 只对物体进行排序是不够的: 我们要对每一个三角形进行排序.
问题是, 对每个三角形进行排序的代价太大! 就算我们能够承受, 这也不是在所有的场合下都能得到正确的结果的. 比如说两个透明的三角形相交时会怎样呢?

没有方法对这样的三角形进行排序, 因为我们需要把B的上半部分画在A的前面, A的下半部分画在B的前面. 唯一的解决方案就是把三角形从相交处分割开来, 但是这样的消耗是不可承受的.
结论
油画家算法需要你在选择排序的粒度好好权衡一下. 如果你仅仅对一些大的的物体进行排序, 速度很快但不是很精确; 如果你对一些小物体进行排序(包括三角形个体的极限情况), 速度会慢一些, 但更加精确.
背面剔除
一般不把背面剔除当成是一种排序技术, 但它确实是一种重要的方法. 它的局限性就是只适用于凸面体.
考虑一下一个简单的凸面体, 如一个球体或立方体. 无论你从哪个角度看, 每个屏幕上的像素都会被覆盖两遍: 一次是物体的前面, 一次是后面.
如果你用背面剔除丢弃了背面的三角形, 那就只剩前面了. 哈哈, 如果每个屏幕上的像素只进行一次判断, 那你就自动得到了一个完美的混合结果,
没有必要排序任何东西.
当然, 大多数的游戏不会只画球体或立方体J 所以只是背面剔除的话不是一个妥善的解决方案.
结论
背面剔除对于凸面体是完美的, 但是对于其它的就无能为力了.
我该怎样让我的游戏看起来更好一些?
最常用的方法:
- 设置DepthBufferEnable 和DepthBufferWriteEnable 为true
- 绘制所有的不透明物体
- 保持DepthBufferEnable 为true, 但是设置DepthBufferWriteEnable为false
- 对alpha混合的物体按照与摄像机的距离进行排序, 然后从后到前画出来
这依赖于三种排序技术的结合
不透明的物体按深度缓冲排序
透明物体和不透明物体仍然会被深度缓冲处理(所以你永远不会通过一个不透明物体看到一个透明的)
油画家算法对透明的物体排序(两个透明物体相交时仍然会有排序错误)
依赖背面剔除来对单个透明物体上的三角形排序(如果物体不是凸面体也会产生错误)
结果并不是非常完美, 但是非常高效, 易于实现, 对于大多数游戏来说也够用了.
当然还可以采取一些措施来改进排序的精确度:
避免alpha混合! 你的不透明物体越多, 排序就越容易, 也越精确. 仔细思考一下, 真得每个地方都需要alpha混合吗?
如果关卡设计师要在玻璃窗上再加一层, 那你应该考虑把设计改成更易于实现的方案. 如果你正使用alpha混合来绘制树木之类的图形,
那考虑用alpha测试来代替它, 只分完全透明和完全不透明这两种情况, 这样不透明的地方仍然可以通过深度缓冲来排序.
放松, 不用担心. 可能排序错误并不是很严重呢? 你可以试着调整一下你的图形(让alpha通道更加柔和, 更加透明一些)
来让这个错误看起来没有那么显眼. 这个方法用在了我们的 Particle 3D sample中, 它并不会对单独一个烟雾中的粒子进行排序,
而是选择了一个合适的粒子纹理让它看起来是好的. 如果你把烟雾的纹理换成更加不透明的, 那排序错误可能就比较容易觉察了.
如果你有透明物体不是凸面体, 或许你可以尝试让它们更加”凸”一些? 就算它们不是完全地凸面体, 那它们越”凸”, 排序错误就越少.
还有就是考虑把复杂的模型分成多块, 这样它们就可以分开进行排序. 一个人体看起来一点也不像凸面体, 但你把它分成头, 胳膊, 驱干等几部分后,
每一块都接近凸面体了.
如果你有部分区域透明的纹理(如树叶), 并且图案边缘包含了一些半透明的像素用于反走样, 那你可以使用双pass渲染技术:
Pass 1: 绘制不透明部分: alpha混合关闭, alpha测试只接受100%不透明的区域, 深度缓冲开启
Pass 2: 绘制边缘: alpha混合开启, alpha测试设置只接受alpha<1的, 深度缓冲开启, 深度写入关闭
以
每个物体渲染两次的代价, 为纹理中间完全不透明的部分提供了100%正确的深度缓冲排序, 和相对精确的半透明边缘排序.
这个方法为纹理裁剪的边缘进行了一些反走样, 同时也保证了不用对每一棵树或者草叶进行额外的排序. 在我们的 Billboard sample
中使用了这个技巧: 请阅读一下Billboard.fx中的pass和注释.
使用 z prepass. 当你需要淡出一个原来不透明的物体又不想透过它看到的是它自己的另一部分时, 这是一个好方法.
例如从右边看一个人类的身体. 如果它是玻璃做的, 你应该会希望透过右手臂看到躯干和左手臂.
但如果它是实心的(不透明)你会希望透过右手臂看到后面的背景, 而不应该是躯干和左手臂. 要达到这个目标需要这样做:
设置 ColorWriteChannels=None, 开启深度缓冲
绘制物体到深度缓冲(不影响颜色缓冲)
设置ColorWriteChannels=All, DepthBufferFunction=Equal, 开启alpha混合
再次绘制这个物体, 这样就只有最近的这一面与颜色缓冲进行混合了
Published Wednesday, February 18, 2009 1:47 PM by ShawnHargreaves
相关推荐
在3D渲染中,Alpha混合用于实现物体的透明效果,如树叶、玻璃或半透明材质。在2D图像处理中,它可以用于创建层叠图像的效果,比如图片合成、文字叠加等。在游戏开发中,Alpha测试和Alpha覆盖也是常见的优化手段,以...
正确的深度排序可以确保近处的物体遮挡远处的物体,使得游戏场景显得更加立体真实。 copyPixels是ActionScript 3(AS3)中一个非常重要的功能,它允许开发者将一个显示对象的一部分复制到另一个位置。在处理遮挡和...
同时,这也有助于他们掌握更复杂的渲染技术,如深度排序(以解决半透明物体重叠时的正确绘制顺序问题)和多级渐变混合(Multi-Sample Anti-Aliasing, MSAA)等。 总之,Alpha混合是DirectX 9编程中的关键一环,对于...
同时,确保深度测试正确配置,以避免透明物体的排序问题,因为OpenGL默认按顺序绘制,后面的物体可能覆盖前面的物体,即使前面的物体部分透明。 此外,性能也是考虑因素之一。Alpha混合通常比纯色渲染更耗能,因为...
为了混合半透明像素,我们需要开启Alpha混合功能。这可以通过调用`glEnable(GL_BLEND)`来实现,并设置合适的混合函数,如`glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)`,这使得新绘制的像素颜色与已有颜色...
5. **优化透明效果**:虽然alpha混合和深度缓冲区能处理大部分情况,但效率可能不高,尤其是在大量透明物体存在时。优化策略包括:分组渲染(相同透明度的物体一起绘制)、使用alpha测试(只绘制alpha值超过某个阈值...
通常,这种合成算法会按照像素的深度顺序进行,确保近处的物体遮挡住远处的物体,这被称为Z缓冲或深度测试。然而,`alphablendnosort.c`的名称暗示了它可能是一个不依赖于像素排序的透明合成实现,可能使用了不同的...
4. **合并**:对排序后的像素信息进行合并,通常是通过alpha混合来完成,以创建出正确的透明效果。这一步可能涉及到多个遍历缓冲区的过程,根据排序结果逐个处理像素。 5. **输出**:最后,将处理好的图像输出到帧...
4. **深度冲突**:由于透明物体的深度排序问题,可能导致阴影错位或者消失。Unity可能需要额外的优化来解决这种深度冲突,例如使用Depth Prepass或者Depth Postpass。 5. **性能考虑**:阴影计算对GPU资源消耗较大...
4. **Alpha Blending**:对于可见的透明物体,使用Alpha Blending进行混合,但此时由于已经正确排序,可以避免深度排序问题。 5. **边缘光处理**:在Shader中添加边缘检测逻辑,为物体边缘添加增强的光照效果。 6....
- **多边形排序**:透明对象通常需要后方物体先渲染,前方物体后渲染,以避免颜色混淆。 - **像素着色器**:更高级的透明效果可以通过自定义像素着色器来实现,允许在GPU上进行复杂的透明度计算。 通过理解和实践...
在Unity3D中,物体透明穿插问题是一个常见的视觉效果问题,当两个或多个透明物体重叠时,...对于更复杂的场景,可能还需要进一步优化,例如使用排序图(Sorting Layer)或者深度预烘焙等技术来处理大量透明物体的交互。
4. **深度排序**:透明物体的正确渲染还需要考虑深度信息。由于近处的物体应覆盖远处的物体,所以通常需要对透明物体进行后处理排序,以确保正确显示。 5. **光照和阴影**:透明物体的光照和阴影处理也相对复杂,...
半透明效果,也称为Alpha混合或透明度,是通过调整像素的Alpha值来实现的。Alpha通道是颜色模型中的一个额外组成部分,用于表示颜色的透明度,通常在RGB(红绿蓝)颜色模型中添加一个A(Alpha)通道,形成RGBA。...
考虑对两个多边形(1和2)进行alpha混合,不同的绘制次序会得到不同的结果。(这里假定多边形1离观察者最近,那么正确的过程应该先画多边形2,再画多边形1。正如您再现实中所见到的那样,从这两个<透明的>多边形背后...
这个Shader可能包含了深度预pass、深度排序以及正确的混合模式设置,以确保无论物体如何堆叠,都能正确呈现遮挡关系。 渐隐效果,也就是物体从完全透明逐渐变为完全不透明,或者反之,是通过控制物体的Alpha值来...
然而,单纯使用Alpha测试可能导致深度排序问题,即近处的透明物体可能会遮挡住远处的物体。为解决这个问题,可以使用混合模式,同时调整深度缓冲的处理方式,确保透明物体的正确渲染。 **颜色混合(Color Blending...
在3D场景中,多个物体可能会同时覆盖同一像素,Z缓冲器会存储每个像素对应位置的深度值,确保近的物体在前,远的物体在后,从而实现正确的深度排序和绘制。 其次,深度测试/排序是3D图形渲染中不可或缺的部分。深度...
2. 自定义混合模式:除了标准的Alpha混合模式,Ghost Shaders还支持多种自定义混合模式,如Additive、Subtractive和Multiply等,这使得开发者可以创造出各种独特的视觉效果,如火焰、烟雾或者光晕。 3. 次表面散射...
总结来说,画一个透明的平面涉及到多个技术环节,包括但不限于阿尔法通道的理解和使用、3D几何建模、光照处理、深度排序以及渲染优化。这个过程需要结合合适的软件工具和编程技巧,通过实践和调整参数来达到理想的...