因此,我的目标是创建一个绘制表面多边形的系统,它基本上围绕多边形创建一个虚线边框。问题是我希望这个边框是一个设置大小,这意味着每个破折号应该是多边形周围的设置大小。此外,我正在努力弄清楚如何制作它,以便如果你增加表面多边形的边框大小,它不会向外扩展,只有向内,这样的方式尺寸是倾斜的。
长话短说我开始基本上计算我自己的虚线边框并手工绘制每个破折号。这个问题出现在它们相遇的角度,并且当仪表板延伸到多边形之外时会切断额外的长度。附图显示了我到目前为止所拥有的内容以及它本质上应该是什么样子。我也想要保持多边形的正常边界与图片中的边界一样,但这不是强制性的。
我想我很惊讶这在NASA Worldwind中很难做到,其中directX约为20行。这让我觉得我以错误的方式去做。
就像一张纸条。我研究过使用模板缓冲器,但事实证明这几乎是浪费时间来完成工作并在世界风中正确运行。我认为我没有足够的把握来正确地做到这一点。
P.S。我开始使用的东西都没有一成不变。我只需要最终结果是正确的。谢谢你的帮助。
TLDR:需要a来绘制内部边界为设定宽度的多边形。
答案 0 :(得分:2)
我建议首先绘制(绿色)区域,然后绘制虚线(白色)线 绘制直线时,可以使用Geometry Shader将线段转换为四边形(带有4个点的三角形条纹),它将给定线条厚度中的实线填充的薄区域包围起来。碎片着色器finnaly必须划线(切割线的部分)。最后,Fragment Shader必须生成虚线(切割出的部分)。
要绘制线条,必须使用Primitive类型GL_LINE_STRIP_ADJACENCY
(请参阅GLSL Tutorial - Primitive Assembly),因为每个线段必须知道其前身继承者,计算角落中的角平分线。如果多边形由线列表定义,则可以轻松完成。必须在点列表的开头添加列表的最后一个点,并且必须在点列表的末尾添加列表的第一个点。
e.g。如果多边形由点 A , B , C 和 D 组成,那么点的列表GL_LINE_STRIP_ADJACENCY
将 D , A , B , C , D 和 A 。这将给出以下4个线段:
Vertex Shader只需要通过多边形的角点:
#version 400
layout (location = 0) in vec3 inPos;
out TVertexData
{
out vec3 pos;
} outData;
void main()
{
outData.pos = inPos;
gl_Position = vec4( inPos, 1.0 );
}
Geometry Shader计算每个线段末端起始端的角平分线,并根据线的粗细生成四边形。
由于片段着色器仍然需要生成虚线,因此计算线的长度和线的中心并将其传递给片段着色器。
#version 400
layout( lines_adjacency ) in;
layout( triangle_strip, max_vertices = 4 ) out;
in TVertexData
{
vec3 pos;
} inData[];
out TGeometryData
{
vec3 linePos;
vec3 lineMidPoint;
float lineLen;
} outData;
uniform float u_thickness;
void main()
{
if ( gl_InvocationID != 0 )
return;
vec3 pos0 = inData[1].pos;
vec3 pos1 = inData[2].pos;
vec3 dirPred = normalize( inData[0].pos - pos0 );
vec3 dirSucc = normalize( inData[3].pos - pos1 );
vec3 dirLine = normalize( pos1 - pos0 );
vec3 dirNorm = normalize( dirPred - dirLine * dot(dirLine, dirPred) );
dirSucc = faceforward( dirSucc, -dirNorm, dirSucc );
vec3 dir0 = abs( dot(dirPred, dirLine) ) > 0.99 ? dirNorm : normalize( dirPred + dirLine );
vec3 dir1 = abs( dot(dirSucc, dirLine) ) > 0.99 ? dirNorm : normalize( dirSucc - dirLine );
vec3 pos01 = pos0 + dir0 * u_thickness / dot(dir0, dirNorm);
vec3 pos11 = pos1 + dir1 * u_thickness / dot(dir1, dirNorm);
vec3 lineMidPoint0 = (pos0 + pos1) * 0.5;
vec3 lineMidPoint1 = lineMidPoint0 + dirNorm * u_thickness;
outData.lineLen = length( pos1 - pos0 );
outData.lineMidPoint = lineMidPoint0;
outData.linePos = pos0;
gl_Position = vec4(pos0, 1.0); EmitVertex();
outData.linePos = pos1;
gl_Position = vec4(pos1, 1.0); EmitVertex();
outData. lineMidPoint = lineMidPoint1;
outData.linePos = pos01;
gl_Position = vec4(pos01, 1.0); EmitVertex();
outData.linePos = pos11;
gl_Position = vec4(pos11, 1.0); EmitVertex();
EndPrimitive();
}
最后,Fragment Shader通过丢弃间隙中的片段来生成虚线。
#version 400
in TGeometryData
{
vec3 linePos;
vec3 lineMidPoint;
float lineLen;
} inData;
out vec4 fragColor;
uniform float u_dashLen;
uniform float u_gapLen;
uniform vec4 u_color;
void main()
{
float midDist = length( inData.linePos - inData.lineMidPoint );
float modDist = mod( midDist + u_dashLen * 0.5, u_dashLen + u_gapLen );
float onDash = max( step( modDist, u_dashLen ),
step( inData.lineLen * 0.5 - u_dashLen, midDist ) );
if ( onDash < 0.5 )
discard;
fragColor = u_color * onDash;
}
注意,此Fragment Shader使用discard
关键字来丢弃虚线间隙中的片段。如果使用Blending,则可以省略(if ( onDash < 0.5 ) discard;
),因为间隙中的片段将使用alpha通道0绘制。
如果首先绘制填充(绿色)多边形,然后绘制虚线(白色)线,则结果可能如下所示: