Manually Calculating the Depth value in a compute shader

Godot Version

Godot Version 4.3

Question

Hi there,

I am currently working on a small project where I implement an optical Illusion for VR in Godot 4.3


It currently looks like this

To achive this I basicly reversed the depth value for specific Fragments. That worked if nothing obscures the cube. The parts with the Effect will show up infront of any object.

My Solution was to calculate the Depth Value of both Faces for each fragment and then to just flip them. Currently I am doing this in a compute shader and am writing the result in a texture that is then used by my fragment shader.

But right now the calculated depth Values are wrong and I dont know why.

This is my code for projecting the vertecies into screen space. I multiplied the x and y coordinates with the resolution for easier use later on

Vector3 porjectVertex(Vector3 inVertex)
{
    Projection invViewMatrix = new Projection (cam.GetTransform().AffineInverse());
    Projection projectionMatrix = cam.GetCameraProjection();
    Rect2 res = cam.GetViewport().GetVisibleRect();
    
	Vector4 vertex = new Vector4(inVertex.X,inVertex.Y,inVertex.Z,1);
	vertex = projectionMatrix * invViewMatrix * vertex ;
	vertex = vertex * (float)(1.0/vertex.W);
	return new Vector3((float)((vertex.X + 1.0) / 2.0) * res.Size.X ,(float)(1-((vertex.Y + 1.0) / 2.0)) * res.Size.Y,(float)(vertex.Z *  2.0 - 1.0));
}

This is the code that does the actual depth calculation. It mostly consist of a barycentric interpolation of the 3 z Values of my face vertecies


float calcZ(vec2 ScreenUV, vec3 V1, vec3 V2, vec3 V3)
{
    // calculate weights for barycentric Interpolation of z Values 

	float upper = ((V2.y - V3.y) * (ScreenUV.x - V3.x)) + ((V3.x - V2.x) * (ScreenUV.y - V3.y));
	float lower = ((V2.y - V3.y) * (V1.x - V3.x)) + ((V3.x - V2.x) * (V1.y - V3.y));
	float W_v1 = upper / lower ;

	float upper2 = ((V3.y - V1.y) * (ScreenUV.x - V3.x)) + ((V1.x - V3.x) * (ScreenUV.y - V3.y));
	float lower2 = ((V2.y - V3.y) * (V1.x - V3.x)) + ((V3.x-V2.x) * (V1.y - V3.y));
	float W_v2 = upper2 / lower2 ;

	float W_v3 = 1.0 - W_v1 - W_v2;


    // second test if fragment is in triangle
    if(W_v1 < 0 || W_v2 < 0 || W_v3 < 0)
    {
        return -1;
    }

    // calc z Value

    float z1 = V1.z ;
    float z2 = V2.z ;
    float z3 = V3.z ; 

    float z = (W_v1 * z1 + W_v2 * z2 + W_v3 * z3) / (W_v1 + W_v2 + W_v3);


    float depth = (1/z - 1/params.nearPlane)/(1/params.farPlane - 1/params.nearPlane); 



    return 1 - depth;
}

and for testing pourposes I wrote a simple fragment shader that shows me the differences of my calculated Values and the ones godot calculated

	vec4 clip_pos = PROJECTION_MATRIX * vec4(VERTEX, 1.0);
	clip_pos.xyz /= clip_pos.w;

	vec4 tex = texture(exclusionmask,SCREEN_UV);
	
	if(tex.x == 1.0 && tex.y != 1.0 && tex.z != 1.0)
	{
		float zDiff = clip_pos.z - tex.z;
		float zDiff2 = clip_pos.z - tex.y;
		tex = vec4(zDiff,0.0,0.0,1.0);

	}else
	{
		tex = vec4(0.0,0.0,0.0,0.0);
	}
	ALBEDO = tex.xyz;

If any of you have and Idea what I might be doing wrong or have a better solution to my problem please let me know.

Any help is greatly appreciated

Thanks

Did it break after updating Godot or after some refactoring? I think godot 4.3 changed how the z buffer works but since you are using a compute shader it may not apply.

