godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.08k stars 69 forks source link

Expose CanvasLayer.layer to CanvasItem shaders #8549

Open robbertzzz opened 7 months ago

robbertzzz commented 7 months ago

Describe the project you are working on

Any 2D game that features parallaxing implemented through CanvasLayers

Describe the problem or limitation you are having in your project

I want to apply different effects at different depths in a shader, without having to use separate materials for each layer. A common use case is depth-based fog; having access to the layer in the shader allows users to apply fog at different depths, i.e. through mapping the layer to a gradient. This is a very common approach to fog in 3D and it would be great to be able to do the same in 2D.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

CanvasItem shaders would have a normalized DEPTH constant in the range [0,1] representing layers [128, -128] that can be read in vertex(), fragment() and light(). This range would make DEPTH function more or less like DEPTH in a Spatial shader, where nearest pixels are at depth 0 and furthest pixels at depth 1.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

See above.

If this enhancement will not be used often, can it be worked around with a few lines of script?

No

Is there a reason why this should be core and not an add-on in the asset library?

This can only be implemented in the rendering engine

Calinou commented 7 months ago
ProFiLeR4100 commented 1 month ago

+1 I wanted to implement "fog of war" for turn based game using only shaders, but there is no access to layer index or depth buffer, because of this interactive elements like cursor or path are also being affected by shader.

image of cursor and path being affected by shader

As a workaround I will try to set material to every tile, then export uniforms to global in order to save memory, but still if I understand how render works it will call shader per each tile rather than in one pass which will cost performance.

Update: Looks like global uniform arrays for base types (vec*, bool, etc.) are not supported, so my workaround is not possible to implement without this proposal or without bombarding every tile in tileset with new values which will damage performance (I can use single material for all tiles, but there are already 1000 tiles and I need to update every one of them, one by one) or without splitting tilemap into different one in order to apply materials for background layers only.