Skip to content

Commit 9ff1c58

Browse files
committed
Implemented Variance Shadow Mapping
1 parent d85159d commit 9ff1c58

File tree

8 files changed

+77
-47
lines changed

8 files changed

+77
-47
lines changed

MP-APS/.vs/MP-APS/v15/.suo

3.5 KB
Binary file not shown.

MP-APS/.vs/MP-APS/v15/Browse.VC.db

-36.8 MB
Binary file not shown.

MP-APS/Core/RenderSystem.cpp

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ void RenderSystem::Init(const pugi::xml_node& rendererNode) {
2121
std::abort();
2222
}
2323

24+
queryHardwareCaps();
25+
2426
#ifdef _DEBUG
2527
std::cout << "OpenGL Version: " << glGetString(GL_VERSION) << '\n';
2628
std::cout << "GLSL Version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << '\n';
2729
std::cout << "OpenGL Driver Vendor: " << glGetString(GL_VENDOR) << '\n';
2830
std::cout << "OpenGL Renderer: " << glGetString(GL_RENDERER) << '\n';
2931
#endif
3032

31-
getHardwareFeatures();
32-
3333
const auto width = rendererNode.attribute("width").as_uint();
3434
const auto height = rendererNode.attribute("height").as_uint();
3535

@@ -145,7 +145,7 @@ void RenderSystem::Render(const Camera& camera, RenderListIterator renderListBeg
145145
glActiveTexture(GL_TEXTURE2);
146146
glBindTexture(GL_TEXTURE_2D, m_skybox.GetBRDFLUT());
147147
glActiveTexture(GL_TEXTURE7);
148-
glBindTexture(GL_TEXTURE_2D, m_shadowDepthTexture);
148+
glBindTexture(GL_TEXTURE_2D, m_shadowColorTexture);
149149

150150
pbrShader.Bind();
151151
pbrShader.SetUniform("camPos", camera.GetPosition()).SetUniformi("wireframe", globalWireframe).SetUniform("lightSpaceMatrix", m_lightSpaceMatrix);
@@ -198,6 +198,12 @@ void RenderSystem::UpdateView(const Camera& camera) {
198198
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), glm::value_ptr(m_projMatrix));
199199
}
200200

201+
/***********************************************************************************/
202+
void RenderSystem::queryHardwareCaps() {
203+
// Anisotropic filtering
204+
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &m_caps.MaxAnisotropy);
205+
}
206+
201207
/***********************************************************************************/
202208
void RenderSystem::setDefaultState() {
203209
glFrontFace(GL_CCW);
@@ -289,12 +295,12 @@ void RenderSystem::renderShadowMap(const SceneBase& scene, RenderListIterator re
289295

290296
glCullFace(GL_FRONT); // Solve peter-panning
291297
glViewport(0, 0, m_shadowMapResolution, m_shadowMapResolution);
292-
m_shadowDepthFBO.Bind();
298+
m_shadowFBO.Bind();
293299
glClear(GL_DEPTH_BUFFER_BIT);
294300

295301
renderModelsNoTextures(shadowDepthShader, renderListBegin, renderListEnd);
296302

297-
m_shadowDepthFBO.Unbind();
303+
m_shadowFBO.Unbind();
298304
glViewport(0, 0, m_width, m_height);
299305
glCullFace(GL_BACK);
300306
}
@@ -327,33 +333,49 @@ void RenderSystem::setupTextureSamplers() {
327333
glSamplerParameteri(m_samplerPBRTextures, GL_TEXTURE_WRAP_T, GL_REPEAT);
328334
glSamplerParameteri(m_samplerPBRTextures, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
329335
glSamplerParameteri(m_samplerPBRTextures, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
330-
glSamplerParameterf(m_samplerPBRTextures, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_features.MaxAnisotropy);
336+
glSamplerParameterf(m_samplerPBRTextures, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_caps.MaxAnisotropy);
331337

332338
}
333339

334340
/***********************************************************************************/
335341
void RenderSystem::setupShadowMap() {
336-
m_shadowDepthFBO.Init("Shadow Depth FBO");
337-
m_shadowDepthFBO.Bind();
342+
const static float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
338343

344+
m_shadowFBO.Init("Shadow Depth FBO");
345+
m_shadowFBO.Bind();
346+
347+
// Depth texture
339348
if (m_shadowDepthTexture) {
340349
glDeleteTextures(1, &m_shadowDepthTexture);
341350
}
342351
glGenTextures(1, &m_shadowDepthTexture);
343352
glBindTexture(GL_TEXTURE_2D, m_shadowDepthTexture);
344-
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, m_shadowMapResolution, m_shadowMapResolution, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
353+
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, m_shadowMapResolution, m_shadowMapResolution, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
345354
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
346355
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
347356
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); // Clamp to border to fix over-sampling
348357
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
349-
const float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
350-
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
358+
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
359+
360+
// Colour texture for Variance Shadow Mapping (VSM)
361+
if (m_shadowColorTexture) {
362+
glDeleteTextures(1, &m_shadowColorTexture);
363+
}
364+
glGenTextures(1, &m_shadowColorTexture);
365+
glBindTexture(GL_TEXTURE_2D, m_shadowColorTexture);
366+
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, m_shadowMapResolution, m_shadowMapResolution, 0, GL_RGBA, GL_FLOAT, nullptr);
367+
glGenerateMipmap(GL_TEXTURE_2D);
368+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Hardware linear filtering gives us soft shadows for free!
369+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
370+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); // Clamp to border to fix over-sampling
371+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
372+
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_caps.MaxAnisotropy); // Anisotropic filtering for sharper angles
373+
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
351374

