How to make a Sprite2D transparent in light and visible in darkness?
Asked Answered
F

11

0

Hi, I'm trying to code a shader that makes a Sprite2D transparent dependently on the lights by changing the alpha of the texture color. I started by making it invisible in the dark and visible in the light, and it works flawlessly. But then, when I try to make the opposite, it just doesn't work, no matter what I try. This is what happens when I make the sprite visible only in the light:

This is what happens when I make it visible only in the dark:

For reference, here's the code of the shader:

shader_type canvas_item;

uniform float light_opacity : hint_range(0, 1);
uniform float dark_opacity : hint_range(0, 1);

void fragment() {
	COLOR = texture(TEXTURE, UV);
	
	if (AT_LIGHT_PASS) COLOR.a *= light_opacity;
	else COLOR.a *= dark_opacity;
}

What am I doing wrong?

Fortdefrance answered 18/8, 2021 at 9:52 Comment(0)
A
0

Try changing line 10 to else COLOR.a *= (1.0 - light_opacity);

Athenaathenaeum answered 18/8, 2021 at 16:56 Comment(0)
F
0

@Megalomaniak said: Try changing line 10 to else COLOR.a *= (1.0 - light_opacity);

That's actually something I didn't think of to improve readability and usage, thank you! Unfortunately, though, it didn't solve the problem, though. :/

Fortdefrance answered 18/8, 2021 at 18:42 Comment(0)
C
0

I probably shouldn't say anything because I know nothing about shaders but it looks like it's only set up for the first option. If it's under the light, it makes it visible, else it makes it invisible. You would need a reverse for both those statements if you want the opposite to happen. Like I say, haven't used shaders at all yet. It just appears that it's doing two things, making the dark invisible and the light visible in the first example. I suppose though, if it's assumed the sprite is transparent, it would be just one thing. I think the logic would still be different though, because you would actually want the whole thing to be visible when you start if it's in the dark and you are doing the opposite.

Characteristically answered 18/8, 2021 at 22:3 Comment(0)
A
0

Share your scene for debug?

Athenaathenaeum answered 19/8, 2021 at 1:22 Comment(0)
F
0

@Megalomaniak said: Share your scene for debug?

Here you go.

Fortdefrance answered 19/8, 2021 at 9:50 Comment(0)
A
0

Well it's certainly working as expected for me:

If you want the opposite effect just switch the parts to the right of = sign on lines 9 and 10. edit: Yeah I see the issue now, the if/else logic seems to cause a second draw call for the sprite texture. I'm not sure that this is a workable solution for what you want to achieve.

What might work is if you have 2 of those lights and 1 has a inverted light mask/texture perhaps then have them in different light mask groups. Have the 'invisible' sprites be only affected by the inverted/negative lights group.

And I've tested that too and it's a no go.

Athenaathenaeum answered 19/8, 2021 at 13:5 Comment(0)
S
0

Showing the sprite only in the light worked for me as well, but making the sprite only visible in darkness didn't.

What I think is happening is that AT_LIGHT_PASS only modifies the light pass itself, rather than the fragment, so setting COLOR.a in the light pass is just changing the alpha of the light rather than the sprite's alpha. I'm not totally sure though if that is the case though.

Sofko answered 19/8, 2021 at 13:13 Comment(0)
A
0

Yeah I don't think there's any sort of light-prepass for 2D since "lights" aren't really lights quite the same way they are in 3D.

Athenaathenaeum answered 19/8, 2021 at 15:18 Comment(0)
A
0

Having slept on it I think I vaguely recall someone previously dealing with a related/similar issue and they went on to make their custom shaded object unshaded and then in the shader build their own custom lighting pipeline for the object.

They actually needed to deal with multiple light sources but in your case you might have an easier time since based on the example here at least it looks like your light source is a flashlight type thing that would be used by a single player character?

You could input the light vectors such as it's location and direction as a constructed shader parameter in the form of uniform matrix perhaps and then use that within the shader to calculate the effect of visible shadow but invisibility in the light in fragment alone.

Athenaathenaeum answered 20/8, 2021 at 5:4 Comment(0)
F
0

@Megalomaniak said: Yeah I don't think there's any sort of light-prepass for 2D since "lights" aren't really lights quite the same way they are in 3D.

So technically in 3D it would have been possible?

@Megalomaniak said: You could input the light vectors such as it's location and direction as a constructed shader parameter in the form of uniform matrix perhaps and then use that within the shader to calculate the effect of visible shadow but invisibility in the light in fragment alone.

Unfortunately I don't think I'm enough skilled in shader programming yet to do something like this :/

Fortdefrance answered 20/8, 2021 at 10:23 Comment(0)
A
0

One idea is to maybe simply script your invisible character to become invisible depending on distance to the player by changing the self-modulation value of the canvas-object in respect/response to the distance from the player. You can always add another if encapsulating that logic depending on if the flashlight is oriented towards the invisible character, later.

This way you wont need a custom shader and it wont actually be dependent on lighting info at all.

Athenaathenaeum answered 20/8, 2021 at 18:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.