-
-
Notifications
You must be signed in to change notification settings - Fork 20.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix scaling issue in draw_line
and similar methods
#69851
Conversation
For completeness, this is kind of a re-implementation of #44361 (which was closed because the PR author lost interest) |
This changes the public API, so the "breaks compat" label is needed (however, the default behavior remains the same). |
Indeed the current approach in this PR (which I suggested) is compat breaking as it changes the behavior for cases where user explicitely passes A possible non compat breaking alternative suggested in godotengine/godot-proposals#1363 (comment):
So e.g
to:
Bool parameters are cryptic/meh and with such change when someone always wants a quad then they would also be force to specify the
@dalexeev I think you've misunderstood me. I was talking about if it would need to be done automatically. But exposing the choice to the user is as simple as for |
The difficulty with the "thin rectangle" is that the offset must depend on the |
If you're referring to something like this it could be handled by just zeroing the |
The lines will overlap in the corners, which will be noticeable with a translucent color. |
There are 3 options:
|
66ee292
to
52ca69d
Compare
Test project: fix-scaling-issue.zip Notes:
godot/servers/rendering/renderer_canvas_cull.cpp Lines 1316 to 1343 in 97df6de
|
36e4f2a
to
d4b01e5
Compare
@clayjohn @kleonc Could you review or at least comment on this PR please? This is needed for #41239 and issues like #71131. See also this comment about polyline. |
This change makes sense to me. It is a very small breaking change, but indeed it is very counterintuitive that a line of width 1.002 would scale with the canvasitem while a line of 0.999 won't. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should merge this before 4.0. It is a breaking change, but the new behaviour makes much more sense, and it likely won't break many projects because the only change in behaviour will be for people using this with a width (0.0, 1.001] (which with the old behaviour is the exact same as using the default of 1.0, but now will actually scale).
Will just need to be rebased onto current master |
d4b01e5
to
2743f53
Compare
Rebased. The only thing that bothers me is that the polyline and arc methods remain inconsistent. |
@@ -597,7 +597,7 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, | |||
Vector2 end_left; | |||
Vector2 end_right; | |||
|
|||
if (p_width > 1.001) { | |||
if (p_width >= 0.0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@clayjohn Should we maybe not draw anything when p_width == 0.0
? Probably this is such a corner case that it's not worth checking but I wonder what's your opinion on this.
@@ -628,7 +628,7 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, | |||
// This value is empirically determined to provide good antialiasing quality | |||
// while not making lines appear too soft. | |||
float border_size = 1.25f; | |||
if (p_width < 1.0f) { | |||
if (0.0f <= p_width && p_width < 1.0f) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that this doesn't change the previous behavior for default thin lines, meaning antialiasing for them is still kinda broken. Here's the same zoomed in line drawn in v4.0.beta11.official [91713ce] with width = 1.0
and without/with antialiasing (with this PR the default width = -1.0
will give the same result):
It should be fine to leave it like that in this PR. Just wanted to point it out, maybe we should somehow address antialiasing thin lines later, in a separate PR.
scene/main/canvas_item.cpp
Outdated
@@ -556,6 +556,7 @@ void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vec | |||
|
|||
void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, real_t p_width) { | |||
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); | |||
ERR_FAIL_COND_MSG(p_width < 0, "The draw_rect() \"width\" argument must be non-negative."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not convinced about disallowing to draw a rect with line primitives. I think it would make more sense to make the p_width
work the same as in draw_line
etc. and just add a relevant note in draw_rect
's docs about its limitations (like potential brighter corner for translucent colors caused by the overlap, missing pixels at the corners, etc.).
E.g. for debugging you often don't really care about these issues, you just want to draw a simple rect (and width not scaling with the zoom might be desired).
Also with such change now by default non-filled rects would be drawn as quads so I wonder how it would affect all built-in controls / editor plugins. I think many of them could be using draw_rect
with default width. It could also affect performance.
So yeah, I think we should allow thin rects despite of all their quirks.
Implementation-wise: just draw the thin sides with zero offsets (right from the corners) and accept this often won't be perfect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@dalexeev godot/servers/rendering_server.h Line 288 in 60d0317
so it shouldn't be hard to make polyline and arc methods interpret the width in the same manner. |
2743f53
to
ac0b82f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks @dalexeev for all the patience with the subject. 🙂
CanvasItem.draw_polyline
❌ - The thin option is not supported.
CanvasItem.draw_polyline_colors
❌ - The thin option is not supported.
CanvasItem.draw_arc
❌ - The thin option is not supported.
RenderingServer.canvas_item_add_polyline
❌ - The thin option is not supported.
Adding support for thin lines in polylines/arc (in a manner consistent with this PR) is a potential material for a separate PR.
ac0b82f
to
a8cbb62
Compare
Thanks! |
Does this fix either of the related issues, or it's only the first step towards fixing them? |
#44332 would be fixed by adding support for thin lines in polylines. I can tackle this (+arc). Unless @dalexeev you've already started doing so? |
No, I didn't start. I can try later, but if someone has a desire to deal with this, I will be glad, as I am not sure of my skills. |
Yeah, I'll (try to) do it. |
CanvasItem.draw_line
and a few other methods havewidth
parameter. There is a check in the current implementation: if width is greater than 1, a four-point primitive is drawn, otherwise a two-point primitive. This causes the lines ofwidth <= 1
to remain thin when theCanvasItem
is scaled, while the thickness of other lines scales proportionately. This issue has been reported several times, for example #51978.While in some cases this behavior is desirable, in other cases (such as pixel games) it can be inconvenient and inconsistent (you cannot use values between 0.0 and 1.0). The only workaround for this problem is a hack with
width = 1.002
.This PR implements kleonc's suggestion to change the API as follows. Change the default value of the
width
parameter to-1
and treat negative values as an indicator of a two-point line primitive. In this case, if you explicitly specifywidth = 1
, then the line will scale correctly.List of methods to check (which have
width
parameter and are related to line drawing)CanvasItem.draw_line
✔️CanvasItem.draw_dashed_line
✔️CanvasItem.draw_multiline
✔️CanvasItem.draw_multiline_colors
✔️CanvasItem.draw_polyline
❌ - The thin option is not supported.CanvasItem.draw_polyline_colors
❌ - The thin option is not supported.CanvasItem.draw_arc
❌ - The thin option is not supported.CanvasItem.draw_primitive
✔️ - Removed unusedwidth
parameter.CanvasItem.draw_rect
✔️ - The thin option does not work perfectly, there is a note in the docs.RenderingServer.canvas_item_add_line
✔️RenderingServer.canvas_item_add_multiline
✔️RenderingServer.canvas_item_add_polyline
❌ - The thin option is not supported.RenderingServer.canvas_item_add_primitive
✔️ - Removed unusedwidth
parameter.