It was always written in Godot 4.3 never tried it in 4.2 or lower
I am aware of the Changes done in 4.3 and my code should account for that.

OK I found one Error in my code after taking a break from it, but its still weird.

It wasnt in anything I posted here though. I just wrote my result into an ivec3 and because all my results were between 0 - 1 it all got rounded down to zero.

So now I can finally send values to my fragmentshader properly and the results are mixed. My effect works on some Faces of my cube but not others:


I’ve highlighted the areas where the effect should be vidible but sometimes is’nt with my glorious Paint Skills.
This is just the best visible case but it happens all over the cube.

From testing I know the depth Values I calculate in my compute shader are not correct. They deviate from the ones I calculate in my shader the closer I am to the Mesh

I just used these lines of code to check that

vec4 clip_pos = PROJECTION_MATRIX * vec4(VERTEX,1.0);
clip_pos.xzy / clip_pos.w ;

vec4 tex = texture(exclusionmask,SCREEN_UV);
ALBEDO = vec3(abs(tex.g - clip_pos.z));

without that test my Fragment shader currently looks like this

	ALPHA_HASH_SCALE = 1.0;

	vec4 clip_pos = PROJECTION_MATRIX * vec4(VERTEX,1.0);
	clip_pos.xzy / clip_pos.w ;

	vec4 tex = texture(exclusionmask,SCREEN_UV);
	vec3 color = vec3(0.5,0.5,0.5);

	if(tex.r == 1.0)
	{
		if(abs(tex.b - clip_pos.z) > abs(tex.g - clip_pos.z) )
		{
			DEPTH = tex.b ;
		}else
		{
			DEPTH = tex.g;
		}

	}else
	{
		DEPTH = clip_pos.z;
	}
	ALBEDO = color;

I have made some changes to my projection function and to my calculation of the depth values.

The Projection Code:

Vector3 projectVertex(Vector3 inVertex)
{
    Projection invViewMatrix = new Projection (cam.GetTransform().AffineInverse());
    Projection projectionMatrix = cam.GetCameraProjection();
    Rect2 res = cam.GetViewport().GetVisibleRect();
    
	Vector4 vertex = new Vector4(inVertex.X,inVertex.Y,inVertex.Z,1);
	vertex = projectionMatrix * invViewMatrix * vertex ;
    vertex.X = vertex.X / vertex.W;
    vertex.Y = vertex.Y / vertex.W;
    vertex.Z = vertex.Z / vertex.W;
	return new Vector3((float)((vertex.X + 1.0) / 2.0) * res.Size.X ,(float)(1-((vertex.Y + 1.0) / 2.0)) * res.Size.Y,vertex.Z);
}

And the depth Calculation:

float calcZ(vec2 ScreenUV, vec3 V1, vec3 V2, vec3 V3)
{
	float upper = ((V2.y - V3.y) * (ScreenUV.x - V3.x)) + ((V3.x - V2.x) * (ScreenUV.y - V3.y));
	float lower = ((V2.y - V3.y) * (V1.x - V3.x)) + ((V3.x - V2.x) * (V1.y - V3.y));
	float W_v1 = upper / lower ;

	float upper2 = ((V3.y - V1.y) * (ScreenUV.x - V3.x)) + ((V1.x - V3.x) * (ScreenUV.y - V3.y));
	float lower2 = ((V2.y - V3.y) * (V1.x - V3.x)) + ((V3.x-V2.x) * (V1.y - V3.y));
	float W_v2 = upper2 / lower2 ;

	float W_v3 = 1.0 - W_v1 - W_v2;

    if(W_v1 < 0 || W_v2 < 0 || W_v3 < 0)
    {
        return -1;
    }

    float z1 = V1.z ;
    float z2 = V2.z ;
    float z3 = V3.z ; 

    float z = (W_v1 * z1 + W_v2 * z2 + W_v3 * z3) ;


    return  1 - z ;
}

Right now I am unsure where the problem lies. I think my calculations are the same in my c# script and my fragment shader but apparently not.

Any help is appreciated

Thank you