Sponza рэндэрлэх оролдлого 11, Normal mapping

Normal mapping ашигласнаар объектийн геометр өгөгдлүүд хэдий цөөн ч гадаргуу нь сүүдрийн тусламжтайгаар илүү их деталтай харагдах боломжтой болдог. Normal map бол пискел болгон дээрээ гадаргуун нормал чиглэлийг хадгалж байх бөгөөд үүнийг ашиглан гэрлийн ойлтын алгоритм ажиллана.



Гэрлийн тооцооллыг нормал map дээр хийхийн тулд гэрэл болон нормал тооцооллыг texture-space руу оруулах хэрэгтэй. Үүний тулд TBN хэмээх матриц хэрэглэдэг. Энэ матриц нь tangent, bitangent, normal гэсэн гурван векторуудаас бүрдэнэ. Матрицаа гаргаж авахдаа tangent векторуудыг урьдчилаад тооцоолсон байх хэрэгтэй. Assimp санд модел уншихад aiProcess_CalcTangentSpace гэх горим байх бөгөөд үүнийг ашигласнаар tangent векторуудыг авч shader лүү дамжуулах боломж бүрддэг. Ингээд shader-т нормал болон тангент оройн векторууд орж ирэх үед bintangent-ийг энэ хоёрыг вектор үржвэрээр (cross product) үржих байдлаар гаргаж авна. Ингэсэн тохиолдолд энэ гурван вектороо ашиглаад 3x3 хэмжээтэй квадрат матриц гаргаж авах боломжтой. Энэ матрицаараа view-space дотор байгаа гэрлийн чиглэлийг үржсэнээр texture-space дотор гэрлийн тооцооллыг хийх боломж бүрддэг. Assimp сан tangent болон bitangent векторуудыг хоёуланг нь урьдчилан тооцооллочихдог тул vertex shader дотор вектор үржвэр үржиж bitangent ийг олох шаардлагагүй. Гэхдээ ашигласан ч болно чанарын ялгаа нээх харагдахгүй байна лээ.




Vertex Shader
#version 330
layout(location=0) in vec4 in_position; // model-space
layout(location=1) in vec3 in_normal;   // model-space
layout(location=2) in vec2 in_texcoord;
layout(location=3) in vec3 in_tangent;
layout(location=4) in vec3 in_bitangent;

out vec2 vTexcoord;
out vec3 vPosition; // world-space
out vec3 vNormal;   // view-space
out vec3 vEyeDir;   // view-space
out vec3 vLightDir; // view-space

uniform mat4 mvpMatrix;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat3 normalMatrix;

uniform int hasNormalMap;
uniform vec3 lightPosition; // world-space

void main(void)
{
    gl_Position = mvpMatrix * in_position;
    
    vTexcoord = in_texcoord;
    
    vPosition = (modelMatrix * in_position).xyz;
    
    vNormal = (normalMatrix * in_normal).xyz;
    
    vec3 tbnNormal    = normalize(vNormal);
    vec3 tbnTangent   = normalize(normalMatrix * in_tangent);
    //vec3 tbnBitangent = normalize(normalMatrix * in_bitangent);
    vec3 tbnBitangent  = normalize(cross(tbnNormal, tbnTangent));
    mat3 tbnMatrix = transpose(mat3(tbnTangent, tbnBitangent, tbnNormal));
    
    vec3 posInEyespace = (viewMatrix * modelMatrix * in_position).xyz;
    vEyeDir = vec3(0,0,0) - posInEyespace;

    vec3 lightPosInEyespace = (viewMatrix * vec4(lightPosition, 1.0)).xyz;
    vLightDir = lightPosInEyespace + vEyeDir;


    if (hasNormalMap != 0) {
        vLightDir = normalize(tbnMatrix * vLightDir);
        vNormal   = normalize(tbnMatrix * vNormal);
    }

    
}

Fragment Shader
#version 330
uniform sampler2D material_diffuse_texture;
uniform sampler2D material_normal_texture;
uniform sampler2D material_ambient_texture;
uniform sampler2D material_specular_texture;
uniform sampler2D material_opacity_texture;
uniform float     material_shininess; 
uniform vec4      material_diffuse_color;

