I want to draw a preliminary dotted line like line in graphedit, i want the line is gradient and is dotted line.

so i use line2d do it.use dotted line texture create line,and use gradient texture and shader to change color.

this problem is uv is not in 0-1, it will be greater than 1 and I don’t know the maximum.So there is a problem with the graphics now.

I hope it is the global gradient viande

this is my code as attached

the shader is

shader_type canvas_item;
render_mode blend_mix;
uniform sampler2D gradient;
void fragment()
{
	COLOR = texture(TEXTURE, UV);
	vec4 gradient_color=texture(gradient, UV);
	COLOR = vec4(gradient_color.rgb, COLOR.a);
}

i think problem is uv.

i need your help please,thanks a lot. BR.

I don't know if it will fix the issue or not, but maybe try using SCREEN UV instead of UV? It won't give exactly the same result, since the color applied to the line will be dependent on screen position rather than staying consistent, but I think it would at least fully color the Line2D.

What is the size of the gradient texture? I think its ratio needs to be the same as TEXTURE for the UV coordinates to work correctly.

Edit: I downloaded the project and found a solution that works:

shader_type canvas_item;
render_mode blend_mix;
uniform vec4 color : hint_color= vec4(0.05,0.05,0.6,1);
uniform sampler2D gradient;
void fragment()
{	
	vec2 work_UV = UV;
	while (work_UV.x > 1.0) {
		work_UV.x = work_UV.x - 1.0;
	}
	while (work_UV.y > 1.0) {
		work_UV.y = work_UV.y - 1.0;
	}
	
	COLOR = texture(TEXTURE, work_UV);
	vec4 gradient_color=texture(gradient, work_UV);
	COLOR = vec4(gradient_color.rgb, COLOR.a);
}

All I did was wrap the UV coordinates around if they extend beyond the 0-1 boundary. It seems to be working when I tested it once the UV is kept within the 0-1 boundary.

Thank you very much for your reply. I did try this scheme, but this scheme is not what I want to achieve.

I hope the purpose is to have a color at the head of the line segment, a color at the end of the line segment, and a gradient in the middle. not like a looping effect

i want it like this

Maybe try this?

shader_type canvas_item;
render_mode blend_mix;
uniform vec4 color : hint_color= vec4(0.05,0.05,0.6,1);
uniform sampler2D gradient;
varying vec2 clamped_UV;

void vertex()
{
	if (UV.x > 1.0 || UV.y > 1.0) {
		clamped_UV = vec2(1.0, 1.0);
	} else {
		clamped_UV = UV;
	}
}

void fragment()
{	
	
	vec2 work_UV = UV;
	while (work_UV.x > 1.0) {
		work_UV.x = work_UV.x - 1.0;
	}
	while (work_UV.y > 1.0) {
		work_UV.y = work_UV.y - 1.0;
	}
	
	COLOR = texture(TEXTURE, work_UV);
	vec4 gradient_color=texture(gradient, clamped_UV);
	COLOR = vec4(gradient_color.rgb, COLOR.a);
}

It still keeps the dashed line, but the gradient applied is not repeating, which I think may be the look you are wanting (if I understand correctly).

Edit: Screenshot:

This is what i want,Thank you very much for your help

If you have time, can you explain the code to me. i think clamped_UV is vec2(1.0, 1.0) if UV.x > 1.0 or UV.y > 1.0 . so the line will be a same color in the second half, i think it will like this but the code is magic.it can get this result

i want to know why you do it ,and the result is right.

void vertex()
{
    if (UV.x > 1.0 || UV.y > 1.0) {
        clamped_UV = vec2(1.0, 1.0);
    } else {
        clamped_UV = UV;
    }
}

@vmjcv said: This is what i want,Thank you very much for your help

Awesome, happy to help!

If you have time, can you explain the code to me. i think clamped_UV is vec2(1.0, 1.0) if UV.x > 1.0 or UV.y > 1.0 . so the line will be a same color in the second half, i think it will like this (image omitted to save space) but the code is magic.it can get this result: (image omitted to save space) i want to know why you do it ,and the result is right.

I can try to explain how it works, though my explanation may be poor due to my lack of shader experience. There are two problems that the shader fixes: The gradient needs to be mapped from the first point to the second point, and the dashes need to tile across the length of the line.


