Skip to content

File ShadowSystem.h

File List > render > ShadowSystem.h

Go to the documentation of this file

#pragma once

#include "Light.h"
#include "RenderConfigs.h"
#include "Texture.h"
#include "buffers/StorageBuffer.h"
#include "buffers/UniformBuffer.h"
#include "buffers/FrameBuffer.h"
#include "PolygonLight.h"
#include "shaders/RenderShader.h"

#include <unordered_map>
#include <vector>
#include <memory>
#include <array>

struct ShadowSystem {

public:
    // In GLSL (shader), the size of vec3 equals to vec4 due to std140 alignment
    // See: https://registry.khronos.org/OpenGL/specs/gl/glspec45.core.pdf#page=159

    struct PointStruct
    {
        PointStruct(const Light& light);

        alignas(16) glm::vec3 color{ 1 };   
        alignas(16) glm::vec3 pos{ 0 };     

        alignas(4) float power{ 1.0f };     
        alignas(4) int use_shadow{ 1 };     
        alignas(4) float radius{ 0.05f };   
    };

    struct SunStruct
    {
        SunStruct(const Light& light, const glm::mat4& proj);

        alignas(16) glm::vec3 color{ 1 };         
        alignas(16) glm::vec3 pos{ 0 };           
        alignas(16) glm::vec3 dir{ 1, 0, 0 };     

        alignas(4) float power{ 1.0f };           
        alignas(4) int use_shadow{ 1 };           
        alignas(16) glm::mat4 proj_trans;         
    };

    struct SpotStruct
    {
        SpotStruct(const Light& light);

        alignas(16) glm::vec3 color{ 1 };         
        alignas(16) glm::vec3 pos{ 0 };           
        alignas(16) glm::vec3 dir{ 1, 0, 0 };     

        alignas(4) float power{ 1.0f };           
        alignas(4) int use_shadow{ 1 };           
        alignas(4) float cutoff{ 0.9f };          
        alignas(4) float outer_cutoff{ 0.8f };    
    };

    struct AreaStruct
    {
        AreaStruct(const Light& light);

        alignas(16) glm::vec3 color{ 1 };         
        alignas(16) glm::mat4 trans{ 1 };         

        alignas(4) float power{ 1.0f };           
        alignas(4) int use_shadow{ 1 };           
        alignas(4) float ratio{ 1.0f };           
    };

    struct PolyStruct
    {
        alignas(16) glm::vec3 color{ 1 };         

        alignas(4) float power{ 1.0f };           
        alignas(4) int use_shadow{ 1 };           
        alignas(4) int n{ 3 };                    
    };

    struct PolyVertStruct
    {
        alignas(16) glm::vec3 v{ 0, 0, 0 };       
    };

    static const GLuint Sizeof_Point    = sizeof(PointStruct);    
    static const GLuint Sizeof_Sun      = sizeof(SunStruct);      
    static const GLuint Sizeof_Spot     = sizeof(SpotStruct);     
    static const GLuint Sizeof_Area     = sizeof(AreaStruct);     
    static const GLuint Sizeof_Poly     = sizeof(PolyStruct);     
    static const GLuint Sizeof_PolyVert = sizeof(PolyVertStruct); 

    struct SceneInfo {
        int point_count{ 0 };       
        int sun_count{ 0 };         
        int spot_count{ 0 };        
        int area_count{ 0 };        
        int poly_count{ 0 };        
        int poly_verts_count{ 0 };  
    };

public:
    std::vector<PointStruct> point_list; 
    std::vector<SunStruct> sun_list;     
    std::vector<SpotStruct> spot_list;   
    std::vector<AreaStruct> area_list;   
    std::vector<PolyStruct> poly_list;   
    std::vector<PolyVertStruct> poly_verts; 

    mutable std::unordered_map<int, Texture> shadow_cache;   
    std::unordered_map<int, Texture> shadow_maps;            
    std::unordered_map<int, glm::mat4> proj_matrices;        

    StorageBuffer point_buffer;      
    StorageBuffer sun_buffer;        
    StorageBuffer spot_buffer;       
    StorageBuffer area_buffer;       
    StorageBuffer poly_buffer;       
    StorageBuffer poly_verts_buffer; 

    UniformBuffer info; 

private:
    using _LightInfo = std::tuple<int, Light*>;                      
    std::unordered_map<int, _LightInfo> light_info_cache;            
    GLuint cache_w{};                                                
    GLuint cache_h{};                                                
    bool prev_moment_shadow{ false };                                

    static std::array<FrameBuffer, 4> _shadowmap_buffer;  
    static std::array<ChainedShader, 4> _shadowmap_shader; 
    static std::array<glm::mat4, 6> _point_6side;          

public:
    ShadowSystem();

    ~ShadowSystem();

    void Init();

    void Bind() const;

public:
    static constexpr int shadow_slot[16]{31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16}; 

public:
    void ParseLightData(const std::unordered_map<int, std::shared_ptr<Light>>& light_list, bool using_moment_shadow = false);

    void ParsePolygonLightData(const std::unordered_map<int, std::shared_ptr<PolygonLight>>& poly_light_list);

public:
    SceneInfo GetSceneInfo() const;

    GLsizei GetTotalCount() const;

    GLuint GetSlotOffset(LightType _type) const;

    void Resize(GLuint _w, GLuint _h);

public:
    void UpdateLight(Light* light);

    void Update(int frame, RenderConfigs* config);

    void BindShadowMap() const;

public:
    void InitShadowMap(Light* light, bool using_moment_shadow);

    void UpdateProjMatrix(Light* light);

    void ConstructSAT(Light* light, const RenderConfigs* config);

public:
    static void EnableShadowMap();

    void BindShadowMapBuffer(Light* light, Texture& shadow_map);

    void BindShadowMapShader(Light* light, const glm::mat4& proj);

    void BindTargetTrans(Light* light, const glm::mat4& _trans);
};