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