Direct3D 线条粗细
Posted
技术标签:
【中文标题】Direct3D 线条粗细【英文标题】:Direct3D Line thickness 【发布时间】:2011-01-17 19:33:21 【问题描述】:使用 Direct3D 绘制线条列表时如何更改线条粗细?
This post 表示不支持线宽并继续提供解决方法。其他选择?
当我们讨论这个话题时,着色器是否允许使用虚线图案绘制线条?
【问题讨论】:
【参考方案1】:您可以使用几何着色器,该着色器将线段作为输入并输出四边形(由两个三角形组成的三角形条带),以便四边形的宽度在屏幕空间中保持不变并与所需线相匹配厚度。它工作得非常好(因为在 CAD 3D 引擎中实现了它)。
如果几何着色器不是一个选项,解决方法可能是使用顶点着色器,但这需要对 VB 进行一些返工。请记住,VS 必须了解整个线段,因此您最终将为每个 VB 元素存储 p 和 p+1,加上索引/顶点重复的成本(取决于使用的拓扑和如果您将您的线渲染为索引图元)。
如果性能不是问题,那么在 CPU 上进行扩展可能是可行的方法。
编辑:
关于破折号模式:您也可以使用几何着色器来模拟 glLineStipple
行为。
如果您有GL_LINES
拓扑,即隔离线,则模式会在每个新线段处重新开始。因此,您只需在几何着色器中计算线段的屏幕空间水平起点(或垂直起点,取决于方向),并将这些额外信息传递给像素着色器。然后像素着色器将负责根据 factor 和 pattern 值丢弃片段(DirectX 10/11 Integer 和 Bitwise 指令使其变得容易)。
同样,这很有效,您可以将它与模拟宽度线结合起来(使用上面提到的第一种技术)。
现在,如果您有GL_LINE_STRIP
拓扑,则模式会在每个新图元处重新启动(因此对于每个新绘制调用)。情况变得有点复杂,因为您需要知道之前已渲染的像素数,以及每个线段的像素数。
您可以通过使用 DirectX 10 流输出功能在临时 VB 中渲染线条来实现这一点(该 VB 的每个元素对应于每个段的屏幕空间长度)。然后你必须对这个 VB 做一个 Parallel Prefix Sum(又名 Scan)(用于累积每个线段长度值)。
最后,你像GL_LINES
一样渲染你的线条,但在PS中使用这个额外的扫描VB信息。
【讨论】:
【参考方案2】:Direct3D 不仅不支持线条粗细,而且任何现有的 GPU 也不支持。我知道没有 GPU 甚至可以绘制正确的线(它们都是通过使用退化多边形来假线 - 也就是说,第二个和第三个顶点位于同一位置,所以三角形基本上折叠成一条线)。
虽然可以在 OpenGL 中设置线宽,但 OpenGL 驱动程序会创建拉伸四边形(当前 GPU 也不支持,并且每个四边形使用两个三角形进行模拟)以在屏幕上绘制“线” .
因此,可能没有办法为此创建挤压四边形。正如 Stringer Bell 在他的回答中解释的那样,有几种方法可以实现这一目标。
对我来说最简单的方法是创建一个顶点缓冲区,其中包含每个顶点两次,法线指向“右”或“左”,具体取决于它们是线的右边缘还是左边缘。然后一个非常简单的顶点着色器可以执行挤压(通过将顶点位置更改为其法向量的倍数)。通过这种方式,您可以快速更改线宽,而无需在 CPU 上重新计算几何图形。如果您想根据对象的大小或距离调整线宽,这会很有用。
【讨论】:
这是一个有趣的解决方案。您是否获得了与 glLineWidth 调用相同的结果(基于每个像素)? 我没有按像素检查,但对于无纹理、抗锯齿的线条,结果应该足够相似。使用纹理(例如,模拟 OpenGL 的点画图案)肯定会让您进入一个痛苦的世界,纹理坐标的非线性插值(NVidia Quadros 处理的非常糟糕,即使与几乎相同的 Geforce 部分相比)。着色器需要执行大量额外的工作才能使 texcoords 正确。 您可以自己尝试,只需使用某种“以屏幕像素为单位的线条长度”作为纹理坐标,并使用带有点画图案的纹理绘制线条。您会惊讶于图案的不均匀程度。至少我是。 ;-)【参考方案3】:"The ID3DXLine interface implements line drawing using textured triangles."
【讨论】:
【参考方案4】:关于您的虚线图案(点画)问题,您最好的办法可能是将线渲染为细四边形,并在像素着色器中对其应用纹理,其中纹理包含您的虚线图案。您需要将采样器地址模式设置为换行,例如:
SamplerState wrapTriLinear
AddressU = WRAP;
AddressV = WRAP;
【讨论】:
以上是关于Direct3D 线条粗细的主要内容,如果未能解决你的问题,请参考以下文章
Direct3D中 SetTextureStageState 函数