Search code examples
openglgeometryrectangles

How to scale primitives similar to Imgui?


I would like my renderer to act similar to imgui. What ever size imgui application has, imgui widget window size do not change.

that is how imgui looks like when resolution is 1280x720

enter image description here

and that is how it looks when resolution is 1920x1017

enter image description here

primitives are all the time the same size

in my application resizing a window causes different sides to be different thickness or unpleasant phenomena.

my app unfilled rect 1280x720

enter image description here

my app the same rect 1920x1017

enter image description here

as you can see higher resolution causes in this case bottom side of unfilled rect to be different thickness then the other sides (it may not be shown in a photo, but in a screen it is shown and it is very annoying).

imgui has not got this problem. My app renderer is almost the same (without few advanced options).

How could I implement that? Why does it work like this? I asked imgui creator, but he told me it is not about imgui and he cannot help.


Solution

  • In general, one way or another, any primitive you draw will ultimately end up in clip space and then normalized device coordinates. You may apply some matrix transforms to the input positions or whatnot, but the vertex shader, by definition, outputs clip-space coordinates. These clipspace coordinates are then projected to normalized device coordinates.

    In normalized device coordinates (NDC), your viewport (your "screen") extends from -1 to 1 in x and y direction (hence the "normalized"). NDC are relative to your viewport. That means if you specify a vertex of your primitive such that it ends up at position (-0.5, 0.25) in NDC, that means it will be 1/4 of the full width of the screen along x and 5/8 along y:

    illustration of NDC

    If you want to place primitives at specific pixel locations inside your viewport, then you will have to compute their coordinates such that they end up at the corresponding NDC coordinates. For example, let's say you have an 800×600 viewport and you want to place a vertex at pixel coordinates (50, 40). In this case, you want the vertex coordinates to end up being

    x_NDC = 2 * (50 + 0.5) / 800 - 1
    y_NDC = 2 * (40 + 0.5) / 600 - 1
    

    The + 0.5 is to account for the fact that sample locations in OpenGL are at the centers of the pixel grid:

    enter image description here

    In general, to place a vertex at pixel coordinates (x, y) on the near plane, you want your vertex shader to return the coordinates

    x_clip = 2.0f * (x + 0.5f) / W - 1
    y_clip = 2.0f * (y + 0.5f) / H - 1
    z_clip = 0
    w_clip = 1
    

    where W and H are the width and height of the viewport and assuming the origin of your pixel coordinates is the lower left corner.