1

I am trying to implement geometry shader for line thickness using OpenGL 4.3.

I followed accepted answer and other given solutions of stackoverflow, but it is wrong according to the screenshot. Is there any proper way how can I get a normal of a screen? It seems correct in the first frame but the moment I move my mouse, the camera changes and offset direction is not correct. The shader is updated by camera matrix in while loop.

GLSL Geometry shader to replace glLineWidth

Vertex shader

#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 projection_view_model;

void main()
{
    gl_Position = projection_view_model * vec4(aPos, 1.0); 
}

Fragment shader

#version 330 core
//resources:
//https://stackoverflow.com/questions/6017176/gllinestipple-deprecated-in-opengl-3-1
out vec4 FragColor;


uniform vec4 uniform_fragment_color;

void main()
{
       FragColor = uniform_fragment_color;
}

Geometry shader

#version 330 core
layout (lines) in;
layout(triangle_strip, max_vertices = 4) out;

uniform float u_thickness ;
uniform   vec2    u_viewportSize ;

in gl_PerVertex
{
  vec4 gl_Position;
  //float gl_PointSize;
  //float gl_ClipDistance[];
} gl_in[];

void main() {   


 //https://stackoverflow.com/questions/54686818/glsl-geometry-shader-to-replace-gllinewidth


   vec4 p1 = gl_in[0].gl_Position;
    vec4 p2 = gl_in[1].gl_Position;

    vec2 dir    = normalize((p2.xy - p1.xy) * u_viewportSize);
    vec2 offset = vec2(-dir.y, dir.x) * u_thickness*100 / u_viewportSize;

    gl_Position = p1 + vec4(offset.xy * p1.w, 0.0, 0.0);
    EmitVertex();
    gl_Position = p1 - vec4(offset.xy * p1.w, 0.0, 0.0);
    EmitVertex();
    gl_Position = p2 + vec4(offset.xy * p2.w, 0.0, 0.0);
    EmitVertex();
    gl_Position = p2 - vec4(offset.xy * p2.w, 0.0, 0.0);
    EmitVertex();

    EndPrimitive();
}
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • You do not necessarily need a geoemtry shader: [Drawing a line in modern OpenGL](https://stackoverflow.com/questions/60440682/drawing-a-line-in-modern-opengl/60440937#60440937) – Rabbid76 Aug 21 '22 at 17:05
  • I would like to avoid calls from CPU to GPU – PetrasVestartasEPFL Aug 21 '22 at 17:07
  • I updated the code according to your comment I still see the distortion. I updated the image. Do you think it is due to perspective? – PetrasVestartasEPFL Aug 21 '22 at 17:15
  • 1
    The thickness of the line depends on the Z coordinate. This shader is designed for drawing in 2D, not 3D. In 2D all the Z coordinates are the same. – Rabbid76 Aug 21 '22 at 17:17
  • Any ideas how geometry shader should be transformed to 3D? – PetrasVestartasEPFL Aug 21 '22 at 17:23
  • Well, you need to vary `offset` based on the Z coordinate. – new Q Open Wid Aug 21 '22 at 17:27
  • @newQOpenGLWidget Sorry, but no. This is just a wild but wrong guess. Actually `offset.xy * p1.w` should handle that. I just don't see why it doesn't work – Rabbid76 Aug 21 '22 at 17:28
  • Normally the p1.w is controlled in the vertex shader, gl_Position = projection_view_model * vec4(aPos, 1.0f); but it has no effect, the momment I zoom in or zoom out the line thickness stays the same – PetrasVestartasEPFL Aug 21 '22 at 17:31
  • Actually it works if I use p1.w the width stays the same. I remove p1.w the thickness is scaled. But still why there is rotation of segment in the first place? Why the thickness offset is not perpendicular to the line? – PetrasVestartasEPFL Aug 21 '22 at 17:33
  • Actually, `offset.xy * p1.w` should compensate the perspective divide for the thickness of the line. That should do the trick. – Rabbid76 Aug 21 '22 at 17:35
  • I set the viewport size like this: _shader_line.setVec2("u_viewportSize", glm::vec2(opengl_globals::SCR_WIDTH, opengl_globals::SCR_HEIGHT)); – PetrasVestartasEPFL Aug 21 '22 at 17:39
  • No, with the square size also I see the non orthogonal offset. – PetrasVestartasEPFL Aug 21 '22 at 17:42
  • 1
    I actually do not see what is wrong. In my opinion, it should work. Sorry, no clue. – Rabbid76 Aug 21 '22 at 17:49
  • 1
    I don't know what the problem is with your code, but the original example works fine (I just tested it): https://github.com/Rabbid76/graphics-snippets/blob/master/example/cpp/opengl/example_shader_geometry_1_line.cpp – Rabbid76 Aug 21 '22 at 18:41
  • I copied your camera settings, but the result is the same. I made a short video. It is strange that positions of lines vertices are drawn correctly in 3d, but not the offset. https://www.youtube.com/watch?v=rzTfpskFZNA – PetrasVestartasEPFL Aug 21 '22 at 19:59
  • Is there any way that this line of code is wrong? normalize((p2.xy - p1.xy) Since this is just direction of a line why there is no cross product? – PetrasVestartasEPFL Aug 21 '22 at 20:15
  • @PetrasVestartasEPFL Try `normalize(p2.xy/p2.w - p1.xy/p1.w)` – Rabbid76 Aug 21 '22 at 20:17

1 Answers1

1

To get the direction of the line in normalized device space, the x and y components of the clip space coordinated must be divided by the w component (perspective divide):

vec2 dir = normalize((p2.xy - p1.xy) * u_viewportSize);

vec2 dir = normalize((p2.xy / p2.w - p1.xy / p1.w) * u_viewportSize);
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • It feels really correct. My screengrab: https://www.youtube.com/watch?v=DACKSymGVDY Thank you very much for so much time on my issue. On another subject do you have any references how to create an ortho camera without perspective distortion? – PetrasVestartasEPFL Aug 21 '22 at 20:28
  • @PetrasVestartasEPFL An orthographic projection cannot have a perspective distortion, because the projection rays are parallel. – Rabbid76 Aug 21 '22 at 20:32
  • Thank you, i ll try to check how can I implement it. From your code I see there was a previous code for ortho. But when I use that matrix I cannot see anything. – PetrasVestartasEPFL Aug 21 '22 at 21:16