[rshapes] `DrawRectangleLines()` lines flickering when zooming out due to `RL_LINES` vs `RL_QUADS`
arceryz opened this issue · 3 comments
Please, before submitting a new issue verify and check:
- I tested it on latest raylib version from master branch
- I checked there is no similar issue already reported
- I checked the documentation on the wiki
- My code has no errors or misuse of raylib
Issue description
When working with DrawRectangleLines
, the behavior as expected is to have the rectangle drawn with RL_LINES, i.e pure OpenGL lines with no artefacts at small distances like DrawLine
. However, DrawRectangleLines
(and possible other fake *Lines
drawing methods) are rendered with Quads when SUPPORT_QUADS_DRAW_MODE
is true. While I understand that this may be for avoiding draw order issues (as stated in the source comment), intuitively one would expect that *Lines
methods are drawn with pure OpenGL lines to avoid artefacts.
So I would recommend not mixing RL_LINES and Quads when possible and to be clear which or the other any function in rshapes.c
is using.
I encountered this when creating an infinite grid when zooming in and out on a tool, using DrawRectangleLines
would have the rectangle flickering at high levels of zoom, because the quads become sub-pixel sized. It is not a big issue, because I can just implement a custom DrawRectangleLines
that draws 4 lines instead (as expected). But I think it may be better to have all the *Lines
function (except the Ex
versions with lineWidth
) to be rendered always with RL_LINES and not quads.
It is in particular this piece of code in rshapes.c
:
// Draw rectangle outline
// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues
void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
{
#if defined(SUPPORT_QUADS_DRAW_MODE)
DrawRectangle(posX, posY, width, 1, color);
DrawRectangle(posX + width - 1, posY + 1, 1, height - 2, color);
DrawRectangle(posX, posY + height - 1, width, 1, color);
DrawRectangle(posX, posY + 1, 1, height - 2, color);
#else
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(posX + 1, posY + 1);
rlVertex2f(posX + width, posY + 1);
...
See the gif for a demonstration of the issue and how it may work counterintuitively for Raylib users. (Expectation: rectangle remains a rectangle at big distance).
Environment
Windows, vanilla Raylib 5.0 C
Issue Screenshot
The left square is the expected behavior (4 lines) and the right square is DrawRectangleLines
.
The camera is zoomed out progressively. With greater zoom levels, DrawRectangleLines
becomes basically pointless.
Code Example
It is python code because I wrote quickly, but it is nothing special and would look the same in C.
from pyray import *
init_window(800, 800, "Bug")
camera: Camera2D = Camera2D(Vector2(0, 0), Vector2(0, 0), 0, 1)
while not window_should_close():
begin_drawing()
begin_mode_2d(camera)
clear_background(BLACK)
draw_line(10, 10, 210, 10, WHITE)
draw_line(210, 10, 210, 210, WHITE)
draw_line(210, 210, 10, 210, WHITE)
draw_line(10, 210, 10, 10, WHITE)
draw_rectangle_lines(300, 10, 200, 200, WHITE)
camera.zoom -= get_frame_time() * 0.1
end_mode_2d()
end_drawing()
@arceryz Good catch! And thanks for reporting! I expected OpenGL driver to manage that properly on its side... but effectively lines rendering is completely different than triangles... It probably can't be addressed from raylib side but just be properly documented.
@raysan5 Would it be an option to have all the pure *Lines
drawing methods (expect the *Ex
variants) just implemented with RL_LINES, and the *LinesEx
methods, which have thickness, be implemented using triangles/quads? I think this would make most sense, since of course lines with thickness can't avoid this issue so we can leave *LinesEx
untouched. This way you can just say that the *Lines
drawing methods are safe at faraway distances.
@arceryz DrawRectangleLines()
has been reviewed with the proposed fix BUT notice that this change can derive in other unexpected issues: When drawing with GL_LINES
first pixel position calculation could be offseted by one pixel depending on the GPU/drivers, I'm afraid it's an impossible issue to be fixed.
Also note that DrawRectangleRoundedLines()
now should be reviewed for consistency with other Draw*Lines()
functions.