WebGL MRT与延迟渲染

519 阅读2分钟

WebGL之延迟着色 - Jeff.Zhong - 博客园 (cnblogs.com)

MRT

image.png

  • FBO
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
const fbo = {
  framebuffer: fb,
  textures: []
};

// 创建颜色纹理
for(let i = 0; i < 3; i++){
  const tex = initTexture(gl, { informat: gl.RGBA16F, type: gl.FLOAT }, width, height);
  framebufferInfo.textures.push(tex);
  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.TEXTURE_2D, tex, 0);
}

// 创建深度渲染缓冲区
const depthBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);
  • draw buffer
gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2]);
  • gbuffer着色器
#version 300 es
in vec4 aPosition;
in vec4 aNormal;
uniform mat4 modelMatrix;
uniform mat4 vpMatrix;
out vec3 vPosition;
out vec3 vNormal;

void main() {
  gl_Position = vpMatrix * modelMatrix * aPosition;
  vNormal = vec3(transpose(inverse(modelMatrix)) * aNormal);
  vPosition = vec3(modelMatrix * aPosition);
}
#version 300 es
precision highp float;
layout (location = 0) out vec3 gPosition;// 每个片元的位置
layout (location = 1) out vec3 gNormal;  // 每个片元的法向量
layout (location = 2) out vec4 gColor;   // 每个片元的颜色
uniform vec4 color;
in vec3 vPosition;
in vec3 vNormal;

void main() {
  gPosition = vPosition;
  gNormal = normalize(vNormal);
  gColor = color;
}

光照处理

image.png

image.png

  • 光照处理着色器
#version 300 es
#define GLSLIFY 1
in vec3 aPosition;
in vec2 aTexcoord;
out vec2 texcoord;
void main() {
    texcoord = aTexcoord;
    gl_Position = vec4(aPosition, 1.0);
}
#version 300 es
precision highp float;
#define GLSLIFY 1
uniform vec3 viewPosition;
uniform vec3 lightDirection;
uniform vec3 lightColor;
uniform vec3 ambientColor;
uniform float shininess;
uniform sampler2D gPosition;
uniform sampler2D gNormal;
uniform sampler2D gColor;
struct PointLight {
    vec3 position;
    vec3 color;
    float shininess;
    float line;
    float quad;
};
uniform PointLight pointLights[10];
struct SpotLight {
    vec3 position;
    vec3 direction;
    vec3 color;
    float outerRad;
    float innerRad;
    float shininess;
};
uniform SpotLight spotLights[3];
in vec2 texcoord;
out vec4 FragColor;
/*
* 点光源
*/
vec3 getPointLights(vec3 fragPos, vec3 normal, vec3 color, vec3 viewDir) {
    vec3 ret = vec3(0.0);
    for(int i = 0; i < 10; i++) {
        vec3 lightPos = pointLights[i].position;
        vec3 lightColor = pointLights[i].color;
        float lightShininess = pointLights[i].shininess;
        vec3 lightDir = normalize(lightPos - fragPos);
        float cosTheta = max(dot(lightDir, normal), 0.0);
        vec3 diffuse = lightColor * color * cosTheta;
        // 高光
        vec3 halfwayDir = normalize(lightDir + viewDir);
        float specularIntensity = pow(max(dot(normal, halfwayDir), 0.0), lightShininess);
        vec3 specular = lightColor * specularIntensity;
        // 光强衰减
        float dis = distance(lightPos, fragPos);
        float att = 1.0 / (1.0 + pointLights[i].line * dis + pointLights[i].quad * (dis * dis));
        ret += (diffuse + specular) * att;
    }
    return ret;
}
/*
* 聚光灯
*/
vec3 getSpotLights(vec3 fragPos, vec3 normal, vec3 color, vec3 viewDir) {
    vec3 ret = vec3(0.0);
    for(int i = 0; i < 3; i++) {
        vec3 lightPos = spotLights[i].position;
        vec3 lightColor = spotLights[i].color;
        float lightShininess = spotLights[i].shininess;
        vec3 lightDir = normalize(spotLights[i].direction);
        float outerLimit = cos(spotLights[i].outerRad); //照射范围角度|模糊外径角度
        float innerLimit = cos(spotLights[i].innerRad); //模糊内径角度
        vec3 surToLightDir = normalize(lightPos - fragPos); // 点光源反向 光源位置-顶点位置
        float dotFromDirection = dot(surToLightDir, lightDir); //光源方向与表面光线方向的夹角
        float inlightBloom = smoothstep(outerLimit, innerLimit, dotFromDirection); //聚光灯范围 + 边缘模糊
        float cosTheta = max(dot(surToLightDir, normal), 0.0); // 光线方向和法向量的夹角,它们的点积即可求出夹角余弦值(范围0-90度)
        vec3 diffuse = lightColor * color * cosTheta * inlightBloom;
        // 高光
        vec3 halfwayDir = normalize(surToLightDir + viewDir);
        float specularIntensity = pow(max(dot(normal, halfwayDir), 0.0), lightShininess);
        vec3 specular = lightColor * specularIntensity * inlightBloom;
        ret += (diffuse + specular);
    }
    return ret;
}
void main() {
    vec3 fragPos = texture(gPosition, texcoord).rgb; //每个片元的位置
    vec3 normal = texture(gNormal, texcoord).rgb; //每个片元的法向
    vec3 color = texture(gColor, texcoord).rgb; //每个片元的颜色
    
    vec3 viewDir = normalize(viewPosition - fragPos); //视点方向
    vec3 lightDir = normalize(lightDirection); // 平行光方向
    
    float cosTheta = max(dot(lightDir, normal), 0.0); // 光线方向和法向量夹角
    
    // 环境光
    vec3 ambient = ambientColor * color;
    // 漫反射
    vec3 diffuse = lightColor * color * cosTheta;
    
    FragColor = vec4(ambient + diffuse + getPointLights(fragPos, normal, color, viewDir) + getSpotLights(fragPos, normal, color, viewDir), 1.0);
}