我最近开始学习C++中的DirectX编程,我对其他语言的图形编程有一些经验,但我对DirectX场景还很陌生。
无论如何,我想问一个关于透明纹理的问题。到目前为止,我一直使用alpha测试,因为这已经满足了我的需求,但我最近开始想知道,"合适的"游戏引擎是如何为植物和树木等具有平滑透明度的事物呈现出如此好看的半透明纹理的。
每次我使用alpha测试时,texures都会看起来很块状,而且非常糟糕。我希望能够拥有光滑、半透明的纹理,如我所期望的那样绘制。
我的猜测是,如何按顺序执行渲染调用,从远离相机的东西开始,然后移近。然而,我真的看不出这对预先制作的模型是如何工作的,例如,如果你有一个树模型,其中树叶和树干共享一个模型,如何保证后面的树叶会绘制,树干会在树叶上正确绘制,而且前面的叶子在树干上看起来是正确的。
我尝试过上面的方法,还禁用了烟雾颗粒等透明物体的z缓冲,这有点奏效,但看起来很乱,效果也因视角而异。所以这似乎并不理想。
简言之,"正确"游戏使用什么方法将平滑的alpha纹理(具有一系列alpha值)正确绘制到树叶等物体的3D场景中。
谢谢,迈克尔。
有序透明度基本上是使用painters算法实现的。
如果一个对象需要在另一个对象的前面和后面绘制,或者单个对象有多个子组件是透明的,则画家的算法会失败。我们不能简单地将网格的子组件相对于彼此进行排序。
虽然它不能解决z缓冲区允许我们优化渲染的问题。大多数游戏都使用这种稍微复杂一点的算法作为渲染的基础。
- 渲染按材质状态或从前到后排序的所有不透明对象以避免透支
- 渲染从前到后排序的所有透明对象
游戏结合使用各种技术来避免这个问题。
将模型拆分为不重叠的透明部分。通常情况下,这是隐含的,因为游戏的透明对象通常使用与模型其他部分不同的材质。也可以拆分具有多个透明层的模型,使每个新模型的层不重叠。例如,可以将松树模型径向拆分为5个部分。
这在固定功能管道中更为常见。现代游戏只是试图避免这个问题。
避免在模型中使用半透明零件。仅对抗锯齿边使用透明度,并且透明对象可以将世界干净地拆分为两组独立的对象。(例如,窗户或水上飞机)。像这样分割世界并前后渲染这些块,可以绘制我们的抗锯齿边,而不会在其他透明对象上造成明显的剪切。只要你的阿尔法测试设置得高于约30%,即使它们重叠,边缘本身也会看起来很好。
半透明对象通常渲染为粒子效果。草和烟是最常见的例子。效果或草对象组的点列表按每帧进行排序。这是一个比排序任意子网格简单得多的问题。许多户外游戏都有复杂的草地和树叶实例化系统。这使它们能够正确排序渲染单个叶片和叶片,并避免了以这种方式进行渲染的大部分渲染开销,但它们严格限制了对象的类型。
使用加法和减法混合而不是alpha混合,可以以与顺序无关的方式实现许多效果。
如果你的光滑边缘仍然不可接受,有几个简单的选择。您可以抖动透明度低于75%的模型的任何部分。或者,你可以让硬件为你做这件事,通过使用覆盖到阿尔法没有可见的工件。这会导致多采样硬件抖动透支样本中的边缘。它不会给你一个平滑的渐变,但4-16级别的alpha对于抗锯齿边缘来说是完全可以接受的,如果你已经打算使用MSAA,它是免费的。
有很多注意事项和特殊情况。如果你有水,你可能需要使用模具或深度测试来渲染任何与水相交两次的半透明对象。
将摄影机移入和移出透明对象总是有问题的。
渲染一个复杂的半透明对象几乎是不可能的。就像建筑物或鬼魂的x光透视图。许多游戏只是将这种类型的对象渲染为附加对象。但有了现代硬件,各种更复杂的方案是可能的。
更复杂的方案
Depth Peeling是一种渲染方法,使用不同的Z剪裁平面渲染多个过程,以从后到前合成场景,而不管顺序或哪个对象包含alpha。它比您预期的要便宜,因为许多对象只渲染到一个或两个切片。但它并不完美,许多游戏开发商发现它的成本太高。
还有许多其他种类的秩序独立透明度。使用现代GPU和计算,我们可以在一次渲染中渲染到缓冲区,其中每个像素都是一堆可能的切片。然后,我们可以在后处理中对堆栈进行排序并混合这些切片,只有当像素上有透明层时,才会导致性能损失。
OIT仍然主要只用于特殊情况,如2.5D游戏(如《小星球》)。但我相信它最终可能会成为游戏编程的核心工具。