Friday, December 13, 2013

Sponza рэндэрлэх оролдлого 16, Deferred rendering - geometry pass

Deferred rendering алгоритмыг хамгийн боломжит бага хувилбараар нь хэрэгжүүлэх гээд үзье. Өмнөх постоор энэ алгоритм нь geometry болон lighting гэсэн хоёр pass дамжин ажилладагийг мэдэж авсан билээ. Энэ удаагийн постоор эхний pass-д шаардагдах мэдээллийг тодорхойлж үүсгэе.

G-Buffer :
  • Albedo
  • Normal
  • Depth
Эдгээр гурван төрлийн текстуруудыг эхний ээлжинд гаргаж авах гээд оролдоё. Үүний тулд харгалзах хувьсагчидыгаа ч гэсэн зарлаж өгөе.
    GLuint gbufferFBO; // G-Buffer т хэрэглэх frame buffer object
    GLuint colourTexture; // albedo
    GLuint normalTexture; // normal
    GLuint depthTexture; // depth

Мөн дээрээс нь текстуруудээ FBO ийн хамтаар үүсгээд харгалзах байрлалд нь онооё
    glGenTextures(1, &colourTexture);
    glBindTexture(GL_TEXTURE_2D, colourTexture);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, windowWidth, windowHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

    glGenTextures(1, &normalTexture);
    glBindTexture(GL_TEXTURE_2D, normalTexture);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, windowWidth, windowHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

    glGenTextures(1, &depthTexture);
    glBindTexture(GL_TEXTURE_2D, depthTexture);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, windowWidth, windowHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);

    glGenFramebuffers(1, &gbufferFBO);
    glBindFramebuffer(GL_FRAMEBUFFER, gbufferFBO);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colourTexture, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, normalTexture, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);

    GLenum buffers[2];
    buffers[0] = GL_COLOR_ATTACHMENT0;
    buffers[1] = GL_COLOR_ATTACHMENT1;

    glDrawBuffers(2, buffers);

Одоо эдгээр текстуруудрүү albedo, normal, depth мэдээллүүдийг рэндэрлэх код болон shader ээ бичье.
Рэндэрлэхдээ
    glBindFramebuffer(GL_FRAMEBUFFER, gbufferFBO);

    glClearColor(0.0f, 0.5f, 1.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    for (AbstractSceneObject* sceneObject : sceneObjects) {
        glUseProgram(gbufferProgramID);
        glm::mat4 modelMatrix = sceneObject->getModelMatrix();
        mvpMatrix = projectionMatrix * viewMatrix * modelMatrix;
        normalMatrix = glm::inverseTranspose(glm::mat3(viewMatrix * modelMatrix));
        glUniformMatrix4fv(glGetUniformLocation(gbufferProgramID, "mvpMatrix"), 1, GL_FALSE, glm::value_ptr(mvpMatrix));
        glUniformMatrix4fv(glGetUniformLocation(gbufferProgramID, "modelMatrix"), 1, GL_FALSE, glm::value_ptr(modelMatrix));
        glUniformMatrix4fv(glGetUniformLocation(gbufferProgramID, "viewMatrix"), 1, GL_FALSE, glm::value_ptr(viewMatrix));
        glUniformMatrix3fv(glGetUniformLocation(gbufferProgramID, "normalMatrix"), 1, GL_FALSE, glm::value_ptr(normalMatrix));
        sceneObject->render(gbufferProgramID);
        glUseProgram(0);
    }
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
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; // view-space
out vec3 vNormal;   // view-space
out vec3 vEyeDir;   // view-space

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

uniform int hasNormalMap;

void main(void)
{
    gl_Position = mvpMatrix * in_position;    
    vTexcoord = in_texcoord;    
    vPosition = (viewMatrix * 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;
    if (hasNormalMap==1) {
        vNormal = normalize(tbnMatrix * in_normal);
    }
}

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 vec3      material_diffuse_color;
uniform vec3      material_ambient_color;
uniform vec3      material_specular_color;
uniform vec3      meterial_emissive_color;

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

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

out vec4 out_color;
out vec4 out_normal;

void main(void)
{
    vec4 diffuseColor  = texture2D(material_diffuse_texture, vTexcoord);
    vec4 ambientColor  = texture2D(material_ambient_texture, vTexcoord);
    vec4 normalColor   = texture2D(material_normal_texture , vTexcoord);
    vec4 specularColor = texture2D(material_specular_texture, vTexcoord);
    vec4 opacityColor  = texture2D(material_opacity_texture, vTexcoord);

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

    if (hasDiffuseMap==0) {
        diffuseColor = vec4(material_diffuse_color, 1.0);
    }
    
    vec3 normal = normalize(vNormal);
    if (hasNormalMap != 0) {
        vec3 nTex = normalColor.xyz;
        normal = nTex * 2.0 - 1.0;
        normal = normalize(normal);
    }
   
    if (hasOpacityMap!=0){
        if (opacityColor.rgb==vec3(0,0,0))
            discard;
        else {
            out_color = diffuseColor;
            out_normal = vec4(normal, 1.0);
        }
    } else {
        out_color = diffuseColor;
        out_normal = vec4(normal, 1.0);
    }
}

Өмнө нь бичиж байсан Blinn-Phong гэрэлтүүлгийн shader кодоос бүх гэрэлтүүлгийн кодыг нь авч хаяад зөвхөн albedo болон normal хоёрыг рэндэрлэж гаргаж байна. out_color, out_normal гэсэн хоёр хувьсагч нь харгалзан albedo, normal текстурлуу очиж хадгалагдах пикселийн мэдээллийг агуулна. Харин depth утгууд маань програмчлах шаардлагагүйгээр автоматаар рэндэрлэгдэнэ.

Хүссэн үр дүнгүүд


Albedo буюу зөвхөн гадаргууны өнгүүд 

View-Space доторхи normal векторын утгуудыг пиксел хэлбэрээр хадгалсан байдал


Depth буюу Z-Buffer ийг рэндэрлэж харвал иймэрхүү
За одоогийн байдлаар шаардлагатай мэдээллүүдийг нь гаргаж авч чадсан гэж үзэж байна. G-Buffer ийнхээ Layout-ийг art pipeline аасаа хамааруулаад хүссэнээрээ зохион байгуулж болно.