I'm trying to convert some code from rasterization shader to a raytracing shader - glsl

From what I seen the dFdx and dFdy functions don't run in the closet hit shader. So I have to convert to something like it. I'd think this the equivlent but I'm not getting the same result. Am I missing something?
From the raster shader that I got from LearnOpenGl https://learnopengl.com/PBR/Lighting :
vec3 getNormalFromMap()
{
vec3 tangentNormal = texture(normalMap, TexCoords).xyz * 2.0 - 1.0;
vec3 Q1 = dFdx(WorldPos);
vec3 Q2 = dFdy(WorldPos);
vec2 st1 = dFdx(TexCoords);
vec2 st2 = dFdy(TexCoords);
vec3 N = normalize(Normal);
vec3 T = normalize(Q1*st2.t - Q2*st1.t);
vec3 B = -normalize(cross(N, T));
mat3 TBN = mat3(T, B, N);
return normalize(TBN * tangentNormal);
}
My attempted recreation of it:
vec3 getNormalFromMap(MaterialInfo material, Vertex vertex)
{
vec3 T = normalize(mat3(meshProperties[gl_InstanceCustomIndexEXT].ModelTransform * MeshTransform[gl_InstanceCustomIndexEXT].Transform) * vec3(vertex.tangent));
vec3 B = normalize(mat3(meshProperties[gl_InstanceCustomIndexEXT].ModelTransform * MeshTransform[gl_InstanceCustomIndexEXT].Transform) * vec3(vertex.BiTangant));
vec3 N = normalize(mat3(meshProperties[gl_InstanceCustomIndexEXT].ModelTransform * MeshTransform[gl_InstanceCustomIndexEXT].Transform) * vertex.normal);
mat3 TBN = transpose(mat3(T, B, N));
vec3 normal = texture(TextureMap[material.NormalMapID], vertex.uv).xyz;
normal = normalize(normal * 2.0 - 1.0);
return TBN * normal;
}
On the comments from the code it says it should be able to be done the normal way so I'm just trying figure if my conversion code is wrong of if the problem is somewhere else in the shader.
https://learnopengl.com/code_viewer_gh.php?code=src/6.pbr/1.2.lighting_textured/1.2.pbr.fs
// ----------------------------------------------------------------------------
// Easy trick to get tangent-normals to world-space to keep PBR code simplified.
// Don't worry if you don't get what's going on; you generally want to do normal
// mapping the usual way for performance anways; I do plan make a note of this
// technique somewhere later in the normal mapping tutorial.

Never mind I figured it out.
Turns out that I was transposing the TBN matix when I should have been and forgot to normalize the TBN * normal.
Old Code:
vec3 getNormalFromMap(MaterialInfo material, Vertex vertex)
{
vec3 T = normalize(mat3(meshProperties[gl_InstanceCustomIndexEXT].ModelTransform * MeshTransform[gl_InstanceCustomIndexEXT].Transform) * vec3(vertex.tangent));
vec3 B = normalize(mat3(meshProperties[gl_InstanceCustomIndexEXT].ModelTransform * MeshTransform[gl_InstanceCustomIndexEXT].Transform) * vec3(vertex.BiTangant));
vec3 N = normalize(mat3(meshProperties[gl_InstanceCustomIndexEXT].ModelTransform * MeshTransform[gl_InstanceCustomIndexEXT].Transform) * vertex.normal);
mat3 TBN = transpose(mat3(T, B, N));
vec3 normal = texture(TextureMap[material.NormalMapID], vertex.uv).xyz;
normal = normalize(normal * 2.0 - 1.0);
return TBN * normal;
}
Fixed Code:
vec3 getNormalFromMap(MaterialInfo material, Vertex vertex)
{
vec3 T = normalize(mat3(meshProperties[gl_InstanceCustomIndexEXT].ModelTransform * MeshTransform[gl_InstanceCustomIndexEXT].Transform) * vec3(vertex.tangent));
vec3 B = normalize(mat3(meshProperties[gl_InstanceCustomIndexEXT].ModelTransform * MeshTransform[gl_InstanceCustomIndexEXT].Transform) * vec3(vertex.BiTangant));
vec3 N = normalize(mat3(meshProperties[gl_InstanceCustomIndexEXT].ModelTransform * MeshTransform[gl_InstanceCustomIndexEXT].Transform) * vertex.normal);
mat3 TBN = mat3(T, B, N);
vec3 normal = texture(TextureMap[material.NormalMapID], vertex.uv).xyz;
normal = normalize(normal * 2.0 - 1.0);
return normalize(TBN * normal);
}

