SOLVED Bump map shader, what is the normal matrix needed?

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
pandoragami
Posts: 226
Joined: Wed Jan 26, 2011 5:37 pm
Contact:

SOLVED Bump map shader, what is the normal matrix needed?

Post by pandoragami »

Hello,

I tried to make this http://apoorvaj.io/exploring-bump-mappi ... .html#toc8 tutorial work with Irrlicht and so far I'm not sure what is the variable

Code: Select all

uniform mat4 norm_mtx;// in bump.vert


I'm guessing it's the inverse transpose of the world matrix supposedly called the normal matrix, I'm also new to this stuff. I'm almost positive the two other
variables are correct

Code: Select all

uniform mat4 model_mtx;//ETS_WORLD
uniform mat4 proj_mtx;//ETS_PROJECTION
Anyways, the code below seems to make the cube "vanish" meaning that if the line

Code: Select all

cubenode->setMaterialType((video::E_MATERIAL_TYPE) bump_map_shader);
is included then the cube vanishes.

main.cpp

Code: Select all

 
 
 
#include <irrlicht.h>
#include <iostream>
 
using namespace irr;
 
IrrlichtDevice* device = 0;
bool UseHighLevelShaders = false;
bool UseCgShaders = false;
 
irr::scene::ILightSceneNode* light_node = NULL;
irr::scene::ISceneNode* node = NULL;
 
class bump_map_effect_shader : public video::IShaderConstantSetCallBack
{
public:
 
