阅读 37

OpenGL_JS-normalMapping

image.png

image.png

  • 顶点着色器
export const vs_normalMapping = 
`#version 300 es
precision mediump float;
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
layout (location = 3) in vec3 aTangent;
layout (location = 4) in vec3 aBitangent;

out vec3 FragPos;
out vec2 TexCoords;
out vec3 TangentLightPos;
out vec3 TangentViewPos;
out vec3 TangentFragPos;

uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;

uniform vec3 lightPos;
uniform vec3 viewPos;

void main()
{
    FragPos = vec3(model * vec4(aPos, 1.0));   
    TexCoords = aTexCoords;
    
    mat3 normalMatrix = transpose(inverse(mat3(model)));
    vec3 T = normalize(normalMatrix * aTangent);
    vec3 N = normalize(normalMatrix * aNormal);
    T = normalize(T - dot(T, N) * N);
    vec3 B = cross(N, T);
    
    mat3 TBN = transpose(mat3(T, B, N));    
    TangentLightPos = TBN * lightPos;
    TangentViewPos  = TBN * viewPos;
    TangentFragPos  = TBN * FragPos;
        
    gl_Position = projection * view * model * vec4(aPos, 1.0);
}`
复制代码
  • 片元着色器
export const fs_normalMapping = 
`#version 300 es
precision mediump float;

out vec4 FragColor;

in  vec3 FragPos;
in  vec2 TexCoords;
in  vec3 TangentLightPos;
in  vec3 TangentViewPos;
in  vec3 TangentFragPos;

uniform sampler2D diffuseMap;
uniform sampler2D normalMap;

uniform vec3 lightPos;
uniform vec3 viewPos;

void main()
{           
     // obtain normal from normal map in range [0,1]
    vec3 normal = texture(normalMap, TexCoords).rgb;
    // transform normal vector to range [-1,1]
    normal = normalize(normal * 2.0 - 1.0);  // this normal is in tangent space
   
    // get diffuse color
    vec3 color = texture(diffuseMap, TexCoords).rgb;
    // ambient
    vec3 ambient = 0.1 * color;
    // diffuse
    vec3 lightDir = normalize(TangentLightPos - TangentFragPos);
    float diff = max(dot(lightDir, normal), 0.0);
    vec3 diffuse = diff * color;
    // specular
    vec3 viewDir = normalize(TangentViewPos - TangentFragPos);
    vec3 reflectDir = reflect(-lightDir, normal);
    vec3 halfwayDir = normalize(lightDir + viewDir);  
    float spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);

    vec3 specular = vec3(0.2) * spec;
    FragColor = vec4(ambient + diffuse + specular, 1.0);
}`
复制代码
  • 贴图与法线贴图
    gl.enable(gl.DEPTH_TEST);
    shader = new Shader(gl, vs_normalMapping, fs_normalMapping);
    diffuseMap = loadTexture("../../textures/brickwall.jpg", 4, false);
    normalMap = loadTexture("../../textures/brickwall_normal.jpg", 4, false);
    shader.use(gl);
    shader.setInt(gl, "diffuseMap", 0);
    shader.setInt(gl, "normalMap", 1);
    lightPos = vec3.fromValues(0.5, 1.0, 0.3);
    function loadTexture(url, nrComponents, gammaCorrection) {
        const textureID = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_2D, textureID);
        const level = 0;
        const srcType = gl.UNSIGNED_BYTE;
        const pixel = new Uint8Array([0, 0, 255, 255]);
        gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, 1, 1, 0, gl.RGBA, srcType, pixel);
        const image = new Image();
        image.onload = function () {
            let internalFormat;
            let dataFormat;
            if (nrComponents == 1) {
                internalFormat = dataFormat = gl.RED;
            }
            else if (nrComponents == 3) {
                internalFormat = gammaCorrection ? gl.SRGB : gl.RGB;
                dataFormat = gl.RGB;
            }
            else if (nrComponents == 4) {
                internalFormat = gammaCorrection ? gl.SRGB8_ALPHA8 : gl.RGBA8;
                dataFormat = gl.RGBA;
            }
            gl.bindTexture(gl.TEXTURE_2D, textureID);
            gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, image.naturalWidth, image.naturalHeight, 0, dataFormat, gl.UNSIGNED_BYTE, image);
            gl.generateMipmap(gl.TEXTURE_2D);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
        };
        image.src = url;
        return textureID;
    }
