我建議先繪製(綠色)區域,然後再繪製一條虛線(白色)線條。
繪製直線時,可以使用Geometry Shader將線段轉換爲四邊形(包含4個點的三角形條紋),這些四邊形包圍在給定線條粗細中由實線填充的薄區域。片段着色器finnaly必須衝破線(切割線的部分)。最後,Fragment Shader必須產生虛線(切出部分)。
畫線,所述Primitive類型GL_LINE_STRIP_ADJACENCY
必須使用(見GLSL Tutorial - Primitive Assembly),因爲每個線段具有知道其前身和後繼者,來計算在拐角處的角度平分線。如果多邊形是由一系列線條定義的,那麼可以很容易地完成。列表的最後一點必須添加在點列表的開始位置,列表的第一個點必須添加在點列表的末尾。
例如如果一個多邊形組成的點的甲,乙,Ç和d,那麼爲GL_LINE_STRIP_ADJACENCY
點的清單將是d,甲,乙,Ç,D和A。這會得到下列4線段:
- 甲到乙,與前身d和後繼Ç
- 乙到Ç,與前身甲和繼任者D
- C到d,與前身乙和後繼甲
- d到甲,與前身Ç和後繼乙
的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;
),因爲間隙中的片段將用0通道繪製。
如果先填充(綠色)多邊形,並且虛線(白色)繪製線條第二,那麼結果可能會是這樣的:
你當然可以這樣做是幾何着色器,吐出兩個三角形本身和粗線邊框。然而,這是相當先進的。所有線圖庫都必須考慮連接時的斜角,圓角,斜角等。這是一個不平凡的主題。可能太多以至於無法回答。 – Robinson
你能否指出我在哪裏可以找到關於幾何着色器的更多信息?我很驚訝,使一個簡單的邊界是如此艱難。 – crychair
那裏有很多東西。谷歌的「幾何着色器+ opengl」,也許「幾何着色器+粗線+ opengl」。 – Robinson