在 OpenGL/GLSL 中绘制镶嵌的 LineLoop
Drawing tessallated LineLoops in OpenGL/GLSL
我正在球体(行星边界)上渲染一些 LineLoop,并希望将它们镶嵌成较短的线,以防止长线剪裁到球体中。
例子:
这是我当前的源代码:
C++ 绘图调用:
void Border::Draw() const
{
glBindVertexArray(_vao);
glPatchParameteri(GL_PATCH_VERTICES, 2);
glDrawArrays(GL_PATCHES, 0, _size);
glBindVertexArray(0);
}
顶点着色器:
#version 400
in layout(location = 0) vec3 position;
void main()
{
gl_Position = vec4(position, 1.0);
}
曲面细分控制着色器:
#version 400
layout (vertices = 2) out;
void main()
{
if(gl_InvocationID == 0)
{
//get the distance between two points
float dist = length(gl_in[0].gl_Position - gl_in[1].gl_Position);
gl_TessLevelOuter[0] = 1;
//divide line in segments of size 1.0
gl_TessLevelOuter[1] = abs(dist);
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
曲面细分评估着色器
#version 400
layout (isolines, equal_spacing) in;
uniform float planetRadius;
uniform mat4 view;
uniform mat4 projection;
void main()
{
vec4 p = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);
//offset point so it is on the spheres surface
p = normalize(p);
p *= planetRadius;
gl_Position = projection * view * p;
}
片段着色器:
#version 400
out vec4 outColor;
void main()
{
outColor = vec4(1.0, 1.0, 1.0, 1.0);
}
镶嵌似乎没有像我预期的那样工作(等值线的文档也很糟糕)。
这是我用 LineLoops 绘制它时的样子,只有 Vertex/Fragment 着色器:
这就是我实施曲面细分后的样子:
这些线条看起来也没有镶嵌,并且与以前的长度相同。
你好 Jhonny
编辑:
自己找到了解决方案。请查看下面的答案部分。
我找到了解决办法。问题在于镶嵌着色器无法绘制线条。因此,如果您有一条由点 {p1, p2, p3, p4, p5, p6}
定义的线带,它会在以下之间画线:
p1 -> p2
p3 -> p4
p5 -> p6
我通过给着色器每个点 2 次来修复它,所以我的列表如下所示:
{p1, p2, p2, p3, p3, p4, p4, p5, p5, p6, p6, p1}
细分着色器创建以下行:
p1 -> p2
p2 -> p3
p3 -> p4
p4 -> p5
p5 -> p6
p6 -> p1
我的着色器现在看起来像这样:
苔丝控制:
#version 430
layout (vertices = 2) out;
void main()
{
if(gl_InvocationID == 0)
{
float dist = length(gl_in[0].gl_Position.xyz - gl_in[1].gl_Position.xyz);
gl_TessLevelOuter[0] = 1;
gl_TessLevelOuter[1] = dist;
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
TessEval:
#version 430
layout (isolines, equal_spacing) in;
uniform float planetRadius;
uniform mat4 view;
uniform mat4 projection;
void main()
{
//only interpolate and normalize xyz coordinates. Thanks to @aslg
vec3 p = mix(gl_in[0].gl_Position.xyz, gl_in[1].gl_Position.xyz, gl_TessCoord.x);
p = normalize(p);
p *= planetRadius;
gl_Position = projection * view * vec4(p, 1.0);
}
我正在球体(行星边界)上渲染一些 LineLoop,并希望将它们镶嵌成较短的线,以防止长线剪裁到球体中。
例子:
这是我当前的源代码: C++ 绘图调用:
void Border::Draw() const
{
glBindVertexArray(_vao);
glPatchParameteri(GL_PATCH_VERTICES, 2);
glDrawArrays(GL_PATCHES, 0, _size);
glBindVertexArray(0);
}
顶点着色器:
#version 400
in layout(location = 0) vec3 position;
void main()
{
gl_Position = vec4(position, 1.0);
}
曲面细分控制着色器:
#version 400
layout (vertices = 2) out;
void main()
{
if(gl_InvocationID == 0)
{
//get the distance between two points
float dist = length(gl_in[0].gl_Position - gl_in[1].gl_Position);
gl_TessLevelOuter[0] = 1;
//divide line in segments of size 1.0
gl_TessLevelOuter[1] = abs(dist);
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
曲面细分评估着色器
#version 400
layout (isolines, equal_spacing) in;
uniform float planetRadius;
uniform mat4 view;
uniform mat4 projection;
void main()
{
vec4 p = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);
//offset point so it is on the spheres surface
p = normalize(p);
p *= planetRadius;
gl_Position = projection * view * p;
}
片段着色器:
#version 400
out vec4 outColor;
void main()
{
outColor = vec4(1.0, 1.0, 1.0, 1.0);
}
镶嵌似乎没有像我预期的那样工作(等值线的文档也很糟糕)。
这是我用 LineLoops 绘制它时的样子,只有 Vertex/Fragment 着色器:
这就是我实施曲面细分后的样子:
这些线条看起来也没有镶嵌,并且与以前的长度相同。
你好 Jhonny
编辑: 自己找到了解决方案。请查看下面的答案部分。
我找到了解决办法。问题在于镶嵌着色器无法绘制线条。因此,如果您有一条由点 {p1, p2, p3, p4, p5, p6}
定义的线带,它会在以下之间画线:
p1 -> p2
p3 -> p4
p5 -> p6
我通过给着色器每个点 2 次来修复它,所以我的列表如下所示:
{p1, p2, p2, p3, p3, p4, p4, p5, p5, p6, p6, p1}
细分着色器创建以下行:
p1 -> p2
p2 -> p3
p3 -> p4
p4 -> p5
p5 -> p6
p6 -> p1
我的着色器现在看起来像这样:
苔丝控制:
#version 430
layout (vertices = 2) out;
void main()
{
if(gl_InvocationID == 0)
{
float dist = length(gl_in[0].gl_Position.xyz - gl_in[1].gl_Position.xyz);
gl_TessLevelOuter[0] = 1;
gl_TessLevelOuter[1] = dist;
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
TessEval:
#version 430
layout (isolines, equal_spacing) in;
uniform float planetRadius;
uniform mat4 view;
uniform mat4 projection;
void main()
{
//only interpolate and normalize xyz coordinates. Thanks to @aslg
vec3 p = mix(gl_in[0].gl_Position.xyz, gl_in[1].gl_Position.xyz, gl_TessCoord.x);
p = normalize(p);
p *= planetRadius;
gl_Position = projection * view * vec4(p, 1.0);
}