# How to draw a screen space decal along a desired projection direction and control which surfaces it affects?

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):

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;
}

#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
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:

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!