防止像素着色器过度绘制单个ERG

时间:2013-12-21 15:51:00

标签: direct3d hlsl pixel-shader tessellation

背景

使用gluTess从GDI + DrawString(..)路径在Direct3D9中构建三角形列表:

tessellated text

然后使用像素着色器(v3.0)填充形状。使用不透明值绘制时,一切看起来都很好:

opaque output

问题

在某些字体大小的情况下,如果颜色具有alpha分量(即Argb#55FFFFFF),我们就会开始看到这些令人讨厌的镶嵌瑕疵,其中三角形可能会略微重叠:

transparent output

在较大的字体大小时,问题是有时不存在:

larger font test

使用英特尔卓越的GPA帧分析器像素历史记录工具,我们可以看到出现伪像的区域,像素已从单个Erg“触摸”了3次。

Erg analysis

我正试图找出如何阻止我的像素着色器多次触摸同一个像素。

与过度绘制预防相关的其他解决方案似乎都与zbuffer策略有关,但是这个问题更多地与在单个像素着色器通道中绘制单个2D三角形列表有关。

我试图想出一个解决方案,我有点失落。我希望HLSL可能有某种“只触摸每个像素一次”的标志,但我一直无法找到类似的东西。我发现最接近的是将BLENDOP设置为MAX而不是ADD。但是当混合场景中的其他颜色时输出不正确。

我也有SRCBLEND = ONE,DSTBLEND = INVSRCALPHA。生成正确输出的唯一标志组合(尽管有过度绘制工件。)

我在GPA帧分析器中使用了SEPARATEALPHABLENDENABLE,听起来像几乎正是我在这里所需要的 - 将混合设置为MAX但仅限于“alpha”通道,但是我可以确定,该设置(和相应的BLENDOPALPHA)根本不会影响任何内容。

我想到的最后一件事是将文本烘焙到纹理上不透明,然后将该纹理重新绘制到应用了相应alpha值的场景中,但是这实际上并不适用于此项目,因为我还支持渐变画笔,其中停止值可能包含alpha,意味着仍然可以看到工件,或者如果我们在烘焙到纹理之前将alpha从终止值剥离,则最终输出只是明显错误。此外,整个努力将非常昂贵。

任何提示或指示都将不胜感激。谢谢你的阅读。

1 个答案:

答案 0 :(得分:1)

你所看到的问题不应该发生。

如果你的两个三角形重叠,那是因为你已经放置了这些顶点,当绘制相邻的三角形时,它们会重叠。可能发生的是这两个相邻的三角形共享两个顶点,但每个三角形都有自己的每个顶点的副本,这些副本的位置非常非常不同。

解决问题的方法是不要试图让像素着色器只在使用索引缓冲区(如果你还没有)时触摸像素,并让每个三角形之间的共享顶点实际上共享同一个顶点并且不要使用与相邻三角形所使用的相同的地方。

如果您无法控制正在使用的曲面细分算法,则可能必须在生成顶点缓冲区后运行顶点缓冲区以检测和合并彼此非常小的容差范围内的顶点。即使没有索引缓冲区,一个天真的解决方案就是:

  1. 对于顶点缓冲区中的每个顶点,将其位置与顶点缓冲区其余部分中的每个其他顶点进行比较。

  2. 如果两个顶点在另一个顶点的小容差范围内,则将第二个顶点的位置替换为您要比较的顶点的位置。

  3. 这应该具有将两个顶点的位置配对的效果,如果它们足够接近你认为它们是相同的。

    现在,重叠三角形不应该有任何问题。在日常渲染中,两个三角形始终彼此共享边缘,并且您不会得到它们看起来每个如此轻微重叠的效果。硬件保证采样点位于线的一侧或另一侧,但不能同时存在,无论该点与线的距离有多近(即使它在数学上 on 这条线,它仍然在一边或另一边失败。)