0

I have the following problem: I am drawing a 2D scene using opengl which contains a set of points. Each point is specified whith it's XY coords. I'd like to use a marker symbol - something like a triangle, a cross or a quad to render points. The problem is that a marker size should be constant on a screen when zooming the scene - something like using GL_POINTS. So each time I change the scale I have to recalculate my markers coordinates, and that is not convenient - I'd like to do it once when getting a new rendering point position. Is there any issues?

Mikhail Zimka
  • 694
  • 1
  • 9
  • 20

1 Answers1

2

The easiest approach is probably that you have textures with your symbols, and then draw them with point sprites. If you need help with that approach, my answer here explains how to use point sprites:

Render large circular points in modern OpenGL

Another approach that comes to mind is that you apply the scaling of the geometry in the vertex shader after all other transformations, including the projection, have been applied.

The best that comes to mind immediately is that you pass two attributes for each vertex into the vertex shader:

  • The center of the marker, which is the same value for all vertices of one marker.
  • The relative offset from the center of the marker.

Then in the vertex shader, you apply all the usual transformations, up to and including the projection transformation, to the center only. Then you add the relative offset.

Sketching out the vertex shader, it could look like this:

in vec3 centerPos;
in vec2 relativePos;
uniform mat4 ModelViewProj;
...

void main() {
    ...
    vec4 projCenterPos = ModelViewProj * vec4(centerPos, 1.0);
    gl_Position = vec4(
        projCenterPos.xy + projCenterPos.w * relativePos,
        projCenterPos.zw);
}

Since the relative offset is applied after the projection, you have to take into account that we now have homogenous coordinates, where x, y, and z will be divided by w as part of the fixed function processing after the vertex shader. To make the size constant after this perspective division, the code above multiplies the offset by w.

Since relativePos is essentially applied in NDC (Normalized Device Coordinates), where the range in x- and y-directions is [-1.0, 1.0], the values will have to be fairly small. For example, an offset of 0.02 corresponds to 1% of the window size.

If you want the sizing to be more flexible, you could pass in another scale factor to control the size of the sprite, and multiply relativePos by the factor in the calculation above. You could then keep the relative positions e.g. within a range of [-1.0, 1.0], and then scale them down appropriately:

...
uniform float spriteSize;
...

    gl_Position = vec4(
        projCenterPos.xy + spriteSize * projCenterPos.w * relativePos,
        projCenterPos.zw);
Community
  • 1
  • 1
Reto Koradi
  • 53,228
  • 8
  • 93
  • 133