How do I apply normal map lighting effects before my shader? [2D]

DejaVuLoopDejaVuLoop Posts: 4Member

I wrote a simple 2D shader that turns an image grayscale and then limits how many shades of gray can be outputted to 6.

However, when I add a normal map to the sprite with the shader, and then add a 2D light to the scene, the shader no longer locks the image down to six different shades of gray.

I want godot to solve for the lighting effects on the normal map, and then pass those results to my shader. How do I do this?


  • MegalomaniakMegalomaniak Posts: 2,884Admin

    Vertex > Fragment > Lighting this is the order of the pipeline.

    In your fragment shader you are not doing to your NORMAL output what you are doing to your COLOR output thus the NORMAL output goes into the Lighting shader as is.

  • SIsilicon28SIsilicon28 Posts: 757Moderator

    Which means you'll have to calculate the NORMAL yourself.

  • DejaVuLoopDejaVuLoop Posts: 4Member

    Thanks for the responses. I'm wondering, after doing some research, if I could turn my shader into a screen-reading shader on a post-processing layer of sorts.

    Would that actually work, or am I just going to run into another pipeline order issue?

  • SIsilicon28SIsilicon28 Posts: 757Moderator

    Here's what I would do. Take your fragment shader program, and put most of it into its own function. The function will accept UV coordinates and return a colour. In your fragment shader, you may run that same function to get the COLOR value, but you can also use it to calculate the NORMAL. Just run the function two more times with a small offset along x and y respectively. Then calculate the difference between those and the original colour value (red component only). This should give you your normal. I'll post some code later.

  • MegalomaniakMegalomaniak Posts: 2,884Admin

    Or possibly all the posterization could be done straight in the lighting shader. Not sure, but it might save some on total operations done by the shader. Trouble is AFAIK, converting the default/builtin materials into editable custom shader doesn't export the lighting shader. :(

  • DejaVuLoopDejaVuLoop Posts: 4Member

    I didn't figure out how to do this in 2D, but I discovered that if I ported the scene to 3D and used a screen-reading shader it works fine.

    I think I'll stick with this approach because I prefer the way Godot handles light in 3D, plus I enjoy the extra control I get from camera settings, tone mapping, etc.

  • HebeCRAFTHebeCRAFT Posts: 1Member

    You can use a new canvas layer. Put your shader in there, change the "layer" property to a higher number than your main game (2 should be enough) and prevent your Light2D from casting onto layer two (under "Range" -> "Layer Max", set it to 1 or 0). Then your light will process before your shader.

    Things like this are why CanvasLayer sticks around. It makes even Leveltransitions really easy to implement.

Leave a Comment

BoldItalicStrikethroughOrdered listUnordered list
Align leftAlign centerAlign rightToggle HTML viewToggle full pageToggle lights
Drop image/file