Related

How to fix floating point errors in OpenGL PBR

After finishing my PBR implementation I noticed that when I get close to a reflective surface, artifacts appear which I think are floating point errors.
I would really wish not to using doubles as my GPU tends to handle doubles in a performance heavy way
Here's my PBR IBL code (All the environment maps are correct as well as the deferred buffers):
// Deferred rendering
vec2 texcoord = gl_FragCoord.xy / textureSize(R_GBP, 0);
vec3 P = texture2D(R_GBP, texcoord).xyz;
vec4 A = texture2D(R_GBA, texcoord).rgba;
vec3 N = texture2D(R_GBN, texcoord).xyz;
float M = texture2D(R_GBM, texcoord).r;
float R = texture2D(R_GBR, texcoord).r;
vec3 V = normalize(R_CameraPos - P);
vec3 T = reflect(-V, N);
vec3 F0 = mix(vec3(0.04), A.rgb, M);
float NDV = max(dot(N, V), 0);
vec3 kS = FresnelSchlickRoughness(NDV, F0, R);
vec3 kD = (1 - kS) * (1 - M);
vec3 irr = textureCube(R_EnvironmentIrradiance, N).rgb;
vec3 dfs = irr * A.rgb;
const float MaxReflectionLod = 4;
vec3 preF_col = textureLod(R_EnvironmentPreFilter, T, R * MaxReflectionLod).rgb;
vec2 brdf = texture2D(R_EnvironmentBRDF, vec2(NDV, R)).rg;
vec3 specular = preF_col * (kS * brdf.x + brdf.y);
vec3 ambient = kD * dfs + specular;

How to calculate TBN matrix properly on GLSL

I have used normal mapping using GLSL for my application (an imaging sonar simulation) and I got problems by calculating the TBN matrix on shaders. The normal vectors contain lower resolution on border in comparison with the center of image.
Follows my vertex code:
#version 130
out vec3 pos;
out vec3 normal;
out mat3 TBN;
void main() {
pos = (gl_ModelViewMatrix * gl_Vertex).xyz;
normal = gl_NormalMatrix * gl_Normal.xyz;
vec3 n = normalize(normal);
vec3 t = normalize(cross(normal, vec3(-1,0,0)));
vec3 b = cross(t, n) + cross(n, t);
TBN = transpose(mat3(t,b,n));
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_MultiTexCoord0;
}
Part of my fragment code:
#version 130
in vec3 pos;
in vec3 normal;
in mat3 TBN;
uniform sampler2D normalTexture;
void main() {
vec3 newNormal = (texture2D(normalTexture, gl_TexCoord[0].st).rgb * 2.0 - 1) * TBN;
newNormal = normalize(newNormal);
...
}
This is the resulting figure:
How can I calculate the TBN matrix to compute the normal mapping properly?
Thanks in advance,

Normal mapping GLSL using LibGDX

