• 2D
  • [Godot 2] How to make eyes glow in the dark?

I'm trying to make creatures' eyes turn white when they're outside the range of light sources, as I depicted in the mockup below.

How can I achieve this?

5 days later

Well, i see 2 methods there. First of all, you can play with shaders: http://docs.godotengine.org/en/2.1/learning/features/shading/shader_materials.html#introduction https://godotengine.org/qa/6172/changing-into-gray-the-colours-of-a-texture

Secondly, you can just create 2 sprites like on the screenshot and display it together with proper transparency.

I guess you're using skeletal animation so the first method is probably more efficent. With the second one you will have more work to do.

I played around with shaders a bit, but I ran into the problem that the CanvasModulate seems to override them. I know very little about shaders yet, but I tried this fragment shader:

if (!AT_LIGHT_PASS) { 
    // The eyes are the only fully black part of the sprite
	if (COLOR.rgb == vec3(0,0,0) && COLOR.a == 1) { // can't do COLOR.rgba == vec4 for some reason !?
		COLOR = color(1,1,1,1); 
	} 
}

But it does nothing unless the sprite is in the light, because of the CanvasModulate (or maybe because the CanvasModulate is set to pitch black, but that's how I'd like to have it). I asked another question about that. For the specific case in that question I did end up using a separate sprite, and just set its material to unshaded. So that worked for that, because that can be white all the time, but for the eyes I need them to not be glowing when in the light, so they must be shaded.

I also played around with some lighting shaders similar to the fragment one above, but in all of that I got the impression that if only I could override the CanvasModulate, then I think I might get it to work.

look at canvas modulate as if it where to do this:

COLOR.rgba *= vec4("your canvas modulate color")

after all of the fragment shader calculations, if it's pitch black then it'll do a multiplication by 0 and you know how that goes, i don't know if you already fed the texture(TEXTURE,UV) content to COLOR but i'll mention it just in case.

I don't know exactly how the AT_LIGHT_PASS boolean but i wouldn't suggest using it. what i would suggest is that you do the full calculation inside the shader by feeding the distance from the light to the shader with material_set_param() on your main process and changing the eye color, maybe even gradually, after a threshold, something like this:

shader_type canvas_item;

uniform float distance_from_light;

uniform float threshold;

void fragment(){
	COLOR = texture(TEXTURE,UV);
	if (COLOR.rgba == vec4(0.0,0.0,0.0,1.0) && distance_from_light < threshold){
		COLOR.rgb = vec3(1.0,1.0,1.0) / distance_from_light;
	}
}

idk if you're using godot 2 or 3 though so you'll have to interpret it accordingly, good luck.

I'm using Godot 2 (it's in the title). What's the equivalent in Godot 2 for texture(TEXTURE, UV)? Nevermind, I found that it's tex().

I tested it without considering the light just to see if it would override the CanvasModulate and it doesn't seem to. The full code of the shader, as I tried that is this:

COLOR = tex(TEXTURE, UV);
if (COLOR.rgb == vec3(0,0,0) && COLOR.a == 1) { 
	COLOR = color(1,1,1,1); 
}

The shader works, though, but the effect is only visible when I drag the sprite into the light. The same was happening to how I was doing it previously.

ok i believe i made what you wanted here you just need to set the threshold variable to your light radius, let me know if it works

you could just use area enter and change the sprite for simplicity sake... Shaders are another good option.

6 days later

@meinkush Sorry about the delay, my time's been taken by other stuff. I had downloaded your project, but only got to test it today.

That does work indeed. I was trying to make it more automatized in terms of not needing to set that threshold manually, but considering I won't have many different lights with different sizes (at most 4 or 5 is what I planned for), I guess I can manually set them without much of a hassle. I played around with it for a bit and didn't take much for me to see that 600 was close to what I want.

Thank you.

no problem @woopdeedoo, you could use some areas like @rukiri mentioned to make the lights set the radius automatically on contact, although it'll still need some validation if two or more cover the same space.

4 months later

@meinkush, I just revisited this project again and I noticed one problem though: it still doesn't work with the CanvasModulate that I'm using to keep everything dark outside the lights. I hadn't noticed this before because I only tested it in your example, which didn't include a CanvasModulate. As soon as I added a CanvasModulate to it, with the color set to full black, I got the same problem I was having before, where the CanvasModulate overrides everything.

Hmmm...