diff --git a/aggregated-graphics-samples.sln b/aggregated-graphics-samples.sln
index a9b9a0a..f96bcb9 100644
--- a/aggregated-graphics-samples.sln
+++ b/aggregated-graphics-samples.sln
@@ -51,6 +51,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "deferred-shading", "deferre
{67B01ECD-2613-4FA0-84F7-87F5BCF40EB1} = {67B01ECD-2613-4FA0-84F7-87F5BCF40EB1}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shadowmapping-poisson-stable", "shadowmapping-poisson-stable\shadowmapping-poisson-stable.vcxproj", "{DD90A343-7897-442B-9D19-7FF0676E80EB}"
+ ProjectSection(ProjectDependencies) = postProject
+ {8D9D4A3E-439A-4210-8879-259B20D992CA} = {8D9D4A3E-439A-4210-8879-259B20D992CA}
+ {51CC36B3-921E-4853-ACD5-CB6CBC27FBA1} = {51CC36B3-921E-4853-ACD5-CB6CBC27FBA1}
+ {67B01ECD-2613-4FA0-84F7-87F5BCF40EB1} = {67B01ECD-2613-4FA0-84F7-87F5BCF40EB1}
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -123,6 +130,14 @@ Global
{3FA565CC-1B90-4EF7-9E43-8031ABA1118B}.Release|x64.Build.0 = Release|x64
{3FA565CC-1B90-4EF7-9E43-8031ABA1118B}.Release|x86.ActiveCfg = Release|Win32
{3FA565CC-1B90-4EF7-9E43-8031ABA1118B}.Release|x86.Build.0 = Release|Win32
+ {DD90A343-7897-442B-9D19-7FF0676E80EB}.Debug|x64.ActiveCfg = Debug|x64
+ {DD90A343-7897-442B-9D19-7FF0676E80EB}.Debug|x64.Build.0 = Debug|x64
+ {DD90A343-7897-442B-9D19-7FF0676E80EB}.Debug|x86.ActiveCfg = Debug|Win32
+ {DD90A343-7897-442B-9D19-7FF0676E80EB}.Debug|x86.Build.0 = Debug|Win32
+ {DD90A343-7897-442B-9D19-7FF0676E80EB}.Release|x64.ActiveCfg = Release|x64
+ {DD90A343-7897-442B-9D19-7FF0676E80EB}.Release|x64.Build.0 = Release|x64
+ {DD90A343-7897-442B-9D19-7FF0676E80EB}.Release|x86.ActiveCfg = Release|Win32
+ {DD90A343-7897-442B-9D19-7FF0676E80EB}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/framework/framework.vcxproj b/framework/framework.vcxproj
index e68d13b..2aaa181 100644
--- a/framework/framework.vcxproj
+++ b/framework/framework.vcxproj
@@ -140,6 +140,7 @@
+
diff --git a/framework/framework.vcxproj.filters b/framework/framework.vcxproj.filters
index 2eb3e0c..cc3fa78 100644
--- a/framework/framework.vcxproj.filters
+++ b/framework/framework.vcxproj.filters
@@ -96,6 +96,9 @@
Header Files
+
+ Resource Files
+
diff --git a/framework/shaders/common/noise2d.h b/framework/shaders/common/noise2d.h
index 3e76bf7..48b639e 100644
--- a/framework/shaders/common/noise2d.h
+++ b/framework/shaders/common/noise2d.h
@@ -2,7 +2,7 @@
float hash(vec2 p)
{
p = 50. * fract(p * 0.3183099 + vec2(0.71, 0.113));
- return -1. + 2. * fract(p.x * p.y * (p.x + p.y));
+ return fract(p.x * p.y * (p.x + p.y));
}
float noise(vec2 p)
diff --git a/framework/shaders/common/noise3d.h b/framework/shaders/common/noise3d.h
new file mode 100644
index 0000000..174fd5a
--- /dev/null
+++ b/framework/shaders/common/noise3d.h
@@ -0,0 +1,23 @@
+// https://www.shadertoy.com/view/4sfGzS
+float hash(vec3 p) // replace this by something better
+{
+ p = fract( p*0.3183099+.1 );
+ p *= 17.0;
+ return fract( p.x*p.y*p.z*(p.x+p.y+p.z) );
+}
+
+float noise( in vec3 x )
+{
+ vec3 i = floor(x);
+ vec3 f = fract(x);
+ f = f*f*(3.0-2.0*f);
+
+ return mix(mix(mix( hash(i+vec3(0,0,0)),
+ hash(i+vec3(1,0,0)),f.x),
+ mix( hash(i+vec3(0,1,0)),
+ hash(i+vec3(1,1,0)),f.x),f.y),
+ mix(mix( hash(i+vec3(0,0,1)),
+ hash(i+vec3(1,0,1)),f.x),
+ mix( hash(i+vec3(0,1,1)),
+ hash(i+vec3(1,1,1)),f.x),f.y),f.z);
+}
\ No newline at end of file
diff --git a/screenshots/shadowmapping-poisson-stable.jpg b/screenshots/shadowmapping-poisson-stable.jpg
new file mode 100644
index 0000000..b3024a3
Binary files /dev/null and b/screenshots/shadowmapping-poisson-stable.jpg differ
diff --git a/shadowmapping-poisson-stable/shaders/pcf.h b/shadowmapping-poisson-stable/shaders/pcf.h
new file mode 100644
index 0000000..15621c1
--- /dev/null
+++ b/shadowmapping-poisson-stable/shaders/pcf.h
@@ -0,0 +1,13 @@
+#include "common/poisson32.h"
+
+float pcf(sampler2DShadow shadowMap, vec4 clipPos, float bias, mat2 jitter)
+{
+ clipPos.z += bias;
+ float sum = 0.;
+ for (int i = 0; i < 32; ++i)
+ {
+ vec2 offset = jitter * poisson32[i];
+ sum += textureProj(shadowMap, vec4(clipPos.xy + offset, clipPos.zw));
+ }
+ return sum/32.;
+}
diff --git a/shadowmapping-poisson-stable/shaders/phong.frag b/shadowmapping-poisson-stable/shaders/phong.frag
new file mode 100644
index 0000000..c932165
--- /dev/null
+++ b/shadowmapping-poisson-stable/shaders/phong.frag
@@ -0,0 +1,116 @@
+#version 450
+#extension GL_GOOGLE_include_directive : enable
+#include "common/transforms.h"
+#include "common/noise2d.h"
+#include "common/noise3d.h"
+#include "pcf.h"
+
+#include "common/linearizeDepth.h"
+
+layout(constant_id = 0) const bool c_screenSpaceNoise = true;
+layout(constant_id = 1) const bool c_showNoise = false;
+
+layout(binding = 2) uniform Light
+{
+ vec4 viewPos;
+ vec4 ambient;
+ vec4 diffuse;
+ vec4 specular;
+} light;
+
+layout(binding = 3) uniform Material
+{
+ vec4 ambient;
+ vec4 diffuse;
+ vec4 specular;
+ float shininess;
+} surface;
+
+layout(binding = 4) uniform Parameters
+{
+ vec4 screenSize; // x, y, 1/x, 1/y
+ float radius;
+ float zbias;
+ float jitterDensity;
+};
+
+layout(binding = 5) uniform sampler2DShadow shadowMap;
+
+layout(location = 0) in vec4 worldPos;
+layout(location = 1) in vec3 viewPos;
+layout(location = 2) in vec3 viewNormal;
+layout(location = 3) in vec2 texCoord;
+
+layout(location = 0) out vec3 oColor;
+
+float screenNoise(vec4 fragCoord)
+{
+ vec2 uv = fragCoord.xy * screenSize.zw;
+ float aspectRatio = screenSize.x * screenSize.w;
+ uv.x *= aspectRatio;
+ return noise(uv * screenSize.x);
+}
+
+float worldNoise(vec3 worldPos, float z, float density)
+{
+ float w = 1./z;
+ return noise(worldPos * density * w);
+}
+
+mat2 jitter(float a, float x, float y)
+{
+ float s = sin(a);
+ float c = cos(a);
+ mat2 rot = mat2(
+ c,-s,
+ s, c);
+ mat2 scale = mat2(
+ x, 0.,
+ 0., y);
+ return rot * scale;
+}
+
+vec3 phong(vec3 n, vec3 l, vec3 v,
+ vec3 Ka, vec3 Ia,
+ vec3 Kdiff, vec3 Idiff,
+ vec3 Kspec, vec3 Ispec,
+ float shininess,
+ float shadow)
+{
+ float NdL = max(dot(n, l), 0.);
+ vec3 r = reflect(-l, n);
+ float RdV = max(dot(r, v), 0.);
+ return Ka * Ia + shadow * (Kdiff * NdL * Idiff) + (Kspec * pow(RdV, shininess) * Ispec);
+}
+
+void main()
+{
+ vec3 n = normalize(viewNormal);
+ vec3 l = normalize(light.viewPos.xyz - viewPos);
+ vec3 v = -normalize(viewPos);
+
+ float theta;
+ if (c_screenSpaceNoise)
+ theta = screenNoise(gl_FragCoord);
+ else
+ theta = worldNoise(worldPos.xyz, viewPos.z, jitterDensity);
+
+ float shadow;
+ if (dot(n, l) <= 0.)
+ shadow = 0.;
+ else
+ {
+ vec4 shadowPos = shadowProj * worldPos;
+ vec2 scale = radius/textureSize(shadowMap, 0) * shadowPos.w;
+ mat2 jitMat = jitter(theta * TWO_PI, scale.x, scale.y);
+ shadow = pcf(shadowMap, shadowPos, zbias, jitMat);
+ }
+
+ oColor = phong(n, l, v,
+ surface.ambient.rgb, light.ambient.rgb,
+ surface.diffuse.rgb, light.diffuse.rgb,
+ surface.specular.rgb, light.specular.rgb,
+ surface.shininess, shadow);
+ if (c_showNoise)
+ oColor *= theta;
+}
diff --git a/shadowmapping-poisson-stable/shaders/shadowMap.vert b/shadowmapping-poisson-stable/shaders/shadowMap.vert
new file mode 100644
index 0000000..553534a
--- /dev/null
+++ b/shadowmapping-poisson-stable/shaders/shadowMap.vert
@@ -0,0 +1,14 @@
+#version 450
+#extension GL_GOOGLE_include_directive : enable
+#include "common/transforms.h"
+
+layout(location = 0) in vec4 position;
+
+out gl_PerVertex {
+ vec4 gl_Position;
+};
+
+void main()
+{
+ gl_Position = worldLightProj * position;
+}
diff --git a/shadowmapping-poisson-stable/shaders/transform.vert b/shadowmapping-poisson-stable/shaders/transform.vert
new file mode 100644
index 0000000..27ab88d
--- /dev/null
+++ b/shadowmapping-poisson-stable/shaders/transform.vert
@@ -0,0 +1,21 @@
+#version 450
+#extension GL_GOOGLE_include_directive : enable
+#include "common/transforms.h"
+
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec3 normal;
+
+layout(location = 0) out vec4 oWorldPos;
+layout(location = 1) out vec3 oViewPos;
+layout(location = 2) out vec3 oViewNormal;
+out gl_PerVertex {
+ vec4 gl_Position;
+};
+
+void main()
+{
+ oWorldPos = world * position;
+ oViewPos = (worldView * position).xyz;
+ oViewNormal = mat3(normalView) * normal;
+ gl_Position = worldViewProj * position;
+}
diff --git a/shadowmapping-poisson-stable/shadowmapping-poisson-stable.cpp b/shadowmapping-poisson-stable/shadowmapping-poisson-stable.cpp
new file mode 100644
index 0000000..d668844
--- /dev/null
+++ b/shadowmapping-poisson-stable/shadowmapping-poisson-stable.cpp
@@ -0,0 +1,378 @@
+#include "graphicsApp.h"
+#include "colorTable.h"
+#include "quadric/include/cube.h"
+#include "quadric/include/sphere.h"
+#include "quadric/include/teapot.h"
+#include "quadric/include/plane.h"
+
+class StablePoissonShadowMapping : public GraphicsApp
+{
+ enum {
+ Cube = 0, Teapot, Sphere, Ground,
+ MaxObjects
+ };
+
+ struct alignas(16) Constants
+ {
+ VkBool32 screenSpaceNoise;
+ VkBool32 showNoise;
+ };
+
+ struct alignas(16) Parameters
+ {
+ rapid::float4a screenSize; // x, y, 1/x, 1/y
+ float radius;
+ float zbias;
+ float jitterDensity;
+ };
+
+ std::unique_ptr objects[MaxObjects];
+ std::shared_ptr> materials;
+ std::shared_ptr> parameters;
+ std::shared_ptr shadowMapPipeline;
+ std::shared_ptr phongShadowPipeline;
+ std::shared_ptr shadowMap;
+ std::shared_ptr shadowSampler;
+ DescriptorSet smDescriptor;
+ DescriptorSet descriptor;
+
+ rapid::matrix objTransforms[MaxObjects];
+ Constants constants = {true, false};
+ float radius = 10.f;
+ float jitterDensity = 6.f;
+
+public:
+ explicit StablePoissonShadowMapping(const AppEntry& entry):
+ GraphicsApp(entry, TEXT("Poisson stable percentage closer filtering"), 1280, 720, true)
+ {
+ setupViewProjection();
+ setupTransforms();
+ setupMaterials();
+ updateParameters();
+ createShadowMap();
+ createMeshObjects();
+ setupDescriptorSets();
+ setupGraphicsPipelines();
+
+ renderScene(drawCmdBuffer);
+ blit(msaaFramebuffer->getColorView(), FrontBuffer);
+ blit(msaaFramebuffer->getColorView(), BackBuffer);
+
+ timer->run();
+ }
+
+ virtual void render(uint32_t bufferIndex) override
+ {
+ updateView();
+ updateTransforms();
+ submitCommandBuffers(bufferIndex);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2)); // Cap fps
+ }
+
+ virtual void onKeyDown(char key, int repeat, uint32_t flags) override
+ {
+ switch (key)
+ {
+ case AppKey::PgUp:
+ if (radius <= 19.5f)
+ {
+ radius += 0.5f;
+ updateParameters();
+ }
+ break;
+ case AppKey::PgDn:
+ if (radius >= 1.5f)
+ {
+ radius -= 0.5f;
+ updateParameters();
+ }
+ break;
+ case AppKey::Home:
+ if (!constants.screenSpaceNoise)
+ {
+ if (jitterDensity < 10.f)
+ {
+ jitterDensity += 1.f;
+ updateParameters();
+ std::cout << "Jitter density: " << jitterDensity << std::endl;
+ }
+ }
+ break;
+ case AppKey::End:
+ if (!constants.screenSpaceNoise)
+ {
+ if (jitterDensity > 2.f)
+ {
+ jitterDensity -= 1.f;
+ updateParameters();
+ std::cout << "Jitter density: " << jitterDensity << std::endl;
+ }
+ }
+ break;
+ case AppKey::Space:
+ constants.screenSpaceNoise = !constants.screenSpaceNoise;
+ setupGraphicsPipelines();
+ renderScene(drawCmdBuffer);
+ break;
+ case AppKey::Enter:
+ constants.showNoise = !constants.showNoise;
+ setupGraphicsPipelines();
+ renderScene(drawCmdBuffer);
+ break;
+ }
+ VulkanApp::onKeyDown(key, repeat, flags);
+ }
+
+ virtual void updateLightSource()
+ {
+ magma::helpers::mapScoped(lightSource,
+ [this](auto *light)
+ {
+ constexpr float ambientFactor = 0.4f;
+ light->viewPosition = viewProj->getView() * lightViewProj->getPosition();
+ light->ambient = ghost_white * ambientFactor;
+ light->diffuse = ghost_white;
+ light->specular = ghost_white;
+ });
+ }
+
+ void updateView()
+ {
+ constexpr float speed = 0.001f;
+ constexpr float amplitude = 2.f;
+ static float t = 0.f;
+ t += timer->millisecondsElapsed() * speed;
+ const float truck = sinf(t) * amplitude;
+ const auto& position = viewProj->getPosition();
+ viewProj->setPosition(truck, position.y, position.z);
+ const auto& focus = viewProj->getFocus();
+ viewProj->setFocus(truck, focus.y, focus.z);
+ viewProj->updateView();
+ viewProj->updateProjection();
+ updateViewProjTransforms();
+ }
+
+ void updateTransforms()
+ {
+ const rapid::matrix rotation = rapid::rotationY(rapid::radians(-spinX/4.f));
+ std::vector> transforms(MaxObjects);
+ transforms[Cube] = objTransforms[Cube] * rotation,
+ transforms[Teapot] = objTransforms[Teapot] * rotation,
+ transforms[Sphere] = objTransforms[Sphere] * rotation,
+ transforms[Ground] = objTransforms[Ground];
+ updateObjectTransforms(transforms);
+ }
+
+ void updateParameters()
+ {
+ if (!parameters)
+ parameters = std::make_shared>(device);
+ magma::helpers::mapScoped(parameters,
+ [this](auto *parameters)
+ {
+ parameters->screenSize = rapid::float4a(float(width), float(height), 1.f/width, 1.f/height);
+ parameters->radius = radius;
+ // Bias depends on filter radius to avoid shadow leakage
+ parameters->zbias = rapid::mapRange(1.0f, 20.0f, radius, 0.0f, 0.025f);
+ // Jitter density is perspective-corrected
+ float zDelta = viewProj->getFarZ() - viewProj->getNearZ();
+ parameters->jitterDensity = jitterDensity * zDelta;
+ });
+ }
+
+ void setupViewProjection()
+ {
+ viewProj = std::make_unique();
+ viewProj->setPosition(0.f, 11.f, -18.f);
+ viewProj->setFocus(0.f, 0.f, -1.f);
+ viewProj->setFieldOfView(45.f);
+ viewProj->setNearZ(1.f);
+ viewProj->setFarZ(100.f);
+ viewProj->setAspectRatio(width/(float)height);
+ viewProj->updateView();
+ viewProj->updateProjection();
+
+ lightViewProj = std::make_unique();
+ lightViewProj->setPosition(-8.f, 12.f, 1.f);
+ lightViewProj->setFocus(0.f, 0.f, 0.f);
+ lightViewProj->setFieldOfView(70.f);
+ lightViewProj->setNearZ(5.f);
+ lightViewProj->setFarZ(30.f);
+ lightViewProj->setAspectRatio(1.f);
+ lightViewProj->updateView();
+ lightViewProj->updateProjection();
+
+ updateViewProjTransforms();
+ }
+
+ void setupTransforms()
+ {
+ createTransformBuffer(MaxObjects);
+ constexpr float radius = 4.f;
+ objTransforms[Cube] = rapid::translation(radius, 1.f, 0.f) * rapid::rotationY(rapid::radians(30.f));
+ const rapid::matrix upset =
+ rapid::rotationX(rapid::radians(-98.f)) *
+ rapid::rotationZ(rapid::radians(-30.f)) *
+ rapid::translation(0.f, 2.05f, 0.f);
+ objTransforms[Teapot] = upset *
+ rapid::rotationY(rapid::radians(-140.f)) *
+ rapid::translation(radius, 0.f, 0.f) * rapid::rotationY(rapid::radians(150.f));
+ objTransforms[Sphere] = rapid::translation(radius, 1.5f, 0.f) * rapid::rotationY(rapid::radians(270.f));
+ constexpr float bias = -0.05f; // Shift slightly down to get rid of shadow leakage
+ objTransforms[Ground] = rapid::translation(0.f, bias, 0.f);
+ }
+
+ void setupMaterials()
+ {
+ materials = std::make_shared>(device, MaxObjects);
+ magma::helpers::mapScoped(materials,
+ [this](magma::helpers::AlignedUniformArray& materials)
+ {
+ constexpr float ambientFactor = 0.4f;
+ materials[Cube].ambient = medium_sea_green * ambientFactor;
+ materials[Cube].diffuse = medium_sea_green;
+ materials[Cube].specular = medium_sea_green;
+ materials[Cube].shininess = 2.f; // High roughness for metal look like
+
+ materials[Teapot].ambient = pale_golden_rod * ambientFactor;
+ materials[Teapot].diffuse = pale_golden_rod;
+ materials[Teapot].specular = pale_golden_rod;
+ materials[Teapot].shininess = 128.f; // Low roughness for plastic look like
+
+ materials[Sphere].ambient = medium_blue * ambientFactor;
+ materials[Sphere].diffuse = medium_blue;
+ materials[Sphere].specular = deep_sky_blue;
+ materials[Sphere].shininess = 2.f;
+
+ materials[Ground].ambient = floral_white * ambientFactor;
+ materials[Ground].diffuse = floral_white;
+ materials[Ground].specular = floral_white * 0.1f;
+ materials[Ground].shininess = 2.f;
+ });
+ }
+
+ void createShadowMap()
+ {
+ constexpr VkFormat depthFormat = VK_FORMAT_D16_UNORM; // 16 bits of depth is enough for a tiny scene
+ constexpr VkExtent2D extent{2048, 2048};
+ shadowMap = std::make_shared(device, depthFormat, extent);
+ shadowSampler = std::make_shared(device, magma::samplers::magMinNearestCompareLessOrEqual);
+ }
+
+ void createMeshObjects()
+ {
+ objects[Cube] = std::make_unique(cmdCopyBuf);
+ objects[Teapot] = std::make_unique(16, cmdCopyBuf);
+ objects[Sphere] = std::make_unique(1.5f, 64, 64, false, cmdCopyBuf);
+ objects[Ground] = std::make_unique(100.f, 100.f, false, cmdCopyBuf);
+ }
+
+ void setupDescriptorSets()
+ { // Shadow map shader
+ smDescriptor.layout = std::make_shared(device,
+ magma::bindings::VertexStageBinding(0, magma::descriptors::DynamicUniformBuffer(1)));
+ smDescriptor.set = descriptorPool->allocateDescriptorSet(smDescriptor.layout);
+ smDescriptor.set->update(0, transforms);
+ // Lighting shader
+ descriptor.layout = std::shared_ptr(new magma::DescriptorSetLayout(device,
+ {
+ magma::bindings::VertexStageBinding(0, magma::descriptors::DynamicUniformBuffer(1)),
+ magma::bindings::FragmentStageBinding(1, magma::descriptors::UniformBuffer(1)),
+ magma::bindings::FragmentStageBinding(2, magma::descriptors::UniformBuffer(1)),
+ magma::bindings::FragmentStageBinding(3, magma::descriptors::DynamicUniformBuffer(1)),
+ magma::bindings::FragmentStageBinding(4, magma::descriptors::UniformBuffer(1)),
+ magma::bindings::FragmentStageBinding(5, magma::descriptors::CombinedImageSampler(1))
+ }));
+ descriptor.set = descriptorPool->allocateDescriptorSet(descriptor.layout);
+ descriptor.set->update(0, transforms);
+ descriptor.set->update(1, viewProjTransforms);
+ descriptor.set->update(2, lightSource);
+ descriptor.set->update(3, materials);
+ descriptor.set->update(4, parameters);
+ descriptor.set->update(5, shadowMap->getDepthView(), shadowSampler);
+ }
+
+ void setupGraphicsPipelines()
+ {
+ if (!shadowMapPipeline)
+ {
+ shadowMapPipeline = createShadowMapPipeline(
+ "shadowMap.o",
+ objects[0]->getVertexInput(),
+ magma::renderstates::fillCullFrontCW, // Draw only back faces to get rid of shadow acne
+ smDescriptor.layout,
+ shadowMap);
+ }
+
+ std::shared_ptr specialization(new magma::Specialization(
+ this->constants,
+ {
+ magma::SpecializationEntry(0, &Constants::screenSpaceNoise),
+ magma::SpecializationEntry(1, &Constants::showNoise)
+ }
+ ));
+
+ phongShadowPipeline = createCommonSpecializedPipeline(
+ "transform.o", "phong.o",
+ std::move(specialization),
+ objects[0]->getVertexInput(),
+ descriptor.layout);
+ }
+
+ void renderScene(std::shared_ptr cmdBuffer)
+ {
+ cmdBuffer->begin();
+ {
+ shadowMapPass(cmdBuffer);
+ lightingPass(cmdBuffer);
+ }
+ cmdBuffer->end();
+ }
+
+ void shadowMapPass(std::shared_ptr cmdBuffer)
+ {
+ cmdBuffer->beginRenderPass(shadowMap->getRenderPass(), shadowMap->getFramebuffer(),
+ {
+ magma::clears::depthOne
+ });
+ {
+ cmdBuffer->setViewport(magma::Viewport(0, 0, shadowMap->getExtent()));
+ cmdBuffer->setScissor(magma::Scissor(0, 0, shadowMap->getExtent()));
+ cmdBuffer->bindPipeline(shadowMapPipeline);
+ for (uint32_t i = Cube; i < Ground; ++i)
+ {
+ cmdBuffer->bindDescriptorSet(shadowMapPipeline, smDescriptor.set, transforms->getDynamicOffset(i));
+ objects[i]->draw(cmdBuffer);
+ }
+ }
+ cmdBuffer->endRenderPass();
+ }
+
+ void lightingPass(std::shared_ptr cmdBuffer)
+ {
+ cmdBuffer->beginRenderPass(msaaFramebuffer->getRenderPass(), msaaFramebuffer->getFramebuffer(),
+ {
+ magma::ClearColor(0.35f, 0.53f, 0.7f, 1.0f),
+ magma::clears::depthOne
+ });
+ {
+ cmdBuffer->setViewport(magma::Viewport(0, 0, msaaFramebuffer->getExtent()));
+ cmdBuffer->setScissor(magma::Scissor(0, 0, msaaFramebuffer->getExtent()));
+ cmdBuffer->bindPipeline(phongShadowPipeline);
+ for (uint32_t i = Cube; i < MaxObjects; ++i)
+ {
+ cmdBuffer->bindDescriptorSet(phongShadowPipeline, descriptor.set, {
+ transforms->getDynamicOffset(i),
+ materials->getDynamicOffset(i)
+ });
+ objects[i]->draw(cmdBuffer);
+ }
+ }
+ cmdBuffer->endRenderPass();
+ }
+};
+
+std::unique_ptr appFactory(const AppEntry& entry)
+{
+ return std::make_unique(entry);
+}
diff --git a/shadowmapping-poisson-stable/shadowmapping-poisson-stable.vcxproj b/shadowmapping-poisson-stable/shadowmapping-poisson-stable.vcxproj
new file mode 100644
index 0000000..c9a28ce
--- /dev/null
+++ b/shadowmapping-poisson-stable/shadowmapping-poisson-stable.vcxproj
@@ -0,0 +1,187 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 15.0
+ {DD90A343-7897-442B-9D19-7FF0676E80EB}
+ shadowmappingpoissonstable
+ 10.0.16299.0
+
+
+
+ Application
+ true
+ v141
+ Unicode
+
+
+ Application
+ false
+ v141
+ true
+ Unicode
+
+
+ Application
+ true
+ v141
+ Unicode
+
+
+ Application
+ false
+ v141
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ $(VK_SDK_PATH)\Include;..\third-party;..\framework
+ _DEBUG;VK_USE_PLATFORM_WIN32_KHR;%(PreprocessorDefinitions)
+
+
+ Windows
+ $(VK_SDK_PATH)\Lib;..\x64\Debug
+ vulkan-1.lib;magma.lib;quadric.lib;framework.lib;Shcore.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ $(VK_SDK_PATH)\Include;..\third-party;..\framework
+ _DEBUG;VK_USE_PLATFORM_WIN32_KHR;%(PreprocessorDefinitions)
+
+
+ Windows
+ $(VK_SDK_PATH)\Lib32;..\Debug
+ vulkan-1.lib;magma.lib;quadric.lib;framework.lib;Shcore.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ $(VK_SDK_PATH)\Include;..\third-party;..\framework
+ NDEBUG;VK_USE_PLATFORM_WIN32_KHR;%(PreprocessorDefinitions)
+ MultiThreaded
+
+
+ true
+ true
+ Windows
+ $(VK_SDK_PATH)\Lib32;..\Release
+ vulkan-1.lib;magma.lib;quadric.lib;framework.lib;Shcore.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ $(VK_SDK_PATH)\Include;..\third-party;..\framework
+ NDEBUG;VK_USE_PLATFORM_WIN32_KHR;%(PreprocessorDefinitions)
+ MultiThreaded
+
+
+ true
+ true
+ Windows
+ $(VK_SDK_PATH)\Lib;..\x64\Release
+ vulkan-1.lib;magma.lib;quadric.lib;framework.lib;Shcore.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+ Document
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ %(Filename).o
+ %(Filename).o
+ %(Filename).o
+ %(Filename).o
+
+
+ Document
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ %(Filename).o
+ %(Filename).o
+ %(Filename).o
+ %(Filename).o
+
+
+ Document
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ $(VK_SDK_PATH)\Bin32\glslangValidator.exe -V %(FullPath) -I..\framework\shaders -o %(Filename).o
+ %(Filename).o
+ %(Filename).o
+ %(Filename).o
+ %(Filename).o
+
+
+
+
+
+
\ No newline at end of file
diff --git a/shadowmapping-poisson-stable/shadowmapping-poisson-stable.vcxproj.filters b/shadowmapping-poisson-stable/shadowmapping-poisson-stable.vcxproj.filters
new file mode 100644
index 0000000..ccb08a4
--- /dev/null
+++ b/shadowmapping-poisson-stable/shadowmapping-poisson-stable.vcxproj.filters
@@ -0,0 +1,38 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+
+
+ Resource Files
+
+
+
+
+ Resource Files
+
+
+ Resource Files
+
+
+ Resource Files
+
+
+
\ No newline at end of file