Sending Information From the Fragment Shader to the Light Shader

Godot Version

v4.5.1.stable.official

Question

Hello, everyone!

Is there a way to set a variable in the fragment shader so that it can then be accessed through the light shader? Assuming that lighting is done on a per-pixel basis (default behavior), I would believe it to be possible.

For context, I’m trying to use a normal map to affect the geometry of a mesh but not its lighting (for stylized highlights for eyes). I am aware that this can be accomplished through other means, but the above would drastically simplify my workflow.

Thank you for your time.

Can you describe in more detail what exactly you’re after?

In terms of my current workflow, I’m looking for something like this:

[varying/something else] vec3 Original_Normal;

void fragment() {
Original_Normal = NORMAL;
NORMAL_MAP = texture(...).rgb;
}

void light() {
[light process that uses unmodified normal](Original_Normal);
[light process that uses modified normal](NORMAL);
}

I meant description/mockup of the effect.

After spending a bit of time in Paint, I have a mock-up:

I am aware that I can do this by adding a separate mesh on top of the eye for the highlight, but I wanted to see if I could accomplish this with just shaders (possibly, by using another pass).

You don’t need a separate mesh. You can just add an additional shader pass on the same mesh. This would probably be the easiest way as it wouldn’t require manual lighting calculations.

To do exactly what you ask, you can either sample the normal map in the light() function and perturb the normal yourself, or to actually send something from fragment() to light() function you can abuse one of the built ins you don’t need, for example BACKLIGHT.

2 Likes

Understood! Abusing the backlight does work, but I’ll test each of those solutions and adjust things accordingly. Thank you!

1 Like

You should be able to use varying to pass values from the fragment() to the light() functions.

1 Like

I’m ashamed I wasn’t aware of this :smile:

1 Like

The main problem that I had with varying is that it stores the values on a per-vertex basis (no idea if there’s a way around that), whereas I’d want the values stored on a per-pixel basis.

After testing all of the above ideas, recomputing the normal map in the light shader yielded the best results. (Using the backlight had other issues, especially as it cannot be modified in the light shader.)

It should be per pixel if you don’t touch the varying in the vertex function. Just assign it in the fragment function and read it in the light function.

That said I’d still go with the additional shader pass approach. It requires the least effort to set up.

Originally, I tested a varying variable in the fragment shader (as that seemed to be the obvious solution at the time), and since the test mesh was low-poly, it was easy to tell that it was just interpolating the value throughout vertices. (It is possible that it was interpolating it on a per-pixel basis, but it definitely didn’t look like it, as it was lighting certain mesh polygons.) However, I can look into it again to see if I overlooked something else (possibly, a project setting or something else).

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.