godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
89.55k stars 20.67k forks source link

Line2D doesn't draw full gradient if it doesn't have enough points #50076

Open KoBeWi opened 3 years ago

KoBeWi commented 3 years ago

Godot version

3.3 / 6ef0b8f

System information

W10

Issue description

ndlJcQAFvJ It would maybe make sense if the offsets were ignored and instead it used only the colors, but it's not the case.

Steps to reproduce

  1. Add Line2D
  2. Add 2 points to it
  3. Add a gradient to gradient property, with 3 colors

Minimal reproduction project

No response

Calinou commented 3 years ago

We could add a node configuration warning for this purpose.

kleonc commented 3 years ago

Line2D doesn't draw full gradient if it doesn't have enough points

In fact, Gradient is being drawn accurately in Line2D only in some simple cases, even if there are more points in Line2D than color points in the Gradient. In most cases it's really just an approximation of the used Gradient. Iterpolation is not being done accurately because what's interpolated in the end are vertex colors and even though vertex colors are properly assigned according to the Gradient, everything in between vertices might be color-wise "desynchronized" with the Gradient.

8hH2F7W4uX

There's kinda the same issue with the width curve of Line2D.

timcode77 commented 2 years ago

I get exactly the same problem in v3.4.4.stable.official [419e713a2].

Calinou commented 2 years ago

Fixing this probably involves automatically creating "subdivision" points behind the scenes, and ensuring the line is made of at least as many points as the gradient.

It may not be worth the added complexity, so maybe we should just document that you have to create enough points for the gradient's color to be accurately represented.

timcode77 commented 2 years ago

Fixing this probably involves automatically creating "subdivision" points behind the scenes, and ensuring the line is made of at least as many points as the gradient.

It may not be worth the added complexity, so maybe we should just document that you have to create enough points for the gradient's color to be accurately represented.

I think the problem runs deeper. See the series of screen grabs below. In these examples, the line always has 3 points and it has the same gradient with 3 colors. Yet only the first (leftmost, black) and last (rightmost, white) color get properly rendered. The middle color (red) doesn't always get properly rendered in the line. Therefore, just adding the same amount of points in the line as there are colors in the gradient are not sufficient to fix this problem.

image

image

image

image

Calinou commented 2 years ago

@timcode77 What I mean is that the subdivided points should also be created at the same offset as the gradient. This should make it possible to render any gradient correctly, no matter how many points your line is actually made of.

timcode77 commented 2 years ago

@timcode77 What I mean is that the subdivided points should also be created at the same offset as the gradient. This should make it possible to render any gradient correctly, no matter how many points your line is actually made of.

Ah ok. I misunderstood you. I was confusing "points": the things Line2D is comprised of in the editor and that are accessible to the user. Whereas you are talking about "subdivided points" which you are proposing get calculated behind the scenes and are not accessible to the user. Is that right?

Calinou commented 2 years ago

Whereas you are talking about "subdivided points" which you are proposing get calculated behind the scenes and are not accessible to the user. Is that right?

Yes :slightly_smiling_face:

kleonc commented 2 years ago

What I mean is that the subdivided points should also be created at the same offset as the gradient. This should make it possible to render any gradient correctly, no matter how many points your line is actually made of.

Note that this would work for a linear gradient. In 3.5+/4.0 there are also constant and cubic interpolation modes (added in #60982/#53321). Constant interpolation could be easily handled by doubling the "gradient points" within the line. Cubic interpolation based only on the vertex colors would be possible in a dedicated shader, which I'd guess is unlikely to be done (so I'd assume it won't be supported for Line2D.gradient property).

But the thing is... there are gradient textures. Applying gradient with a texture is trivial and it works already (it of course has its own quirks):

rq1qE5Shvl


I guess using the Gradient directly to assign vertex colors for the line mesh (that's what happens for Line2D.gradient property) is supposed to be cheaper than the texture gradient and that's the reason it exists in the first place? If so then I wonder if making gradients be correctly rendered by increasing the line mesh vertex count wouldn't neglect the benefits of this solution over using the gradient textures.

Also note that currently there's only one texture in the Line2D so by design you can't apply some Texture and a GradientTexture on top of it. Nonetheless it's not hard to work around that: 9bbUmTpHXT

shader_type canvas_item;

uniform sampler2D gradient_texture: hint_albedo;
uniform vec2 default_texture_tiling_factor = vec2(1.0);

void fragment() {
    COLOR = texture(TEXTURE, UV * default_texture_tiling_factor) * texture(gradient_texture, UV);
}

BTW this example perfectly shows that texture UVs are kinda bugged and this for sure could be improved? :thinking:


To sum up: not really sure what should be done about this issue. :slightly_smiling_face: