Line2D shader help

Godot Version

4.7 stable

Question

Hi, I have a vine object that can follow points in the scene using bone2d and it doesn’t use a texture, it uses a line2d with a width curve to change the size in case I want to add more objects using the same base in the future. We just recently switched to pixel art fairly far into the design process for the game I’m working on, for some of the other things in-game I’m using a pixelate shader to save time so I figured I’d try that here, but I have no clue how to make the shader affect the vine object without a texture on it, I tried adding a fill texture but it doesn’t seem to be working using the same shader from before that I found on the asset store. I am kind of new to godot’s shader language, I’ve only used it for simple things like recoloring on my own and I can’t find anything on similar cases to this so I just figured I’d see if anyone had any insights on how to make a shader work in this instance or better ways to do this than a shader. I tried using a subviewport but the object moves so much around the scene it was a pain to work around in the editor so I wanted to try and find an alternative before sticking with that.

Here’s the other shader in case you need it, again I didn’t write it I got it off the asset store but it doesn’t seem to be doing anything crazy.

uniform int amount = 40;

void fragment()
{
	vec2 grid_uv = round(UV * float(amount)) / float(amount);
	
	vec4 text = texture(TEXTURE, grid_uv);
	
	COLOR = text;
}

a. Was the fill texture one uniform color?

b. Were you expecting this to pixelate outside of the polygon that results from rendering your Line2D?

If a. is true, you may want to check a texture with non uniform color first (like noise) to see if that pixelates within the polygon, but not outside the smooth edges of the polygon that makes up the Line2D.

If it does pixelate your shader works, but you may need to run it in a different processing step.

Sharing a screenshot of what you observe and a sketch of what you expect to happen would help immensely as well.

I don’t know about shaders by the way, just seeing a round off at some number that’s 40 here, seems like a very big pixel to me, but :person_shrugging:, I’m the Scalable Vector Shapes 2D guy… Not the pixels are still all the rage guy :rofl:.

a. It was, I used a curvexyz texture to test so I could also change the color easily if I wanted to.

b. No, I just wanted to pixelate the polygon itself, I want to avoid any other pixels if possible.

I just tried a noise texture but it didn’t seem to work any more I’ll attach screenshots at the bottom. How can I run the shader at different process steps? I figured if it would help I could try that anyway.

This is the shader running on the icon sprite

This is what I want the shader to look like or at least something similar, ideally less chunky but I’ll take what I can get. That was done using a subviewport and messing with scale, its just really annoying to get working in game because of the targeting and actual placement of the node.

This is what it looks like with the shader running while I have a curvexyz fill texture attached.

This is what it looks like with the shader running with a noisetexture attached.

Have you set the Line2D texture mode to tile and the canvasitem texture to repeat?

https://docs.godotengine.org/en/stable/classes/class_canvasitem.html#class-canvasitem-property-texture-repeat

Ok I feel dumb I didnt apply the noise texture right, it is definitely applying only within the object, here’s what it looks like with tile on, how could I go about fixing that?

Calling in the expert: @normalized ? What was that thing with the processing steps again?

Just saw this, just updated everything, tile seems to work but the canvasitem texture set to repeat doesn’t sem to be changing anything, not sure whats going on there. There’s also the issue that it seems to be stretching the pixel grid inside the line2d.

It was only to check if your shader does anything. I think it does

Setting a uniform white texture may work with it, but to color outside the lines of the polygon that is rendered from your Line2D you may have to stuff the whole line2D inside a subviewport and run your shader on that subviewport… Something like that .

Is there a way to show items in a subviewport independent of location? the biggest issue I was running into is because the vine moves around a decently large area and the size can be updated in real time, it was clipping out of the viewport, I suppose I could just have such a massive subviewport that it doesn’t matter but it still limits how you can move the node selecting in game instead of the tree and I wasn’t sure if there were any issues with having a subviewport that big.

That may hamper performance due to the transparent area you’ll be pixelating needlessly.

Then again. GPU probably won’t mind all that much.

You could try a sprite with a ViewportTexture, so it could render in a buffer off screen, I guess.

You could calculate the bounding box of the line2D programmatically, I guess.

Seems like a lot of fuss.

If I were you, wait for @normalized’s answer, and use the ideas I came up with as an interesting learning exercise… Shaders are not my forté, but what you want shouldn’t be this complex.

Alright, I’ll wait and see what they say, thank you so much for the help! I had no clue it was even working on the line at all, I appreciate it a ton!

Okay… Just one more thing you could try. Why not draw all your vines inside a separate CanvasLayer and run your shader on that CanvasLayer? Maybe with a subviewportcontainer set to full rect (entire window) with a subviewport inside… So one transparent subviewport contains all the vines.

This should fix it, right? As long as you get it right in the draw order..

I hadn’t thought about using a separate canvaslayer Ill try that out real quick, thanks for the idea! I’ll have to set it up for a separate layer in front of my backgrounds but I don’t see why it wouldn’t work, I’ll reply once I’ve tested it out

Not CanvasLayer. CanvasGroup is what you want. Canvas group node runs a screen reading shader under the hood anyway. It’s a less cumbersome alternative to rendering a subviewport.

Look at CanvasGroup node reference page and use the shader code presented there in a custom shader. Pixelize the screen uv coordinate the shader uses to read the screen and you’re done.

That worked great thank you so much, I had no clue CanvasGroup even existed. Have a good one!