352-
m_shadowDepthFBO.AttachTexture(m_shadowDepthTexture, GLFramebuffer::AttachmentType::DEPTH);
353-
m_shadowDepthFBO.DrawBuffer(GLFramebuffer::GLBuffer::NONE);
354-
m_shadowDepthFBO.ReadBuffer(GLFramebuffer::GLBuffer::NONE);
375+
m_shadowFBO.AttachTexture(m_shadowDepthTexture, GLFramebuffer::AttachmentType::DEPTH);
376+
m_shadowFBO.AttachTexture(m_shadowColorTexture, GLFramebuffer::AttachmentType::COLOR0);
355377

356-
m_shadowDepthFBO.Unbind();
378+
m_shadowFBO.Unbind();
357379
}
358380

359381
/***********************************************************************************/

MP-APS/Core/RenderSystem.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class RenderSystem {
4343
);
4444

4545
private:
46-
struct Features {
46+
struct HardwareCaps {
4747
float MaxAnisotropy;
4848
int MaxArrayTextureLayers;
4949
int MaxTextureSamples;
@@ -53,11 +53,12 @@ class RenderSystem {
5353
int MaxFragmentUniformBlocks;
5454
int MaxComputeWorkGroupSize;
5555
int MaxComputeWorkGroupCount;
56-
} m_features;
56+
} m_caps;
5757

5858
// Helper functions
5959

60-
60+
//
61+
void queryHardwareCaps();
6162
// Sets the default state required for rendering
6263
void setDefaultState();
6364
// Render models contained in the renderlist
@@ -92,8 +93,8 @@ class RenderSystem {
9293
GLuint m_samplerPBRTextures{ 0 };
9394

9495
// Shadow mapping
95-
GLuint m_shadowMapResolution{ 1024 }, m_shadowDepthTexture{ 0 };
96-
GLFramebuffer m_shadowDepthFBO;
96+
GLuint m_shadowMapResolution{ 1024 }, m_shadowDepthTexture{ 0 }, m_shadowColorTexture{ 0 };
97+
GLFramebuffer m_shadowFBO;
9798

9899
// Environment map
99100
Skybox m_skybox;

MP-APS/Data/Shaders/PBRps.glsl

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,28 +39,27 @@ layout (location = 1) out vec4 BrightColor;
3939
const float PI = 3.14159265359;
4040

4141
// ----------------------------------------------------------------------------
42-
float ComputeShadow(const vec4 fragPosLightSpace, const vec3 N, const vec3 L) {
42+
// Piecewise linear interpolation
43+
float linstep(const float low, const float high, const float value) {
44+
return clamp((value - low) / (high - low), 0.0, 1.0);
45+
}
46+
47+
// ----------------------------------------------------------------------------
48+
// Variance shadow mapping
49+
float ComputeShadow(const vec4 fragPosLightSpace) {
4350
// Perspective divide
44-
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
45-
projCoords = projCoords * 0.5 + 0.5; // [0, 1]
51+
vec2 screenCoords = fragPosLightSpace.xy / fragPosLightSpace.w;
52+
screenCoords = screenCoords * 0.5 + 0.5; // [0, 1]
4653

47-
const float closestDepth = texture(shadowMap, projCoords.xy).r;
48-
const float currentDepth = projCoords.z;
49-
const float bias = max(0.05 * (1.0 - dot(N, L)), 0.005); // Bias to solve shadow acne
50-
51-
// PCF
52-
float shadow = 0.0;
53-
const vec2 texelSize = 1.0 / textureSize(shadowMap, 0);
54-
for(int x = -2; x <= 2; ++x) {
55-
for(int y = -2; y <= 2; ++y) {
56-
const float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r;
57-
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
58-
}
59-
}
60-
61-
shadow /= 25.0;
54+
const float distance = fragPosLightSpace.z; // Use raw distance instead of linear junk
55+
const vec2 moments = texture2D(shadowMap, screenCoords.xy).rg;
56+
57+
const float p = step(distance, moments.x);
58+
const float variance = max(moments.y - (moments.x * moments.x), 0.00002);
59+
const float d = distance - moments.x;
60+
const float pMax = linstep(0.2, 1.0, variance / (variance + d*d)); // Solve light bleeding
6261

63-
return shadow;
62+
return min(max(p, pMax), 1.0);
6463
}
6564

6665
// ----------------------------------------------------------------------------
@@ -155,9 +154,9 @@ void main() {
155154
// scale light by NdotL
156155
float NdotL = max(dot(N, L), 0.0);
157156

158-
const float shadow = ComputeShadow(fragData.FragPosLightSpace, N, L);
157+
const float shadow = ComputeShadow(fragData.FragPosLightSpace);
159158
// add to outgoing radiance Lo
160-
Lo = (kD * albedo / PI + specular) * radiance * NdotL * (1.0 - shadow); // note that we already multiplied the BRDF by the Fresnel (kS) so we won't multiply by kS again
159+
Lo = (kD * albedo / PI + specular) * radiance * NdotL * shadow; // note that we already multiplied the BRDF by the Fresnel (kS) so we won't multiply by kS again
161160
}
162161

163162
// ambient lighting (we now use IBL as the ambient term)
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
#version 440 core
22

3+
in float VertexDepth;
4+
5+
out vec4 FragColor;
6+
37
void main() {
4-
// gl_FragDepth = gl_FragCoord.z;
8+
const float depth = VertexDepth;
9+
10+
const float dx = dFdx(depth);
11+
const float dy = dFdy(depth);
12+
const float moment2 = depth * depth + 0.25 * (dx * dx + dy * dy);
13+
14+
FragColor = vec4(depth, moment2, 0.0, 1.0);
515
}

MP-APS/Data/Shaders/shadowdepthvs.glsl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ layout (location = 0) in vec3 position;
44
uniform mat4 lightSpaceMatrix;
55
uniform mat4 modelMatrix;
66

7+
out float VertexDepth;
8+
79
void main() {
810
gl_Position = lightSpaceMatrix * modelMatrix * vec4(position, 1.0);
11+
VertexDepth = gl_Position.z;
912
}

MP-APS/SceneBase.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@ void SceneBase::Init(const std::string_view sceneName) {
1515
void SceneBase::Update(const double dt) {
1616
}
1717

18-
/***********************************************************************************/
19-
void SceneBase::AddIBLProbe(const glm::vec3& position, const float radiusOfInfluence) {
20-
m_IBLProbes.emplace_back(position, radiusOfInfluence);
21-
}
22-
2318
/***********************************************************************************/
2419
void SceneBase::AddLight(const StaticDirectionalLight& light) {
2520
m_staticDirectionalLights.push_back(light);

0 commit comments

Comments
 (0)