Home:ALL Converter>Implement normal mapping GLSL and raylib

Implement normal mapping GLSL and raylib

Ask Time:2022-01-15T20:14:30         Author:Sanico

Json Formatter

I'm trying to implement normal mapping to my shaders but I keep getting weird results.
I already implemented diffuse and specular light (which are working). I first calculated the normalized vector from the normal map : Ni = 2 * normalColor - 1 then calculated the binormal vector thanks to the cross vector of normal and tangent.
Finally I created the TBN matrix by transposing (tangent, binormal, normal)

Here is my code and some screenshots.

Vertex shader

#version 330

// Input vertex attributes
in vec3 vertexPosition;
in vec2 vertexTexCoord;
in vec3 vertexNormal;
in vec4 vertexColor;
in vec4 vertexTangent;

// Input uniform values
uniform mat4 mvp;

// Output vertex attributes (to fragment shader)
out vec2 fragTexCoord;
out vec4 fragColor;
out vec3 fragPosition;
out vec4 fragTangent;
out vec3 fragNormal;
// out vec3 fragBiTangent;


// NOTE: Add here your custom variables

void main()
{
    // Send vertex attributes to fragment shader
    fragTexCoord = vertexTexCoord;
    fragColor = vertexColor;
    //added
    fragNormal = vertexNormal;
    fragPosition = vertexPosition;
    fragTangent = vertexTangent;


    // Calculate final vertex position
    gl_Position = mvp*vec4(vertexPosition, 1.0);
}

Fragment Shader

#version 330

// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord;
in vec4 fragColor;
in vec3 fragNormal;
in vec3 fragPosition;
in vec4 fragTangent;

// Input uniform values
uniform sampler2D texture0;     // diffuse texture
uniform vec4 colDiffuse;
uniform vec3 lightPos;          // light position
uniform mat4 matModel;          // pos, rotation and scaling of object
uniform vec3 viewPos;           // eyes position
uniform sampler2D normalMap;    // normal texture


// Output fragment color
out vec4 finalColor;

// NOTE: Add here your custom variables
vec3 unHomogenous(vec4 v)
{
    return v.xyz/v.w;
}

void main()
{
    //=====================LOAD TEXTURES=============================

    // Texel color fetching from texture sampler
    vec4 texelColor = texture(texture0, fragTexCoord);

    // obtain normal from normal map in range [0,1]
    vec3 normalColor = texture(normalMap, fragTexCoord).xyz;
    

    //=======================PARAMETERS==============================

    // calculate normal in world coordinates
    mat3 matNormal = transpose(inverse(mat3(matModel)));    //CPU heavy
    vec3 worldNormal = normalize(matNormal * fragNormal);

    // Calculate the location of this fragment (pixel) in world coordinates
    vec3 worldPosition = unHomogenous(matModel * vec4(fragPosition, 1.0));

    //=======================NORMAL MAPPING========================

    // transform normal vector to range [-1,1]
    vec3 normal = normalize(normalColor * 2.0 - 1.0); 

    normal = normalize(matNormal * normal);
    vec3 tangent = normalize(matNormal * fragTangent.xyz);
    vec3 binormal = normalize(cross(normal, tangent));

    mat3 TBN = mat3(tangent, binormal, worldNormal);
    TBN = transpose(TBN);
    
  

    //=======================DIFFUSING LIGHT===========================

    // Shading is calculated by diffuse = (LightVect dot NormalVect) * Diffused color  

    vec3 ambiant = 0.01 * texelColor.xyz ;

    // find light source : L = Lightposition - surfacePosition
    vec3 lightDir = normalize(lightPos - worldPosition);
    lightDir *= TBN; // NOT WORKING

    // diffuse the light with the dot matrix :
    float shading = clamp(dot(worldNormal, lightDir), 0.1, 1.0);
    vec3 diffuse = shading * texelColor.xyz;

    //=======================SPECULAR LIGHTNING====================

    //intensity between 0 and 1
    float specularStrength = 1;
    
    // //calculate the view direction vector and corresponding reflect vector along the normal axis
    vec3 viewDir = normalize(viewPos - worldPosition);
    viewDir *= TBN; // NOT WORKING

    vec3 reflectDir = reflect(-lightDir, worldNormal);  
    //Note that we negate the lightDir vector. 
    //The reflect function expects the first vector to point from the light source towards the fragment's position, 
    //but the lightDir vector is currently pointing the other way 
    

    // calclulate the specula component 32 is the shininess value of the highlight
    int shininess = 32;
    float spec = pow(clamp(dot(viewDir, reflectDir), 0.1, 1.0), shininess);

    vec3 lightColor = vec3(1.0,1.0,1.0);
    vec3 specular = specularStrength * spec * texelColor.xyz; 

    

    //=======================RENDER================================
    finalColor = vec4(ambiant + diffuse + specular, 1.0);

}

main.cpp

#include "raylib.h"
#include "rlgl.h"
#include <math.h>  
#include <raymath.h>

int main(void)
{
    // Initialization
    //[...]
    //=====================WALL=======================//

    Vector3 position = { -2.5f, 3.0f, 0.0f };

    Model model = LoadModel("assets/models/wall.obj");
    Texture2D texture = LoadTexture("assets/textures/cgaxis_pbr_17_stone_wall_5_diffuse.png");
    
    // Set normal mapping
    Texture2D normal_texture = LoadTexture("assets/textures/cgaxis_pbr_17_stone_wall_5_normal.png");

    model.materials[0].maps[MATERIAL_MAP_NORMAL].texture = normal_texture;
    //==========Generate mesh and diffuse texture=========//

    GenMeshTangents(model.meshes);   
    
    model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture;            // Set map diffuse texture

   
    //===================SELECT SHADERS====================//

    // Shader shader = LoadShader("assets/shaders/base.vs", "assets/shaders/base.fs");                             // diffuse light
    // Shader shader = LoadShader("assets/shaders/specular.vs", "assets/shaders/specular.fs");                  // diff + specular
    Shader shader = LoadShader("assets/shaders/normal_mapping.vs", "assets/shaders/normal_mapping.fs");      // diff + spec + normal mapping

    // Set shader effect to 3d model
    model.materials[0].shader = shader;  

    //==================Light======================//

    Vector3 sunPos = {0.0f, 2.0f, 0.0f };
    float rotation = 90.0f;
    float radius = 5.0f;

    // Diffuse light
    int lightPosLoc = GetShaderLocation(shader, "lightPos");
    float lightPos[] = {sunPos.x, sunPos.y, sunPos.z};
    SetShaderValue(shader, lightPosLoc, lightPos, SHADER_UNIFORM_VEC3);
    
    //specular light
    int specularPosLoc = GetShaderLocation(shader, "viewPos");
    float specularPos[] = {camera.position.x, camera.position.y, camera.position.z};
    SetShaderValue(shader, specularPosLoc, specularPos, SHADER_UNIFORM_VEC3);


    //RUN & draw
    //[...]
    // De-Initialization
    //--------------------------------------------------------------------------------------
    CloseWindow();        // Close window and OpenGL context
    //--------------------------------------------------------------------------------------

    return 0;
}

diffuse + specular Diffuse and specular light

normal mapping Added normal mapping

Author:Sanico,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/70721321/implement-normal-mapping-glsl-and-raylib
yy