First, let's quickly cover how UV mapping works in relation to this problem, as its an important concept to understand that makes the shader make sense. Keep in mind, this is the super fast and dirty explanation, and if you are curious to learn more, I would highly suggest doing additional research.

UV mapping tells Godot where to place pixels from the texture when drawing. In 2D, most everything is actually a rectangle composed of four vertices. For Line2D, we can just assume that for each point in the line, there are two vertices (a safe assumption for the most part).

Each vertex has a UV coordinate, which is in the range of 0 to 1. (0, 0) is the top left corner, while (1, 1) is the bottom right corner. If a coordinate goes over the UV range, one of two things happens: If the texture is set to repeat, it rolls the UV coordinate back into the 0-1 range and draws the texture as required (essentially, it's a bit more complicated but...), or the coordinate is clamped to the nearest valid position (so (2, -1) becomes (1, 0), as that's the closest valid position).

I probably explained it poorly, so it it doesn't seem to make sense, please look into how UV mapping works from other developers who explain it better than I am here.


First, we need to make the dashed line texture repeat across the length of the entire Line2D node, but without relying on the texture being set to repeat. To make the texture repeat, we need to take the coordinates that are outside of the 0-1 range and place them into the 0-1 range. To do this, we look to see if a coordinate is higher than the given range, and if it is, we subtract 1 until it's in the correct range.

How the shader works: We get the UV coordinate and assign it to a variable (working_uv) and then check if it's coordinates are over the 0-1 range. If it is, then we subtract 1 from the UV coordinates until its in the 0-1 range using a while loop. Then, instead of passing the UV coordinates to the dashed line texture, we instead pass the UV we processed (working_uv).

To put it another way: what we're doing is similar to how the space ship in Asteroids wraps around when it hits the edges of the screen. This makes the dashed line texture repeat as expected, and in 95% of cases it gives the correct result (there are a few edge cases where it may not, but they're unlikely to occur)


Now, to handle the issue of the gradient, we need to tackle the issue of the UV coordinates being out of range, but instead of repeating, we want to instead push the out-of-range vertex UV coordinates to the nearest edge that is in range. This will cause the texture to properly apply the gradient starting from the first point (UV coordinates (0, 0)) to the second point (given coordinates: (3, 2.5) -> code -> desired result: (1, 1)).

To do this, we need to use the vertex function. This function is called on each of the vertices in the Line2D, unlike the fragment function which is called per pixel drawn. However, because we will need to pass the UV position to the fragment so we sample the right part in the texture, we need to define a varying variable, which is simply a variable that we can populate in vertex and access in fragment.

The code in vertex is fairly simple: We check to see if the UV coordinates of the vertex we are processing is out of range on either the X or Y axis. (line 3). If the UV coordinates are out of range, we set clamped_UV to (1, 1); This will take coordinates like (5, 2) and map them to (1, 1). If the UV coordinates are not outside of range, we set clamped_UV to whatever the passed-in UV coordinates are (UV).

Then, in the fragement function, instead of passing UV as the UV coordinates when sampling the gradient texture, we pass clamped_UV instead. For the first point in the Line2D, this will not really do anything (the UV coordinates are (0, 0) and do not need adjusting), but for the second point in the Line2D, this will map it's UV coordinates to the maximum position in the texture if the UV coordinates are out of bounds ((8, 3) becomes (1, 1)).

(Note: This only really works for a Line2D with just two points. For more than two points, I'd recommend using a different approach (like manually drawing the line using the _draw function in a Node2D))


I wrote the whole thing in a single go, and as I mentioned, my shader experience is limited at best, so I'm sure the explanation could be improved. That said, hopefully now it makes a bit more sense on what is going on. It's really just a matter of clamping (for the gradient) and wrapping (for the dashed-line) UV coordinates so they are where you want them for each texture.

we need to use the vertex function. This function is called on each of the vertices in the Line2D, unlike the fragment function which is called per pixel drawn

Thank you very much, I feel that this passage has solved my problem

(Note: This only really works for a Line2D with just two points. For more than two points, I'd recommend using a different approach (like manually drawing the line using the _draw function in a Node2D))

I will also try it, but it must be said that the two-point line2d can already meet my needs. My purpose is to make a flowchart editor plugin. This is only a small part of it, although the current line is ugly , cannot add multiple points, not a curve, but a usable line.

Still very happy that the question has been answered I wish you have a nice day

2 years later