Skip to content

Commit

Permalink
cascaded shadow mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
laudominik committed Jun 24, 2024
1 parent 7a5f489 commit c74d37a
Show file tree
Hide file tree
Showing 15 changed files with 134 additions and 70 deletions.
22 changes: 11 additions & 11 deletions examples/scene3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,17 @@ int main(){
;
return floor;
}())
.addLightSource(light)
.addLightSource(light::make_point({
.pos = secondLightPos,
.color = {1, 1, 1},
.attentuation = {
.constant = 1.0,
.linear = 0.1,
.quadratic = 0.0
}
}))
// .addLightSource(dirLight)
// .addLightSource(light)
// .addLightSource(light::make_point({
// .pos = secondLightPos,
// .color = {1, 1, 1},
// .attentuation = {
// .constant = 1.0,
// .linear = 0.0,
// .quadratic = 0.0
// }
// }))
.addLightSource(dirLight)
// .addLightSource(light::make_dir({
// .direction = {-1, -1, 0},
// .color = {1, 1, 1},
Expand Down
3 changes: 3 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <vector>

// TODO: change from static to editable during runtime
namespace tri::config {
Expand All @@ -18,5 +19,7 @@ namespace tri::config {
static constexpr auto MAX_POINT_LIGHTS = 10;
static constexpr auto MAX_DIR_LIGHTS = 3;
static constexpr auto SKYBOX_SCALE = 10000;
static constexpr std::initializer_list<std::pair<float, float>> CSM_LAYERS = {{0.1f, 15.f}, {15.f, 20.f}, {20.f, 30.f}, {30.f, 40.f}, {40.f, 50.f}, {50.f, 100.f}, {100.f, 300.f}};
static constexpr auto CSM_MAX_CASCADES = 16;
}

3 changes: 1 addition & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
/*
small TODO list:
> add CSM
> add hdr
> add sprites
...
> add gui
> add entity tree
> add hdr
>dynamic lib for scenes (in gui) ?
Expand Down
4 changes: 3 additions & 1 deletion src/shader_path.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#pragma once

#define SHADER_PATH "src/shaders"
#define SHADER_PATH "src/shaders"

/* TODO: make dependent on some ENV VAR */
17 changes: 17 additions & 0 deletions src/shaders/depth/map2d/gs.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#version 410 core

layout(triangles, invocations = 16) in;
layout(triangle_strip, max_vertices = 3) out;

uniform mat4 lightSpaceMatrices[16];

void main()
{
for (int i = 0; i < 3; ++i)
{
gl_Position = lightSpaceMatrices[gl_InvocationID] * gl_in[i].gl_Position;
gl_Layer = gl_InvocationID;
EmitVertex();
}
EndPrimitive();
}
6 changes: 1 addition & 5 deletions src/shaders/depth/map2d/vs.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ uniform mat4 rotation;
uniform mat4 transform;
uniform mat4 projection;
in vec3 vPos;
//in vec3 vCol;
//out vec3 pos;



void main(){
gl_Position = projection * transform * rotation * vec4(vPos, 1.0);
gl_Position = transform * rotation * vec4(vPos, 1.0);
}
2 changes: 1 addition & 1 deletion src/shaders/lib/declarations.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ vec3 testGs(vec2 pt);
vec3 calcPointLight(PointLight light, vec3 normal, vec3 viewDir, vec4 worldPos, float uShininess, float uSpecular, float uDiffuse);
vec3 calcDirLight(DirectionalLight light, vec3 normal, vec3 viewDir, float uShininess, float uSpecular, float uDiffuse);
vec2 parallaxMapping(vec2 texCoords, vec3 viewDir, sampler2D heightmap, float height_scale);
float shadowCalculation(vec4 sPos, sampler2D shadow);
float shadowCalculation(vec4 sPos, sampler2DArray shadow, int layer, float bias);
float omniShadowCalculation(vec3 fragPos, vec3 lightPos, vec3 viewDir, float far_plane, samplerCube depthMap);
20 changes: 9 additions & 11 deletions src/shaders/lib/fragment/shadowCalculation.glsl
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
float shadowCalculation(vec4 sPos, sampler2D shadow){
float shadowCalculation(vec4 sPos, sampler2DArray shadow, int layer, float bias){
vec3 projCoords = sPos.xyz / sPos.w;
projCoords = projCoords * 0.5 + 0.5;
float closestDepth = texture(shadow, projCoords.xy).r;
float closestDepth = texture(shadow, vec3(projCoords.xy, layer)).r;
float currentDepth = projCoords.z;

float bias = 0.005;
float sha = 0.0;
vec2 texelSize = 1.0 / textureSize(shadow, 0);
for(int x = -1; x <= 1; ++x)
{
for(int y = -1; y <= 1; ++y)
{
float pcfDepth = texture(shadow, projCoords.xy + vec2(x, y) * texelSize).r;
sha += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
}
vec2 texelSize = 1.0 / textureSize(shadow, 0).xy;
for(int x = -1; x <= 1; ++x){
for(int y = -1; y <= 1; ++y){
float pcfDepth = texture(shadow, vec3(projCoords.xy + vec2(x, y) * texelSize, layer)).r;
sha += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
}
}
if(projCoords.z > 1.0) return 0.0;
sha /= 9.0;
return sha;
}
56 changes: 37 additions & 19 deletions src/shaders/solid/fs.glsl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#define MAX_POINT_LIGHTS 10
#define MAX_DIR_LIGHTS 3
#define MAX_CASCADES 16


uniform int flatColor;
Expand All @@ -20,8 +21,10 @@ uniform float height_scale;


uniform int hasShadow;
uniform sampler2D shadowMap[MAX_DIR_LIGHTS];
uniform mat4 shadowSpaceMatrix[MAX_DIR_LIGHTS];
uniform sampler2DArray shadowMap[MAX_DIR_LIGHTS];
uniform mat4 shadowSpaceMatrix[MAX_DIR_LIGHTS * MAX_CASCADES];
uniform int cascadeCount;
uniform float cascadePlaneDistances[MAX_CASCADES];

uniform samplerCube shadowCube[MAX_POINT_LIGHTS];
uniform float pointLightFarPlane;
Expand All @@ -43,6 +46,8 @@ uniform vec3 viewPos;
uniform vec3 ambientColor;
uniform float ambientIntensity;

uniform mat4 projection;

in vec3 col;
in vec3 normal;
in vec4 worldPos;
Expand All @@ -56,6 +61,24 @@ in mat4 model;
out vec4 FragColor;
out vec4 BrightColor;


int selectShadowLayer(vec4 projectedCoord){
float depthValue = projectedCoord.z;

int layer = -1;
for (int i = 0; i < cascadeCount; ++i){
if (depthValue < cascadePlaneDistances[i]){
layer = i;
break;
}
}
if (layer == -1){
layer = cascadeCount - 1;
}
return layer;
}


void main()
{
if(flatColor == 1){
Expand Down Expand Up @@ -92,16 +115,19 @@ void main()
}

float sh = 1.0;
int layer;
for(int i = 0; i < uNumDirLights; i++){
vec4 shadowSpacePos = shadowSpaceMatrix[i] * model * ogPos;
sh = min(sh, shadowCalculation(shadowSpacePos, shadowMap[i]));
layer = selectShadowLayer(projection * worldPos);
float bias = max(0.05 * (1.0 - dot(normal_val, uDirectionalLights[i].direction)), 0.005);
bias *= 1 / (cascadePlaneDistances[layer] * 0.5f);

vec4 shadowSpacePos = shadowSpaceMatrix[i * MAX_CASCADES + layer] * worldPos;
sh = min(sh, shadowCalculation(shadowSpacePos, shadowMap[i], layer, bias));
}

if(hasShadow == 1 && uNumPointLights != 0){
for(int i = 0; i < uNumPointLights; i++){
float s = omniShadowCalculation(worldPos.xyz, uPointLights[i].position, viewDir, pointLightFarPlane, shadowCube[i]);
sh = min(sh, s);
}
for(int i = 0; i < uNumPointLights; i++){
float s = omniShadowCalculation(worldPos.xyz, uPointLights[i].position, viewDir, pointLightFarPlane, shadowCube[i]);
sh = min(sh, s);
}

if(hasShadow == 1){
Expand All @@ -119,9 +145,8 @@ void main()
outColor.z = min(outColor.z, 1.0);

float alpha = 1.0;
if (hasTexture == 1 ){
if (hasTexture == 1){
alpha = texture(texture0, texCoords_val).a;
// discard;
}
FragColor = vec4(outColor, alpha);

Expand All @@ -130,12 +155,5 @@ void main()
BrightColor = vec4(FragColor.rgb,0);
} else {
BrightColor = vec4(0, 0, 0,alpha);
}


//FragColor = texture(shadowMap[0], texPos);
//FragColor = vec4(shad, shad, shad, 1.0);

// FragColor = vec4(s, s, s, 1.0);
//FragColor = texture(shadowCube[0], worldPos.xyz - uPointLights[0].position);
}
}
5 changes: 3 additions & 2 deletions src/tricore/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ void Renderer::render(){
windowWidth = width;
windowHeight = height;

glViewport(0, 0, 1024, 1024);
glViewport(0, 0, config::SHADOW_RESOLUTION.w, config::SHADOW_RESOLUTION.h);
populateShadowmaps();

glViewport(0, 0, width, height);
Expand Down Expand Up @@ -146,7 +146,8 @@ Renderer::Renderer(GLFWwindow& window, Camera& camera):
window(window),
camera(camera),
postprocessFrame(1),
postprocessOp(std::make_unique<postprocess::BasePostprocess>()) {
postprocessOp(std::make_unique<postprocess::BasePostprocess>()),
directionalMaps(config::CSM_LAYERS) {

glEnable(GL_DEPTH_TEST);
glEnable(GL_DEPTH_CLAMP);
Expand Down
24 changes: 16 additions & 8 deletions src/tricore/frame/DepthFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ void DepthFrame::setup(int width, int height) {
Frame::setup(width, height);

glGenTextures(1, &depth);
glBindTexture(GL_TEXTURE_2D, depth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, config::SHADOW_RESOLUTION.w, config::SHADOW_RESOLUTION.h, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glBindTexture(GL_TEXTURE_2D_ARRAY, depth);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, config::SHADOW_RESOLUTION.w, config::SHADOW_RESOLUTION.h, shadowCascadeLevels, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
static constexpr float borderColor[] = {1.f, 1.f, 1.f, 1.f};
glTexParameterfv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BORDER_COLOR, borderColor);

glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth, 0);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);

}
void DepthFrame::cleanup(){
Frame::cleanup();
Expand All @@ -27,3 +30,8 @@ void DepthFrame::cleanup(){
GLuint DepthFrame::getDepthMap(){
return depth;
}

void DepthFrame::setCascadeLevels(int levels){
shadowCascadeLevels = levels;
setup(0, 0);
}
4 changes: 3 additions & 1 deletion src/tricore/frame/DepthFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
namespace tri::core {
class DepthFrame : public Frame {
public:
DepthFrame() = default;
DepthFrame() {}

void setCascadeLevels(int levels);
GLuint getDepthMap();
void setup(int width, int height) override;
void cleanup() override;

private:
GLuint depth;
int shadowCascadeLevels{1};
};
}

Expand Down
31 changes: 25 additions & 6 deletions src/tricore/light/DirectionalShadowMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,17 @@ class ShadowProgram : public Program {
public:
ShadowProgram() : Program(
fmt::format("{}/{}/vs.glsl", SHADER_PATH, DEPTH),
fmt::format("{}/{}/fs.glsl", SHADER_PATH, DEPTH)){}
fmt::format("{}/{}/fs.glsl", SHADER_PATH, DEPTH),
fmt::format("{}/{}/gs.glsl", SHADER_PATH, DEPTH)
){}
};

DirectionalShadowMapper::DirectionalShadowMapper(){
DirectionalShadowMapper::DirectionalShadowMapper(const std::vector<std::pair<float, float>>& cascadeLayers) : cascadeLayers(cascadeLayers) {
program = std::make_unique<ShadowProgram>();
assert(cascadeLayers.size() <= config::CSM_MAX_CASCADES);
for(auto& fr : frame){
fr.setCascadeLevels(cascadeLayers.size());
}
}

void DirectionalShadowMapper::setup(int width, int height, unsigned int lightCount) {
Expand All @@ -26,7 +32,10 @@ void DirectionalShadowMapper::setup(int width, int height, unsigned int lightCou
void DirectionalShadowMapper::populate(std::vector<std::shared_ptr<Model>>& models, std::vector<std::shared_ptr<DirectionalLight>>& lights, Camera& camera){
for(auto i = 0u; i < lights.size(); i++){
frame[i].bind();
program->uniformMat4("projection", light::get_lightspace_matrix(*lights[i], camera));
for(auto j = 0; j < cascadeLayers.size(); j++){
const auto& [near, far] = cascadeLayers[j];
program->uniformMat4(fmt::format("lightSpaceMatrices[{}]", j), light::get_lightspace_matrix(*lights[i], camera, near, far));
}
cast(models);
frame[i].unbind();
}
Expand All @@ -35,11 +44,21 @@ void DirectionalShadowMapper::populate(std::vector<std::shared_ptr<Model>>& mode
void DirectionalShadowMapper::attach(const Program& material, std::vector<std::shared_ptr<DirectionalLight>>& lights, Camera& camera) {
static constexpr auto directionalShadowMapBegin = 10;
material.use();
material.uniformInt("cascadeCount", cascadeLayers.size());

if(lights.size() == 0) return;
for(auto i = 0u; i < cascadeLayers.size(); i++){
material.uniformFloat(fmt::format("cascadePlaneDistances[{}]", i), cascadeLayers[i].second);
}

for(auto i = 0u; i < lights.size(); i++){
for(auto i = 0u; i < config::MAX_DIR_LIGHTS; i++){
glActiveTexture(GL_TEXTURE0 + directionalShadowMapBegin + i);
glBindTexture(GL_TEXTURE_2D, frame[i].getDepthMap());
glBindTexture(GL_TEXTURE_2D_ARRAY, frame[i].getDepthMap());
material.uniformInt(fmt::format("shadowMap[{}]", i), directionalShadowMapBegin + i);
material.uniformMat4(fmt::format("shadowSpaceMatrix[{}]", i), light::get_lightspace_matrix(*lights[i].get(), camera));
if(i >= lights.size()) continue;
for(auto j = 0u; j < cascadeLayers.size(); j++){
const auto& [near, far] = cascadeLayers[j];
material.uniformMat4(fmt::format("shadowSpaceMatrix[{}]", i * config::CSM_MAX_CASCADES + j), light::get_lightspace_matrix(*lights[i].get(), camera, near, far));
}
}
}
3 changes: 2 additions & 1 deletion src/tricore/light/DirectionalShadowMapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
namespace tri::core::shadow {
class DirectionalShadowMapper : public ShadowMapper {
public:
DirectionalShadowMapper();
DirectionalShadowMapper(const std::vector<std::pair<float, float>>& cascadeLayers);
void setup(int width, int height, unsigned int lightCount) override;
void populate(std::vector<std::shared_ptr<tri::core::Model>>& models, std::vector<std::shared_ptr<tri::core::DirectionalLight>>& light, tri::core::Camera& camera);
void attach(const Program& material, std::vector<std::shared_ptr<DirectionalLight>>& lights, Camera& camera);
private:
tri::core::DepthFrame frame[tri::config::MAX_DIR_LIGHTS];
std::vector<std::pair<float, float>> cascadeLayers;
};
}
Loading

0 comments on commit c74d37a

Please sign in to comment.