I try to implement normal mapping using LibGDX. So I got some positive results when I calculate diffuse and specular color in vertex shader (at least I think so).
Vertex shader:
attribute vec4 a_position;
attribute vec2 a_texCoord0;
attribute vec3 a_normal;
varying vec2 v_texCoord;
varying float v_diffuse;
varying vec3 v_specular;
varying vec3 v_lightVec;
uniform mat4 u_worldTrans;
uniform mat4 u_projTrans;
uniform mat4 u_matViewInverseTranspose;
uniform mat4 u_matModelView;
const vec3 lightVector = vec3(0.0,0.0,-1.0);
void main()
{
// Output the unmodified vertex position.
gl_Position = u_projTrans * u_worldTrans * a_position;
mat3 normalMatrix = mat3(u_matViewInverseTranspose);
// compute the transformed normal
vec3 n = normalize(normalMatrix * a_normal);
// compute the light vector pointing toward the sun, in model coordinates
// x,y compose the longitude and z the (seasonal) lattitude of the nadir point.
//vec3 lightVec = normalize(vec3(u_matViewInverseTranspose * vec4(u_lightVec, 1.0)));
vec3 lightVec = normalize(normalMatrix * lightVector);
// Calculate a diffuse light intensity
//v_diffuse = dot(lightVec, n);
v_diffuse = clamp(dot(n, lightVec), 0.0, 1.0);
vec4 ecPosition = u_matModelView * a_position;
// compute the reflection vector
vec3 reflectVec = reflect(-lightVec, n);
// compute a unit vector in direction of viewing position
vec3 viewVec = normalize(vec3(-ecPosition));
// Calculate specular light intensity, scale down and apply a tint.
float specIntensity = pow(max(dot(reflectVec, viewVec), 0.0), 8.0);
v_specular = specIntensity *
//gloss color
vec3(1.,.7,.3) *
//gloss intensity
.7;
v_texCoord.y = 1.-a_texCoord0.y;
v_texCoord.x = a_texCoord0.x;
vec3 lightDir = normalize(lightVector - u_matModelView * a_position);
vec3 tangent=a_tangent;
vec3 t = normalize(normalMatrix * tangent);
vec3 b = cross (n, t);
vec3 v;
v.x = dot (lightDir, t);
v.y = dot (lightDir, b);
v.z = dot (lightDir, n);
v_lightVec = normalize (v);
}
Fragment shader:
precision mediump float;
varying vec2 v_texCoord;
varying float v_diffuse;
varying vec3 v_specular;
varying vec3 v_lightVec;
uniform sampler2D u_texture;
uniform sampler2D u_normalMap;
void main()
{
vec3 ground = texture2D(u_texture, v_texCoord).rgb;
vec3 normal = normalize(2.0 * texture2D (u_normalMap, v_texCoord).rgb - 1.0);
float lamberFactor = max (dot (normal, v_lightVec), 0.0);
vec3 color = ( ground.rgb * v_diffuse * lamberFactor + v_specular);
gl_FragColor = vec4 (color, 1.0);
}
Result:
As you can see the result is rendered correctly. Specular spot behaves like from many examples. But I need to implement specular color in fragment shader to get more impressive picture. So I found example from here and now I'm trying to make it works.
Vertex shader:
attribute vec4 a_position;
attribute vec2 a_texCoord0;
attribute vec3 a_normal;
attribute vec3 a_tangent;
varying vec2 v_texCoord;
varying vec3 v_lightVec;
varying vec3 v_eyeVec; //Added
uniform mat4 u_worldTrans;
uniform mat4 u_projTrans;
uniform mat4 u_matViewInverseTranspose;
uniform mat4 u_matModelView;
const vec3 lightVector = vec3(0.0,0.0,-1.0);
void main()
{
// Output the unmodified vertex position.
gl_Position = u_projTrans * u_worldTrans * a_position;
mat3 normalMatrix = mat3(u_matViewInverseTranspose);
// compute the transformed normal
vec3 n = normalize(normalMatrix * a_normal);
v_texCoord.y = 1.-a_texCoord0.y;
v_texCoord.x = a_texCoord0.x;
vec3 lightDir = normalize(lightVector - u_matModelView * a_position);
vec3 tangent=a_tangent;
vec3 t = normalize(normalMatrix * tangent);
vec3 b = cross (n, t);
vec3 v;
v.x = dot (lightDir, t);
v.y = dot (lightDir, b);
v.z = dot (lightDir, n);
v_lightVec = normalize (v);
//Added
vec3 ecPosition = u_matModelView * a_position;
vec3 tmp = vec3(-ecPosition);
v_eyeVec.x = dot(tmp, t);
v_eyeVec.y = dot(tmp, b);
v_eyeVec.z = dot(tmp, n);
v_eyeVec = normalize (v_eyeVec);
}
Fragment shader:
precision mediump float;
varying vec2 v_texCoord;
varying vec3 v_lightVec;
varying vec3 v_eyeVec;
uniform sampler2D u_texture;
uniform sampler2D u_normalMap;
void main()
{
vec3 ground = texture2D(u_texture, v_texCoord).rgb;
vec3 normal = normalize(2.0 * texture2D (u_normalMap, v_texCoord).rgb - 1.0);
//Added
float distSqr = dot(v_lightVec, v_lightVec);
float att = clamp(1.0 - .25 * sqrt(distSqr), 0.0, 1.0);
vec3 lVec = v_lightVec * inversesqrt(distSqr);
vec3 vVec = normalize(v_eyeVec);
vec3 bump = normalize( texture2D(u_normalMap, v_texCoord).xyz * 2.0 - 1.0);
float diffuse = max( dot(lVec, bump), 0.0 );
vec3 specular = pow(clamp(dot(reflect(-lVec, bump), v_eyeVec), 0.0, 1.0), 8.0 ) *
//gloss color
vec3(1.,.7,.3) *
//gloss intensity
.7;
vec3 color = ( ground.rgb * diffuse + specular) * att;
gl_FragColor = vec4 (color, 1.0);
}
Result:
Specular spot is wrong. I thought it happens because of wrong matrix calculation. If it's true why do first couple of shaders work correctly?
How do I get model-view matrix, normal matrix and others in LibGDX?
viewInvTraMatrix.set(camera.view);
viewInvTraMatrix.mul(renderable.worldTransform);
//model-view matrix
program.setUniformMatrix("u_matModelView", viewInvTraMatrix);
viewInvTraMatrix.inv(); //inverse
viewInvTraMatrix.tra(); //transpose
//normal matrix
program.setUniformMatrix("u_matViewInverseTranspose", viewInvTraMatrix);
//other matrix
program.setUniformMatrix("u_worldTrans", renderable.worldTransform);
program.setUniformMatrix("u_projTrans", camera.combined);
So, my question is what is wrong in the last couple of shaders?
The problem was in my model(mesh). After some time of digging I found out that my mesh doesn't have tangents and binormals. It happend because I used Blender 2.58 which cannot export model to FBX with tangent space. Fortunately, they fixed this bug in Blender 2.71 and later. So, when you export your model, you should tick Tangent Space parameter and choose version FBX 7.4 binary. To ensure that your mesh contains tangents and binormals, you can use fbx-converter tool to convert your fbx file to g3dj format instead of default g3db by using additional option like below:
fbx-converter.exe -o g3dj yourModel.fbx yourConvertedModel.g3dj
Then open it in some program like Notepad and check that attributes contain TANGENT and BINORMAL
"version": [ 0, 1],
"id": "",
"meshes": [
{
"attributes": ["POSITION", "NORMAL", "TANGENT", "BINORMAL", "TEXCOORD0"],
"vertices": [
0.257400, 58.707802, -0.257400, 0.000000, 1.000000, -0.000000, 0.941742,
Only one thing I don't understand, why does lamberFactor work with wrong tangent attribute(actually, without it)? Most likely, diffuse color is wrong calculated, but in my example(on sphere) it looks pretty satisfactorily. I hope it will help somebody else.
EDIT
By the way, to get a normal & a model-view matrices, I use the following code:
myMatrix.set(camera.view);
myMatrix.mul(renderable.worldTransform);
program.setUniformMatrix(u_matModelView, myMatrix); //pass model-view matrix
myMatrix.inv();
myMatrix.tra();
program.setUniformMatrix(u_matNormal, myMatrix); //pass normal matrix

GLSL (user defined) function parameters and uniform blocks strange behavior

I am writing simple deferred rendering 'engine' for fun and encountered a strange behaviour with GLSL. Calling a function caused a slight malfunction while simply pasting the content of the function solved the problem (details below).
Am I doing something terribly wrong or is it possible that I hit a limitation or a glsl compiler bug (14.12 AMD Catalyst Omega drivers) ?
Original call (in a for loop over shadow):
ColorOut.rgb += phong(position.xyz, normal, color, Shadows[shadow].position.xyz, Shadows[shadow].color.rgb);
Using this, the color of my shadow casting lights are all the same, Shadows[shadow].color.rgb seem to always be equal the to first one of the array (in the phong function at least).
My 'solution' was to replace the call by the content of the function:
vec3 L = normalize(Shadows[shadow].position.xyz - position.xyz);
float dNL = dot(normal, L);
float diffuseFactor = max(dNL, minDiffuse);
vec3 V = normalize(cameraPosition - position.xyz);
vec3 R = normalize(reflect(-L, normal));
float specularFactor = pow(max(dot(R, V), 0.f), 8.0);
ColorOut.rgb += diffuseFactor * color * Shadows[shadow].color.rgb + specularFactor * Shadows[shadow].color.rgb;
With this, everything works fine.
Other related code snippets, shadow casting lights data structure:
layout(std140, binding = 2) uniform ShadowBlock
{
vec4 position;
vec4 color;
mat4 depthMVP;
} Shadows[8];
The phong function:
vec3 phong(vec3 p, vec3 N, vec3 diffuse, vec3 lp, vec3 lc)
{
vec3 L = normalize(lp - p);
float dNL = dot(N, L);
float diffuseFactor = max(dNL, minDiffuse);
vec3 V = normalize(cameraPosition - p);
vec3 R = normalize(reflect(-L, N));
float specularFactor = pow(max(dot(R, V), 0.f), 8.0);
return diffuseFactor * diffuse * lc + specularFactor * lc;
}

OpenGL shader lssue

I tried to incorporate attentuation, but it failed does nothing.
I have diffuse, ambient, and specular lighting working. I just need to dim the light as the fragments get further away from the light.
Also, i have the attenuation parameter for my light:
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.0004f);
This is the floor lighting, the light is positioned just behind the cube:
http://oi43.tinypic.com/i39fuo.jpg
.vert
varying vec3 N;
varying vec3 v;
varying vec3 c;
varying float dist;
void main(void)
{
vec4 ecPos;
vec3 aux;
ecPos = gl_ModelViewMatrix * gl_Vertex;
aux = vec3(gl_LightSource[0].position-ecPos);
dist = length(aux);
c = vec3(gl_Color);
v = vec3(gl_ModelViewMatrix * gl_Vertex);
N = normalize(gl_NormalMatrix * gl_Normal);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
.frag
varying vec3 N;
varying vec3 v;
varying vec3 c;
varying float dist;
void main (void)
{
float att;
att = 1.0 / (gl_LightSource[0].constantAttenuation +
gl_LightSource[0].linearAttenuation * dist +
gl_LightSource[0].quadraticAttenuation * dist * dist);
vec3 L = normalize(gl_LightSource[0].position.xyz - v);
vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0)
vec3 R = normalize(-reflect(L,N));
float nDotL = max(dot(N,L), 0.0);
float rDotE = max(dot(R,E),0.0);
float power = pow(rDotE, gl_FrontMaterial.shininess);
//calculate Ambient Term:
vec4 Iamb = gl_FrontLightProduct[0].ambient * att;
//calculate Diffuse Term:
vec4 Idiff = gl_FrontLightProduct[0].diffuse * nDotL * att;
Idiff = clamp(Idiff, 0.0, 1.0);
// calculate Specular Term:
vec4 Ispec = gl_FrontLightProduct[0].specular * power * att;
Ispec = clamp(Ispec, 0.0, 1.0);
// write Total Color:
gl_FragColor = Iamb + Idiff + Ispec + c;
}
From this image i cant' really see anything. How about setting a small object as lightsource.
Which object's use this shader?
Some things that come to my mind:
You normalized your normal in your vertex shader, which is an unnecessary step.
Passed vectors from vertex to fragment shader must be normalized inside fragment shader since they will be interpolated.
Aslong you don't do any length based calculations in your vertex shader, which you aren't no normalization is necessary in vertex shader.
You should normalize the normal in fragment shader, then you don't need to normalize your reflect vector.
Attenuation is not based on anything "complex" calculated in shader. So output it and then check the rest. How does your diffuse term looks like?
Further hints:
You could place the light vector and attenuation calculation inside vertex shader and pass it as to fragment shader (pack it in a 4 vec component) to save interpolators.
the final specular clamp is unecessary, the values should be within [0, 1] range automatically. If not you have a problem.