zoukankan      html  css  js  c++  java
  • Shadow Map -- 点阴影(全方位)

      

      昨晚终于把点阴影(深度CubeMap)程序调通了,思想不难,基本就是在上节定向光阴影基础上稍作修改,但是CG程序不太方便Debug,需要输出中间效果图进行判断,耽搁了一会儿。

      过程如下:

      

      1、将深度渲染到CubeMap上

      为了以后使用方便,在Texture文件中扩展功能,添加一个生成CubeMap的函数

    GLuint WKS::CubeMap::GenDepthCubeMap(GLuint width, GLuint height) {
        glGenTextures(1, &this->textureID);
        glBindTexture(GL_TEXTURE_CUBE_MAP, this->textureID);
        for (GLuint i = 0; i < 6; i++) {
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
            glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
        }
        glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
        return this->textureID;
    }

      同样为了以后方便,在DefferredShading文件中扩展功能,添加附加深度CubeMap到帧缓冲的函数

           (注:暂时遇到一点奇怪的问题,同时添加颜色缓冲纹理和2D深度缓冲纹理(或深度缓冲对象RBO)是没有问题的。但是如果是深度CubeMap,同时再添加颜色缓冲纹理就会报错,现在没找到解决办法,不过做阴影渲染只需要深度CubeMap,额……)

    void DeferredShading::setupDepthBufferByCubeMap(GLuint texId) {
        this->BindGBuffer();
        glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texId, 0);
        //检查帧缓冲是否完整
        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
            std::cout << "ERROR::FRAMEBUFFER:: Depth CubeMap is not added to FrameBuffer correctly!" << std::endl;
        else std::cout << "Successful:: Depth CubeMap is added to FrameBuffer correctly" << std::endl;
        this->BindDefaultBuffer();
    }

      既然渲染深度到CubeMap,那么就需要6个方向的view矩阵,并传入shader,故新建了个ShadowMap文件完成这些操作。

    //ShadowMap.h
    
    #pragma once
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    #include "../BaseFile/Shader.h"
    
    class ShadowMap
    {
    public:
        ShadowMap();
        ~ShadowMap();
        void updateLightSpaceMatrix(glm::vec3 lightPos);
        void transmitMat2Shader(Shader* shader);
    
    private:
        void setup();
    
    private:
        glm::mat4 shadowProj;
        std::vector<glm::mat4> shadowTransforms;
    };

      

    //ShadowMap.cpp
    
    #include "./ShadowMap.h"
    
    
    ShadowMap::ShadowMap()
    {
        this->setup();
    }
    
    ShadowMap::~ShadowMap()
    {
    }
    
    void ShadowMap::setup() {
        this->shadowProj = glm::perspective(glm::radians(90.0f), 800.0f / 800, 1.0f, 100.0f);
    }
    
    void ShadowMap::updateLightSpaceMatrix(glm:: vec3 lightPos) {
        this->shadowTransforms.clear();
        shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0)));
        shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(-1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0)));
        shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, 1.0, 0.0), glm::vec3(0.0, 0.0, 1.0)));
        shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, -1.0, 0.0), glm::vec3(0.0, 0.0, -1.0)));
        shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, 0.0, 1.0), glm::vec3(0.0, -1.0, 0.0)));
        shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, 0.0, -1.0), glm::vec3(0.0, -1.0, 0.0)));
    }
    
    void ShadowMap::transmitMat2Shader(Shader* shader) {
        shader->use();
        for (int i = 0; i < 6; i++) {
            std::string name = "shadowMatrices["+std::to_string(i)+"]";
            shader->setMat4(name, this->shadowTransforms[i]);
        }
    }

      现在来看看着色器咋样的^_^

      我们不必在 OpenGL 程序中控制 View ,渲染六遍,将六个方向的深度分别渲染到 CubeMap 的各个面上。几何着色器可以帮助完成这一点,几何着色器中有一个内建变量 gl_Layer ,可以控制当前渲染的图元输出到CubeMap哪一个面。故我们只需要将每个图元在几何着色器中渲染六次,且每次指定输出到一个面,当然得配合传入的对应的 view * projection 矩阵,这样就实现渲染六个方向的深度到CubeMap。

    • 顶点着色器:只需将顶点坐标变换到世界坐标(乘以 model matrix),输出到几何着色器。
    #version 330 core
    layout (location = 0) in vec3 position;
    
    uniform mat4 model;
    
    void main()
    {
        gl_Position = model * vec4(position, 1.0);
    }
    • 几何着色器:需要传入六个view*projection矩阵,通过 gl_Layer 内建变量生成每个方向的深度图。
    #version 330 core
    layout (triangles) in;
    layout (triangle_strip, max_vertices=18) out;
    
    uniform mat4 shadowMatrices[6];
    
    out vec4 FragPos; // FragPos from GS (output per emitvertex)
    
    void main()
    {
        for(int face = 0; face < 6; ++face)
        {
            gl_Layer = face; // built-in variable that specifies to which face we render.
            for(int i = 0; i < 3; ++i) // for each triangle's vertices
            {
                FragPos = gl_in[i].gl_Position;
                gl_Position = shadowMatrices[face] * FragPos;
                EmitVertex();
            }    
            EndPrimitive();
        }
    }
    • 片段着色器:传入光源位置、远平面距离,计算 当前片元到光源的距离 / 远平面距离,输出到深度值。
    #version 330 core
    in vec4 FragPos;
    
    uniform vec3 lightPos;
    uniform float far_plane;
    
    void main()
    {
        // get distance between fragment and light source
        float lightDistance = length(FragPos.xyz - lightPos);
    
        // map to [0;1] range by dividing by far_plane
        lightDistance = lightDistance / far_plane;
        // write this as modified depth
        gl_FragDepth = lightDistance;
    }

      这样就完成了深度CubeMap生成。

      为了测试深度CubeMap是否正确,可以用天空盒的方式显示生成的CubeMap。

      当然了也可以在后续的渲染阴影中,用采样CubeMap的深度值代替颜色值显示深度,这样还可以稍作修改显示实际的深度值(当前片元与光源的距离值),两者直接对比,可以检测第一步(First Pass)是否有问题。

      展示一下我实现的采样CubeMap深度值显示(左图)与 实际深度值显示(右图)的对比:

         

      

      2、使用深度CubeMap渲染全方位阴影

      这一部分就很简单了,很往常渲染基本一样,只需要添加阴影判断。

      在片段着色器中传入深度CubeMap:

    uniform samplerCube shadowMap;

      计算当前的片元的深度,并判断是否在阴影中:

    float ShadowCalculation(vec3 fragPos)
    {
        vec3 light2Frag=fragPos-spotLight.position;
        float closestDepth = texture(shadowMap, light2Frag).r;
        closestDepth*=far_plane;
        float currentDepth=length(light2Frag);
        float shadow = currentDepth-0.05f > closestDepth  ? 1.0 : 0.0;
        return shadow;
    }

      使用这个阴影判断值计算光照值:

    color=vec4(result*(1.0f-shadow)+ambient,1.0f);

      效果图:

        

      OK,至此完成了Shadow Map的总结啦 ^_^。

      

  • 相关阅读:
    [CF703D] Mishka and Interesting sum
    [CF1454F] Array Partition
    [CF13E] Holes
    [CF1110D] Jongmah
    [CF1204D2] Kirk and a Binary String
    [CF936B] Sleepy Game
    [CF546E] Soldier and Traveling
    [CF1025D] Recovering BST
    [CF598C] Nearest vectors
    [CF988E] Divisibility by 25
  • 原文地址:https://www.cnblogs.com/chen9510/p/11726709.html
Copyright © 2011-2022 走看看