Opengl 替换glLineWidth的GLSL几何体着色器
我正在尝试编写一个几何体着色器来替换Opengl 替换glLineWidth的GLSL几何体着色器,opengl,glsl,line,geometry-shader,Opengl,Glsl,Line,Geometry Shader,我正在尝试编写一个几何体着色器来替换glLineWidth行为。我想用一个可定制的宽度来画线(现在用一个统一的颜色就足够了)。线的厚度应始终相同,而与相机投影或线所在位置的距离无关 基于大量的谷歌搜索,我提出了以下几何体着色器: #version 330 layout (lines) in; layout (triangle_strip, max_vertices = 4) out; uniform mat4 u_model_matrix; uniform mat4 u_view
glLineWidth
行为。我想用一个可定制的宽度来画线(现在用一个统一的颜色就足够了)。线的厚度应始终相同,而与相机投影或线所在位置的距离无关
基于大量的谷歌搜索,我提出了以下几何体着色器:
#version 330
layout (lines) in;
layout (triangle_strip, max_vertices = 4) out;
uniform mat4 u_model_matrix;
uniform mat4 u_view_matrix;
uniform mat4 u_projection_matrix;
uniform float u_thickness = 4; // just a test default
void main()
{
float r = u_thickness / 2;
mat4 mv = u_view_matrix * u_model_matrix;
vec4 p1 = mv * gl_in[0].gl_Position;
vec4 p2 = mv * gl_in[1].gl_Position;
vec2 dir = normalize(p2.xy - p1.xy);
vec2 normal = vec2(dir.y, -dir.x);
vec4 offset1, offset2;
offset1 = vec4(normal * r, 0, 0);
offset2 = vec4(normal * r, 0, 0);
vec4 coords[4];
coords[0] = p1 + offset1;
coords[1] = p1 - offset1;
coords[2] = p2 + offset2;
coords[3] = p2 - offset2;
for (int i = 0; i < 4; ++i) {
coords[i] = u_projection_matrix * coords[i];
gl_Position = coords[i];
EmitVertex();
}
EndPrimitive();
}
。。。和我的片段着色器:
#version 330
uniform vec4 u_color = vec4(1, 0, 1, 1);
out vec4 fragColor;
void main() {
fragColor = u_color;
}
我不能让数学在所有情况下都适用。使用正交摄影机时,上述功能可以正常工作:
但对于透视相机,问题是线条不是固定大小。相对于物体的距离,它变得越来越大越来越小
我希望使用透视相机时线条的大小也一样。我做错了什么 我不是专家,但我以前做过这件事,我会提供我的见解 我假设您的
gl\u位置
s直接来自使用投影矩阵计算的顶点着色器。这意味着它们的w
分量是该点的“剪辑空间位置”;这是管道用来赋予投影效果的东西(越远的东西越小)。因此需要考虑到这一点
幸运的是,你唯一需要做的就是用它乘以你的偏移量
coords[0] = p1 + offset1 * p1.w;
coords[1] = p1 - offset1 * p1.w;
coords[2] = p2 + offset2 * p2.w;
coords[3] = p2 - offset2 * p2.w;
这应该会给你想要的效果。我考虑了视口大小,并用它缩放了我的r。我不知道这是否是解决这个问题最有效的方法(我绝对不是数学头脑),但它确实有效 在下面的代码中,我现在在屏幕空间而不是相机/视图空间中完成所有工作,并使用u_viewportInvSize vec2(即1/viewportSize)缩放所需的半径
#version 330
layout (lines) in; // now we can access 2 vertices
layout (triangle_strip, max_vertices = 4) out; // always (for now) producing 2 triangles (so 4 vertices)
uniform vec2 u_viewportInvSize;
uniform mat4 u_modelviewprojection_matrix;
uniform float u_thickness = 4;
void main()
{
float r = u_thickness;
vec4 p1 = u_modelviewprojection_matrix * gl_in[0].gl_Position;
vec4 p2 = u_modelviewprojection_matrix * gl_in[1].gl_Position;
vec2 dir = normalize(p2.xy - p1.xy);
vec2 normal = vec2(dir.y, -dir.x);
vec4 offset1, offset2;
offset1 = vec4(normal * u_viewportInvSize * (r * p1.w), 0, 0);
offset2 = vec4(normal * u_viewportInvSize * (r * p2.w), 0, 0); // changing this to p2 fixes some of the issues
vec4 coords[4];
coords[0] = p1 + offset1;
coords[1] = p1 - offset1;
coords[2] = p2 + offset2;
coords[3] = p2 - offset2;
for (int i = 0; i < 4; ++i) {
gl_Position = coords[i];
EmitVertex();
}
EndPrimitive();
}
#版本330
布局(行)在;//现在我们可以访问2个顶点
布局(三角形带,最大顶点=4)向外;//始终(目前)生成2个三角形(因此4个顶点)
统一的vec2 u_viewportInvSize尺寸;
均匀mat4 u_模型视图投影矩阵;
均匀浮子u_厚度=4;
void main()
{
浮动r=u_厚度;
vec4 p1=u_模型视图[0]中的投影矩阵*gl_]。gl_位置;
vec4 p2=u_模型视图[1]中的投影矩阵*gl_]。gl_位置;
vec2 dir=标准化(p2.xy-p1.xy);
vec2 normal=vec2(dir.y,-dir.x);
vec4抵销1、抵销2;
偏移量1=vec4(正常*u_viewportInvSize*(r*p1.w),0,0);
offset2=vec4(normal*u_viewportInvSize*(r*p2.w),0,0);//将其更改为p2可以解决一些问题
向量4坐标[4];
坐标[0]=p1+偏移量1;
坐标[1]=p1-偏移量1;
坐标[2]=p2+偏移量2;
coords[3]=p2-抵销2;
对于(int i=0;i<4;++i){
gl_位置=坐标[i];
发射顶点();
}
EndPrimitive();
}
几何体着色器并不以快速著称。使用几何体着色器是一个性能杀手,因此只有在所有其他选项都不可用时才建议使用。
答案中提供了一种不使用几何体着色器的可能解决方案
无论如何,如果要使用几何体着色器,请通过顶点着色器中的模型视图投影矩阵变换顶点坐标:
#版本330
在vec4 a_位置;
均匀mat4 u_模型视图投影矩阵;
void main()
{
gl_位置=u_模型视图投影矩阵*a_位置;
}
通过以下方式计算几何体着色器中的规格化设备坐标:
vec3 ndc_1=gl_in[0]。gl_Position.xyz/gl_in[0]。gl_Position.w;
vec3 ndc_2=gl_in[1]。gl_Position.xyz/gl_in[1]。gl_Position.w;
规范化的设备空间是一个立方体,其左、下、近(-1,-1,-1)和右、上、后(1,1,1)
计算直线各点之间的向量。按视口大小缩放,以考虑视口的纵横比。
最后,让学生们排队:
vec2 dir=normalize((ndc_2.xy-ndc_1.xy)*u_视口大小);
vec2 normal=vec2(-dir.y,dir.x);
计算垂直于直线的hal厚度偏移向量,并将其转换为标准化设备空间。这是通过按逆纵横比缩放并乘以2:
vec3 offset=vec3(正常*u_厚度*0.5/u_视口大小*2.0,0.0);
将偏移向量添加到标准化设备坐标并“撤消”透视分割:
gl\u Position=vec4((ndc\u 1+偏移)*gl\u在[0]。gl\u Position.w,gl\u在[0]。gl\u Position.w);
发射顶点();
gl_Position=vec4((ndc_1-偏移)*gl_在[0].gl_Position.w,gl_在[0].gl_Position.w);
发射顶点();
gl_Position=vec4((ndc_2+偏移)*gl_在[1]。gl_Position.w,gl_在[0]。gl_Position.w);
发射顶点();
gl_Position=vec4((ndc_2-偏移)*gl_在[1]。gl_Position.w,gl_在[0]。gl_Position.w);
发射顶点();
这可以进一步优化,并导致以下几何体着色器
#版本330
布局(行)在;//现在我们可以访问2个顶点
布局(三角形带,最大顶点=4)向外;//始终(目前)生成2个三角形(因此4个顶点)
统一的vec2 u_视口大小;
均匀浮子u_厚度=4;
void main()
{
vec4 p1=gl_位于[0]。gl_位置;
vec4 p2=gl_在[1]。gl_位置;
vec2 dir=规格化((p2.xy-p1.xy)*u_视口大小);
vec2 offset=vec2(-dir.y,dir.x)*u_厚度/u_视口大小;
gl_位置=p1+vec4(偏移量.xy*p1.w,0.0,0.0);
发射顶点();
gl_位置=p1-vec4(偏移量.xy*p1.w,0.0,0.0);
发射顶点();
gl_位置=p2+vec4(偏移量为0.xy*p2.w,0.0,0.0);
发射顶点();
gl_位置=p2-vec4(偏移量.xy*p2.w,0.0,0.0);
发射顶点();
EndPrimitive();
}
片段着色器
#版本330
out vec4 fragColor;
均匀vec4 u_颜色=vec4(1,0,1,1);
void main()
{
fragColor=u_颜色;
}
我已经试过了,没什么区别。请注意,我
#version 330
layout (lines) in; // now we can access 2 vertices
layout (triangle_strip, max_vertices = 4) out; // always (for now) producing 2 triangles (so 4 vertices)
uniform vec2 u_viewportInvSize;
uniform mat4 u_modelviewprojection_matrix;
uniform float u_thickness = 4;
void main()
{
float r = u_thickness;
vec4 p1 = u_modelviewprojection_matrix * gl_in[0].gl_Position;
vec4 p2 = u_modelviewprojection_matrix * gl_in[1].gl_Position;
vec2 dir = normalize(p2.xy - p1.xy);
vec2 normal = vec2(dir.y, -dir.x);
vec4 offset1, offset2;
offset1 = vec4(normal * u_viewportInvSize * (r * p1.w), 0, 0);
offset2 = vec4(normal * u_viewportInvSize * (r * p2.w), 0, 0); // changing this to p2 fixes some of the issues
vec4 coords[4];
coords[0] = p1 + offset1;
coords[1] = p1 - offset1;
coords[2] = p2 + offset2;
coords[3] = p2 - offset2;
for (int i = 0; i < 4; ++i) {
gl_Position = coords[i];
EmitVertex();
}
EndPrimitive();
}