可能但相对棘手,你需要一个几何着色器。它们几乎总是在 Direct3D 中可用:最后具有功能级别的 GPU < 11.0 was Intel Sandy Bridge from 2011, computers don’t usually live that long. However, availability in GL and especially GLES varies.
三角形的边
在几何着色器中,为三角形的每个顶点生成
float2
,三角形的 3 个顶点的值为 [ 1, 0 ]、[ 0, 1 ] 和 [ 0, 0 ]。
然后在像素着色器中,使用以下HLSL函数进行边缘检测,未经测试:
inline bool detectEdge( in float2 bary2 )
{
// Compute minimum of these barycentric coordinates
// The third one is redundant because they add up to 1.0
float minBary = min( bary2.x, bary2.y );
minBary = min( minBary, 1.0 - ( bary2.x + bary2.y ) );
// Compute screen-space derivative of that variable
float w = fwidth( minBary );
// We want to return true for 1 pixels-wide line on the edge
// Edges are shared by 2 triangles, each triangle needs 0.5 pixel wide line
return ( minBary * 2 ) < w;
}
几何边缘
你的第一个问题比较复杂。 一种可能的方法是添加一个
DXGI_FORMAT_R8_UINT
类型的顶点属性。对于网格边缘的顶点,将这些字节设置为 1,对于其余的顶点,将这些字节设置为 0。
将这些整数从顶点传递到几何着色器。 在那里,您可以找出三角形的哪些边位于几何体的边上:
inline uint outerEdgesBitmap( uint v0, uint v1, uint v2 )
{
uint res = 0;
if( v0 != 0 && v1 != 0 )
res = 1; // v0-v1 edge is external
if( v1 != 0 && v2 != 0 )
res |= 2; // v1-v2 edge is external
if( v2 != 0 && v0 != 0 )
res |= 4; // v2-v0 edge is external
return res;
}
通过图形管道传递该位图,您可以在像素着色器中检测几何体外边缘上的像素:
inline bool detectEdge( in float2 bary2, uint outerBitmap )
{
float minBary = 1.0;
if( 0 != ( outerBitmap & 1 ) )
minBary = bary2.x;
if( 0 != ( outerBitmap & 2 ) )
minBary = min( minBary, bary2.y );
if( 0 != ( outerBitmap & 4 ) )
minBary = min( minBary, 1.0 - ( bary2.x + bary2.y ) );
// For open edges, we want the entire 1-pixel wide line inside the triangle
return minBary < fwidth( minBary );
}
附注我没有测试过这些 HLSL 函数,但我过去使用过类似的方法,它有效。