    virtual void OnSetConstants(video::IMaterialRendererServices* services,
            s32 userData)
    {
        video::IVideoDriver* driver = services->getVideoDriver();
 
        core::matrix4 worldMatrix = driver->getTransform( video::ETS_WORLD);
        services->setPixelShaderConstant("model_mtx", worldMatrix.pointer(), 16);
 
        core::matrix4 worldInverseTransposeMatrix = worldMatrix;
        worldInverseTransposeMatrix.makeInverse();
        //worldInverseTransposeMatrix = worldInverseTransposeMatrix.getTransposed();
        services->setPixelShaderConstant("norm_mtx", worldInverseTransposeMatrix.pointer(), 16);
 
        core::matrix4 proj = driver->getTransform(video::ETS_PROJECTION);
            services->setPixelShaderConstant("proj_mtx", proj.pointer(), 16);
        s32 TextureLayerID = 0;
            services->setVertexShaderConstant("tex_norm", &TextureLayerID, 1);
        TextureLayerID = 1;
            services->setVertexShaderConstant("tex_diffuse", &TextureLayerID, 1);
        TextureLayerID = 2;
            services->setVertexShaderConstant("tex_depth", &TextureLayerID, 1);
        int type = 3;
            services->setVertexShaderConstant("type", &type, 1);
        int show_tex = 1;
            services->setVertexShaderConstant("show_tex", &show_tex, 1);
        float depth_scale = 2;
            services->setVertexShaderConstant("depth_scale", &depth_scale, 1);
        float num_layers = 3;
            services->setVertexShaderConstant("num_layers", &num_layers, 1);
    }
};
int main()
{
    video::E_DRIVER_TYPE driverType;
 
    // create device
    device = createDevice(irr::video::EDT_OPENGL, core::dimension2d<u32>(640, 480));
 
    if (device == 0)
        return 1;
 
    video::IVideoDriver* driver = device->getVideoDriver();
    scene::ISceneManager* smgr = device->getSceneManager();
    gui::IGUIEnvironment* gui = device->getGUIEnvironment();
 
    io::path vsFileName;
    io::path psFileName;
 
    driverType = video::EDT_OPENGL;
 
    video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();
 
    s32 bump_map_shader = 0;
 
    if (gpu)
    {
        const video::E_GPU_SHADING_LANGUAGE shadingLanguage =
             video::EGSL_DEFAULT;
 
//bump mapping
        psFileName = "bump.frag";
        vsFileName = "bump.vert";
 
        bump_map_effect_shader* bump_map_effect_shader_callback = new bump_map_effect_shader();
 
        bump_map_shader = gpu->addHighLevelShaderMaterialFromFiles(
            vsFileName, "vertexMain", video::EVST_VS_1_1,
            psFileName, "pixelMain", video::EPST_PS_1_1,
            bump_map_effect_shader_callback, video::EMT_TRANSPARENT_ADD_COLOR, 0 , shadingLanguage);
 
        bump_map_effect_shader_callback->drop();
    }
 
    irr::scene::ISceneNode* node = NULL;
 
    node = smgr->addEmptySceneNode( 0,-1);
    node->setPosition( irr::core::vector3df( 0, 0, 0));
 
    light_node = smgr->addLightSceneNode(0, core::vector3df( 0, 0, 0),
        video::SColorf(1.0f, 1.0f, 1.0f, 1.0f), 150.0f);
    //light_node->setVisible( true);
 
    irr::video::SLight  & slight = light_node->getLightData();
    slight.Type = irr::video::ELT_DIRECTIONAL;
 
    slight.AmbientColor = irr::video::SColorf(0.4f,0.24f,0.5f,1.0f);
    slight.SpecularColor = irr::video::SColorf(0.2f,1.0f,0.2f,1.0f);
    slight.DiffuseColor = irr::video::SColorf(0.2f,0.2f,1.0f,1.0f);
 
    node->addChild( light_node);
    irr::scene::ISceneNodeAnimator* anim = 0;
    anim = smgr->createRotationAnimator ( irr::core::vector3df( 0.0f, 0.6f, 0.0f));
        node->addAnimator(anim);
        anim->drop();
//
    scene::ISceneNode* cubenode = smgr->addCubeSceneNode( 50);
    cubenode->setPosition( core::vector3df( 0, 0, 0));
 
    cubenode->setMaterialTexture( 0, driver->getTexture("normal.png"));
    cubenode->setMaterialTexture( 1, driver->getTexture("diffuse.png"));
    cubenode->setMaterialTexture( 2, driver->getTexture("depth.png"));
    cubenode->setMaterialFlag( video::EMF_BLEND_OPERATION, true);
    cubenode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
    cubenode->setMaterialFlag( video::EMF_LIGHTING, true);
    cubenode->setMaterialType((video::E_MATERIAL_TYPE) bump_map_shader);
 
    scene::ICameraSceneNode* cam = smgr->addCameraSceneNode();
    cam->setPosition(core::vector3df( 70, 70,-70));
    cam->setTarget(core::vector3df(0,0,0));
    device->getCursorControl()->setVisible( false);
 
    int lastFPS = -1;
 
    while(device->run())
        if (device->isWindowActive())
    {
        driver->beginScene(true, true, video::SColor(255,255,255,255));
        smgr->drawAll();
        driver->endScene();
 
        int fps = driver->getFPS();
 
        if (lastFPS != fps)
        {
            core::stringw str = L"Irrlicht Engine - Vertex and pixel shader example [";
            str += driver->getName();
            str += "] FPS:";
            str += fps;
 
            device->setWindowCaption(str.c_str());
            lastFPS = fps;
        }
    }
 
    device->drop();
 
    return 0;
}
 
 
bump.vert

Code: Select all

 
//precision highp float;
//#version 130
attribute vec3 vert_pos;
attribute vec3 vert_tang;
attribute vec3 vert_bitang;
attribute vec2 vert_uv;
 
uniform mat4 model_mtx;//ETS_WORLD
uniform mat4 norm_mtx;//worldInverseTransposeMatrix???
uniform mat4 proj_mtx;//ETS_PROJECTION
 
varying vec2 frag_uv;
varying vec3 ts_light_pos; // Tangent space values
varying vec3 ts_view_pos;  //
varying vec3 ts_frag_pos;  //
 
