Get world space coordinates from FRAGCOORD

Godot Version

4.3

Question

In a spatial shader, the FRAGCOORD variable is in screen space. I want it to be in world space and tried to do this:

void fragment() {
	float depth = 1.0 - FRAGCOORD.z;
	vec2 frag_ndc = ((FRAGCOORD.xy / VIEWPORT_SIZE) * 2.0) - 1.0;
	// frag_ndc.y = -frag_ndc.y;
	vec4 frag_view_space_position = INV_PROJECTION_MATRIX * vec4(frag_ndc, depth, 1.0);
	frag_view_space_position /= frag_view_space_position.w;
	vec4 frag_world_space = INV_VIEW_MATRIX * frag_view_space_position;
	vec4 color = vec4(frag_world_space.x, 0.0, 0.0, 1.0);
	ALBEDO.rgb = color.rgb;

}

Here is a video of what is wrong with the shader:

In the video you see, that the color of the cube with the shader on, is red, but changes to black if I rotate the camera.
As the world space coordinate of a fragment, doesn’t change I expect the cube to be colored in different shades of red, without changing color when I rotate the camera.
So something went wrong during the transformation.

I tried different things with the depth, I tried to flip the y coordinate, but nothing helped.
Does anyone know what I did wrong?

Finnaly gave it another try and it was indeed the depth the problem. It seems even with a reverse z buffer like godot has implemented you don’t need to flip the depth buffer. I think it is because I use the INV_PROJECTION_MATRIX and that it allready accounts for that.

So the correct code to go from screen space to world space is as follows (I added some explanation for record):

void fragment() {
	float depth = FRAGCOORD.z;
    // FRAGCOORD go from [0, VIEWPORT_SIZE] so dividing it by VIEWPORT_SIZE 
    // makes it to go from [0, 1]. Multiply it by 2 makes it to [0, 2] and 
    // subtracting 1 makes it go from [-1,1] which is the correct range 
    // for normalized device coordinates (ndc).
	vec2 frag_ndc = ((FRAGCOORD.xy / VIEWPORT_SIZE) * 2.0) - 1.0; 
    // Use the INV_PROJECTION_MATRIX to go from NDC to viewspace.
	vec4 frag_view_space_position = INV_PROJECTION_MATRIX * vec4(frag_ndc, depth, 1.0);
    // make the perspective divide
	frag_view_space_position /= frag_view_space_position.w;
    // Use the INV_VIEW_MATRIX to go from view space to world space
	vec4 frag_world_space = INV_VIEW_MATRIX * frag_view_space_position;
    // use one channel to color a cube, if the cube is in world origin 
    // it should result in a black/red gradient. 
	vec4 color = vec4(frag_world_space.x, 0.0, 0.0, 1.0);
	ALBEDO.rgb = color.rgb;

}
1 Like

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