OpenGL_JS-gammaCorrection

143 阅读2分钟
  • 左边用了gamma,右边没有用gamma image.png
  • 顶点着色器
export var vs_gamma_correction =
`#version 300 es
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;

out    vec3 FragPos;
out    vec3 Normal;
out    vec2 TexCoords;

uniform mat4 projection;
uniform mat4 view;

void main(void)
{
    FragPos = aPos;
    Normal = aNormal;
    TexCoords = aTexCoords;
    gl_Position = projection * view * vec4(aPos, 1.0);
}`
  • 片元着色器
export var fs_gamma_correction = 
`#version 300 es
precision mediump float;

out vec4 FragColor;

in    vec3 FragPos;
in    vec3 Normal;
in    vec2 TexCoords;

uniform sampler2D floorTexture;

uniform vec3 lightPositions[4];
uniform vec3 lightColors[4];
uniform vec3 viewPos;
uniform bool gamma;

vec3 BlinnPhong(vec3 normal, vec3 fragPos, vec3 lightPos, vec3 lightColor)
{
    // diffuse 与视角无关 与光线和法线有关
    vec3 lightDir = normalize(lightPos - fragPos);
    float diff = max(dot(lightDir, normal), 0.0);
    vec3 diffuse = diff * lightColor;
    
    // specular 与视角和法线和光线都有关
    vec3 viewDir = normalize(viewPos - fragPos);
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = 0.0;
    vec3 halfwayDir = normalize(lightDir + viewDir);  
    spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
    vec3 specular = spec * lightColor;    
    
    // simple attenuation 淡出的distance
    float max_distance = 1.5;
    float distance = length(lightPos - fragPos);
    float attenuation = 1.0 / (gamma ? distance * distance : distance); 

    diffuse *= attenuation;  //diffuse和specualr都乘上了
    specular *= attenuation;
    
    return diffuse + specular;
}

void main()
{           
    vec3 color = texture(floorTexture, TexCoords).rgb; //底板颜色
    vec3 lighting = vec3(0.0); 
    for(int i = 0; i < 4; ++i)  //四个灯
        lighting += BlinnPhong(normalize(Normal), FragPos, lightPositions[i], lightColors[i]);
    color *= lighting; //
    if(gamma) 
        color = pow(abs(color), vec3(1.0/2.2)); //直接pow呢
    FragColor = vec4(color, 1.0); 
}`
  • Texture
let floorTexture = loadTexture("../../textures/wood.png", 4, false);
let floorTextureGammaCorrected = loadTexture("../../textures/wood.png", 4, true);
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;
}
let shader = null;
let glPlaneVAO = 0;
let lightPositions = null;
let lightColors = null;
let projection = mat4.create(), view = mat4.create();
let camera = new Camera(vec3.fromValues(0.0, 0.0, 3.0), vec3.fromValues(0.0, 1.0, 0.0));
let deltaTime = 0.0;
let lastFrame = 0.0;
    gl.enable(gl.DEPTH_TEST);
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    shader = new Shader(gl, vs_gamma_correction, fs_gamma_correction);
    let planeVertices = [
        10.0, -0.5, 10.0, 0.0, 1.0, 0.0, 10.0, 0.0,
        -10.0, -0.5, 10.0, 0.0, 1.0, 0.0, 0.0, 0.0,
        -10.0, -0.5, -10.0, 0.0, 1.0, 0.0, 0.0, 10.0,
        10.0, -0.5, 10.0, 0.0, 1.0, 0.0, 10.0, 0.0,
        -10.0, -0.5, -10.0, 0.0, 1.0, 0.0, 0.0, 10.0,
        10.0, -0.5, -10.0, 0.0, 1.0, 0.0, 10.0, 10.0
    ];
    const POSITION_LOCATION = 0;
    const NORMAL_LOCATION = 1;
    const TEXCOORD_0_LOCATION = 2;
    const sizeFloat = 4;
    glPlaneVAO = gl.createVertexArray();
    let planeVBO = gl.createBuffer();
    gl.bindVertexArray(glPlaneVAO);
    gl.bindBuffer(gl.ARRAY_BUFFER, planeVBO);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(planeVertices), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(POSITION_LOCATION);
    gl.vertexAttribPointer(POSITION_LOCATION, 3, gl.FLOAT, false, 8 * sizeFloat, 0);
    gl.enableVertexAttribArray(NORMAL_LOCATION);
    gl.vertexAttribPointer(NORMAL_LOCATION, 3, gl.FLOAT, false, 8 * sizeFloat, (3 * sizeFloat));
    gl.enableVertexAttribArray(TEXCOORD_0_LOCATION);
    gl.vertexAttribPointer(TEXCOORD_0_LOCATION, 2, gl.FLOAT, false, 8 * sizeFloat, (6 * sizeFloat));
    gl.bindVertexArray(null);
    floorTexture = loadTexture("../../textures/wood.png", 4, false);
    floorTextureGammaCorrected = loadTexture("../../textures/wood.png", 4, true);
    shader.use(gl);
    let floorTextureLocation = gl.getUniformLocation(shader.programId, "floorTexture");
    gl.uniform1i(floorTextureLocation, 0);
    lightPositions = new Float32Array([
        -3.0, 0.0, 0.0,
        -1.0, 0.0, 0.0,
        1.0, 0.0, 0.0,
        3.0, 0.0, 0.0
    ]);
    lightColors = new Float32Array([
        0.25, 0.25, 0.25,
        0.50, 0.50, 0.50,
        0.75, 0.75, 0.75,
        1.00, 1.00, 1.00
    ]);
  • drawCall
function render(vao, shader) {
   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);
   shader.use(gl);
   mat4.perspective(projection, (camera.Zoom) * Math.PI / 180, canvas.width / canvas.height, 0.1, 100.0);
   view = camera.GetViewMatrix();
   gl.uniformMatrix4fv(gl.getUniformLocation(shader.programId, "projection"), false, projection);
   gl.uniformMatrix4fv(gl.getUniformLocation(shader.programId, "view"), false, view);
   gl.uniform3fv(gl.getUniformLocation(shader.programId, "lightPositions"), lightPositions);
   gl.uniform3fv(gl.getUniformLocation(shader.programId, "lightColors"), lightColors);
   gl.uniform3fv(gl.getUniformLocation(shader.programId, "viewPos"), camera.Position);
   gl.uniform1i(gl.getUniformLocation(shader.programId, "gamma"), gammaEnabled ? 1 : 0);
   gl.bindVertexArray(glPlaneVAO);
   gl.activeTexture(gl.TEXTURE0);
   let floorTex = gammaEnabled ? floorTextureGammaCorrected : floorTexture;
   gl.bindTexture(gl.TEXTURE_2D, floorTex);
   gl.drawArrays(gl.TRIANGLES, 0, 6);
}
//# sourceMappingURL=gamma_correction.js.map