mat3 transpose(in mat3 inMatrix)
{
    vec3 i0 = inMatrix[0];
    vec3 i1 = inMatrix[1];
    vec3 i2 = inMatrix[2];
 
    mat3 outMatrix = mat3(
        vec3(i0.x, i1.x, i2.x),
        vec3(i0.y, i1.y, i2.y),
        vec3(i0.z, i1.z, i2.z)
    );
 
    return outMatrix;
}
mat3 m3( mat4 m )
{
    mat3 result;
 
    result[0][0] = m[0][0]; 
    result[0][1] = m[0][1]; 
    result[0][2] = m[0][2]; 
 
 
    result[1][0] = m[1][0]; 
    result[1][1] = m[1][1]; 
    result[1][2] = m[1][2]; 
 
    result[2][0] = m[2][0]; 
    result[2][1] = m[2][1]; 
    result[2][2] = m[2][2]; 
 
    return result;
}
 
void main(void)
{
    gl_Position = proj_mtx * vec4(vert_pos, 1.0);
    ts_frag_pos = vec3(model_mtx * vec4(vert_pos, 1.0));
    vec3 vert_norm = cross(vert_bitang, vert_tang);
 
    vec3 t = normalize(m3(norm_mtx) * vert_tang);
    vec3 b = normalize(m3(norm_mtx) * vert_bitang);
    vec3 n = normalize(m3(norm_mtx) * vert_norm);
    mat3 tbn = transpose(mat3(t, b, n));
 
    vec3 light_pos = vec3(1, 2, 0);
    ts_light_pos = tbn * light_pos;
    // Our camera is always at the origin
    ts_view_pos = tbn * vec3(0, 0, 0);
    ts_frag_pos = tbn * ts_frag_pos;
 
    frag_uv = vert_uv;
} 
 

bump.frag

Code: Select all

 
//precision highp float;
//#version 130
uniform sampler2D tex_norm;
uniform sampler2D tex_diffuse;
uniform sampler2D tex_depth;
/*
    The type is controlled by the radio buttons below the canvas.
    0 = No bump mapping
    1 = Normal mapping
    2 = Parallax mapping
    3 = Steep parallax mapping
    4 = Parallax occlusion mapping
*/
uniform int type;
uniform int show_tex;
uniform float depth_scale;
uniform float num_layers;
 
varying vec2 frag_uv;
varying vec3 ts_light_pos;
varying vec3 ts_view_pos;
varying vec3 ts_frag_pos;
 
vec2 parallax_uv(vec2 uv, vec3 view_dir)
{
    if (type == 2) 
    {
        // Parallax mapping
        float depth = texture2D(tex_depth, uv).r;    
        vec2 p = view_dir.xy * (depth * depth_scale) / view_dir.z;
        return uv - p;          
    }   
    else 
    {
        float layer_depth = 1.0 / num_layers;
        float cur_layer_depth = 0.0;
        vec2 delta_uv = view_dir.xy * depth_scale / (view_dir.z * num_layers);
        vec2 cur_uv = uv;
 
        float depth_from_tex = texture2D(tex_depth, cur_uv).r;
                
        for (int i = 0; i < 32; i++) 
        {
            cur_layer_depth += layer_depth;
            cur_uv -= delta_uv;
            depth_from_tex = texture2D(tex_depth, cur_uv).r;
            
            if (depth_from_tex < cur_layer_depth)           
                i = 32;            
        }
    
        
        if (type == 3) 
        {
            // Steep parallax mapping
            return cur_uv;
        } 
        else 
        {
            // Parallax occlusion mapping
            vec2 prev_uv = cur_uv + delta_uv;
            float next = depth_from_tex - cur_layer_depth;
            float prev = texture2D(tex_depth, prev_uv).r - cur_layer_depth
                         + layer_depth;
            float weight = next / (next - prev);
            return mix(cur_uv, prev_uv, weight);
        }
        
    }
    
}
 