uniform int hasOpacityMap;
uniform int hasAmbientMap;
uniform int hasNormalMap;
uniform int hasSpecularMap;

uniform float ambientIntensity;

uniform vec3 lightPosition; // world-space
uniform vec3 spotDir;

in vec2 vTexcoord;
in vec3 vPosition; // world-space
in vec3 vNormal;   // view-space
in vec3 vEyeDir;   // view-space
in vec3 vLightDir; // view-space

out vec4 out_color;

void main(void)
{
    vec3 lightColor = vec3(1.0, 1.0, 1.0);

    vec4 diffuseColor  = texture2D(material_diffuse_texture, vTexcoord);
    vec4 ambientColor  = texture2D(material_ambient_texture, vTexcoord);
    vec4 normalColor   = vec4(texture2D(material_normal_texture , vTexcoord).xyz, 1.0);
    vec4 specularColor = texture2D(material_specular_texture, vTexcoord);
    vec4 opacityColor  = texture2D(material_opacity_texture, vTexcoord);

    if (hasAmbientMap==0) {
        ambientColor = diffuseColor;
    }

    vec4 resAmbientColor  = vec4(0, 0, 0, 0);
    vec4 resDiffuseColor  = vec4(0, 0, 0, 0);
    vec4 resSpecularColor = vec4(0, 0, 0, 0);
    vec4 resultColor      = vec4(0, 0, 0, 0);

    // ambient calculation
    float ambientFraction = 0.25;
    //resAmbientColor = vec4((ambientFraction * lightColor * ambientColor.xyz).xyz, 1.0);
    resAmbientColor = vec4((ambientFraction * ambientColor.xyz).xyz, 1.0);
    
    vec3 normal = normalize(vNormal);
    if (hasNormalMap != 0) {
        vec3 nTex = normalColor.xyz;
        normal = nTex * 2.0 - 1.0;
        normal = normalize(normal);
    }
    vec3 lightDirection = normalize(vLightDir);

    // diffuse calculation, lambertian cosinus
    float lambertcos = max(0.0, dot(normal, lightDirection));
    //resDiffuseColor = vec4((lambertcos * lightColor * diffuseColor.xyz).xyz, 1.0);
    resDiffuseColor = vec4((lightColor * diffuseColor.xyz).xyz, 1.0);

    // specular calculation, blinn-phong
    float lightDistance = length(lightPosition-vPosition);
    vec3 halfVector = normalize(normalize(vEyeDir) + lightDirection);
    // Blinn-Phong needs shininiess about 4 * Phong shininess
    float specularcoeff = pow(max(0.0, dot(normal, halfVector)), 4.0 * material_shininess); 
    resSpecularColor = vec4((specularcoeff * lightColor * specularColor.xyz).xyz, 1.0);

    float attenuation = 0.0;
    if (lambertcos>0.0) {
        float constant = 1.0;
        float linear   = 0.0014;
        float quadric  = 0.000007;
        attenuation = 1.0 / (constant + linear*lightDistance + quadric*lightDistance*lightDistance);
    } 
    //attenuation = 1.0;
    if (hasSpecularMap!=1) {
        resSpecularColor = vec4(0.347, 0.347, 0.347, 1.0);
    }

    //resultColor = clamp(resAmbientColor + attenuation * (resDiffuseColor + resSpecularColor), 0.0, 1.0);
    if (lambertcos>0.0) {
        resultColor = clamp(resAmbientColor + attenuation * lambertcos *(resDiffuseColor + resSpecularColor), 0.0, 1.0);
    } else {
        resultColor = clamp(resAmbientColor + attenuation * (resDiffuseColor + resSpecularColor), 0.0, 1.0);
    }
    
    if (hasOpacityMap!=0){
        if (opacityColor.rgb==vec3(0,0,0))
            discard;
        else
            out_color = resultColor;
    } else {
        out_color = resultColor;
    }
    
}




Popular posts from this blog

Apache Spark + Cassandra. Hello World