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!


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.