void main(void)
{   
    vec3 light_dir = normalize(ts_light_pos - ts_frag_pos); 
    vec3 view_dir = normalize(ts_view_pos - ts_frag_pos);
 
    // Only perturb the texture coordinates if a parallax technique is selected
    //(condition) ? (if_true) : (if_false)
    vec2 uv = (type < 2) ? frag_uv : parallax_uv( frag_uv, view_dir);
 
    vec3 albedo = texture2D(tex_diffuse, uv).rgb;
    
    if (show_tex == 0) 
    { 
        albedo = vec3(1,1,1); 
    }
    
    vec3 ambient = 0.3 * albedo;
 
    if (type == 0) 
    {
        // No bump mapping
        vec3 norm = vec3(0,0,1);
        float diffuse = max(dot(light_dir, norm), 0.0);
        gl_FragColor = vec4(diffuse * albedo + ambient, 1.0);
    }   
    else 
    {
        // Normal mapping
        vec3 norm = normalize(texture2D(tex_norm, uv).rgb * 2.0 - 1.0);
        float diffuse = max(dot(light_dir, norm), 0.0);
        gl_FragColor = vec4(diffuse * albedo + ambient, 1.0);
    }   
}
 
depth.png Image
diffuse.png Image
normal.png Image

All images at
https://imgur.com/a/ZbZtl
pandoragami
Posts: 226
Joined: Wed Jan 26, 2011 5:37 pm
Contact:

Re: SOLVED Bump map shader, what is the normal matrix needed

Post by pandoragami »

I managed to solve it using the code from this site https://www.gamedev.net/forums/topic/52 ... -tangents/

It now works, there might be lots of unneeded code in the source and shaders but it's all for simplicity to show step by step what's happening.

main.cpp

Code: Select all

 
#include <irrlicht.h>
#include <iostream>
 
using namespace irr;
 
IrrlichtDevice* device = 0;
bool UseHighLevelShaders = false;
bool UseCgShaders = false;
 
irr::scene::ILightSceneNode* light_node = NULL;
irr::scene::ISceneNode* node = NULL;
 
class bump_map_effect_shader : public video::IShaderConstantSetCallBack
{
public:
 
