aboutsummaryrefslogtreecommitdiffstatsci
diff options
context:
space:
mode:
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>2019-04-29 18:41:04 +0200
committerj-p <jp_bruyere@hotmail.com>2019-05-02 03:07:11 +0200
commitd54a090d4a6665e7e8fbb6986da11051b243736a (patch)
tree471a402a9e930cb6062db76adb01843f30ca6822
parente386dd78b32bec43a1e8666bd4b482a0bbc83c24 (diff)
shadow mapping
-rw-r--r--samples/data/models/shadow.binbin0 -> 29660 bytes
-rw-r--r--samples/data/models/shadow.glb3
-rw-r--r--samples/deferred/EnvironmentPipeline.cs15
-rw-r--r--samples/deferred/deferred.csproj6
-rw-r--r--samples/deferred/deferredPbrRenderer.cs143
-rw-r--r--samples/deferred/main.cs127
-rw-r--r--samples/deferred/shaders/GBuffPbr.frag4
-rw-r--r--samples/deferred/shaders/compose.frag14
-rw-r--r--samples/deferred/shaders/compose_with_shadows.frag277
-rw-r--r--samples/deferred/shaders/shadow.geom37
-rw-r--r--samples/deferred/shaders/shadow.vert8
-rw-r--r--samples/deferred/shaders/show_gbuff.frag6
-rw-r--r--samples/deferred/shaders/tone_mapping.frag2
-rw-r--r--samples/deferred/shadowMapRenderer.cs155
-rw-r--r--spirv.xml2
-rw-r--r--vke/src/DescriptorSetLayout.cs3
-rw-r--r--vke/src/Device.cs292
-rw-r--r--vke/src/ExtensionMethods.cs3
-rw-r--r--vke/src/Instance.cs11
-rw-r--r--vke/src/PbrModel.cs22
-rw-r--r--vke/src/PhysicalDevice.cs27
-rw-r--r--vke/src/PipelineCache.cs4
-rw-r--r--vke/src/PipelineLayout.cs2
-rw-r--r--vke/src/VkWindow.cs4
24 files changed, 878 insertions, 289 deletions
diff --git a/samples/data/models/shadow.bin b/samples/data/models/shadow.bin
new file mode 100644
index 0000000..b332f19
--- /dev/null
+++ b/samples/data/models/shadow.bin
Binary files differ
diff --git a/samples/data/models/shadow.glb b/samples/data/models/shadow.glb
new file mode 100644
index 0000000..63d5bf9
--- /dev/null
+++ b/samples/data/models/shadow.glb
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:cfb8aee60b56b163b91fabdf39c6956498d1cf3a3780db1a0c92b0671f4ccfe0
+size 33552
diff --git a/samples/deferred/EnvironmentPipeline.cs b/samples/deferred/EnvironmentPipeline.cs
index e372561..1d18151 100644
--- a/samples/deferred/EnvironmentPipeline.cs
+++ b/samples/deferred/EnvironmentPipeline.cs
@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
using VK;
namespace CVKL {
- class EnvironmentCube : GraphicPipeline {
+ public class EnvironmentCube : GraphicPipeline {
GPUBuffer vboSkybox;
@@ -24,7 +24,7 @@ namespace CVKL {
vboSkybox = new GPUBuffer<float> (staggingQ, cmdPool, VkBufferUsageFlags.VertexBuffer, box_vertices);
- cubemap = KTX.KTX.Load (staggingQ, cmdPool, cubemapPathes[0],
+ cubemap = KTX.KTX.Load (staggingQ, cmdPool, cubemapPathes[2],
VkImageUsageFlags.Sampled, VkMemoryPropertyFlags.DeviceLocal, true);
cubemap.CreateView (VkImageViewType.Cube, VkImageAspectFlags.Color, 6, 0, cubemap.CreateInfo.mipLevels);
cubemap.CreateSampler (VkSamplerAddressMode.ClampToEdge);
@@ -188,13 +188,8 @@ namespace CVKL {
DescriptorSetLayout dsLayout = new DescriptorSetLayout (Dev,
new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler));
- DescriptorSet dset = dsPool.Allocate (dsLayout);
GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false);
-
- DescriptorSetWrites dsUpdate = new DescriptorSetWrites (dsLayout);
- dsUpdate.Write (Dev, dset, cubemap.Descriptor);
-
cfg.Layout = new PipelineLayout (Dev, dsLayout);
cfg.Layout.AddPushConstants (
new VkPushConstantRange (VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, (uint)Marshal.SizeOf<Matrix4x4> () + 8));
@@ -231,6 +226,12 @@ namespace CVKL {
VkImageSubresourceRange subRes = new VkImageSubresourceRange (VkImageAspectFlags.Color, 0, numMips, 0, 6);
using (GraphicPipeline pl = new GraphicPipeline (cfg)) {
+
+ DescriptorSet dset = dsPool.Allocate (dsLayout);
+ DescriptorSetWrites dsUpdate = new DescriptorSetWrites (dsLayout);
+ dsUpdate.Write (Dev, dset, cubemap.Descriptor);
+ Dev.WaitIdle ();
+
using (Framebuffer fb = new Framebuffer (pl.RenderPass, dim, dim, imgFbOffscreen)) {
CommandBuffer cmd = cmdPool.AllocateCommandBuffer ();
cmd.Start (VkCommandBufferUsageFlags.OneTimeSubmit);
diff --git a/samples/deferred/deferred.csproj b/samples/deferred/deferred.csproj
index ac0b35f..0a3b19a 100644
--- a/samples/deferred/deferred.csproj
+++ b/samples/deferred/deferred.csproj
@@ -13,7 +13,7 @@
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
- <DefineConstants>DEBUG</DefineConstants>
+ <DefineConstants>DEBUG;_WITH_VKVG;_WITH_SHADOWS</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@@ -25,11 +25,11 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
- <GLSLShader Include="shaders\**\*.frag;shaders\**\*.vert;shaders\**\*.comp" />
+ <GLSLShader Include="shaders\**\*.frag;shaders\**\*.vert;shaders\**\*.comp;shaders\**\*.geom" />
<Datas Include="..\data\**\*.*">
<Link>data\%(RecursiveDir)%(Filename)%(Extension)</Link>
</Datas>
- <Compile Include="main.cs;EnvironmentPipeline.cs;deferredPbrRenderer.cs" />
+ <Compile Include="main.cs;EnvironmentPipeline.cs;deferredPbrRenderer.cs;shadowMapRenderer.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Numerics" />
diff --git a/samples/deferred/deferredPbrRenderer.cs b/samples/deferred/deferredPbrRenderer.cs
index 575d0eb..e6dafd8 100644
--- a/samples/deferred/deferredPbrRenderer.cs
+++ b/samples/deferred/deferredPbrRenderer.cs
@@ -6,14 +6,14 @@ using VK;
using CVKL;
namespace deferred {
- class DeferredPbrRenderer : IDisposable {
+ public class DeferredPbrRenderer : IDisposable {
Device dev;
SwapChain swapChain;
- PresentQueue presentQueue;
+ public PresentQueue presentQueue;
- VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1;
- VkFormat hdrFormat = VkFormat.R32g32b32a32Sfloat;
- VkFormat mrtFormat = VkFormat.R32g32b32a32Sfloat;
+ public static VkSampleCountFlags NUM_SAMPLES = VkSampleCountFlags.SampleCount4;
+ public static VkFormat HDR_FORMAT = VkFormat.R32g32b32a32Sfloat;
+ public static VkFormat MRT_FORMAT = VkFormat.R32g32b32a32Sfloat;
public enum DebugView {
none,
@@ -26,10 +26,12 @@ namespace deferred {
roughness,
depth,
prefill,
- irradiance
+ irradiance,
+ shadowMap
}
public DebugView currentDebugView = DebugView.none;
+ public int lightNumDebug = 0;
public struct Matrices {
public Matrix4x4 projection;
@@ -45,21 +47,27 @@ namespace deferred {
public struct Light {
public Vector4 position;
public Vector4 color;
+ public Matrix4x4 mvp;
}
public Matrices matrices = new Matrices {
gamma = 1.2f,
exposure = 2.0f,
- scaleIBLAmbient = 1.0f,
+ scaleIBLAmbient = 0.5f,
};
- Light[] lights = {
+ public Light[] lights = {
new Light {
- position = new Vector4(1),
- color = new Vector4(1)
+ position = new Vector4(2.5f,3.5f,2,0f),
+ color = new Vector4(1,0.8f,0.8f,1)
+ },
+ new Light {
+ position = new Vector4(-2.5f,2.5f,2,0f),
+ color = new Vector4(0.8f,0.8f,1,1)
}
};
- public Vector4 lightPos = new Vector4 (1, 0, 0, 0);
+
+ const float lightMoveSpeed = 0.1f;
Framebuffer[] frameBuffers;
Image gbColorRough, gbEmitMetal, gbN_AO, gbPos, hdrImg;
@@ -71,12 +79,14 @@ namespace deferred {
public PipelineCache pipelineCache;
Pipeline gBuffPipeline, composePipeline, toneMappingPipeline, debugPipeline;
- HostBuffer uboMatrices, uboLights;
+ public HostBuffer uboMatrices { get; private set; }
+ public HostBuffer<Light> uboLights { get; private set; }
RenderPass renderPass;
- PbrModel model;
+ public PbrModel model { get; private set; }
public EnvironmentCube envCube;
+ public ShadowMapRenderer shadowMapRenderer;
public BoundingBox modelAABB;
@@ -92,20 +102,33 @@ namespace deferred {
pipelineCache = new PipelineCache (dev);
+ descriptorPool = new DescriptorPool (dev, 3,
+ new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer, 3),
+ new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, 5),
+ new VkDescriptorPoolSize (VkDescriptorType.InputAttachment, 6)
+ );
+
+ uboMatrices = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, matrices, true);
+ uboLights = new HostBuffer<Light> (dev, VkBufferUsageFlags.UniformBuffer, lights, true);
+
+#if WITH_SHADOWS
+ shadowMapRenderer = new ShadowMapRenderer (dev, this);
+#endif
+
init (nearPlane, farPlane);
}
void init (float nearPlane, float farPlane) {
- renderPass = new RenderPass (dev, samples);
+ renderPass = new RenderPass (dev, NUM_SAMPLES);
renderPass.AddAttachment (swapChain.ColorFormat, VkImageLayout.PresentSrcKHR, VkSampleCountFlags.SampleCount1);//swapchain image
- renderPass.AddAttachment (dev.GetSuitableDepthFormat(), VkImageLayout.DepthStencilAttachmentOptimal, samples);
- renderPass.AddAttachment (swapChain.ColorFormat, VkImageLayout.ColorAttachmentOptimal, samples, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff0 (color + roughness) and final color before resolve
- renderPass.AddAttachment (VkFormat.R8g8b8a8Unorm, VkImageLayout.ColorAttachmentOptimal, samples, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff1 (emit + metal)
- renderPass.AddAttachment (mrtFormat, VkImageLayout.ColorAttachmentOptimal, samples, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff2 (normals + AO)
- renderPass.AddAttachment (mrtFormat, VkImageLayout.ColorAttachmentOptimal, samples, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff3 (Pos + depth)
- renderPass.AddAttachment (hdrFormat, VkImageLayout.ColorAttachmentOptimal, samples);//hdr color
+ renderPass.AddAttachment (dev.GetSuitableDepthFormat(), VkImageLayout.DepthStencilAttachmentOptimal, NUM_SAMPLES);
+ renderPass.AddAttachment (swapChain.ColorFormat, VkImageLayout.ColorAttachmentOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff0 (color + roughness) and final color before resolve
+ renderPass.AddAttachment (VkFormat.R8g8b8a8Unorm, VkImageLayout.ColorAttachmentOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff1 (emit + metal)
+ renderPass.AddAttachment (MRT_FORMAT, VkImageLayout.ColorAttachmentOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff2 (normals + AO)
+ renderPass.AddAttachment (MRT_FORMAT, VkImageLayout.ColorAttachmentOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff3 (Pos + depth)
+ renderPass.AddAttachment (HDR_FORMAT, VkImageLayout.ColorAttachmentOptimal, NUM_SAMPLES);//hdr color
renderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) });
renderPass.ClearValues.Add (new VkClearValue { depthStencil = new VkClearDepthStencilValue (1.0f, 0) });
@@ -133,9 +156,9 @@ namespace deferred {
new VkAttachmentReference (4, VkImageLayout.ShaderReadOnlyOptimal),
new VkAttachmentReference (5, VkImageLayout.ShaderReadOnlyOptimal));
//tone mapping
- subpass[SP_TONE_MAPPING].AddColorReference ((samples == VkSampleCountFlags.SampleCount1) ? 0u : 2u, VkImageLayout.ColorAttachmentOptimal);
+ subpass[SP_TONE_MAPPING].AddColorReference ((NUM_SAMPLES == VkSampleCountFlags.SampleCount1) ? 0u : 2u, VkImageLayout.ColorAttachmentOptimal);
subpass[SP_TONE_MAPPING].AddInputReference (new VkAttachmentReference (6, VkImageLayout.ShaderReadOnlyOptimal));
- if (samples != VkSampleCountFlags.SampleCount1)
+ if (NUM_SAMPLES != VkSampleCountFlags.SampleCount1)
subpass[SP_TONE_MAPPING].AddResolveReference (0, VkImageLayout.ColorAttachmentOptimal);
renderPass.AddSubpass (subpass);
@@ -156,12 +179,6 @@ namespace deferred {
VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe,
VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead);
-
- descriptorPool = new DescriptorPool (dev, 3,
- new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer, 3),
- new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, 4),
- new VkDescriptorPoolSize (VkDescriptorType.InputAttachment, 6)
- );
descLayoutMain = new DescriptorSetLayout (dev,
new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer),//matrices and params
@@ -171,6 +188,9 @@ namespace deferred {
new VkDescriptorSetLayoutBinding (4, VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer),//lights
new VkDescriptorSetLayoutBinding (5, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler),//ui overlay
new VkDescriptorSetLayoutBinding (6, VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer));//materials
+#if WITH_SHADOWS
+ descLayoutMain.Bindings.Add (new VkDescriptorSetLayoutBinding (7, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler));
+#endif
descLayoutTextures = new DescriptorSetLayout (dev,
new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler),
@@ -187,12 +207,10 @@ namespace deferred {
new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment),//Pos + depth
new VkDescriptorSetLayoutBinding (4, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment));//hdr
- dsMain = descriptorPool.Allocate (descLayoutMain);
- dsGBuff = descriptorPool.Allocate (descLayoutGBuff);
- GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, samples);
-
- if (samples != VkSampleCountFlags.SampleCount1) {
+ GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, NUM_SAMPLES);
+ cfg.rasterizationState.cullMode = VkCullModeFlags.Back;
+ if (NUM_SAMPLES != VkSampleCountFlags.SampleCount1) {
cfg.multisampleState.sampleShadingEnable = true;
cfg.multisampleState.minSampleShading = 0.5f;
}
@@ -221,7 +239,7 @@ namespace deferred {
gBuffPipeline = new GraphicPipeline (cfg);
}
-
+ cfg.rasterizationState.cullMode = VkCullModeFlags.Front;
//COMPOSE PIPELINE
cfg.blendAttachments.Clear ();
cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
@@ -233,7 +251,11 @@ namespace deferred {
using (SpecializationInfo constants = new SpecializationInfo (
new SpecializationConstant<uint> (0, (uint)lights.Length))) {
cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/FullScreenQuad.vert.spv");
+#if WITH_SHADOWS
+ cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/compose_with_shadows.frag.spv", constants);
+#else
cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/compose.frag.spv", constants);
+#endif
composePipeline = new GraphicPipeline (cfg);
}
//DEBUG DRAW use subpass of compose
@@ -245,19 +267,25 @@ namespace deferred {
cfg.SubpassIndex = SP_TONE_MAPPING;
toneMappingPipeline = new GraphicPipeline (cfg);
+ dsMain = descriptorPool.Allocate (descLayoutMain);
+ dsGBuff = descriptorPool.Allocate (descLayoutGBuff);
+
envCube = new EnvironmentCube (dsMain, gBuffPipeline.Layout, presentQueue, renderPass);
matrices.prefilteredCubeMipLevels = envCube.prefilterCube.CreateInfo.mipLevels;
- uboMatrices = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, matrices, true);
- uboLights = new HostBuffer<Light> (dev, VkBufferUsageFlags.UniformBuffer, lights, true);
- DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings.GetRange (0, 5).ToArray ());
- uboUpdate.Write (dev,
+ DescriptorSetWrites dsMainWrite = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings.GetRange (0, 5).ToArray ());
+ dsMainWrite.Write (dev,
uboMatrices.Descriptor,
envCube.irradianceCube.Descriptor,
envCube.prefilterCube.Descriptor,
envCube.lutBrdf.Descriptor,
uboLights.Descriptor);
+
+#if WITH_SHADOWS
+ dsMainWrite = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings[7]);
+ dsMainWrite.Write (dev, shadowMapRenderer.shadowMap.Descriptor);
+#endif
}
public void LoadModel (Queue transferQ, string path) {
@@ -276,8 +304,9 @@ namespace deferred {
modelAABB = model.DefaultScene.AABB;
}
-
+ Image uiImage;
public void WriteUiImgDesciptor (Image uiImage) {
+ this.uiImage = uiImage;
DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings[5]);
uboUpdate.Write (dev, uiImage.Descriptor);
}
@@ -285,6 +314,10 @@ namespace deferred {
public void buildCommandBuffers (CommandBuffer[] cmds) {
for (int i = 0; i < swapChain.ImageCount; ++i) {
cmds[i].Start ();
+#if WITH_VKVG
+ uiImage.SetLayout (cmds[i], VkImageAspectFlags.Color, VkImageLayout.Undefined, VkImageLayout.ShaderReadOnlyOptimal,
+ VkPipelineStageFlags.TopOfPipe, VkPipelineStageFlags.FragmentShader);
+#endif
recordDraw (cmds[i], frameBuffers[i]);
cmds[i].End ();
}
@@ -315,7 +348,10 @@ namespace deferred {
else {
debugPipeline.Bind (cmd);
uint debugValue = (uint)currentDebugView - 1;
- debugValue += (uint)((envCube.debugFace << 8) + (envCube.debugMip << 16));
+ if (currentDebugView == DebugView.shadowMap)
+ debugValue += (uint)((lightNumDebug << 8));
+ else
+ debugValue += (uint)((envCube.debugFace << 8) + (envCube.debugMip << 16));
cmd.PushConstant (debugPipeline.Layout, VkShaderStageFlags.Fragment, debugValue, (uint)Marshal.SizeOf<Matrix4x4> ());
}
@@ -328,12 +364,17 @@ namespace deferred {
renderPass.End (cmd);
}
- #region update
+ public void MoveLight (Vector4 dir) {
+ lights[lightNumDebug].position += dir * lightMoveSpeed;
+#if WITH_SHADOWS
+ shadowMapRenderer.updateShadowMap = true;
+#endif
+ }
+
+#region update
public void UpdateView (Camera camera) {
camera.AspectRatio = (float)swapChain.Width / swapChain.Height;
- lights[0].position = lightPos;
-
matrices.projection = camera.Projection;
matrices.view = camera.View;
matrices.model = camera.Model;
@@ -349,7 +390,7 @@ namespace deferred {
uboMatrices.Update (matrices, (uint)Marshal.SizeOf<Matrices> ());
}
- #endregion
+#endregion
void createGBuff () {
gbColorRough?.Dispose ();
@@ -358,11 +399,11 @@ namespace deferred {
gbPos?.Dispose ();
hdrImg?.Dispose ();
- gbColorRough = new Image (dev, swapChain.ColorFormat, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height, VkImageType.Image2D, samples);
- gbEmitMetal = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height, VkImageType.Image2D, samples);
- gbN_AO = new Image (dev, mrtFormat, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height, VkImageType.Image2D, samples);
- gbPos = new Image (dev, mrtFormat, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height, VkImageType.Image2D, samples);
- hdrImg = new Image (dev, hdrFormat, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal | VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height, VkImageType.Image2D, samples);
+ gbColorRough = new Image (dev, swapChain.ColorFormat, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height, VkImageType.Image2D, NUM_SAMPLES);
+ gbEmitMetal = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height, VkImageType.Image2D, NUM_SAMPLES);
+ gbN_AO = new Image (dev, MRT_FORMAT, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height, VkImageType.Image2D, NUM_SAMPLES);
+ gbPos = new Image (dev, MRT_FORMAT, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height, VkImageType.Image2D, NUM_SAMPLES);
+ hdrImg = new Image (dev, HDR_FORMAT, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal | VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height, VkImageType.Image2D, NUM_SAMPLES);
gbColorRough.CreateView ();
gbColorRough.CreateSampler ();
@@ -433,6 +474,10 @@ namespace deferred {
model.Dispose ();
envCube.Dispose ();
+#if WITH_SHADOWS
+ shadowMapRenderer.Dispose ();
+#endif
+
descriptorPool.Dispose ();
}
}
diff --git a/samples/deferred/main.cs b/samples/deferred/main.cs
index 152cdb7..b8cac2e 100644
--- a/samples/deferred/main.cs
+++ b/samples/deferred/main.cs
@@ -13,10 +13,15 @@ namespace deferred {
}
}
- protected override void configureEnabledFeatures (ref VkPhysicalDeviceFeatures features) {
- base.configureEnabledFeatures (ref features);
- features.samplerAnisotropy = true;
- features.sampleRateShading = true;
+ protected override void configureEnabledFeatures (VkPhysicalDeviceFeatures available_features, ref VkPhysicalDeviceFeatures features) {
+ base.configureEnabledFeatures (available_features, ref features);
+
+ features.samplerAnisotropy = available_features.samplerAnisotropy;
+ features.sampleRateShading = available_features.sampleRateShading;
+ features.geometryShader = available_features.geometryShader;
+
+ if (available_features.textureCompressionBC) {
+ }
}
protected override void createQueues () {
@@ -26,26 +31,27 @@ namespace deferred {
string[] modelPathes = {
"../data/models/DamagedHelmet/glTF/DamagedHelmet.gltf",
- "/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/Avocado/glTF/Avocado.gltf",
- "/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/BarramundiFish/glTF/BarramundiFish.gltf",
- "/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/BoomBoxWithAxes/glTF/BoomBoxWithAxes.gltf",
- "/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/Box/glTF/Box.gltf",
- "/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/EnvironmentTest/glTF/EnvironmentTest.gltf",
- "/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/MetalRoughSpheres/glTF/MetalRoughSpheres.gltf",
- "/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/OrientationTest/glTF/OrientationTest.gltf",
- "/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/Buggy/glTF/Buggy.gltf",
- "/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/2CylinderEngine/glTF-Embedded/2CylinderEngine.gltf",
- "/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/FlightHelmet/glTF/FlightHelmet.gltf",
- "/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/GearboxAssy/glTF/GearboxAssy.gltf",
- "/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/Lantern/glTF/Lantern.gltf",
- "/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/SciFiHelmet/glTF/SciFiHelmet.gltf",
- "/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/Sponza/glTF/Sponza.gltf",
- "/mnt/devel/vkChess/data/chess.gltf",
- "/home/jp/gltf/camaro/scene.gltf",
- "/home/jp/gltf/chessold/scene.gltf",
- "../data/models/Hubble.glb",
- "../data/models/MER_static.glb",
- "../data/models/ISS_stationary.glb",
+ "../data/models/shadow.glb",
+ //"/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/Avocado/glTF/Avocado.gltf",
+ //"/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/BarramundiFish/glTF/BarramundiFish.gltf",
+ //"/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/BoomBoxWithAxes/glTF/BoomBoxWithAxes.gltf",
+ //"/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/Box/glTF/Box.gltf",
+ //"/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/EnvironmentTest/glTF/EnvironmentTest.gltf",
+ //"/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/MetalRoughSpheres/glTF/MetalRoughSpheres.gltf",
+ //"/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/OrientationTest/glTF/OrientationTest.gltf",
+ //"/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/Buggy/glTF/Buggy.gltf",
+ //"/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/2CylinderEngine/glTF-Embedded/2CylinderEngine.gltf",
+ //"/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/FlightHelmet/glTF/FlightHelmet.gltf",
+ //"/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/GearboxAssy/glTF/GearboxAssy.gltf",
+ //"/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/Lantern/glTF/Lantern.gltf",
+ //"/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/SciFiHelmet/glTF/SciFiHelmet.gltf",
+ //"/mnt/devel/vulkan/glTF-Sample-Models-master/2.0/Sponza/glTF/Sponza.gltf",
+ //"/mnt/devel/vkChess/data/chess.gltf",
+ //"/home/jp/gltf/camaro/scene.gltf",
+ //"/home/jp/gltf/chessold/scene.gltf",
+ //"../data/models/Hubble.glb",
+ //"../data/models/MER_static.glb",
+ //"../data/models/ISS_stationary.glb",
};
int curModelIndex = 0;
@@ -68,6 +74,7 @@ namespace deferred {
uiImage.CreateView (VkImageViewType.ImageView2D, VkImageAspectFlags.Color);
uiImage.CreateSampler (VkFilter.Nearest, VkFilter.Nearest, VkSamplerMipmapMode.Nearest, VkSamplerAddressMode.ClampToBorder);
uiImage.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
+ uiImage.SetName ("uiImage");
}
void vkvgDraw () {
@@ -103,7 +110,7 @@ namespace deferred {
ctx.ShowText (string.Format ($"Gamma: {renderer.matrices.gamma,5} "));
y += dy;
ctx.MoveTo (x, y);
- ctx.ShowText (string.Format ($"Light pos: {renderer.lightPos.ToString ()} "));
+ ctx.ShowText (string.Format ($"Light pos: {renderer.lights[0].position.ToString ()} "));
y += dy;
ctx.MoveTo (x, y);
ctx.ShowText (string.Format ($"{"Debug draw (numpad 0->9)",-30} : {renderer.currentDebugView.ToString ()} "));
@@ -180,8 +187,8 @@ namespace deferred {
}
#endif
- Program () {
- camera = new Camera (Utils.DegreesToRadians (45f), 1f, 0.1f, 256f);
+ Program () : base(true) {
+ camera = new Camera (Utils.DegreesToRadians (45f), 1f, 0.1f, 16f);
camera.SetPosition (0, 0, 2);
#if WITH_VKVG
@@ -205,7 +212,12 @@ namespace deferred {
public override void UpdateView () {
renderer.UpdateView (camera);
updateViewRequested = false;
+#if WITH_SHADOWS
+ if (renderer.shadowMapRenderer.updateShadowMap)
+ renderer.shadowMapRenderer.update_shadow_map (cmdPool);
+#endif
}
+
public override void Update () {
if (reloadModel) {
renderer.LoadModel (transferQ, modelPathes[curModelIndex]);
@@ -213,27 +225,31 @@ namespace deferred {
camera.Model = Matrix4x4.CreateScale (1f / Math.Max (Math.Max (renderer.modelAABB.Width, renderer.modelAABB.Height), renderer.modelAABB.Depth));
updateViewRequested = true;
rebuildBuffers = true;
+#if WITH_SHADOWS
+ renderer.shadowMapRenderer.updateShadowMap = true;
+#endif
}
+
if (rebuildBuffers) {
buildCommandBuffers ();
rebuildBuffers = false;
}
- #if WITH_VKVG
+#if WITH_VKVG
vkvgDraw ();
- #endif
+#endif
}
protected override void OnResize () {
- #if WITH_VKVG
+#if WITH_VKVG
initUISurface ();
renderer.WriteUiImgDesciptor (uiImage);
- #endif
+#endif
UpdateView ();
renderer.Resize ();
buildCommandBuffers ();
}
- #region Mouse and keyboard
+#region Mouse and keyboard
protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) {
switch (key) {
case Key.F:
@@ -243,7 +259,7 @@ namespace deferred {
renderer.envCube.debugFace = 5;
} else {
renderer.envCube.debugFace++;
- if (renderer.envCube.debugFace > 5)
+ if (renderer.envCube.debugFace >= 5)
renderer.envCube.debugFace = 0;
}
rebuildBuffers = true;
@@ -255,11 +271,23 @@ namespace deferred {
renderer.envCube.debugMip = (int)renderer.envCube.prefilterCube.CreateInfo.mipLevels - 1;
} else {
renderer.envCube.debugMip++;
- if (renderer.envCube.debugMip > renderer.envCube.prefilterCube.CreateInfo.mipLevels)
+ if (renderer.envCube.debugMip >= renderer.envCube.prefilterCube.CreateInfo.mipLevels)
renderer.envCube.debugMip = 0;
}
rebuildBuffers = true;
break;
+ case Key.L:
+ if (modifiers.HasFlag (Modifier.Shift)) {
+ renderer.lightNumDebug--;
+ if (renderer.lightNumDebug < 0)
+ renderer.lightNumDebug = (int)renderer.lights.Length - 1;
+ } else {
+ renderer.lightNumDebug++;
+ if (renderer.lightNumDebug >= renderer.lights.Length)
+ renderer.lightNumDebug = 0;
+ }
+ rebuildBuffers = true;
+ break;
case Key.Keypad0:
case Key.Keypad1:
case Key.Keypad2:
@@ -277,39 +305,48 @@ namespace deferred {
renderer.currentDebugView = DeferredPbrRenderer.DebugView.irradiance;
rebuildBuffers = true;
break;
+ case Key.S:
+ if (modifiers.HasFlag (Modifier.Control)) {
+ renderer.pipelineCache.Save ();
+ Console.WriteLine ($"Pipeline Cache saved.");
+ } else {
+ renderer.currentDebugView = DeferredPbrRenderer.DebugView.shadowMap;
+ rebuildBuffers = true;
+ }
+ break;
case Key.Up:
if (modifiers.HasFlag (Modifier.Shift))
- renderer.lightPos -= Vector4.UnitZ;
+ renderer.MoveLight(-Vector4.UnitZ);
else
camera.Move (0, 0, 1);
break;
case Key.Down:
if (modifiers.HasFlag (Modifier.Shift))
- renderer.lightPos += Vector4.UnitZ;
+ renderer.MoveLight (Vector4.UnitZ);
else
camera.Move (0, 0, -1);
break;
case Key.Left:
if (modifiers.HasFlag (Modifier.Shift))
- renderer.lightPos -= Vector4.UnitX;
+ renderer.MoveLight (-Vector4.UnitX);
else
camera.Move (1, 0, 0);
break;
case Key.Right:
if (modifiers.HasFlag (Modifier.Shift))
- renderer.lightPos += Vector4.UnitX;
+ renderer.MoveLight (Vector4.UnitX);
else
camera.Move (-1, 0, 0);
break;
case Key.PageUp:
if (modifiers.HasFlag (Modifier.Shift))
- renderer.lightPos += Vector4.UnitY;
+ renderer.MoveLight (Vector4.UnitY);
else
camera.Move (0, 1, 0);
break;
case Key.PageDown:
if (modifiers.HasFlag (Modifier.Shift))
- renderer.lightPos -= Vector4.UnitY;
+ renderer.MoveLight (-Vector4.UnitY);
else
camera.Move (0, -1, 0);
break;
@@ -332,10 +369,6 @@ namespace deferred {
camera.Type = Camera.CamType.FirstPerson;
Console.WriteLine ($"camera type = {camera.Type}");
break;
- case Key.S:
- renderer.pipelineCache.Save ();
- Console.WriteLine ($"Pipeline Cache saved.");
- break;
case Key.KeypadAdd:
curModelIndex++;
if (curModelIndex >= modelPathes.Length)
@@ -354,17 +387,17 @@ namespace deferred {
}
updateViewRequested = true;
}
- #endregion
+#endregion
protected override void Dispose (bool disposing) {
if (disposing) {
if (!isDisposed) {
renderer.Dispose ();
- #if WITH_VKVG
+#if WITH_VKVG
uiImage?.Dispose ();
vkvgSurf?.Dispose ();
vkvgDev.Dispose ();
- #endif
+#endif
}
}
diff --git a/samples/deferred/shaders/GBuffPbr.frag b/samples/deferred/shaders/GBuffPbr.frag
index 1375af4..27182d6 100644
--- a/samples/deferred/shaders/GBuffPbr.frag
+++ b/samples/deferred/shaders/GBuffPbr.frag
@@ -213,10 +213,10 @@ void main()
ao = texture(aoMap, inUV1).r;
vec3 n = getNormal();
- vec3 v = ubo.camPos.xyz - inWorldPos;
+ vec3 p = inWorldPos;
outColorRough = vec4 (baseColor.rgb, perceptualRoughness);
outEmitMetal = vec4 (emissive, metallic);
outN_AO = vec4 (n, ao);
- outPos = vec4 (v, linearDepth(gl_FragCoord.z));
+ outPos = vec4 (p, linearDepth(gl_FragCoord.z));
} \ No newline at end of file
diff --git a/samples/deferred/shaders/compose.frag b/samples/deferred/shaders/compose.frag
index 95da239..4b5c205 100644
--- a/samples/deferred/shaders/compose.frag
+++ b/samples/deferred/shaders/compose.frag
@@ -18,6 +18,7 @@ layout (constant_id = 0) const uint NUM_LIGHTS = 1;
struct Light {
vec4 position;
vec4 color;
+ mat4 mvp;
};
layout (set = 0, binding = 4) uniform UBOLights {
@@ -67,7 +68,7 @@ vec3 getIBLContribution(PBRInfo pbrInputs, vec3 n, vec3 reflection)
float lod = (pbrInputs.perceptualRoughness * ubo.prefilteredCubeMipLevels);
// retrieve a scale and bias to F0. See [1], Figure 3
vec3 brdf = (texture(samplerBRDFLUT, vec2(pbrInputs.NdotV, 1.0 - pbrInputs.perceptualRoughness))).rgb;
- vec3 diffuseLight = texture(samplerIrradiance, n).rgb;
+ vec3 diffuseLight = texture(samplerIrradiance, reflection).rgb;
vec3 specularLight = textureLod(prefilteredMap, reflection, lod).rgb;
@@ -166,13 +167,15 @@ void main()
vec3 specularEnvironmentR90 = vec3(1.0) * reflectance90;
vec3 n = subpassLoad(samplerN_AO, gl_SampleID).rgb;
- vec3 v = subpassLoad(samplerPos, gl_SampleID).rgb; // Vector from surface point to camera
+ vec3 pos = subpassLoad(samplerPos, gl_SampleID).rgb;
+ vec3 v = normalize(ubo.camPos.xyz - pos); // Vector from surface point to camera
vec3 colors = vec3(0);
+ vec3 lightTarget = vec3(0);
for (int i=0; i<NUM_LIGHTS; i++) {
- vec3 l = normalize(lights[i].position.xyz); // Vector from surface point to light
+ vec3 l = normalize(lights[i].position.xyz-pos); // Vector from surface point to light
vec3 h = normalize(l+v); // Half vector between both l and v
vec3 reflection = -normalize(reflect(v, n));
reflection.y *= -1.0f;
@@ -208,9 +211,10 @@ void main()
vec3 specContrib = F * G * D / (4.0 * NdotL * NdotV);
// Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law)
vec3 color = NdotL * lights[i].color.rgb * (diffuseContrib + specContrib);
-
// Calculate lighting contribution from image based lighting source (IBL)
- colors += color + getIBLContribution(pbrInputs, n, reflection);
+ colors += (color + getIBLContribution(pbrInputs, n, reflection));
+
+
}
colors /= NUM_LIGHTS;
diff --git a/samples/deferred/shaders/compose_with_shadows.frag b/samples/deferred/shaders/compose_with_shadows.frag
new file mode 100644
index 0000000..e3294ae
--- /dev/null
+++ b/samples/deferred/shaders/compose_with_shadows.frag
@@ -0,0 +1,277 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout (set = 0, binding = 0) uniform UBO {
+ mat4 projection;
+ mat4 model;
+ mat4 view;
+ vec4 camPos;
+ float exposure;
+ float gamma;
+ float prefilteredCubeMipLevels;
+ float scaleIBLAmbient;
+} ubo;
+
+layout (constant_id = 0) const uint NUM_LIGHTS = 1;
+
+struct Light {
+ vec4 position;
+ vec4 color;
+ mat4 mvp;
+};
+
+layout (set = 0, binding = 4) uniform UBOLights {
+ Light lights[NUM_LIGHTS];
+};
+
+const float M_PI = 3.141592653589793;
+const float c_MinRoughness = 0.04;
+#define SHADOW_FACTOR 0.55
+
+layout (input_attachment_index = 0, set = 2, binding = 0) uniform subpassInputMS samplerColorRough;
+layout (input_attachment_index = 1, set = 2, binding = 1) uniform subpassInputMS samplerEmitMetal;
+layout (input_attachment_index = 2, set = 2, binding = 2) uniform subpassInputMS samplerN_AO;
+layout (input_attachment_index = 3, set = 2, binding = 3) uniform subpassInputMS samplerPos;
+
+layout (set = 0, binding = 1) uniform samplerCube samplerIrradiance;
+layout (set = 0, binding = 2) uniform samplerCube prefilteredMap;
+layout (set = 0, binding = 3) uniform sampler2D samplerBRDFLUT;
+layout (set = 0, binding = 7) uniform sampler2DArray samplerShadowMap;
+
+layout (location = 0) in vec2 inUV;
+
+layout (location = 0) out vec4 outColor;
+
+// Encapsulate the various inputs used by the various functions in the shading equation
+// We store values in this struct to simplify the integration of alternative implementations
+// of the shading terms, outlined in the Readme.MD Appendix.
+struct PBRInfo
+{
+ float NdotL; // cos angle between normal and light direction
+ float NdotV; // cos angle between normal and view direction
+ float NdotH; // cos angle between normal and half vector
+ float LdotH; // cos angle between light direction and half vector
+ float VdotH; // cos angle between view direction and half vector
+ float perceptualRoughness; // roughness value, as authored by the model creator (input to shader)
+ float metalness; // metallic value at the surface
+ vec3 reflectance0; // full reflectance color (normal incidence angle)
+ vec3 reflectance90; // reflectance color at grazing angle
+ float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2])
+ vec3 diffuseColor; // color contribution from diffuse lighting
+ vec3 specularColor; // color contribution from specular lighting
+};
+
+// Calculation of the lighting contribution from an optional Image Based Light source.
+// Precomputed Environment Maps are required uniform inputs and are computed as outlined in [1].
+// See our README.md on Environment Maps [3] for additional discussion.
+vec3 getIBLContribution(PBRInfo pbrInputs, vec3 n, vec3 reflection)
+{
+ float lod = (pbrInputs.perceptualRoughness * ubo.prefilteredCubeMipLevels);
+ // retrieve a scale and bias to F0. See [1], Figure 3
+ vec3 brdf = (texture(samplerBRDFLUT, vec2(pbrInputs.NdotV, 1.0 - pbrInputs.perceptualRoughness))).rgb;
+ vec3 diffuseLight = texture(samplerIrradiance, reflection).rgb;
+
+ vec3 specularLight = textureLod(prefilteredMap, reflection, lod).rgb;
+
+ vec3 diffuse = diffuseLight * pbrInputs.diffuseColor;
+ vec3 specular = specularLight * (pbrInputs.specularColor * brdf.x + brdf.y);
+
+ // For presentation, this allows us to disable IBL terms
+ // For presentation, this allows us to disable IBL terms
+ diffuse *= ubo.scaleIBLAmbient;
+ specular *= ubo.scaleIBLAmbient;
+
+ return diffuse + specular;
+}
+
+// Basic Lambertian diffuse
+// Implementation from Lambert's Photometria https://archive.org/details/lambertsphotome00lambgoog
+// See also [1], Equation 1
+vec3 diffuse(PBRInfo pbrInputs)
+{
+ return pbrInputs.diffuseColor / M_PI;
+}
+
+// The following equation models the Fresnel reflectance term of the spec equation (aka F())
+// Implementation of fresnel from [4], Equation 15
+vec3 specularReflection(PBRInfo pbrInputs)
+{
+ return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0);
+}
+
+// This calculates the specular geometric attenuation (aka G()),
+// where rougher material will reflect less light back to the viewer.
+// This implementation is based on [1] Equation 4, and we adopt their modifications to
+// alphaRoughness as input as originally proposed in [2].
+float geometricOcclusion(PBRInfo pbrInputs)
+{
+ float NdotL = pbrInputs.NdotL;
+ float NdotV = pbrInputs.NdotV;
+ float r = pbrInputs.alphaRoughness;
+
+ float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL)));
+ float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV)));
+ return attenuationL * attenuationV;
+}
+
+// The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D())
+// Implementation from "Average Irregularity Representation of a Roughened Surface for Ray Reflection" by T. S. Trowbridge, and K. P. Reitz
+// Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games [1], Equation 3.
+float microfacetDistribution(PBRInfo pbrInputs)
+{
+ float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness;
+ float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0;
+ return roughnessSq / (M_PI * f * f);
+}
+
+// Gets metallic factor from specular glossiness workflow inputs
+float convertMetallic(vec3 diffuse, vec3 specular, float maxSpecular) {
+ float perceivedDiffuse = sqrt(0.299 * diffuse.r * diffuse.r + 0.587 * diffuse.g * diffuse.g + 0.114 * diffuse.b * diffuse.b);
+ float perceivedSpecular = sqrt(0.299 * specular.r * specular.r + 0.587 * specular.g * specular.g + 0.114 * specular.b * specular.b);
+ if (perceivedSpecular < c_MinRoughness) {
+ return 0.0;
+ }
+ float a = c_MinRoughness;
+ float b = perceivedDiffuse * (1.0 - maxSpecular) / (1.0 - c_MinRoughness) + perceivedSpecular - 2.0 * c_MinRoughness;
+ float c = c_MinRoughness - perceivedSpecular;
+ float D = max(b * b - 4.0 * a * c, 0.0);
+ return clamp((-b + sqrt(D)) / (2.0 * a), 0.0, 1.0);
+}
+
+float textureProj(vec4 P, float layer, vec2 offset)
+{
+ float shadow = 1.0;
+ vec4 shadowCoord = P / P.w;
+ shadowCoord.st = shadowCoord.st * 0.5 + 0.5;
+
+ if (shadowCoord.z > -1.0 && shadowCoord.z < 1.0)
+ {
+ float dist = texture(samplerShadowMap, vec3(shadowCoord.st + offset, layer)).r;
+ if (shadowCoord.w > 0.0 && dist < shadowCoord.z)
+ shadow = SHADOW_FACTOR;
+ }else
+ shadow = 0.05f;//for debug view out of light proj
+
+ return shadow;
+}
+
+float filterPCF(vec4 sc, float layer)
+{
+ ivec2 texDim = textureSize(samplerShadowMap, 0).xy;
+ float scale = 1.5;
+ float dx = scale * 1.0 / float(texDim.x);
+ float dy = scale * 1.0 / float(texDim.y);
+
+ float shadowFactor = 0.0;
+ int count = 0;
+ int range = 1;
+
+ for (int x = -range; x <= range; x++)
+ {
+ for (int y = -range; y <= range; y++)
+ {
+ shadowFactor += textureProj(sc, layer, vec2(dx*x, dy*y));
+ count++;
+ }
+
+ }
+ return shadowFactor / count;
+}
+
+void main()
+{
+ if (subpassLoad(samplerPos, gl_SampleID).a == 1.0f)
+ discard;
+
+ float perceptualRoughness = subpassLoad(samplerColorRough, gl_SampleID).a;
+ float metallic = subpassLoad(samplerEmitMetal, gl_SampleID).a;
+ vec3 diffuseColor;
+ vec4 baseColor = vec4(subpassLoad(samplerColorRough, gl_SampleID).rgb, 1);
+ vec3 emissive = subpassLoad (samplerEmitMetal, gl_SampleID).rgb;
+
+ vec3 f0 = vec3(0.04);
+
+ diffuseColor = baseColor.rgb * (vec3(1.0) - f0);
+ diffuseColor *= 1.0 - metallic;
+
+ float alphaRoughness = perceptualRoughness * perceptualRoughness;
+
+ vec3 specularColor = mix(f0, baseColor.rgb, metallic);
+
+ // Compute reflectance.
+ float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);
+
+ // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
+ // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
+ float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
+ vec3 specularEnvironmentR0 = specularColor.rgb;
+ vec3 specularEnvironmentR90 = vec3(1.0) * reflectance90;
+
+ vec3 n = subpassLoad(samplerN_AO, gl_SampleID).rgb;
+ vec3 pos = subpassLoad(samplerPos, gl_SampleID).rgb;
+ vec3 v = normalize(ubo.camPos.xyz - pos); // Vector from surface point to camera
+
+ vec3 colors = vec3(0);
+ vec3 lightTarget = vec3(0);
+
+ for (int i=0; i<NUM_LIGHTS; i++) {
+
+ vec3 l = normalize(lights[i].position.xyz-pos); // Vector from surface point to light
+ vec3 h = normalize(l+v); // Half vector between both l and v
+ vec3 reflection = -normalize(reflect(v, n));
+ reflection.y *= -1.0f;
+
+ float NdotL = clamp(dot(n, l), 0.001, 1.0);
+ float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
+ float NdotH = clamp(dot(n, h), 0.0, 1.0);
+ float LdotH = clamp(dot(l, h), 0.0, 1.0);
+ float VdotH = clamp(dot(v, h), 0.0, 1.0);
+
+ PBRInfo pbrInputs = PBRInfo(
+ NdotL,
+ NdotV,
+ NdotH,
+ LdotH,
+ VdotH,
+ perceptualRoughness,
+ metallic,
+ specularEnvironmentR0,
+ specularEnvironmentR90,
+ alphaRoughness,
+ diffuseColor,
+ specularColor
+ );
+
+ // Calculate the shading terms for the microfacet specular shading model
+ vec3 F = specularReflection(pbrInputs);
+ float G = geometricOcclusion(pbrInputs);
+ float D = microfacetDistribution(pbrInputs);
+
+ // Calculation of analytical lighting contribution
+ vec3 diffuseContrib = (1.0 - F) * diffuse(pbrInputs);
+ vec3 specContrib = F * G * D / (4.0 * NdotL * NdotV);
+ // Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law)
+ vec4 shadowClip = lights[i].mvp * vec4(pos, 1);
+ float shadowFactor = filterPCF(shadowClip, i);
+
+
+ vec3 color = NdotL * lights[i].color.rgb * (diffuseContrib + specContrib);
+
+ // Calculate lighting contribution from image based lighting source (IBL)
+ colors += shadowFactor * (color + getIBLContribution(pbrInputs, n, reflection));
+
+
+ }
+ colors /= NUM_LIGHTS;
+
+
+ const float u_OcclusionStrength = 1.0f;
+ const float u_EmissiveFactor = 1.0f;
+
+ //AO is in the alpha channel of the normalAttachment
+ colors = mix(colors, colors * subpassLoad(samplerN_AO, gl_SampleID).a, u_OcclusionStrength);
+ colors += emissive;
+
+ outColor = vec4(colors, baseColor.a);
+} \ No newline at end of file
diff --git a/samples/deferred/shaders/shadow.geom b/samples/deferred/shaders/shadow.geom
new file mode 100644
index 0000000..283586d
--- /dev/null
+++ b/samples/deferred/shaders/shadow.geom
@@ -0,0 +1,37 @@
+#version 420
+
+#define NUM_LIGHTS 2
+
+layout (triangles, invocations = NUM_LIGHTS) in;
+layout (triangle_strip, max_vertices = 3) out;
+
+struct Light {
+ vec4 position;
+ vec4 color;
+ mat4 mvp;
+};
+layout (set = 0, binding = 0) uniform UBO {
+ mat4 projection;
+ mat4 model;
+ mat4 view;
+};
+layout (set = 0, binding = 1) uniform UBOLights {
+ Light lights[NUM_LIGHTS];
+};
+
+//layout (location = 0) in int inInstanceIndex[];
+
+layout(push_constant) uniform PushConsts {
+ mat4 model;
+} pc;
+
+void main()
+{
+ for (int i = 0; i < gl_in.length(); i++)
+ {
+ gl_Layer = gl_InvocationID;
+ gl_Position = lights[gl_InvocationID].mvp * model * pc.model * gl_in[i].gl_Position;
+ EmitVertex();
+ }
+ EndPrimitive();
+} \ No newline at end of file
diff --git a/samples/deferred/shaders/shadow.vert b/samples/deferred/shaders/shadow.vert
new file mode 100644
index 0000000..548f093
--- /dev/null
+++ b/samples/deferred/shaders/shadow.vert
@@ -0,0 +1,8 @@
+#version 450
+
+layout (location = 0) in vec4 inPos;
+
+void main()
+{
+ gl_Position = inPos;
+} \ No newline at end of file
diff --git a/samples/deferred/shaders/show_gbuff.frag b/samples/deferred/shaders/show_gbuff.frag
index 9195fed..a494688 100644
--- a/samples/deferred/shaders/show_gbuff.frag
+++ b/samples/deferred/shaders/show_gbuff.frag
@@ -10,6 +10,7 @@ layout (input_attachment_index = 3, set = 2, binding = 3) uniform subpassInputMS
layout (set = 0, binding = 1) uniform samplerCube samplerIrradiance;
layout (set = 0, binding = 2) uniform samplerCube prefilteredMap;
layout (set = 0, binding = 3) uniform sampler2D samplerBRDFLUT;
+layout (set = 0, binding = 7) uniform sampler2DArray samplerShadowMap;
layout (push_constant) uniform PushCsts {
layout(offset = 64)
@@ -29,6 +30,7 @@ const uint roughness = 6;
const uint depth = 7;
const uint prefill = 8;
const uint irradiance = 9;
+const uint shadowMap = 10;
vec4 sampleCubeMap (samplerCube sc, uint face, uint lod) {
vec2 uv = 2.0 * inUV - vec2(1.0);
@@ -76,6 +78,10 @@ void main()
case depth:
outColor = vec4(subpassLoad(samplerPos, gl_SampleID).aaa, 1);
break;
+ case shadowMap:
+ vec3 d = texture(samplerShadowMap, vec3(inUV, bitfieldExtract (imgIdx, 8, 8))).rrr;
+ outColor = vec4(d*d*d, 1);
+ break;
default:
if (imgNum == prefill)
outColor = sampleCubeMap (prefilteredMap, bitfieldExtract (imgIdx, 8, 8), bitfieldExtract (imgIdx, 16, 8));
diff --git a/samples/deferred/shaders/tone_mapping.frag b/samples/deferred/shaders/tone_mapping.frag
index 14cc6ab..482ffba 100644
--- a/samples/deferred/shaders/tone_mapping.frag
+++ b/samples/deferred/shaders/tone_mapping.frag
@@ -2,6 +2,8 @@
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
+#define WITH_VKVG 0
+
layout (set = 0, binding = 0) uniform UBO {
mat4 projection;
mat4 model;
diff --git a/samples/deferred/shadowMapRenderer.cs b/samples/deferred/shadowMapRenderer.cs
new file mode 100644
index 0000000..e34b60f
--- /dev/null
+++ b/samples/deferred/shadowMapRenderer.cs
@@ -0,0 +1,155 @@
+/*shadow mapping greatly inspired from:
+* Vulkan Example - Deferred shading with shadows from multiple light sources using geometry shader instancing
+* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
+* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+*/
+using System;
+using System.Numerics;
+using System.Runtime.InteropServices;
+using CVKL;
+using VK;
+using static deferred.DeferredPbrRenderer;
+
+namespace deferred {
+ public class ShadowMapRenderer : IDisposable {
+ Device dev;
+
+ public static uint SHADOWMAP_SIZE = 4096;
+ public static VkFormat SHADOWMAP_FORMAT = VkFormat.D32SfloatS8Uint;
+ public static VkSampleCountFlags SHADOWMAP_NUM_SAMPLES = VkSampleCountFlags.SampleCount1;
+ public bool updateShadowMap = true;
+
+ public float depthBiasConstant = 1.5f;
+ public float depthBiasSlope = 1.75f;
+ float lightFOV = Utils.DegreesToRadians (60);
+ float lightFarPlane;
+
+
+
+ RenderPass shadowPass;
+ Framebuffer fbShadowMap;
+ public Image shadowMap { get; private set; }
+ Pipeline shadowPipeline;
+ DescriptorPool descriptorPool;
+ DescriptorSetLayout descLayoutShadow;
+ DescriptorSet dsShadow;
+ DeferredPbrRenderer renderer;
+
+ public ShadowMapRenderer (Device dev, DeferredPbrRenderer renderer, float farPlane = 16f) {
+ this.lightFarPlane = farPlane;
+ this.dev = dev;
+ this.renderer = renderer;
+
+ descriptorPool = new DescriptorPool (dev, 1,
+ new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer, 2)
+ );
+
+ init ();
+ }
+
+ void init () {
+
+ //Shadow map renderpass
+ shadowPass = new RenderPass (dev, VkSampleCountFlags.SampleCount1);
+ shadowPass.AddAttachment (SHADOWMAP_FORMAT, VkImageLayout.DepthStencilReadOnlyOptimal, SHADOWMAP_NUM_SAMPLES);
+ shadowPass.ClearValues.Add (new VkClearValue { depthStencil = new VkClearDepthStencilValue (1.0f, 0) });
+
+ SubPass subpass0 = new SubPass ();
+ subpass0.SetDepthReference (0);
+ shadowPass.AddSubpass (subpass0);
+
+ shadowPass.AddDependency (Vk.SubpassExternal, 0,
+ VkPipelineStageFlags.FragmentShader, VkPipelineStageFlags.EarlyFragmentTests,
+ VkAccessFlags.ShaderRead, VkAccessFlags.DepthStencilAttachmentWrite);
+ shadowPass.AddDependency (0, Vk.SubpassExternal,
+ VkPipelineStageFlags.LateFragmentTests, VkPipelineStageFlags.FragmentShader,
+ VkAccessFlags.DepthStencilAttachmentWrite, VkAccessFlags.ShaderRead);
+
+ descLayoutShadow = new DescriptorSetLayout (dev,
+ new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Geometry, VkDescriptorType.UniformBuffer),//matrices
+ new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Geometry, VkDescriptorType.UniformBuffer));//lights
+
+ GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList);
+ cfg.rasterizationState.cullMode = VkCullModeFlags.Back;
+ cfg.rasterizationState.depthBiasEnable = true;
+ cfg.dynamicStates.Add (VkDynamicState.DepthBias);
+
+ cfg.RenderPass = shadowPass;
+
+ cfg.Layout = new PipelineLayout (dev, descLayoutShadow);
+ cfg.Layout.AddPushConstants (
+ new VkPushConstantRange (VkShaderStageFlags.Geometry, (uint)Marshal.SizeOf<Matrix4x4> ())
+ );
+
+ cfg.AddVertexBinding<PbrModel.Vertex> (0);
+ cfg.SetVertexAttributes (0, VkFormat.R32g32b32Sfloat);
+
+ cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/shadow.vert.spv");
+ cfg.AddShader (VkShaderStageFlags.Geometry, "shaders/shadow.geom.spv");
+
+ shadowPipeline = new GraphicPipeline (cfg);
+
+ //shadow map image
+ shadowMap = new Image (dev, SHADOWMAP_FORMAT, VkImageUsageFlags.DepthStencilAttachment | VkImageUsageFlags.Sampled, VkMemoryPropertyFlags.DeviceLocal, SHADOWMAP_SIZE, SHADOWMAP_SIZE,
+ VkImageType.Image2D, SHADOWMAP_NUM_SAMPLES, VkImageTiling.Optimal, 1, (uint)renderer.lights.Length);
+ shadowMap.CreateView (VkImageViewType.ImageView2DArray, VkImageAspectFlags.Depth, shadowMap.CreateInfo.arrayLayers);
+ shadowMap.CreateSampler (VkSamplerAddressMode.ClampToBorder);
+ shadowMap.Descriptor.imageLayout = VkImageLayout.DepthStencilReadOnlyOptimal;
+
+ fbShadowMap = new Framebuffer (shadowPass, SHADOWMAP_SIZE, SHADOWMAP_SIZE, (uint)renderer.lights.Length);
+ fbShadowMap.attachments.Add (shadowMap);
+ fbShadowMap.Activate ();
+
+ dsShadow = descriptorPool.Allocate (descLayoutShadow);
+
+ DescriptorSetWrites dsWrite = new DescriptorSetWrites (dsShadow, descLayoutShadow);
+ dsWrite.Write (dev, renderer.uboMatrices.Descriptor, renderer.uboLights.Descriptor);
+ }
+
+ public void update_light_matrices () {
+ Matrix4x4 proj = Matrix4x4.CreatePerspectiveFieldOfView (lightFOV, 1, 0.1f, lightFarPlane);
+ for (int i = 0; i < renderer.lights.Length; i++) {
+ Matrix4x4 view = Matrix4x4.CreateLookAt (renderer.lights[i].position.ToVector3 (), Vector3.Zero, Vector3.UnitY);
+ renderer.lights[i].mvp = view * proj;
+ }
+ renderer.uboLights.Update (renderer.lights);
+ dev.WaitIdle ();
+ }
+
+ public void update_shadow_map (CommandPool cmdPool) {
+ update_light_matrices ();
+
+ CommandBuffer cmd = cmdPool.AllocateAndStart ();
+
+ shadowPass.Begin (cmd, fbShadowMap);
+
+ cmd.SetViewport (SHADOWMAP_SIZE, SHADOWMAP_SIZE);
+ cmd.SetScissor (SHADOWMAP_SIZE, SHADOWMAP_SIZE);
+
+ cmd.BindDescriptorSet (shadowPipeline.Layout, dsShadow);
+
+ Vk.vkCmdSetDepthBias (cmd.Handle, depthBiasConstant, 0.0f, depthBiasSlope);
+
+ shadowPipeline.Bind (cmd);
+
+ if (renderer.model != null) {
+ renderer.model.Bind (cmd);
+ renderer.model.DrawAll (cmd, shadowPipeline.Layout, true);
+ }
+
+ shadowPass.End (cmd);
+
+ renderer.presentQueue.EndSubmitAndWait (cmd);
+ updateShadowMap = false;
+ }
+
+
+ public void Dispose () {
+ shadowPipeline?.Dispose ();
+ fbShadowMap?.Dispose ();
+ shadowPass?.Dispose ();
+ shadowMap?.Dispose ();
+ descriptorPool?.Dispose ();
+ }
+ }
+}
diff --git a/spirv.xml b/spirv.xml
index f1d94ee..9635ad6 100644
--- a/spirv.xml
+++ b/spirv.xml
@@ -2,6 +2,8 @@
<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties">
<ItemType Name="GLSLShader" DisplayName="GLSL Shader" />
<ContentType Name="GLSLShader" ItemType="GLSLShader" DisplayName="GLSL Shader" />
+ <FileExtension Name=".comp" ContentType="GLSLShader" />
+ <FileExtension Name=".geom" ContentType="GLSLShader" />
<FileExtension Name=".frag" ContentType="GLSLShader" />
<FileExtension Name=".vert" ContentType="GLSLShader" />
</ProjectSchemaDefinitions>
diff --git a/vke/src/DescriptorSetLayout.cs b/vke/src/DescriptorSetLayout.cs
index 5a05773..573064b 100644
--- a/vke/src/DescriptorSetLayout.cs
+++ b/vke/src/DescriptorSetLayout.cs
@@ -48,8 +48,7 @@ namespace CVKL {
public DescriptorSetLayout (Device device, VkDescriptorSetLayoutCreateFlags flags, params VkDescriptorSetLayoutBinding[] bindings)
: this (device, flags) {
foreach (VkDescriptorSetLayoutBinding b in bindings)
- Bindings.Add (b);
- Activate ();
+ Bindings.Add (b);
}
#endregion
diff --git a/vke/src/Device.cs b/vke/src/Device.cs
index 9c8700c..1460c81 100644
--- a/vke/src/Device.cs
+++ b/vke/src/Device.cs
@@ -33,180 +33,180 @@ using static VK.Vk;
namespace CVKL {
- public class Device : IDisposable {
- public readonly PhysicalDevice phy;
+ public class Device : IDisposable {
+ public readonly PhysicalDevice phy;
public readonly bool DebugMarkersEnabled;
- VkDevice dev;
- public VkDevice VkDev => dev;
+ VkDevice dev;
+ public VkDevice VkDev => dev;
- internal List<Queue> queues = new List<Queue> ();
+ internal List<Queue> queues = new List<Queue> ();
public ResourceManager resourceManager;
- public Device (PhysicalDevice _phy, bool enableDebugMarkers = false) {
- phy = _phy;
+ public Device (PhysicalDevice _phy, bool enableDebugMarkers = false) {
+ phy = _phy;
DebugMarkersEnabled = enableDebugMarkers;
- }
+ }
- public void Activate (VkPhysicalDeviceFeatures enabledFeatures, params string[] extensions) {
- List<VkDeviceQueueCreateInfo> qInfos = new List<VkDeviceQueueCreateInfo> ();
+ public void Activate (VkPhysicalDeviceFeatures enabledFeatures, params string[] extensions) {
+ List<VkDeviceQueueCreateInfo> qInfos = new List<VkDeviceQueueCreateInfo> ();
List<List<float>> prioritiesLists = new List<List<float>> ();//store pinned lists for later unpin
- foreach (IGrouping<uint, Queue> qfams in queues.GroupBy (q => q.qFamIndex)) {
- int qTot = qfams.Count ();
- uint qIndex = 0;
- List<float>priorities = new List<float> ();
- bool qCountReached = false;//true when queue count of that family is reached
+ foreach (IGrouping<uint, Queue> qfams in queues.GroupBy (q => q.qFamIndex)) {
+ int qTot = qfams.Count ();
+ uint qIndex = 0;
+ List<float> priorities = new List<float> ();
+ bool qCountReached = false;//true when queue count of that family is reached
- foreach (Queue q in qfams) {
- if (!qCountReached)
- priorities.Add (q.priority);
- q.index = qIndex++;
- if (qIndex == phy.QueueFamilies[qfams.Key].queueCount) {
- qIndex = 0;
- qCountReached = true;
- }
- }
+ foreach (Queue q in qfams) {
+ if (!qCountReached)
+ priorities.Add (q.priority);
+ q.index = qIndex++;
+ if (qIndex == phy.QueueFamilies[qfams.Key].queueCount) {
+ qIndex = 0;
+ qCountReached = true;
+ }
+ }
- qInfos.Add (new VkDeviceQueueCreateInfo {
- sType = VkStructureType.DeviceQueueCreateInfo,
- queueCount = qCountReached ? phy.QueueFamilies[qfams.Key].queueCount : qIndex,
- queueFamilyIndex = qfams.Key,
- pQueuePriorities = priorities.Pin ()
- });
+ qInfos.Add (new VkDeviceQueueCreateInfo {
+ sType = VkStructureType.DeviceQueueCreateInfo,
+ queueCount = qCountReached ? phy.QueueFamilies[qfams.Key].queueCount : qIndex,
+ queueFamilyIndex = qfams.Key,
+ pQueuePriorities = priorities.Pin ()
+ });
prioritiesLists.Add (priorities);//add for unpined
- }
+ }
- List<IntPtr> deviceExtensions = new List<IntPtr> ();
- if (DebugMarkersEnabled && !extensions.Contains(Ext.D.VK_EXT_debug_marker))
+ List<IntPtr> deviceExtensions = new List<IntPtr> ();
+ if (DebugMarkersEnabled && !extensions.Contains (Ext.D.VK_EXT_debug_marker))
deviceExtensions.Add (new FixedUtf8String (Ext.D.VK_EXT_debug_marker));
- for (int i = 0; i < extensions.Length; i++)
- deviceExtensions.Add (new FixedUtf8String(extensions[i]));
-
- VkDeviceCreateInfo deviceCreateInfo = VkDeviceCreateInfo.New();
- deviceCreateInfo.queueCreateInfoCount = (uint)qInfos.Count;
- deviceCreateInfo.pQueueCreateInfos = qInfos.Pin();
- deviceCreateInfo.pEnabledFeatures = enabledFeatures.Pin ();
-
- if (deviceExtensions.Count > 0) {
- deviceCreateInfo.enabledExtensionCount = (uint)deviceExtensions.Count;
- deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.Pin();
- }
+ for (int i = 0; i < extensions.Length; i++)
+ deviceExtensions.Add (new FixedUtf8String (extensions[i]));
+
+ VkDeviceCreateInfo deviceCreateInfo = VkDeviceCreateInfo.New ();
+ deviceCreateInfo.queueCreateInfoCount = (uint)qInfos.Count;
+ deviceCreateInfo.pQueueCreateInfos = qInfos.Pin ();
+ deviceCreateInfo.pEnabledFeatures = enabledFeatures.Pin ();
- Utils.CheckResult (vkCreateDevice (phy.Handle, ref deviceCreateInfo, IntPtr.Zero, out dev));
- qInfos.Unpin ();
+ if (deviceExtensions.Count > 0) {
+ deviceCreateInfo.enabledExtensionCount = (uint)deviceExtensions.Count;
+ deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.Pin ();
+ }
+
+ Utils.CheckResult (vkCreateDevice (phy.Handle, ref deviceCreateInfo, IntPtr.Zero, out dev));
+ qInfos.Unpin ();
enabledFeatures.Unpin ();
- foreach (List<float> fa in prioritiesLists)
+ foreach (List<float> fa in prioritiesLists)
fa.Unpin ();
- deviceExtensions.Unpin ();
+ deviceExtensions.Unpin ();
//Vk.LoadDeviceFunctionPointers (dev);
- foreach (Queue q in queues)
- q.updateHandle ();
+ foreach (Queue q in queues)
+ q.updateHandle ();
resourceManager = new ResourceManager (this);
- }
+ }
- public VkSemaphore CreateSemaphore () {
- VkSemaphore tmp;
- VkSemaphoreCreateInfo info = VkSemaphoreCreateInfo.New();
- Utils.CheckResult (vkCreateSemaphore (dev, ref info, IntPtr.Zero, out tmp));
- return tmp;
- }
- public void DestroySemaphore (VkSemaphore semaphore) {
- vkDestroySemaphore (dev, semaphore, IntPtr.Zero);
- }
- public VkFence CreateFence (bool signaled = false) {
- VkFence tmp;
- VkFenceCreateInfo info = VkFenceCreateInfo.New();
- info.flags = signaled ? VkFenceCreateFlags.Signaled : 0;
- Utils.CheckResult (vkCreateFence (dev, ref info, IntPtr.Zero, out tmp));
- return tmp;
- }
- public void DestroyFence (VkFence fence) {
- vkDestroyFence (dev, fence, IntPtr.Zero);
- }
- public void WaitForFence (VkFence fence, ulong timeOut = UInt64.MaxValue) {
- vkWaitForFences (dev, 1, ref fence, 1, timeOut);
- }
- public void ResetFence (VkFence fence) {
- vkResetFences (dev, 1, ref fence);
- }
- public void WaitForFences (NativeList<VkFence> fences, ulong timeOut = UInt64.MaxValue) {
- vkWaitForFences (dev, fences.Count, fences.Data, 1, timeOut);
- }
- public void ResetFences (NativeList<VkFence> fences) {
- vkResetFences (dev, fences.Count, fences.Data);
- }
+ public VkSemaphore CreateSemaphore () {
+ VkSemaphore tmp;
+ VkSemaphoreCreateInfo info = VkSemaphoreCreateInfo.New ();
+ Utils.CheckResult (vkCreateSemaphore (dev, ref info, IntPtr.Zero, out tmp));
+ return tmp;
+ }
+ public void DestroySemaphore (VkSemaphore semaphore) {
+ vkDestroySemaphore (dev, semaphore, IntPtr.Zero);
+ }
+ public VkFence CreateFence (bool signaled = false) {
+ VkFence tmp;
+ VkFenceCreateInfo info = VkFenceCreateInfo.New ();
+ info.flags = signaled ? VkFenceCreateFlags.Signaled : 0;
+ Utils.CheckResult (vkCreateFence (dev, ref info, IntPtr.Zero, out tmp));
+ return tmp;
+ }
+ public void DestroyFence (VkFence fence) {
+ vkDestroyFence (dev, fence, IntPtr.Zero);
+ }
+ public void WaitForFence (VkFence fence, ulong timeOut = UInt64.MaxValue) {
+ vkWaitForFences (dev, 1, ref fence, 1, timeOut);
+ }
+ public void ResetFence (VkFence fence) {
+ vkResetFences (dev, 1, ref fence);
+ }
+ public void WaitForFences (NativeList<VkFence> fences, ulong timeOut = UInt64.MaxValue) {
+ vkWaitForFences (dev, fences.Count, fences.Data, 1, timeOut);
+ }
+ public void ResetFences (NativeList<VkFence> fences) {
+ vkResetFences (dev, fences.Count, fences.Data);
+ }
- public void DestroyShaderModule (VkShaderModule module) {
- vkDestroyShaderModule (VkDev, module, IntPtr.Zero);
- }
- public void WaitIdle () {
- Utils.CheckResult(vkDeviceWaitIdle (dev));
- }
- public VkRenderPass CreateRenderPass (VkRenderPassCreateInfo info) {
- VkRenderPass renderPass;
- Utils.CheckResult (vkCreateRenderPass (dev, ref info, IntPtr.Zero, out renderPass));
- return renderPass;
- }
- internal VkSwapchainKHR CreateSwapChain (VkSwapchainCreateInfoKHR infos) {
- VkSwapchainKHR newSwapChain;
- Utils.CheckResult (vkCreateSwapchainKHR (dev, ref infos, IntPtr.Zero, out newSwapChain));
- return newSwapChain;
- }
- internal void DestroySwapChain (VkSwapchainKHR swapChain) {
- vkDestroySwapchainKHR (dev, swapChain, IntPtr.Zero);
- }
- unsafe public VkImage[] GetSwapChainImages (VkSwapchainKHR swapchain) {
- uint imageCount = 0;
- Utils.CheckResult (vkGetSwapchainImagesKHR (dev, swapchain, out imageCount, IntPtr.Zero));
- if (imageCount == 0)
- throw new Exception ("Swapchain image count is 0.");
- VkImage[] imgs = new VkImage[imageCount];
-
- Utils.CheckResult (vkGetSwapchainImagesKHR (dev, swapchain, out imageCount, imgs.Pin()));
+ public void DestroyShaderModule (VkShaderModule module) {
+ vkDestroyShaderModule (VkDev, module, IntPtr.Zero);
+ }
+ public void WaitIdle () {
+ Utils.CheckResult (vkDeviceWaitIdle (dev));
+ }
+ public VkRenderPass CreateRenderPass (VkRenderPassCreateInfo info) {
+ VkRenderPass renderPass;
+ Utils.CheckResult (vkCreateRenderPass (dev, ref info, IntPtr.Zero, out renderPass));
+ return renderPass;
+ }
+ internal VkSwapchainKHR CreateSwapChain (VkSwapchainCreateInfoKHR infos) {
+ VkSwapchainKHR newSwapChain;
+ Utils.CheckResult (vkCreateSwapchainKHR (dev, ref infos, IntPtr.Zero, out newSwapChain));
+ return newSwapChain;
+ }
+ internal void DestroySwapChain (VkSwapchainKHR swapChain) {
+ vkDestroySwapchainKHR (dev, swapChain, IntPtr.Zero);
+ }
+ unsafe public VkImage[] GetSwapChainImages (VkSwapchainKHR swapchain) {
+ uint imageCount = 0;
+ Utils.CheckResult (vkGetSwapchainImagesKHR (dev, swapchain, out imageCount, IntPtr.Zero));
+ if (imageCount == 0)
+ throw new Exception ("Swapchain image count is 0.");
+ VkImage[] imgs = new VkImage[imageCount];
+
+ Utils.CheckResult (vkGetSwapchainImagesKHR (dev, swapchain, out imageCount, imgs.Pin ()));
imgs.Unpin ();
-
- return imgs;
- }
- unsafe public VkImageView CreateImageView (VkImage image, VkFormat format, VkImageViewType viewType = VkImageViewType.ImageView2D, VkImageAspectFlags aspectFlags = VkImageAspectFlags.Color) {
- VkImageView view;
- VkImageViewCreateInfo infos = VkImageViewCreateInfo.New();
- infos.image = image;
- infos.viewType = viewType;
- infos.format = format;
- infos.components = new VkComponentMapping { r = VkComponentSwizzle.R, g = VkComponentSwizzle.G, b = VkComponentSwizzle.B, a = VkComponentSwizzle.A };
- infos.subresourceRange = new VkImageSubresourceRange (aspectFlags);
-
- Utils.CheckResult (vkCreateImageView (dev, ref infos, IntPtr.Zero, out view));
- return view;
- }
- public void DestroyImageView (VkImageView view) {
- vkDestroyImageView (dev, view, IntPtr.Zero);
- }
- public void DestroySampler (VkSampler sampler) {
- vkDestroySampler (dev, sampler, IntPtr.Zero);
- }
- public void DestroyImage (VkImage img) {
- vkDestroyImage (dev, img, IntPtr.Zero);
- }
- public void DestroyFramebuffer (VkFramebuffer fb) {
- vkDestroyFramebuffer (dev, fb, IntPtr.Zero);
- }
- public void DestroyRenderPass (VkRenderPass rp) {
- vkDestroyRenderPass (dev, rp, IntPtr.Zero);
- }
- // This function is used to request a Device memory type that supports all the property flags we request (e.g. Device local, host visibile)
- // Upon success it will return the index of the memory type that fits our requestes memory properties
- // This is necessary as implementations can offer an arbitrary number of memory types with different
- // memory properties.
- // You can check http://vulkan.gpuinfo.org/ for details on different memory configurations
- internal uint GetMemoryTypeIndex (uint typeBits, VkMemoryPropertyFlags properties) {
+
+ return imgs;
+ }
+ unsafe public VkImageView CreateImageView (VkImage image, VkFormat format, VkImageViewType viewType = VkImageViewType.ImageView2D, VkImageAspectFlags aspectFlags = VkImageAspectFlags.Color) {
+ VkImageView view;
+ VkImageViewCreateInfo infos = VkImageViewCreateInfo.New ();
+ infos.image = image;
+ infos.viewType = viewType;
+ infos.format = format;
+ infos.components = new VkComponentMapping { r = VkComponentSwizzle.R, g = VkComponentSwizzle.G, b = VkComponentSwizzle.B, a = VkComponentSwizzle.A };
+ infos.subresourceRange = new VkImageSubresourceRange (aspectFlags);
+
+ Utils.CheckResult (vkCreateImageView (dev, ref infos, IntPtr.Zero, out view));
+ return view;
+ }
+ public void DestroyImageView (VkImageView view) {
+ vkDestroyImageView (dev, view, IntPtr.Zero);
+ }
+ public void DestroySampler (VkSampler sampler) {
+ vkDestroySampler (dev, sampler, IntPtr.Zero);
+ }
+ public void DestroyImage (VkImage img) {
+ vkDestroyImage (dev, img, IntPtr.Zero);
+ }
+ public void DestroyFramebuffer (VkFramebuffer fb) {
+ vkDestroyFramebuffer (dev, fb, IntPtr.Zero);
+ }
+ public void DestroyRenderPass (VkRenderPass rp) {
+ vkDestroyRenderPass (dev, rp, IntPtr.Zero);
+ }
+ // This function is used to request a Device memory type that supports all the property flags we request (e.g. Device local, host visibile)
+ // Upon success it will return the index of the memory type that fits our requestes memory properties
+ // This is necessary as implementations can offer an arbitrary number of memory types with different
+ // memory properties.
+ // You can check http://vulkan.gpuinfo.org/ for details on different memory configurations
+ internal uint GetMemoryTypeIndex (uint typeBits, VkMemoryPropertyFlags properties) {
// Iterate over all memory types available for the Device used in this example
for (uint i = 0; i < phy.memoryProperties.memoryTypeCount; i++) {
if ((typeBits & 1) == 1) {
diff --git a/vke/src/ExtensionMethods.cs b/vke/src/ExtensionMethods.cs
index bbe120e..632669b 100644
--- a/vke/src/ExtensionMethods.cs
+++ b/vke/src/ExtensionMethods.cs
@@ -49,6 +49,9 @@ namespace CVKL {
Vector4 v4 = Vector4.Transform (new Vector4 (v, translate ? 1f : 0f), mat);
return new Vector3 (v4.X, v4.Y, v4.Z);
}
+ public static Vector3 ToVector3 (this Vector4 v) {
+ return new Vector3 (v.X, v.Y, v.Z);
+ }
public static IntPtr Pin (this object obj) {
if (handles.ContainsKey (obj)) {
diff --git a/vke/src/Instance.cs b/vke/src/Instance.cs
index 7b7998d..06fcfe2 100644
--- a/vke/src/Instance.cs
+++ b/vke/src/Instance.cs
@@ -41,8 +41,10 @@ namespace CVKL {
public static FixedUtf8String VK_KHR_XLIB_SURFACE_EXTENSION_NAME = "VK_KHR_xlib_surface";
public static FixedUtf8String VK_KHR_SWAPCHAIN_EXTENSION_NAME = "VK_KHR_swapchain";
public static FixedUtf8String VK_EXT_DEBUG_REPORT_EXTENSION_NAME = "VK_EXT_debug_report";
- public static FixedUtf8String StandardValidationLayeName = "VK_LAYER_LUNARG_standard_validation";
- public static FixedUtf8String VkTraceLayeName = "VK_LAYER_LUNARG_vktrace";
+ public static FixedUtf8String VK_EXT_DEBUG_UTILS_EXTENSION_NAME = "VK_EXT_debug_utils";
+ public static FixedUtf8String LayerValidation = "VK_LAYER_KHRONOS_validation";
+ public static FixedUtf8String LayerMonitor = "VK_LAYER_LUNARG_monitor";
+ public static FixedUtf8String VkTraceLayeName = "VK_LAYER_LUNARG_vktrace";
public static FixedUtf8String RenderdocCaptureLayerName = "VK_LAYER_RENDERDOC_Capture";
public static FixedUtf8String main = "main";
}
@@ -80,8 +82,9 @@ namespace CVKL {
#if DEBUG
instanceExtensions.Add (Strings.VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
-
- enabledLayerNames.Add (Strings.StandardValidationLayeName);
+ instanceExtensions.Add (Strings.VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ enabledLayerNames.Add (Strings.LayerMonitor);
+ enabledLayerNames.Add (Strings.LayerValidation);
#if RENDERDOC
enabledLayerNames.Add (Strings.RenderdocCaptureLayerName);
#endif
diff --git a/vke/src/PbrModel.cs b/vke/src/PbrModel.cs
index 3965994..a92fbd9 100644
--- a/vke/src/PbrModel.cs
+++ b/vke/src/PbrModel.cs
@@ -158,6 +158,8 @@ namespace CVKL {
specularFactor = new Vector4 (0)
};
+ //materials[i].metallicFactor = 0.1f;
+ //materials[i].roughnessFactor = 0.9f;
descriptorSets[i] = descriptorPool.Allocate (layout);
descriptorSets[i].Handle.SetDebugMarkerName (dev, "descSet " + mats[i].Name);
@@ -210,29 +212,31 @@ namespace CVKL {
//TODO:destset for binding must be variable
//TODO: ADD REFAULT MAT IF NO MAT DEFINED
- public void RenderNode (CommandBuffer cmd, PipelineLayout pipelineLayout, Node node, Matrix4x4 currentTransform) {
+ public void RenderNode (CommandBuffer cmd, PipelineLayout pipelineLayout, Node node, Matrix4x4 currentTransform, bool shadowPass = false) {
Matrix4x4 localMat = node.localMatrix * currentTransform;
-
- cmd.PushConstant (pipelineLayout, VkShaderStageFlags.Vertex, localMat);
+ VkShaderStageFlags matStage = shadowPass ? VkShaderStageFlags.Geometry : VkShaderStageFlags.Vertex;
+ cmd.PushConstant (pipelineLayout, matStage, localMat);
if (node.Mesh != null) {
foreach (Primitive p in node.Mesh.Primitives) {
- cmd.PushConstant (pipelineLayout, VkShaderStageFlags.Fragment, (int)p.material, (uint)Marshal.SizeOf<Matrix4x4> ());
- if (descriptorSets[p.material] != null)
- cmd.BindDescriptorSet (pipelineLayout, descriptorSets[p.material], 1);
+ if (!shadowPass) {
+ cmd.PushConstant (pipelineLayout, VkShaderStageFlags.Fragment, (int)p.material, (uint)Marshal.SizeOf<Matrix4x4> ());
+ if (descriptorSets[p.material] != null)
+ cmd.BindDescriptorSet (pipelineLayout, descriptorSets[p.material], 1);
+ }
cmd.DrawIndexed (p.indexCount, 1, p.indexBase, p.vertexBase, 0);
}
}
if (node.Children == null)
return;
foreach (Node child in node.Children)
- RenderNode (cmd, pipelineLayout, child, localMat);
+ RenderNode (cmd, pipelineLayout, child, localMat, shadowPass);
}
- public void DrawAll (CommandBuffer cmd, PipelineLayout pipelineLayout) {
+ public void DrawAll (CommandBuffer cmd, PipelineLayout pipelineLayout, bool shadowPass = false) {
foreach (Scene sc in Scenes) {
foreach (Node node in sc.Root.Children) {
- RenderNode (cmd, pipelineLayout, node, sc.Root.localMatrix);
+ RenderNode (cmd, pipelineLayout, node, sc.Root.localMatrix, shadowPass);
}
}
}
diff --git a/vke/src/PhysicalDevice.cs b/vke/src/PhysicalDevice.cs
index 3ef7bcb..bf47ee7 100644
--- a/vke/src/PhysicalDevice.cs
+++ b/vke/src/PhysicalDevice.cs
@@ -77,12 +77,23 @@ namespace CVKL {
public class PhysicalDevice {
IntPtr phy;
- public VkPhysicalDeviceProperties deviceProperties { get; private set; }
- public VkPhysicalDeviceFeatures deviceFeatures { get; private set; }
public VkPhysicalDeviceMemoryProperties memoryProperties { get; private set; }
public VkQueueFamilyProperties[] QueueFamilies { get; private set; }
-
- public VkPhysicalDeviceLimits Limits => deviceProperties.limits;
+ public VkPhysicalDeviceProperties Properties {
+ get {
+ VkPhysicalDeviceProperties pdp;
+ vkGetPhysicalDeviceProperties (phy, out pdp);
+ return pdp;
+ }
+ }
+ public VkPhysicalDeviceFeatures Features {
+ get {
+ VkPhysicalDeviceFeatures df;
+ vkGetPhysicalDeviceFeatures (phy, out df);
+ return df;
+ }
+ }
+ public VkPhysicalDeviceLimits Limits => Properties.limits;
public bool HasSwapChainSupport { get; private set; }
public IntPtr Handle => phy;
@@ -93,14 +104,6 @@ namespace CVKL {
}
unsafe void init () {
- VkPhysicalDeviceProperties pdp;
- vkGetPhysicalDeviceProperties (phy, out pdp);
- deviceProperties = pdp;
-
- VkPhysicalDeviceFeatures df;
- vkGetPhysicalDeviceFeatures (phy, out df);
- deviceFeatures = df;
-
// Gather physical Device memory properties
IntPtr tmp = Marshal.AllocHGlobal (Marshal.SizeOf<VkPhysicalDeviceMemoryProperties>());
vkGetPhysicalDeviceMemoryProperties (phy, tmp);
diff --git a/vke/src/PipelineCache.cs b/vke/src/PipelineCache.cs
index fb69e99..c139696 100644
--- a/vke/src/PipelineCache.cs
+++ b/vke/src/PipelineCache.cs
@@ -94,7 +94,9 @@ namespace CVKL {
base.Activate ();
}
- protected override VkDebugMarkerObjectNameInfoEXT DebugMarkerInfo => throw new NotImplementedException ();
+ protected override VkDebugMarkerObjectNameInfoEXT DebugMarkerInfo
+ => new VkDebugMarkerObjectNameInfoEXT (VkDebugReportObjectTypeEXT.PipelineCacheEXT, handle.Handle);
+
public void Delete () {
string path = Path.Combine (globalConfigPath, cacheFile);
diff --git a/vke/src/PipelineLayout.cs b/vke/src/PipelineLayout.cs
index 263f303..1c59f90 100644
--- a/vke/src/PipelineLayout.cs
+++ b/vke/src/PipelineLayout.cs
@@ -66,6 +66,8 @@ namespace CVKL {
public override void Activate () {
if (state != ActivableState.Activated) {
+ foreach (DescriptorSetLayout dsl in DescriptorSetLayouts)
+ dsl.Activate ();
VkPipelineLayoutCreateInfo info = VkPipelineLayoutCreateInfo.New();
VkDescriptorSetLayout[] dsls = DescriptorSetLayouts.Select (dsl => dsl.handle).ToArray ();
diff --git a/vke/src/VkWindow.cs b/vke/src/VkWindow.cs
index b14edd1..b304e75 100644
--- a/vke/src/VkWindow.cs
+++ b/vke/src/VkWindow.cs
@@ -126,7 +126,7 @@ namespace CVKL {
phy = instance.GetAvailablePhysicalDevice ().Where (p => p.HasSwapChainSupport).FirstOrDefault ();
VkPhysicalDeviceFeatures enabledFeatures = default(VkPhysicalDeviceFeatures);
- configureEnabledFeatures (ref enabledFeatures);
+ configureEnabledFeatures (phy.Features, ref enabledFeatures);
if (debugMarkers)
debugMarkers = phy.GetDeviceExtensionSupported (Ext.D.VK_EXT_debug_marker);
@@ -157,7 +157,7 @@ namespace CVKL {
/// override this method to modify enabled features before device creation
/// </summary>
/// <param name="features">Features.</param>
- protected virtual void configureEnabledFeatures (ref VkPhysicalDeviceFeatures features) {
+ protected virtual void configureEnabledFeatures (VkPhysicalDeviceFeatures available_features, ref VkPhysicalDeviceFeatures features) {
}
/// <summary>
/// override this method to create additional queue. Dedicated queue of the requested type will be selected first, created queues may excess