3D基元上的透明纹理问题,XNA 4.0

4

我需要绘制一组大的立方体,每个立方体上都有(可能)唯一的纹理。其中一些纹理还具有透明部分。应该通过透明纹理看到后面的立方体。然而,貌似我绘制立方体的顺序决定了透明度是否有效,这是我想避免的。看这里:

cubeEffect.CurrentTechnique = cubeEffect.Techniques["Textured"];

Block[] cubes = new Block[4];
cubes[0] = new Block(BlockType.leaves, new Vector3(0, 0, 3));
cubes[1] = new Block(BlockType.dirt, new Vector3(0, 1, 3));
cubes[2] = new Block(BlockType.log, new Vector3(0, 0, 4));
cubes[3] = new Block(BlockType.gold, new Vector3(0, 1, 4));


foreach(Block b in cubes) {
    b.shape.RenderShape(GraphicsDevice, cubeEffect);
}

以下是Draw方法中的代码,它会产生如下结果: the first image 正如您所看到的,叶子立方体背后的纹理在另一侧不可见。当我在数组中反向索引3和0时,我得到了这个结果: correct image 很明显,绘制顺序影响到了立方体。我怀疑这可能与混合模式有关,但我不知道从哪里开始。
4个回答

7
您正在依赖深度缓冲来实现遮挡。这种技术仅适用于不透明的物体。
为了实现包含透明物体的正确遮挡,请执行以下操作:
  1. 将DepthBufferEnable和DepthBufferWriteEnable设置为true
  2. 绘制所有不透明几何图形
  3. 保持DepthBufferEnable设置为true,但将DepthBufferWriteEnable更改为false
  4. 按照与相机的距离排序alpha混合对象,然后从后向前顺序绘制它们
摘自Shawn Hargreaves的《深度排序alpha混合对象》

1
绘制透明物体比普通物体更难。原因是默认情况下,当面被渲染时,它会标记所有像素在特定深度处作为已绘制,因此在其后方的像素根本不会被绘制。我建议您购买一本三维渲染书籍,并查找更多详细信息。
最简单的方法是在绘制非透明物体后再绘制透明物体。这适用于透明和半透明物体。请注意,为了正确绘制透明物体,需要对其进行排序(与非透明物体不同)。
在您的特定情况下(非半透明),您可以将纹理渲染更改为对透明部分不进行任何渲染。

1
如果你只有固体或“非固体”的对象,那么你可以维护两个列表并首先渲染固体。然后,非固体可以在最后进行渲染,并按照距离最远的对象进行排序。如果你有一些多边形混合的对象,它们可以是固体/非固体,那么你最好考虑实现某种多通道系统,在这个系统中,你将传递给你的渲染代码哪个通道,然后你可以在那一点上过滤多边形,以确定是否在此通道中进行渲染(你仍然需要排序)。 - Roger Perkins

0

如果对象上没有半透明像素,您可能可以使用此选项。它将完全呈现为实心或不会写入Z缓冲区。 就像Riemers Alpha Testing一样。


这在XNA 3.1中可能有效,但不幸的是,4.0不支持AlphaTest功能。 - Bevin
我目前使用XNA的经验非常有限,但是现在XNA 4中似乎有一个内置的AlphaTestEffect,我不确定它是否存在于所有3个平台上并隐藏了其魔力,或者您是否也可以访问其内部操作。对于您当前的需求,这可能已经足够了。 - Roger Perkins
我发现了AlphaTestEffect,并尝试使用它,但我一定搞错了什么地方,因为结果完全错误。我将在实心块之后绘制透明块。 - Bevin

-2

XNA(以及DirectX和所有主要的3D库)考虑到了一些叫做culling的东西。虽然从你的代码中我无法确定,但从图片来看,我认为这是你的问题。你看不到的多边形顶点顺序错误。如果这是问题,你有两个解决方案:

  • 关闭剔除(如果我没记错的话,device.RenderState.CullMode = CullMode.None;
  • 将纹理应用两次,多边形的点顺序分别为顺时针和逆时针

我知道什么是剔除,我不认为这是问题所在。正如我在示例中展示的那样,通过反转立方体的数组索引,它会显示背后的纹理,没有问题。我认为问题在于首先绘制了叶子立方体,该纹理中的alpha与背景混合(没有其他立方体)。之后,绘制其他立方体,但叶子纹理没有与这些立方体混合。这只是一个理论,但我认为是正确的。 - Bevin
我知道了。那么我认为你需要发布更多的代码,例如你的特效是什么样子的,以及如何初始化和绘制顶点块。 - Andrei Pana
@Andrei Pana - 你可以在这里找到:https://dev59.com/JVPTa4cB1Zd3GeqPiVhj - Bevin
效果与Reimers XNA教程中的相同。 - Bevin
从图像来看,问题似乎是透明物体首先被渲染,写入深度缓冲区,之后任何图形卡认为在该点后面的东西都不会被写入帧缓冲区。正如另一个答案所指出的那样,您需要首先渲染所有固体部分,然后最后渲染透明部分,并按照从远到近的顺序进行排序。 - Roger Perkins
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接