    virtual void OnSetConstants(video::IMaterialRendererServices* services,
            s32 userData)
    {
        video::IVideoDriver* driver = services->getVideoDriver();
 
        core::matrix4 worldMatrix = driver->getTransform( video::ETS_WORLD);
        services->setPixelShaderConstant("model_mtx", worldMatrix.pointer(), 16);
 
        core::matrix4 worldInverseTransposeMatrix = worldMatrix;
        worldInverseTransposeMatrix = worldInverseTransposeMatrix.makeInverse();
        worldInverseTransposeMatrix = worldInverseTransposeMatrix.getTransposed();
        services->setPixelShaderConstant("norm_mtx", worldInverseTransposeMatrix.pointer(), 16);
 
        core::matrix4 proj = driver->getTransform(video::ETS_PROJECTION);
            services->setPixelShaderConstant("proj_mtx", proj.pointer(), 16);
 
        core::vector3df camera_dir = device->getSceneManager()->getActiveCamera()->getAbsolutePosition();
        services->setVertexShaderConstant("mCamPos", reinterpret_cast<f32*>(&camera_dir), 3);
 
        core::matrix4 ViewMatrixInverse = driver->getTransform(video::ETS_VIEW);
        ViewMatrixInverse = ViewMatrixInverse.makeInverse();
            services->setPixelShaderConstant("ViewMatrixInverse", ViewMatrixInverse.pointer(), 16);
 
        s32 TextureLayerID = 0;
            services->setVertexShaderConstant("tex_norm", &TextureLayerID, 1);
        TextureLayerID = 1;
            services->setVertexShaderConstant("tex_diffuse", &TextureLayerID, 1);
        TextureLayerID = 2;
            services->setVertexShaderConstant("tex_depth", &TextureLayerID, 1);
        int type = 1;//1-4
            services->setVertexShaderConstant("type", &type, 1);
        int show_tex = 1;// on or off
            services->setVertexShaderConstant("show_tex", &show_tex, 1);
        float depth_scale = 0.001f;//small number
            services->setVertexShaderConstant("depth_scale", &depth_scale, 1);
        float num_layers = 15;//1-32
            services->setVertexShaderConstant("num_layers", &num_layers, 1);
    }
};
int main()
{
    video::E_DRIVER_TYPE driverType;
 
    // create device
    device = createDevice(irr::video::EDT_OPENGL, core::dimension2d<u32>(640, 480));
 
    if (device == 0)
        return 1;
 
    video::IVideoDriver* driver = device->getVideoDriver();
    scene::ISceneManager* smgr = device->getSceneManager();
    gui::IGUIEnvironment* gui = device->getGUIEnvironment();
 
    io::path vsFileName;
    io::path psFileName;
 
    driverType = video::EDT_OPENGL;
 
    video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();
 
    s32 bump_map_shader = 0;
 
    if (gpu)
    {
        const video::E_GPU_SHADING_LANGUAGE shadingLanguage =
             video::EGSL_DEFAULT;
 
//bump mapping
        psFileName = "bump.frag";
        vsFileName = "bump.vert";
 
        bump_map_effect_shader* bump_map_effect_shader_callback = new bump_map_effect_shader();
 
        bump_map_shader = gpu->addHighLevelShaderMaterialFromFiles(
            vsFileName, "vertexMain", video::EVST_VS_1_1,
            psFileName, "pixelMain", video::EPST_PS_1_1,
            bump_map_effect_shader_callback, video::EMT_TRANSPARENT_ADD_COLOR, 0 , shadingLanguage);
 
        bump_map_effect_shader_callback->drop();
    }
 
    irr::scene::ISceneNode* node = NULL;
 
    node = smgr->addEmptySceneNode( 0,-1);
    node->setPosition( irr::core::vector3df( 0, 0, 0));
 
    light_node = smgr->addLightSceneNode(0, core::vector3df( 0, 0, 0),
        video::SColorf(1.0f, 1.0f, 1.0f, 1.0f), 150.0f);
    //light_node->setVisible( true);
 
    irr::video::SLight  & slight = light_node->getLightData();
    slight.Type = irr::video::ELT_DIRECTIONAL;
 
    slight.AmbientColor = irr::video::SColorf(0.4f,0.24f,0.5f,1.0f);
    slight.SpecularColor = irr::video::SColorf(0.2f,1.0f,0.2f,1.0f);
    slight.DiffuseColor = irr::video::SColorf(0.2f,0.2f,1.0f,1.0f);
 
    node->addChild( light_node);
    irr::scene::ISceneNodeAnimator* anim = 0;
    anim = smgr->createRotationAnimator ( irr::core::vector3df( 0.0f, 0.6f, 0.0f));
        node->addAnimator(anim);
        anim->drop();
//
    scene::ISceneNode* cubenode = smgr->addCubeSceneNode( 50);
    cubenode->setPosition( core::vector3df( 0, 0, 0));
 
    cubenode->setMaterialTexture( 0, driver->getTexture("normal.png"));
    cubenode->setMaterialTexture( 1, driver->getTexture("diffuse.png"));
    cubenode->setMaterialTexture( 2, driver->getTexture("depth.png"));
    cubenode->setMaterialFlag( video::EMF_BLEND_OPERATION, false);
    cubenode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
    cubenode->setMaterialFlag( video::EMF_LIGHTING, true);
    cubenode->setMaterialType((video::E_MATERIAL_TYPE) bump_map_shader);
 
    scene::ICameraSceneNode* cam = smgr->addCameraSceneNode();
    cam->setPosition(core::vector3df( 50, 50,-50));
    cam->setTarget(core::vector3df(0,0,0));
    device->getCursorControl()->setVisible( false);
 
    int lastFPS = -1;
 
    while(device->run())
        if (device->isWindowActive())
    {
        driver->beginScene(true, true, video::SColor(255,0,0,0));
        smgr->drawAll();
        driver->endScene();
 
        int fps = driver->getFPS();
 
        if (lastFPS != fps)
        {
            core::stringw str = L"Irrlicht Engine - Vertex and pixel shader example [";
            str += driver->getName();
            str += "] FPS:";
            str += fps;
 
            device->setWindowCaption(str.c_str());
            lastFPS = fps;
        }
    }
 
    device->drop();
 
    return 0;
}
  
 
bump.vert

