How to render perfect wireframed rectangle in 2D mode with OpenGL?

后端 未结 4 1062
离开以前
离开以前 2020-12-30 03:08

Edit: just so you know: I have not solved this problem perfectly yet, currently I am using 0.5px offset, it seems to work, but as others have said,

相关标签:
4条回答
  • 2020-12-30 03:49

    Try change 0.5 into the odd magic number that's used everywhere 0.375. Used be opengl, and X11 etc.

    Becuase of that diamond rule mentioned and how graphiccards draw to avoid unnecessery overdraws of pixels.

    Provide some link but there's lots of them, just search keywords opengl 0.375 diamond rule if you need more information. It's about how outlines and fills are treated algorithmically in opengl. It's needed for pixelperfect rendering of textures in for example 2d sprites aswell.

    Take a look at this.

    Want to add something; So doing what you want, implementing diamond rule implemented in code would be simply one liner; change 0.5 into 0.375 like this; And it should render properly.

    glTranslatef(0.375, 0.375, 0.0);
    
    0 讨论(0)
  • 2020-12-30 04:01

    @Troubadour described the problem perfectly. It's not a driver bug. GL is acting exactly as specified. It's designed for sub-pixel accurate representation of the world space object in device space. That's what it's doing. Solutions are 1) anti-alias, so the device space affords more fidelity and 2) arrange for a world coordinate system where all transformed vertices fall in the middle of a device pixel. This is the "general" solution you are looking for.

    In all cases you can achieve 2) by moving the input points around. Just shift each point enough to take its transform to the middle of a device pixel.

    For some (unaltered) point sets, you can do it by slighly modifying the view transformation. The 1/2 pixel shift is an example. It works e.g. if the world space is an integer-scaled transform of device space followed by a translation by integers, where world coordinates are also integers. Under many other conditions, though, +1/2 won't work.

    ** Edit **

    NB as I said a uniform shift (1/2 or any other) can be built into the view transform. There is no reason to fiddle with vertex coordinates. Just prepend a translation, e.g. glTranslatef(0.5f, 0.5f, 0.0f);

    0 讨论(0)
  • 2020-12-30 04:06

    Although you've discovered that shifting your points by 0.5 makes the problem go away it's not for the reason that you think.

    The answer does indeed lie in the diamond exit rule which is also at the heart of the correctly accepted answer to Opengl pixel perfect 2D drawing.

    The diagram below shows four fragments/pixels with a diamond inscribed within each. The four coloured spots represent possible starting points for your quad/line loop i.e. the window co-ordinates of the first vertex.

    Possible vertex points outside a fragment's diamond

    You didn't say which way you were drawing the quad but it doesn't matter. I'll assume, for argument's sake, that you are drawing it clockwise. The issue is whether the top left of the four fragments shown will be produced by rasterising either your first or last line (it cannot be both).

    1. If you start on the yellow vertex then the first line passes through the diamond and exits it as it passes horizontally to the right. The fragment will therefore be produced as a result of the first line's rasterisation.

    2. If you start on the green vertex then the first line exits the fragment without passing through the diamond and hence never exits the diamond. However the last line will pass through it vertically and exit it as it ascends back to the green vertex. The fragment will therefore be produced as a result of the last line's rasterisation.

    3. If you start on the blue vertex then the first line passes through the diamond and exits it as it passes horizontally to the right. The fragment will therefore be produced as a result of the first line's rasterisation.

    4. If you start on the red vertex then the first line exits the fragment without passing through the diamond and hence never exits the diamond. The last line will also not pass through the diamond and therefore not exit it as it ascends back to the red vertex. The fragment will therefore not be produced as a result of either line's rasterisation.

    Note that any vertex that is inside the diamond will automatically cause the fragment to be produced as the first line must exit the diamond (provided your quad is actually big enough to leave the diamond of course).

    0 讨论(0)
  • 2020-12-30 04:12

    This is not a bug, this is exactly following the specification. The last pixel of a line is not drawn to prevent overdraw with following line segments, which would cause problems with blending. Solution: Send the last vertex twice.

    Code Update

    // don't use glPolygonMode, it doesn't
    // do what you think it does
    glBegin(GL_LINE_STRIP);
        glVertex2f(a);
        glVertex2f(b);
        glVertex2f(c);
        glVertex2f(d);
        glVertex2f(a);
        glVertex2f(a); // resend last vertex another time, to close the loop
    glEnd();
    

    BTW: You should learn how to use vertex arrays. Immediate mode (glBegin, glEnd, glVertex calls) have been removed from OpenGL-3.x core and onward.

    0 讨论(0)
提交回复
热议问题