diff options
| author | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2019-04-29 18:41:04 +0200 |
|---|---|---|
| committer | j-p <jp_bruyere@hotmail.com> | 2019-05-02 03:07:11 +0200 |
| commit | d54a090d4a6665e7e8fbb6986da11051b243736a (patch) | |
| tree | 471a402a9e930cb6062db76adb01843f30ca6822 | |
| parent | e386dd78b32bec43a1e8666bd4b482a0bbc83c24 (diff) | |
shadow mapping
24 files changed, 878 insertions, 289 deletions
diff --git a/samples/data/models/shadow.bin b/samples/data/models/shadow.bin Binary files differnew file mode 100644 index 0000000..b332f19 --- /dev/null +++ b/samples/data/models/shadow.bin 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 (); + } + } +} @@ -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 |