【转载】Alpha混合物体的深度排序

原文:Alpha混合物体的深度排序

先说个题外话, 本来我想解答一下最近Creators Club论坛上经常出现的一个问题, 意外的是在网上竟然找不到什么全面的答案..

这是个有着复杂答案的简单问题:

为什么我的透明物体的绘制顺序不对或者有些不见了?”

当绘制一个3D场景时, 对图形进行深度排序是非常重要的, 这样离镜头近才画在远处物体的前面. 我们不会希望看到远处的山把近在眼前的建筑给挡住了!

如今有三种深度排序方法得到了广泛的应用:

不幸的是, 每种都有其局限性. 为了达到好的结果, 大多数游戏是把三种方法结合起来使用的.

深度缓冲

深度缓冲简单而有效, 结果也很完美. 但是对于透明的物体它就无能为力了!

这是因为深度缓冲只记录了当前已经绘制的最近像素. 对于不透明的物体, 这已经能够满足我们的需要了. 看一下这个绘制两个三角形的例子, 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 所以只是背面剔除的话不是一个妥善的解决方案.

结论: 背面剔除对于凸面体是完美的, 但是对于其它的就无能为力了.

我该怎样让我的游戏看起来更好一些?

最常用的方法:

1.    设置DepthBufferEnable 和DepthBufferWriteEnable 为true

2.    绘制所有的不透明物体

3.    保持DepthBufferEnable 为true, 但是设置DepthBufferWriteEnable为false

4.    对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

(xoyojank: 这篇文章有助于理解N3的Batch机制, 呵呵)

时间: 2024-10-12 08:18:29

【转载】Alpha混合物体的深度排序的相关文章

深度排序与alpha混合 【转】

  翻译:李现民 最后修改:2012-07-03 原文:Depth sorting alpha blended objects 先说个题外话,本来我想回答在 Creators Club论坛上的一个常见问题,但(意外的是)我竟然没能从网上找到一个令人满意的答案. 问题本身很简单,但答案却有些复杂: “为什么我的透明物体的绘制顺序是错误的,或者为什么它们的一部分不见了?” 当绘制一个3D场景的时候,将图形按深度排序非常重要,只有这样靠近摄像机的物体才能被绘制在(离摄像机)更远的物体的上面.我们不会希

深度排序与alpha混合

原文: https://blogs.msdn.microsoft.com/shawnhar/2009/02/18/depth-sorting-alpha-blended-objects/ 翻译:李现民 最后修改:2012-07-03 "为什么我的透明物体的绘制顺序是错误的,或者为什么它们的一部分不见了?" 当绘制一个3D场景的时候,将图形按深度排序非常重要,只有这样靠近摄像机的物体才能被绘制在(离摄像机)更远的物体的上面.我们不会希望远方的山脉被绘制在近在眼前的建筑物的上面! 当前得到

【转载】D3D深度测试和Alpha混合

原文:D3D深度测试和Alpha混合 1.       深度测试 a)         深度缓冲区:屏幕上每个像素点的深度信息的一块内存缓冲区.D3D通过比较当前绘制的像素点的深度和对应深度缓冲区的点的深度值来决定是否绘制当前像素. b)        D3DPRESENT_PARAMETERS. AutoDepthStencilFormat = D3DFMT_D16 表示深度值由16位二进制表示 开启深度测试:pDevice->SetRenderState( D3DRS_ZENABLE, TR

Unity3D ShaderLab 修改渲染队列进行深度排序

为了更深刻的理解透明度,我们还需要学习一下深度排序,简单来说就是物体被渲染的先后顺序. Unity允许我们通过代码来控制某个特定物体渲染到屏幕的顺序.这个做法类似于photoshop中图层的概念. 开始之前,准备工作还是新建Shader Material,准备测试场景.为了对比 是需要使用2个材质球的. 打开我们的shader,稍微编辑一下即可看到效果.过程简单如下: Shader "91YGame/DepthSort" { Properties { _MainTex ("B

《逐梦旅程 WINDOWS游戏编程之从零开始》笔记8——载入三维模型&amp;Alpha混合技术&amp;深度测试与Z缓存

第17章 三维游戏模型的载入 主要是如何从3ds max中导出.X文件,以及如何从X文件加载三维模型到DirextX游戏程序里.因为复杂的3D物体,要用代码去实现,那太反人类了,所以我们需要一些建模软件. 对于3ds max,要到出.X文件,要装个Panda插件.然后就是作者推荐的一个3D模型资源网站:http://www.cgmodel.com/. 网格模型接口ID3DXMesh 这个接口表示网格,继承自ID3DXBaseMesh.ID3DXMesh接口中的D3DXCreateMesh()可用

【Unity Shaders】Transparency —— 使用渲染队列进行深度排序

本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源(当然你也可以从官网下载). ========================================== 分割线 ========================================== 写在前面 为了让我们真正明白透明度,我们需要了解一下深度排序,或者说,对象的绘制顺序.Unity允许

DirectDraw打造极速图形引擎(Alpha混合)

显然DirectDraw是Windows下写2D图形程序的最好选择,虽然Direct3D也可以写,但是没DirectDraw简单方便,特别对于初学者,一来就接触那么多函数和参数总不是件愉快的事,所以我的文章主要结合我做的工作,谈谈DirectDraw编程中一些比较关键的技术,大多是我自己想出来的.我想先声明,我的文章可以任意转载,源代码可以任意使用和修改. 由于我是业余时间写的文章,所以只能每次发表一篇,希望我的工作可以为大家的游戏增光添彩,同时我的文章主要面向有基本C++,DirectDraw

Unity3D教程宝典之Shader篇:第十三讲 Alpha混合

转载自风宇冲Unity3D教程学院 Alpha Blending,中文译作Alpha混合 Blending就是控制透明的.处于光栅化的最后阶段. 这里例如我们给一个模型贴一个材质,那么在某个点计算出来颜色值称为源,而该点之前累积的颜色值,叫目标. 语法 Blend Off     不混合 Blend SrcFactor DstFactor  SrcFactor是源系数,DstFactor是目标系数 最终颜色 = (Shader计算出的点颜色值 * 源系数)+(点累积颜色 * 目标系数) 属性(往

【转载】Deep Learning(深度学习)学习笔记整理

目录: 一.概述 二.背景 三.人脑视觉机理 四.关于特征 4.1.特征表示的粒度 4.2.初级(浅层)特征表示 4.3.结构性特征表示 4.4.需要有多少个特征? 五.Deep Learning的基本思想 六.浅层学习(Shallow Learning)和深度学习(Deep Learning) 七.Deep learning与Neural Network 八.Deep learning训练过程 8.1.传统神经网络的训练方法 8.2.deep learning训练过程 九.Deep Learn