0
\$\begingroup\$

I am currently programming a complex 2D lighting system which calculates lighting in 3D space.

Something like what I want to achieve (Source @pixpilgames from Twitter):

enter image description here

I recently learned how to program ScreenSpace decals into a deferred rendering lighting pass and I ran into a few problems.

Decal in my case is a long box rendered in the light pass. Here's the shader code for it:

#shader vertex
#version 330 core
layout (location = 0) in vec3 aPos;

uniform mat4 u_Model;
uniform mat4 u_View;
uniform mat4 u_Projection;

out vec4 PositionCS;
out vec4 PositionVS;


void main()
{
    PositionVS = u_View * u_Model * vec4(aPos, 1.0);
    PositionCS = u_Projection * PositionVS;
    gl_Position = PositionCS;
}

#shader fragment
#version 330 core

layout (location = 0) out vec4 gLight;

in vec4 PositionCS;
in vec4 PositionVS;

uniform sampler2D gDepth;

struct Decal {
    sampler2D Texture;
    
    vec3 Color;
};

uniform Decal u_Decal;

uniform mat4 u_InvView;
uniform mat4 u_InvProj;
uniform mat4 u_InvModel;


void main()
{
    vec3 ndcPos = PositionCS.xyz / PositionCS.w;

    vec2 texCoord = ndcPos.xy * 0.5 + 0.5;

    float sampledDepth = texture(gDepth, texCoord).r;
    
    float sampleNdcZ = sampledDepth * 2.0 - 1.0;
        
    vec3 ndcSample = vec3(ndcPos.xy, sampleNdcZ);
    
    vec4 hViewPos     = u_InvProj * vec4(ndcSample, 1.0);
    vec3 viewPosition = hViewPos.xyz / hViewPos.w;

    // Transformation from view-space to world-space
    vec3 WorldPos       = (u_InvView * vec4(viewPosition, 1.0)).xyz;
    vec3 objectPosition = (u_InvModel * vec4(WorldPos, 1.0)).xyz;

    // Bounds check, discard pixels outside the wall in object-space
    if (abs(objectPosition.x) > 0.5) discard;
    else if (abs(objectPosition.y) > 0.5) discard;
    else if (abs(objectPosition.z) > 0.5) discard;
    
    objectPosition.y = 1 - objectPosition.y;
    
    gLight = vec4(texture(u_Decal.Texture, objectPosition.xy + 0.5).xyz * u_Decal.Color, 1.0);
}

First of all, whenever I draw a decal and rotate the camera, I noticed that decals are rendered onto multiple meshes colliding with the long box. Here's a picture:

Decal drawing on the underlying geometry

I know why this is happening, I don't know the solution for it though. I believe it's because the Decal draws onto every pixel that it collides with, checks it's position and maps it.

Additionally, I want to be able to change the direction the decal is projected from (Aka mimic a projector).

Now the question is - Do I have to render all the geometry again into a depth buffer from decal camera's perspective and do all the respective calculations ( I have some ideas on how to compute that )? It would solve both of the problems because the underlying geometry wouldn't have any depth information and I could just change the projector matrices to my liking. It does require rendering the same geometry multiple times. Is there a better way to achieve the same effect?

Thank you!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.