Code: Select all

 
uniform mat4 model_mtx;//ETS_WORLD or model matrix or model view matrix
uniform mat4 norm_mtx;//worldInverseTransposeMatrix
uniform mat4 proj_mtx;//ETS_PROJECTION
uniform mat4 ViewMatrixInverse;
uniform vec3 mCamPos;
varying vec2 frag_uv;
varying vec3 vNormal;
varying vec3 vLightDir;
varying vec3 vViewDir;
 
mat3 transpose(in mat3 inMatrix)
{
    vec3 i0 = inMatrix[0];
    vec3 i1 = inMatrix[1];
    vec3 i2 = inMatrix[2];
 
    mat3 outMatrix = mat3
    (
        vec3(i0.x, i1.x, i2.x),
        vec3(i0.y, i1.y, i2.y),
        vec3(i0.z, i1.z, i2.z)
    );
 
    return outMatrix;
}
 
void main(void)
{   
    //Pass the texture coordinate on through.   
    gl_TexCoord[0] = gl_MultiTexCoord0;
    frag_uv = gl_TexCoord[0].st;    
        
    vLightDir = normalize(-gl_LightSource[0].position.xzy);
    vLightDir.y = -vLightDir.y;
   
    vViewDir = normalize(gl_ModelViewMatrixInverse[3].xyz - gl_Vertex.xyz); 
    mat4 worldMatrix = gl_ModelViewMatrix * gl_ModelViewMatrixInverse;
    
    vec3 test = (gl_NormalMatrix * gl_Normal);
    vec4 result = gl_ModelViewMatrixInverse * vec4(test, 0.0);
    vNormal = normalize( result.xyz);      
    
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
} 
 
bump.frag

Code: Select all

 
uniform sampler2D tex_norm;
uniform sampler2D tex_diffuse;
uniform sampler2D tex_depth;
/*
    
    0 = No bump mapping
    1 = Normal mapping
    2 = Parallax mapping
    3 = Steep parallax mapping
    4 = Parallax occlusion mapping
*/
uniform int type;
uniform int show_tex;
uniform float depth_scale;
uniform float num_layers;
varying vec3 vNormal;
varying vec3 vLightDir;
varying vec3 vViewDir;
//varying vec2 vert_uv;
varying vec2 frag_uv;
 
vec2 parallax_uv(vec2 uv, vec3 view_dir)
{
    if (type == 2) 
    {
        // Parallax mapping
        float depth = texture2D(tex_depth, uv).r;    
        vec2 p = view_dir.xy * (depth * depth_scale) / view_dir.z;
        return uv - p;          
    }   
    else 
    {
        float layer_depth = 1.0 / num_layers;
        float cur_layer_depth = 0.0;
        vec2 delta_uv = view_dir.xy * depth_scale / (view_dir.z * num_layers);
        vec2 cur_uv = uv;
 
        float depth_from_tex = texture2D(tex_depth, cur_uv).r;
                
        for (int i = 0; i < 32; i++) 
        {
            cur_layer_depth += layer_depth;
            cur_uv -= delta_uv;
            depth_from_tex = texture2D(tex_depth, cur_uv).r;
            
            if (depth_from_tex < cur_layer_depth)           
                i = 32;            
        }   
        
        if (type == 3) 
        {
            // Steep parallax mapping
            return cur_uv;
        } 
        else 
        {
            // Parallax occlusion mapping
            vec2 prev_uv = cur_uv + delta_uv;
            float next = depth_from_tex - cur_layer_depth;
            float prev = texture2D(tex_depth, prev_uv).r - cur_layer_depth
                         + layer_depth;
            float weight = next / (next - prev);
            return mix(cur_uv, prev_uv, weight);
        }       
    }   
}
 
