Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Behavior of VERTEX.y in canvas_item Shaders changes drastically depending on whether Compatibility or Forward+ Render Engine is selected #902

Open
d-sacre opened this issue Dec 21, 2024 · 0 comments

Comments

@d-sacre
Copy link

d-sacre commented Dec 21, 2024

Tested versions

Tested with Redot 4.3-stable
Also affects:

  • Godot 4.x (tested up to Godot 4.3-stable)
  • Godot 3.x (tested from Godot 3.5 upwards)

System information

OS and hardware independent

Issue description

The goal was to highlight the square tile map cell over which the mouse cursor is currently hovering with a simple shader. However, when switching the render engine from Forward+ to Compatibility or vice versa, the behavior of the shader changed unexpectedly.
1_redot4-3_shaderVertexDiscrepancy_compatibility-vs-forwardPlus_highlighting-in-game
The shader is of type canvas_item and looks as follows:

  // ADAPTED FROM: https://www.youtube.com/watch?v=7nTQA_6CL6M
  
  shader_type canvas_item;
  
  uniform vec2 globalMousePosition; // DESCRIPTION: Input from GDScript
  uniform vec2 tileSize; // DESCRIPTION: Input from GDScript
  
  varying flat vec2 vertexPosition;
  varying flat vec2 vertexRaw; // REMARK: Only for debugging purposes
  
  void vertex() {
  	vertexPosition = (MODEL_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy; // DESCRIPTION: Take transformations into account
  	vertexRaw = VERTEX; // REMARK: Only for debugging purposes
  }
  
  void fragment() {
  	float isWithinY = step(vertexPosition.y, globalMousePosition.y) * step(globalMousePosition.y, vertexPosition.y + tileSize.y);
  	float isWithinX = step(vertexPosition.x, globalMousePosition.x) * step(globalMousePosition.x, vertexPosition.x + tileSize.x);
  	float isWithin = isWithinY * isWithinX;
  
  	vec4 textureColor = texture(TEXTURE, UV);
  	COLOR = mix(textureColor, vec4(0.7,0.0,0.0,1), 0.7*isWithin);
  
  	/* DESCRIPTION: FOR DEBUGGING PURPOSES ONLY
       // DESCRIPTION: Raw Vertex Color Data
  	COLOR = vec4(vertexRaw, 0.0, 1.0);
      // DESCRIPTION: Normalized Vertex Color data; 
      // VALUES: number of horizontal tiles per screen = 20.0, tile width = 64.0 px,
      // number of vertical tiles per screen = 8.0, tile height = 64.0 px
  	COLOR = vec4(vertexRaw/vec2(10.0*64.0, 8.0*64.0), 0.0, 1.0);
      */
  }

During the debugging, I took a look at the raw vertex color in the tile set
2_redot4-3_shaderVertexDiscrepancy_compatibility-vs-forwardPlus_vertexColor_raw_tileSet
as well as the raw vertex color of the complete screen
3_redot4-3_shaderVertexDiscrepancy_compatibility-vs-forwardPlus_vertexColor_raw_in-game
and the normalized vertex color of the complete screen
4_redot4-3_shaderVertexDiscrepancy_compatibility-vs-forwardPlus_vertexColor_normalized_in-game
It is not only limited to the TileMapLayer Node used for the example. It could also be reproduced for e.g. Sprite2D
5_redot4-3_shaderVertexDiscrepancy_compatibility-vs-forwardPlus_sprite2d_highlighting-in-game

Expected Behavior

Independent of the render engine, the result should be the same, since the documentation documentation for CanvasItem shaders states:

Vertex data (VERTEX) is presented in local space (pixel coordinates, relative to the Node2D's origin). If not written to, these values will not be modified and be passed through as they came. The user can disable the built-in model to world transform (world to screen and projection will still happen later)...

From this statement and the vertex color visualization, the expected behavior would be that shown by the Forward+ render engine.

Probable Cause

It cannot be related to the implementation of the step() function, since the issue also occurs when viewing the raw/normalized vertex colors. This points towards an inconsistency in handling VERTEX.y between the Compatibility and Forward+ render engines, probably occuring during the parsing of the GDShader to GLSL and Glslang/SPIR-V respectively.

Affected Nodes and Versions

  • Any Node2D (including Control Nodes) which can have a Shader Material attached to itself
  • So far, this behavior could be reproduced for all stable versions of Redot 4.x (including Redot 4.3 at the time of writing) and due to the nature of the issue should be platform independent (issue could be confirmed for/tested on Windows, Linux and Web).
  • The issue is inherited from Godot and there present in Godot 3.x as well as Godot 4.x. In Godot 3.x, the Open GLES 3.0 shows the same behavior as Compatibility in Godot 4.x (tested for Godot 3.5 and newer).

Steps to reproduce

  1. Create a scene with Redot 4.3-stable (or any other version of Redot 4.x) with at least an object which has the above shader attached to it and forward the global mouse position to it. Alternatively: Download the example project attached to this issue (Remark: Example requires due to the usage of the TileMapLayer Node Redot 4.3-stable and newer!).
  2. Two Options:
    - Option 1: Swap the render engine each time between Compatibility or Forward+ and reload the project. Then run the project natively with F5/F6.
    - Option 2: Set the render engine to Forward+ and run the project natively with F5/F6 for testing the behavior of Forward+. Run a Remote Debug Session in a browser to test the behavior of Compatibility (Remark: works due to the fact that in Redot 4.3-stable, the web export is not Vulkan based, but no matter what the default render engine is, will utilize Compatibility).

Minimal reproduction project (MRP)

To obtain the vertex color output, simply comment in/out the respective lines in the shader
mrp_canvasItem_redot4-3_tileMapLayer.zip

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant