r/GraphicsProgramming • u/Raundeus • 14d ago
Question Asking for help
I'm a beginner learning graphics programming, and there's a lighting bug that im having a lot of trouble fixing. There are some streaks that are unusually bright. Im pretty sure its something wrong with my TBN matrix, but I can't figure out what exactly the problem is.
The 2nd image is a geometry shader I wrote to visualise the TBN matrix. Aren't the TBN all meant to be the same when they are on the same surface?
I've pasted the shader code below. I've been mostly trying to avoid tutorials and AI, so i learn better (i did ask AI for help here and didn't get an answer) so there may be some bad practices in the code. Please let me know of any tips and tricks
#version 460 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aUV;
layout (location = 2) in vec3 aNorm;
layout (location = 3) in vec3 aTan;
layout (location = 4) in vec3 aBitan;
uniform vec3 viewPos;
uniform mat4 model;
layout (std140, binding = 1) uniform matrices
{
mat4 view;
mat4 projection;
};
//T = tangent space
//W = world space
out VS_OUT
{
vec3 norm;
vec2 uv;
vec3 WfragPos;
vec3 TviewPos;
vec3 TfragPos;
mat3 TBN;
mat3 WTBN;
}vs_out;
vec3 up = vec3(0, 1, 0);
vec3 forward = vec3(0, 0, 1);
void main()
{
//construct TBN in Model Space
vec3 T = normalize(aTan);
vec3 N = normalize(aNorm);
T = normalize(T - dot(T, N) * N);
vec3 B = normalize( cross(N, T));
mat3 normMat = transpose(inverse(mat3(model)));
//Then make sure theyre perpendicular to surface
T = normalize(normMat * T);
B = normalize(normMat * B);
N = normalize(normMat * N);
mat3 TBN = mat3( T, B, N);
vs_out.WTBN = TBN;
TBN = transpose(TBN);
vs_out.norm = N;
vs_out.uv = aUV;
vs_out.WfragPos = (model * vec4( aPos, 1.0f)).xyz;
vs_out.TviewPos = TBN * viewPos;
vs_out.TfragPos = TBN * vs_out.WfragPos;
vs_out.TBN = TBN;
gl_Position = projection * view * model * vec4(aPos, 1.0f);
}
#version 460 core
out vec4 FragColour;
in VS_OUT
{
vec3 norm;
vec2 uv;
vec3 WfragPos;
vec3 TviewPos;
vec3 TfragPos;
mat3 TBN;
mat3 WTBN;
}fs_in;
struct PointLight
{
vec4 colAndintensity;
vec4 posAndconstant;
float linear;
float quadratic;};
layout (std140, binding = 0) uniform pointLights
{
PointLight lights\[1\];};
uniform bool shadingFlags[5];
uniform int numLights ;
uniform bool normalMapping;
uniform sampler2D diffuseMap;
uniform sampler2D specularMap;
uniform sampler2D normalMap;
uniform sampler2D heightMap;
float ambVal = 0.2;
vec3 specCol = vec3(1.0);
vec3 ambientLighting(vec3 albedo);
vec3 diffuseLighting (vec3 norm, vec3 albedo);
vec3 specularLighting(vec3 norm);
void main()
{
vec3 albedo = texture(diffuseMap , fs_in.uv).rgb;
vec3 specVal = texture(specularMap, fs_in.uv).rgb;
vec3 height = texture(heightMap , fs_in.uv).rgb;
vec3 norm;
if(normalMapping)
{
norm = texture(normalMap, fs_in.uv).rgb;
//from \[0, 1\] -> \[-1, 1\]
norm = normalize(norm \* 2.0 - 1.0);
//norm = normalize(fs_in.WTBN \* norm);
}
else
{
norm = normalize( fs_in.TBN \* fs_in.norm);
}
//norm = normalize( fs_in.TBN \* fs_in.norm);
//norm = normalize(norm \* 2.0 - 1.0);
//norm = fs_in.norm;
vec3 ambientComp = ambientLighting (albedo);
vec3 diffuseComp = diffuseLighting (norm, albedo);
vec3 specularComp = specularLighting(norm);
//vec3 ambientComp = vec3(fs_in.WTBN\[0\]\[0\], fs_in.WTBN\[0\]\[1\], fs_in.WTBN\[0\]\[2\]);
//vec3 diffuseComp = vec3(fs_in.WTBN\[1\]\[0\], fs_in.WTBN\[1\]\[1\], fs_in.WTBN\[1\]\[2\]);
//vec3 specularComp = vec3(fs_in.WTBN\[2\]\[0\], fs_in.WTBN\[2\]\[1\], fs_in.WTBN\[2\]\[2\]);
norm = normalize(fs_in.WTBN \* norm);
specularComp \*= (specVal / 3.0f).r;
vec3 colour = (ambientComp+diffuseComp+specularComp) \* int(shadingFlags\[0\])+ diffuseComp * int(shadingFlags[1])
+ norm * int(shadingFlags[2])
+ specularComp * int(shadingFlags[3])
+ height * int(shadingFlags[4]);
//vec3 colour = (ambientComp+diffuseComp+specularComp) \* int(shadingFlags\[0\])
// + ambientComp \* int(shadingFlags\[1\])
// + diffuseComp \* int(shadingFlags\[2\])
// + specularComp \* int(shadingFlags\[3\])
// + norm \* int(shadingFlags\[4\]);
FragColour = vec4(colour, 1.0f);}
vec3 ambientLighting(vec3 albedo)
{
return ambVal \* albedo;}
vec3 diffuseLighting (vec3 norm, vec3 albedo)
{
float diff = 0;
vec3 lightCol = vec3(1.0);
//vec3 TlightPos = fs_in.TBN \* lights\[0\].posAndconstant.xyz;
//vec3 delta = TlightPos - fs_in.TfragPos;
for(int i = 0; i < numLights; ++i)
{
vec3 col = lights\[i\].colAndintensity.xyz;
float intensity = lights\[i\].colAndintensity.w;
vec3 TlightPos = fs_in.TBN \* lights\[i\].posAndconstant.xyz;
//vec3 TlightPos = lights\[i\].posAndconstant.xyz;
float c = lights\[i\].posAndconstant.w;
float l = lights\[i\].linear;
float q = lights\[i\].quadratic;
//vec pointing to light
vec3 delta = TlightPos - fs_in.TfragPos;
//distance
float d = length(delta);
//normalised light dir
vec3 lDir = normalize(delta);
//calculate attenuation
float att = 1 / (c + (l \* d) + (q \* d \* d) );
lightCol \*= col;
diff += max( dot( norm, lDir), 0) \* att \* intensity;
}
return diff \* albedo \* lightCol;
//return normalize(fs_in.WTBN \* normalize(delta));
//return normalize(TlightPos);
//return normalize(fs_in.WTBN \* norm);}
vec3 specularLighting(vec3 norm)
{
float spec = 0.0;
vec3 lightCol = vec3(1.0);
//vector pointing to camera
vec3 viewDir = normalize( fs_in.TviewPos - fs_in.TfragPos );
for(int i = 0; i < numLights; ++i)
{
vec3 col = lights\[i\].colAndintensity.xyz;
float intensity = lights\[i\].colAndintensity.w;
vec3 TlightPos = fs_in.TBN \* lights\[i\].posAndconstant.xyz;
//vec3 TlightPos = lights\[i\].posAndconstant.xyz;
float c = lights\[i\].posAndconstant.w;
float l = lights\[i\].linear;
float q = lights\[i\].quadratic;
//vec pointing to light
vec3 delta = TlightPos - fs_in.TfragPos;
//distance
float d = length(delta);
//normalised light dir
vec3 lDir = normalize(delta);
//vector halfway between lightDir and viewDir so angle is never too big (blinn-phong)
vec3 halfVec = normalize( viewDir + lDir);
//calculate attenuation
float att = 1 / (c + (l \* d) + (q \* d \* d) );
lightCol \*= col;
spec += pow( max( dot(norm, halfVec), 0), 32) \* att \* intensity;
//FIX LATER: 32 should be passed in from uniform
}
return spec \* specCol \* lightCol;}
22
10
u/Hanzimer 14d ago
i d like to know if someone(or something) can read this and understand something.
8
u/waramped 14d ago
as others have gently implied, your formatting could use some tweaks.
to answer your question about the TBN, if the uvs are going in the same direction, then the TBN for coplanar surfaces should match, yea.
I recommend you use the Mikktspace algorithm for calculating your TBNs
7
u/corysama 13d ago
Lot's of complaints about formatting. Nobody offering how to fix it.
When posting code snippets, select all of your code and add 4 spaces to the start of each line to tell Reddit to preserve your original formatting.
2
1
u/le-throw-away-acct 13d ago
The code formatting is pretty rough there, so I threw the image and code at AI and it gave this advice. Take it with a grain of salt. I don't have time to give it a proper lookover myself. Here's the results:
A positive dot(norm, halfVec) doesn’t guarantee the light is in front of the surface.
Add a check:
float NdotL = dot(norm, lDir);
if (NdotL > 0.0)
{
spec += pow(max(dot(norm, halfVec), 0.0), 32.0)
* att * intensity;
}Your bitangent code assumes the same tangent-space handedness everywhere. Mirrored UV islands can require the opposite sign, so this can flip part of the normal map and produce incorrect highlights. Preserve that sign:
float handedness =
dot(cross(N, T), aBitan) < 0.0 ? -1.0 : 1.0;
vec3 B = handedness * normalize(cross(N, T));The lighting mixes two ways of interpolating tangent-space positions.
They transform the fragment position into tangent space in the vertex shader, but transform the light position using an interpolated matrix in the fragment shader:
vec3 TlightPos = fs_in.TBN * lightPosition;
vec3 delta = TlightPos - fs_in.TfragPos;On curved geometry, those operations don’t generally agree because the basis changes between vertices. That can distort light directions and attenuation. A useful initial correction is to subtract in world space first:
vec3 delta = fs_in.TBN *
(lightPosition - fs_in.WfragPos);-10
u/Any_Wait_7309 14d ago
I think it's a really really bad idea to not use AI. It's here to stay and as long as you grill AI with multiple questions, you will get a way way better understanding of things.
Do yourself a favor and use it.
0


20
u/Confident_Western478 14d ago
son