float saturate(float inValue)
{
   return clamp(inValue, 0.0, 1.0);
}
mat3 transpose(in mat3 inMatrix)
{
    vec3 i0 = inMatrix[0];
    vec3 i1 = inMatrix[1];
    vec3 i2 = inMatrix[2];
 
    mat3 outMatrix = mat3
    (
        vec3(i0.x, i1.x, i2.x),
        vec3(i0.y, i1.y, i2.y),
        vec3(i0.z, i1.z, i2.z)
    );
 
    return outMatrix;
}
mat3 MatrixInverse( mat3 inMatrix)
{  
   mat3 T = transpose( inMatrix);
   float det = dot(cross(inMatrix[0], inMatrix[1]), inMatrix[2]);   
   return mat3(cross(T[1], T[2]),
               cross(T[2], T[0]),
               cross(T[0], T[1])) / det;
}
void main(void)
{
    vec3 viewDir = normalize(vViewDir);
    vec3 lightDir = normalize(vLightDir);
        
    //get edge vectors of the pixel triangle
        vec3 dp1  = dFdx(viewDir);      
        vec3 dp2  = dFdy(viewDir);   
        vec2 duv1 = dFdx(gl_TexCoord[0].xy);
        vec2 duv2 = dFdy(gl_TexCoord[0].xy);  
       
    //solve the linear system
        mat3 M = mat3(dp1, dp2, cross(dp1, dp2));
        mat3 inverseM = MatrixInverse(M);
        vec3 T = inverseM * vec3(duv1.x, duv2.x, 0.0);
        vec3 B = inverseM * vec3(duv1.y, duv2.y, 0.0);
       
    //construct tangent frame  
       float maxLength = max(length(T), length(B));
       T = T / maxLength;
       B = B / maxLength;
       
       vec3 t = normalize(T);
       vec3 b = normalize(B);     
      
       vec3 n = normalize(vNormal);
       mat3 tbn = transpose(mat3(t, b, n));
    
        vec3 ts_light_pos; // Tangent space values
        vec3 ts_view_pos;  //
        vec3 ts_frag_pos;  //
 
        vec3 light_pos = lightDir;
        ts_light_pos = tbn * light_pos;
    
        ts_view_pos = tbn * viewDir;
        ts_frag_pos = tbn * ts_frag_pos;    
 
    vec3 light_dir = normalize(ts_light_pos - ts_frag_pos); 
    vec3 view_dir = normalize(ts_view_pos - ts_frag_pos);
 
    // Only perturb the texture coordinates if a parallax technique is selected
    //(condition) ? (if_true) : (if_false)
    vec2 uv = (type < 2) ? frag_uv : parallax_uv( frag_uv, view_dir);
 
    vec3 albedo = texture2D(tex_diffuse, uv).rgb;
    
    if (show_tex == 0) 
    { 
        albedo = vec3(1,1,1); 
    }
    
    vec3 ambient = 0.3 * albedo;
 
    if (type == 0) 
    {
        // No bump mapping
        vec3 norm = vec3(0,0,1);
        float diffuse = max(dot(light_dir, norm), 0.0);
        gl_FragColor = vec4(diffuse * albedo + ambient, 1.0);
    }   
    else 
    {
        // Normal mapping
        vec3 norm = normalize(texture2D(tex_norm, uv).rgb * 2.0 - 1.0);
        float diffuse = max(dot(light_dir, norm), 0.0);
        gl_FragColor = vec4(diffuse * albedo + ambient, 1.0);
    }       
}
 

I'm not guaranteeing that this is the final solution though, but it looks good in the rendered image.
Post Reply