复制代码
  • render
let shader = null;
let glPlaneVAO = 0;
let diffuseMap, normalMap;
let projection = mat4.create(), view = mat4.create();
let lightPos;
let quadVAO = null;
let camera = new Camera(vec3.fromValues(0.0, 0.0, 5.0), vec3.fromValues(0.0, 1.0, 0.0));
function render() {
    let currentFrame = performance.now();
    deltaTime = currentFrame - lastFrame;
    lastFrame = currentFrame;
    processInput();
    gl.clearColor(0.1, 0.1, 0.1, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    mat4.perspective(projection, (camera.Zoom) * Math.PI / 180, canvas.width / canvas.height, 0.1, 100.0);
    view = camera.GetViewMatrix();
    shader.use(gl);
    gl.uniformMatrix4fv(gl.getUniformLocation(shader.programId, "projection"), false, projection);
    gl.uniformMatrix4fv(gl.getUniformLocation(shader.programId, "view"), false, view);
    let model = mat4.create();
    let axis = vec3.create();
    vec3.normalize(axis, vec3.fromValues(1.0, 0.0, 1.0));
    mat4.rotate(model, model, (currentFrame / 1000.0) * Math.PI / 180, axis);
    gl.uniformMatrix4fv(gl.getUniformLocation(shader.programId, "model"), false, model);
    gl.uniform3fv(gl.getUniformLocation(shader.programId, "viewPos"), camera.Position);
    gl.uniform3fv(gl.getUniformLocation(shader.programId, "lightPos"), lightPos);
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, diffuseMap);
    gl.activeTexture(gl.TEXTURE1);
    gl.bindTexture(gl.TEXTURE_2D, normalMap);
    renderQuad();
    mat4.identity(model);
    mat4.translate(model, model, lightPos);
    mat4.scale(model, model, vec3.fromValues(0.1, 0.1, 0.1));
    gl.uniformMatrix4fv(gl.getUniformLocation(shader.programId, "model"), false, model);
    renderQuad();
}
复制代码
function renderQuad() {
    let quadVBO = null;
    if (!quadVAO) {
        let pos1 = vec3.fromValues(-1.0, 1.0, 0.0);
        let pos2 = vec3.fromValues(-1.0, -1.0, 0.0);
        let pos3 = vec3.fromValues(1.0, -1.0, 0.0);
        let pos4 = vec3.fromValues(1.0, 1.0, 0.0);
        let uv1 = vec2.fromValues(0.0, 1.0);
        let uv2 = vec2.fromValues(0.0, 0.0);
        let uv3 = vec2.fromValues(1.0, 0.0);
        let uv4 = vec2.fromValues(1.0, 1.0);
        let nm = vec3.fromValues(0.0, 0.0, 1.0);
        let tangent1 = vec3.create(), bitangent1 = vec3.create();
        let tangent2 = vec3.create(), bitangent2 = vec3.create();
        let edge1 = vec3.create();
        vec3.subtract(edge1, pos2, pos1);
        let edge2 = vec3.create();
        vec3.subtract(edge2, pos3, pos1);
        let deltaUV1 = vec2.create();
        vec2.subtract(deltaUV1, uv2, uv1);
        let deltaUV2 = vec2.create();
        vec2.subtract(deltaUV2, uv3, uv1);
        let f = 1.0 / (deltaUV1[0] * deltaUV2[1] - deltaUV2[0] * deltaUV1[1]);
        tangent1[0] = f * (deltaUV2[1] * edge1[0] - deltaUV1[1] * edge2[0]);
        tangent1[1] = f * (deltaUV2[1] * edge1[1] - deltaUV1[1] * edge2[1]);
        tangent1[2] = f * (deltaUV2[1] * edge1[2] - deltaUV1[1] * edge2[2]);
        vec3.normalize(tangent1, tangent1);
        bitangent1[0] = f * (-deltaUV2[0] * edge1[0] + deltaUV1[0] * edge2[0]);
        bitangent1[1] = f * (-deltaUV2[0] * edge1[1] + deltaUV1[0] * edge2[1]);
        bitangent1[2] = f * (-deltaUV2[0] * edge1[2] + deltaUV1[0] * edge2[2]);
        vec3.normalize(bitangent1, bitangent1);
        vec3.subtract(edge1, pos3, pos1);
        vec3.subtract(edge2, pos4, pos1);
        vec2.subtract(deltaUV1, uv3, uv1);
        vec2.subtract(deltaUV2, uv4, uv1);
        f = 1.0 / (deltaUV1[0] * deltaUV2[1] - deltaUV2[0] * deltaUV1[1]);
        tangent2[0] = f * (deltaUV2[1] * edge1[0] - deltaUV1[1] * edge2[0]);
        tangent2[1] = f * (deltaUV2[1] * edge1[1] - deltaUV1[1] * edge2[1]);
        tangent2[2] = f * (deltaUV2[1] * edge1[2] - deltaUV1[1] * edge2[2]);
        vec3.normalize(tangent2, tangent2);
        bitangent2[0] = f * (-deltaUV2[0] * edge1[0] + deltaUV1[0] * edge2[0]);
        bitangent2[1] = f * (-deltaUV2[0] * edge1[1] + deltaUV1[0] * edge2[1]);
        bitangent2[2] = f * (-deltaUV2[0] * edge1[2] + deltaUV1[0] * edge2[2]);
        vec3.normalize(bitangent2, bitangent2);
        let quadVertices = new Float32Array([
            pos1[0], pos1[1], pos1[2], nm[0], nm[1], nm[2], uv1[0], uv1[1], tangent1[0], tangent1[1], tangent1[2], bitangent1[0], bitangent1[1], bitangent1[2],
            pos2[0], pos2[1], pos2[2], nm[0], nm[1], nm[2], uv2[0], uv2[1], tangent1[0], tangent1[1], tangent1[2], bitangent1[0], bitangent1[1], bitangent1[2],
            pos3[0], pos3[1], pos3[2], nm[0], nm[1], nm[2], uv3[0], uv3[1], tangent1[0], tangent1[1], tangent1[2], bitangent1[0], bitangent1[1], bitangent1[2],
            pos1[0], pos1[1], pos1[2], nm[0], nm[1], nm[2], uv1[0], uv1[1], tangent2[0], tangent2[1], tangent2[2], bitangent2[0], bitangent2[1], bitangent2[2],
            pos3[0], pos3[1], pos3[2], nm[0], nm[1], nm[2], uv3[0], uv3[1], tangent2[0], tangent2[1], tangent2[2], bitangent2[0], bitangent2[1], bitangent2[2],
            pos4[0], pos4[1], pos4[2], nm[0], nm[1], nm[2], uv4[0], uv4[1], tangent2[0], tangent2[1], tangent2[2], bitangent2[0], bitangent2[1], bitangent2[2]
        ]);
        quadVAO = gl.createVertexArray();
        quadVBO = gl.createBuffer();
        gl.bindVertexArray(quadVAO);
        gl.bindBuffer(gl.ARRAY_BUFFER, quadVBO);
        gl.bufferData(gl.ARRAY_BUFFER, quadVertices, gl.STATIC_DRAW);
        gl.enableVertexAttribArray(0);
        gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 14 * sizeFloat, 0);
        gl.enableVertexAttribArray(1);
        gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 14 * sizeFloat, 3 * sizeFloat);
        gl.enableVertexAttribArray(2);
        gl.vertexAttribPointer(2, 2, gl.FLOAT, false, 14 * sizeFloat, 6 * sizeFloat);
        gl.enableVertexAttribArray(3);
        gl.vertexAttribPointer(3, 3, gl.FLOAT, false, 14 * sizeFloat, 8 * sizeFloat);
        gl.enableVertexAttribArray(4);
        gl.vertexAttribPointer(4, 3, gl.FLOAT, false, 14 * sizeFloat, 11 * sizeFloat);
    }
    gl.bindVertexArray(quadVAO);
    gl.drawArrays(gl.TRIANGLES, 0, 6);
    gl.bindVertexArray(null);
}

//# sourceMappingURL=normalMapping.js.map
复制代码
文章分类
前端
文章标签