From 002eece61bb5b1d91dacb8d6f2c96f14613d8fe6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Tue, 5 May 2020 17:09:49 +0200 Subject: [PATCH] shaderc.net integration --- Directory.Build.props | 2 +- .../EnvironmentPipeline.cs | 25 +- addons/VkvgPipeline/VkvgPipeline.cs | 26 +- samples/Directory.Build.props | 2 +- samples/DistanceFieldFontTest/Program.cs | 4 +- samples/Model/Model.csproj | 15 +- samples/Model/main.cs | 13 +- samples/RayTests/DebuDrawPipeline.cs | 78 +++ samples/RayTests/EnvironmentPipeline.cs | 317 +++++++++ samples/RayTests/RayTests.csproj | 36 + samples/RayTests/main-crow.cs | 403 +++++++++++ samples/RayTests/main.cs | 633 ++++++++++++++++++ samples/RayTests/mainShadow.cs | 415 ++++++++++++ samples/RayTests/mainWithDebugDrawer.cs | 412 ++++++++++++ samples/RayTests/modelWithVkvgStats.cs | 359 ++++++++++ samples/RayTests/shaders/GBuffPbr.vert | 37 + samples/RayTests/shaders/GBuffPbrCommon.inc | 56 ++ .../RayTests/shaders/GBuffPbrTexArray.frag | 142 ++++ samples/RayTests/shaders/compose.frag | 158 +++++ samples/RayTests/shaders/debug.frag | 12 + samples/RayTests/shaders/debug.vert | 34 + samples/RayTests/shaders/emissive.frag | 25 + samples/RayTests/shaders/show_gbuff.frag | 92 +++ samples/RayTests/shaders/simpletexture.frag | 15 + samples/RayTests/shaders/skybox.frag | 12 + samples/RayTests/shadowMapRenderer.cs | 157 +++++ samples/RayTests/ui/debug.crow | 13 + samples/RayTests/ui/deferred.style | 61 ++ samples/RayTests/ui/main.crow | 37 + samples/RayTests/ui/materials.crow | 30 + samples/RayTests/ui/menu.crow | 9 + samples/RayTests/ui/sceneItem.crow | 18 + samples/RayTests/ui/scenes.crow | 41 ++ samples/RayTests/ui/testImage.crow | 3 + samples/Textured/main.cs | 4 +- samples/TexturedCube/main.cs | 31 +- samples/Triangle/main.cs | 13 +- samples/compute/delaunay.cs | 4 +- samples/deferred/DeferredPbrRenderer.cs | 15 +- samples/deferred/main.cs | 17 +- samples/deferred/shaders/shadow.geom | 4 + samples/deferred/shaders/shadow.vert | 5 + samples/deferred/shadowMapRenderer.cs | 10 +- samples/pbr/PbrPipeline.cs | 4 +- samples/vkeEditor/FSQPipeline.cs | 41 ++ samples/vkeEditor/ObservablePipelineConfig.cs | 105 +++ samples/vkeEditor/Program.cs | 367 ++++++++++ samples/vkeEditor/VkFormatWidget.cs | 34 + samples/vkeEditor/shaders/main.frag | 9 + samples/vkeEditor/shaders/main.vert | 31 + samples/vkeEditor/ui/main.crow | 84 +++ samples/vkeEditor/ui/testImage.crow | 19 + samples/vkeEditor/vkeEditor.csproj | 14 + vke.net.sln | 26 + vke/src/ExtensionMethods.cs | 36 + vke/src/ShaderInfo.cs | 64 +- vke/src/base/ComputePipeline.cs | 4 +- vke/src/base/DebuDrawPipeline.cs | 8 +- vke/src/base/DescriptorPool.cs | 10 +- vke/src/base/Device.cs | 9 +- vke/src/base/Fence.cs | 2 +- vke/src/base/GraphicPipeline.cs | 9 +- vke/src/base/GraphicPipelineConfig.cs | 64 +- vke/src/base/Image.cs | 2 +- vke/vke.csproj | 4 +- 65 files changed, 4624 insertions(+), 117 deletions(-) create mode 100644 samples/RayTests/DebuDrawPipeline.cs create mode 100644 samples/RayTests/EnvironmentPipeline.cs create mode 100644 samples/RayTests/RayTests.csproj create mode 100644 samples/RayTests/main-crow.cs create mode 100644 samples/RayTests/main.cs create mode 100644 samples/RayTests/mainShadow.cs create mode 100644 samples/RayTests/mainWithDebugDrawer.cs create mode 100644 samples/RayTests/modelWithVkvgStats.cs create mode 100644 samples/RayTests/shaders/GBuffPbr.vert create mode 100644 samples/RayTests/shaders/GBuffPbrCommon.inc create mode 100644 samples/RayTests/shaders/GBuffPbrTexArray.frag create mode 100644 samples/RayTests/shaders/compose.frag create mode 100644 samples/RayTests/shaders/debug.frag create mode 100644 samples/RayTests/shaders/debug.vert create mode 100644 samples/RayTests/shaders/emissive.frag create mode 100644 samples/RayTests/shaders/show_gbuff.frag create mode 100644 samples/RayTests/shaders/simpletexture.frag create mode 100644 samples/RayTests/shaders/skybox.frag create mode 100644 samples/RayTests/shadowMapRenderer.cs create mode 100644 samples/RayTests/ui/debug.crow create mode 100644 samples/RayTests/ui/deferred.style create mode 100644 samples/RayTests/ui/main.crow create mode 100644 samples/RayTests/ui/materials.crow create mode 100644 samples/RayTests/ui/menu.crow create mode 100644 samples/RayTests/ui/sceneItem.crow create mode 100644 samples/RayTests/ui/scenes.crow create mode 100644 samples/RayTests/ui/testImage.crow create mode 100644 samples/vkeEditor/FSQPipeline.cs create mode 100644 samples/vkeEditor/ObservablePipelineConfig.cs create mode 100644 samples/vkeEditor/Program.cs create mode 100644 samples/vkeEditor/VkFormatWidget.cs create mode 100644 samples/vkeEditor/shaders/main.frag create mode 100644 samples/vkeEditor/shaders/main.vert create mode 100755 samples/vkeEditor/ui/main.crow create mode 100644 samples/vkeEditor/ui/testImage.crow create mode 100644 samples/vkeEditor/vkeEditor.csproj diff --git a/Directory.Build.props b/Directory.Build.props index a1d0170..5654285 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,7 @@ $(SolutionDir)build\$(Configuration)\ 0.1.44 $(SpirVTasksReleaseVersion)-beta - 0.1.15 + 0.1.16 $(VkeReleaseVersion)-beta 7.2 diff --git a/addons/EnvironmentPipeline/EnvironmentPipeline.cs b/addons/EnvironmentPipeline/EnvironmentPipeline.cs index 0692a46..017da48 100644 --- a/addons/EnvironmentPipeline/EnvironmentPipeline.cs +++ b/addons/EnvironmentPipeline/EnvironmentPipeline.cs @@ -33,14 +33,19 @@ namespace vke.Environment { cfg.Layout = plLayout; cfg.AddVertexBinding (0, 3 * sizeof (float)); cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat); - cfg.AddShader (VkShaderStageFlags.Vertex, "#EnvironmentPipeline.skybox.vert.spv"); - cfg.AddShader (VkShaderStageFlags.Fragment, STR_FRAG_PATH); + cfg.AddShaders ( + new ShaderInfo (Dev, VkShaderStageFlags.Vertex, "#EnvironmentPipeline.skybox.vert.spv"), + new ShaderInfo (Dev, VkShaderStageFlags.Fragment, STR_FRAG_PATH) + ); + cfg.multisampleState.rasterizationSamples = Samples; layout = cfg.Layout; init (cfg); + cfg.DisposeShaders (); + generateBRDFLUT (staggingQ, cmdPool); generateCubemaps (staggingQ, cmdPool); } @@ -119,10 +124,12 @@ namespace vke.Environment { cfg.RenderPass.AddAttachment (format, VkImageLayout.ShaderReadOnlyOptimal); cfg.RenderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0, 0, 0) }); cfg.RenderPass.AddSubpass (new SubPass (VkImageLayout.ColorAttachmentOptimal)); - cfg.AddShader (VkShaderStageFlags.Vertex, "#EnvironmentPipeline.genbrdflut.vert.spv"); - cfg.AddShader (VkShaderStageFlags.Fragment, "#EnvironmentPipeline.genbrdflut.frag.spv"); + cfg.AddShaders ( + new ShaderInfo (Dev, VkShaderStageFlags.Vertex, "#EnvironmentPipeline.genbrdflut.vert.spv"), + new ShaderInfo (Dev, VkShaderStageFlags.Fragment, "#EnvironmentPipeline.genbrdflut.frag.spv")); using (GraphicPipeline pl = new GraphicPipeline (cfg)) { + cfg.DisposeShaders (); using (FrameBuffer fb = new FrameBuffer (cfg.RenderPass, dim, dim, lutBrdf)) { PrimaryCommandBuffer cmd = cmdPool.AllocateCommandBuffer (); cmd.Start (VkCommandBufferUsageFlags.OneTimeSubmit); @@ -138,6 +145,7 @@ namespace vke.Environment { cmd.Free (); } } + lutBrdf.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; } @@ -191,11 +199,11 @@ namespace vke.Environment { cfg.AddVertexBinding (0, 3 * sizeof (float)); cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat); - cfg.AddShader (VkShaderStageFlags.Vertex, "#EnvironmentPipeline.filtercube.vert.spv"); + cfg.AddShaders (new ShaderInfo (Dev, VkShaderStageFlags.Vertex, "#EnvironmentPipeline.filtercube.vert.spv")); if (target == CBTarget.PREFILTEREDENV) - cfg.AddShader (VkShaderStageFlags.Fragment, "#EnvironmentPipeline.prefilterenvmap.frag.spv"); + cfg.AddShaders (new ShaderInfo (Dev, VkShaderStageFlags.Fragment, "#EnvironmentPipeline.prefilterenvmap.frag.spv")); else - cfg.AddShader (VkShaderStageFlags.Fragment, "#EnvironmentPipeline.irradiancecube.frag.spv"); + cfg.AddShaders (new ShaderInfo (Dev, VkShaderStageFlags.Fragment, "#EnvironmentPipeline.irradiancecube.frag.spv")); Matrix4x4[] matrices = { // POSITIVE_X @@ -215,7 +223,7 @@ namespace vke.Environment { VkImageSubresourceRange subRes = new VkImageSubresourceRange (VkImageAspectFlags.Color, 0, numMips, 0, 6); using (GraphicPipeline pl = new GraphicPipeline (cfg)) { - + cfg.DisposeShaders (); DescriptorSet dset = dsPool.Allocate (dsLayout); DescriptorSetWrites dsUpdate = new DescriptorSetWrites (dsLayout); dsUpdate.Write (Dev, dset, cubemap.Descriptor); @@ -288,6 +296,7 @@ namespace vke.Environment { cmd.Free (); } } + cmap.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; dsLayout.Dispose (); diff --git a/addons/VkvgPipeline/VkvgPipeline.cs b/addons/VkvgPipeline/VkvgPipeline.cs index 5d9fc52..a2df026 100644 --- a/addons/VkvgPipeline/VkvgPipeline.cs +++ b/addons/VkvgPipeline/VkvgPipeline.cs @@ -11,7 +11,7 @@ namespace VkvgPipeline { public class VkvgPipeline : GraphicPipeline { vkvg.Device vkvgDev; vkvg.Surface vkvgSurf; - Image uiImage; + public Image Texture { get; private set; } public vkvg.Context CreateContext () => new vkvg.Context (vkvgSurf); @@ -21,8 +21,8 @@ namespace VkvgPipeline { GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, this.RenderPass.Samples, false); cfg.RenderPass = RenderPass; cfg.Layout = pipeline.Layout; - cfg.AddShader (VkShaderStageFlags.Vertex, "#vke.FullScreenQuad.vert.spv"); - cfg.AddShader (VkShaderStageFlags.Fragment, "#vke.simpletexture.frag.spv"); + cfg.AddShader (dev, VkShaderStageFlags.Vertex, "#vke.FullScreenQuad.vert.spv"); + cfg.AddShader (dev, VkShaderStageFlags.Fragment, "#vke.simpletexture.frag.spv"); cfg.multisampleState.rasterizationSamples = Samples; cfg.blendAttachments[0] = new VkPipelineColorBlendAttachmentState (true); @@ -31,36 +31,34 @@ namespace VkvgPipeline { init (cfg); + cfg.DisposeShaders (); + vkvgDev = new vkvg.Device (instance.Handle, dev.phy.Handle, dev.VkDev.Handle, queue.qFamIndex, vkvg.SampleCount.Sample_4, queue.index); } void initUISurface (int width, int height) { - uiImage?.Dispose (); + Texture?.Dispose (); vkvgSurf?.Dispose (); vkvgSurf = new vkvg.Surface (vkvgDev, width, height); - uiImage = new Image (Dev, new VkImage ((ulong)vkvgSurf.VkImage.ToInt64 ()), VkFormat.B8g8r8a8Unorm, + Texture = new Image (Dev, new VkImage ((ulong)vkvgSurf.VkImage.ToInt64 ()), VkFormat.B8g8r8a8Unorm, VkImageUsageFlags.ColorAttachment, (uint)vkvgSurf.Width, (uint)vkvgSurf.Height); - uiImage.CreateView (VkImageViewType.ImageView2D, VkImageAspectFlags.Color); - uiImage.CreateSampler (VkFilter.Nearest, VkFilter.Nearest, VkSamplerMipmapMode.Nearest, VkSamplerAddressMode.ClampToBorder); - uiImage.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + Texture.CreateView (VkImageViewType.ImageView2D, VkImageAspectFlags.Color); + Texture.CreateSampler (VkFilter.Nearest, VkFilter.Nearest, VkSamplerMipmapMode.Nearest, VkSamplerAddressMode.ClampToBorder); + Texture.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; } public void Resize (int width, int height, DescriptorSetWrites dsUpdate) { initUISurface (width, height); - dsUpdate.Write (Dev, uiImage.Descriptor); + dsUpdate.Write (Dev, Texture.Descriptor); } public void RecordDraw (PrimaryCommandBuffer cmd) { Bind (cmd); - uiImage.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.ColorAttachmentOptimal, VkImageLayout.ShaderReadOnlyOptimal, - VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader); cmd.Draw (3, 1, 0, 0); - uiImage.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.ShaderReadOnlyOptimal, VkImageLayout.ColorAttachmentOptimal, - VkPipelineStageFlags.FragmentShader, VkPipelineStageFlags.BottomOfPipe); } public void DrawResources (vkvg.Context ctx, int width, int height) { ResourceManager rm = Dev.resourceManager; @@ -124,7 +122,7 @@ namespace VkvgPipeline { } } protected override void Dispose (bool disposing) { - uiImage?.Dispose (); + Texture?.Dispose (); vkvgSurf?.Dispose (); vkvgDev.Dispose (); diff --git a/samples/Directory.Build.props b/samples/Directory.Build.props index 2fbe0d7..899a632 100644 --- a/samples/Directory.Build.props +++ b/samples/Directory.Build.props @@ -21,7 +21,7 @@ - TRACE;DEBUG;NETSTANDARD;NETSTANDARD2_0;WITH_SHADOWS;WITH_VKVG + TRACE;DEBUG;NETSTANDARD;NETSTANDARD2_0;WITH_SHADOWS;_WITH_VKVG NETSTANDARD;NETSTANDARD2_0;WITH_SHADOWS;_WITH_VKVG diff --git a/samples/DistanceFieldFontTest/Program.cs b/samples/DistanceFieldFontTest/Program.cs index d5ecf8f..906931d 100644 --- a/samples/DistanceFieldFontTest/Program.cs +++ b/samples/DistanceFieldFontTest/Program.cs @@ -94,8 +94,8 @@ namespace DistanceFieldFontTest { cfg.AddVertexBinding (0, 5 * sizeof (float)); cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32Sfloat); - cfg.AddShader (VkShaderStageFlags.Vertex, "#shaders.main.vert.spv"); - cfg.AddShader (VkShaderStageFlags.Fragment, "#shaders.main.frag.spv"); + cfg.AddShader (dev, VkShaderStageFlags.Vertex, "#shaders.main.vert.spv"); + cfg.AddShader (dev, VkShaderStageFlags.Fragment, "#shaders.main.frag.spv"); pipeline = new GraphicPipeline (cfg); diff --git a/samples/Model/Model.csproj b/samples/Model/Model.csproj index 6ad34e9..701a289 100644 --- a/samples/Model/Model.csproj +++ b/samples/Model/Model.csproj @@ -1,5 +1,12 @@ + - - - - + + + + + + + PreserveNewest + + + \ No newline at end of file diff --git a/samples/Model/main.cs b/samples/Model/main.cs index 6e040d8..7799f2c 100644 --- a/samples/Model/main.cs +++ b/samples/Model/main.cs @@ -1,14 +1,14 @@ // Copyright (c) 2019 Jean-Philippe Bruyère // // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +using System; using System.Numerics; using System.Runtime.InteropServices; using vke; using vke.glTF; using Vulkan; -namespace ModelSample -{ +namespace ModelSample { class Program : VkWindow { static void Main (string[] args) { #if DEBUG @@ -82,11 +82,16 @@ namespace ModelSample cfg.AddVertexBinding (0); cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat, VkFormat.R32g32Sfloat); - cfg.AddShader (VkShaderStageFlags.Vertex, "#shaders.model.vert.spv"); - cfg.AddShader (VkShaderStageFlags.Fragment, "#shaders.model.frag.spv"); + using (shaderc.Compiler comp = new shaderc.Compiler()) { + + cfg.AddShaders (comp.CreateShaderInfo (dev, "shaders/model.vert", shaderc.ShaderKind.VertexShader)); + cfg.AddShaders (comp.CreateShaderInfo (dev, "shaders/model.frag", shaderc.ShaderKind.FragmentShader)); + } pipeline = new GraphicPipeline (cfg); + cfg.DisposeShaders (); + helmet = new SimpleModel (presentQueue, Utils.DataDirectory + "models/DamagedHelmet/glTF/DamagedHelmet.gltf"); dsMatrices = descriptorPool.Allocate (descLayoutMatrix); diff --git a/samples/RayTests/DebuDrawPipeline.cs b/samples/RayTests/DebuDrawPipeline.cs new file mode 100644 index 0000000..fef2751 --- /dev/null +++ b/samples/RayTests/DebuDrawPipeline.cs @@ -0,0 +1,78 @@ +using System; +using System.Numerics; +using System.Runtime.InteropServices; +using VK; + +namespace CVKL { + public class DebugDrawPipeline : GraphicPipeline { + public HostBuffer Vertices; + uint vertexCount; + uint vboLength = 100 * 6 * sizeof (float); + + public DebugDrawPipeline (Device dev, DescriptorSetLayout dsLayout, VkFormat colorFormat, VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1) : + base (new RenderPass (dev, colorFormat), "Debug draw pipeline") { + + GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.LineList, samples); + cfg.rasterizationState.lineWidth = 1.0f; + cfg.RenderPass = RenderPass; + cfg.Layout = new PipelineLayout(dev, dsLayout); + cfg.Layout.AddPushConstants ( + new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf () * 2) + ); + cfg.AddVertexBinding (0, 6 * sizeof(float)); + cfg.SetVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat); + + cfg.blendAttachments[0] = new VkPipelineColorBlendAttachmentState (true); + + cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/debug.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/debug.frag.spv"); + + layout = cfg.Layout; + + init (cfg); + + Vertices = new HostBuffer (dev, VkBufferUsageFlags.VertexBuffer, vboLength); + Vertices.Map (); + } + + public void AddLine (Vector3 start, Vector3 end, float r, float g, float b) { + float[] data = { + start.X, start.Y, start.Z, + r, g, b, + end.X, end.Y, end.Z, + r, g, b + }; + Vertices.Update (data, 12 * sizeof (float), vertexCount * 6 * sizeof (float)); + vertexCount+=2; + } + + public void RecordDraw (CommandBuffer cmd, Framebuffer fb, Camera camera) { + RenderPass.Begin (cmd, fb); + const int ratio = 8; + cmd.SetViewport (fb.Width/ratio, fb.Height/ratio, (ratio-1) * (int)fb.Width / ratio, (ratio-1) * (int)fb.Height / ratio); + //cmd.SetViewport (200, 200,100,100,-10,10);//, 4 * (int)fb.Width / 5, 4 * (int)fb.Height / 5); + cmd.SetScissor (fb.Width / ratio, fb.Height / ratio, (ratio-1) * (int)fb.Width / ratio, (ratio-1) * (int)fb.Height / ratio); + //cmd.SetScissor (200, 200,100,100); + + Matrix4x4 ortho = Matrix4x4.CreateOrthographic (4, 4.0f / camera.AspectRatio,-1,1); + + cmd.PushConstant (layout, VkShaderStageFlags.Vertex, ortho); + + Bind (cmd); + + cmd.BindVertexBuffer (Vertices); + cmd.Draw (vertexCount); + RenderPass.End (cmd); + } + + protected override void Dispose (bool disposing) { + if (disposing) { + Vertices.Unmap (); + Vertices.Dispose (); + } + + base.Dispose (disposing); + } + } + +} diff --git a/samples/RayTests/EnvironmentPipeline.cs b/samples/RayTests/EnvironmentPipeline.cs new file mode 100644 index 0000000..32f8e6a --- /dev/null +++ b/samples/RayTests/EnvironmentPipeline.cs @@ -0,0 +1,317 @@ +using System; +using System.Numerics; +using System.Runtime.InteropServices; +using Vulkan; + +namespace vke { + public class EnvironmentCube : GraphicPipeline { + + GPUBuffer vboSkybox; + + public Image cubemap { get; private set; } + public Image lutBrdf { get; private set; } + public Image irradianceCube { get; private set; } + public Image prefilterCube { get; set; } + + public EnvironmentCube (string cubemapPath, DescriptorSet dsSkybox, PipelineLayout plLayout, Queue staggingQ, RenderPass renderPass, PipelineCache cache = null) + : base (renderPass, cache, "EnvCube pipeline") { + + using (CommandPool cmdPool = new CommandPool (staggingQ.Dev, staggingQ.index)) { + + vboSkybox = new GPUBuffer (staggingQ, cmdPool, VkBufferUsageFlags.VertexBuffer, box_vertices); + + cubemap = KTX.KTX.Load (staggingQ, cmdPool, cubemapPath, + VkImageUsageFlags.Sampled, VkMemoryPropertyFlags.DeviceLocal, true); + cubemap.CreateView (VkImageViewType.Cube, VkImageAspectFlags.Color); + cubemap.CreateSampler (VkSamplerAddressMode.ClampToEdge); + cubemap.SetName ("skybox Texture"); + cubemap.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + + GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, renderPass.Samples, false); + cfg.RenderPass = renderPass; + cfg.Layout = plLayout; + cfg.AddVertexBinding (0, 3 * sizeof (float)); + cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat); + cfg.AddShader (VkShaderStageFlags.Vertex, "#deferred.skybox.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "#deferred.skybox.frag.spv"); + cfg.multisampleState.rasterizationSamples = Samples; + + layout = cfg.Layout; + + init (cfg); + + generateBRDFLUT (staggingQ, cmdPool); + generateCubemaps (staggingQ, cmdPool); + } + + } + + public void RecordDraw (CommandBuffer cmd) { + Bind (cmd); + cmd.BindVertexBuffer (vboSkybox); + cmd.Draw (36); + } + + #region skybox + + static float[] box_vertices = { + 1.0f, 1.0f,-1.0f, // +X side + 1.0f, 1.0f, 1.0f, + 1.0f,-1.0f, 1.0f, + 1.0f,-1.0f, 1.0f, + 1.0f,-1.0f,-1.0f, + 1.0f, 1.0f,-1.0f, + + -1.0f,-1.0f,-1.0f, // +X side + -1.0f,-1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + -1.0f, 1.0f,-1.0f, + -1.0f,-1.0f,-1.0f, + + -1.0f, 1.0f,-1.0f, // +Y side + -1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f,-1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f,-1.0f, + + -1.0f,-1.0f,-1.0f, // -Y side + 1.0f,-1.0f,-1.0f, + 1.0f,-1.0f, 1.0f, + -1.0f,-1.0f,-1.0f, + 1.0f,-1.0f, 1.0f, + -1.0f,-1.0f, 1.0f, + + -1.0f, 1.0f, 1.0f, // +Z side + -1.0f,-1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f,-1.0f, 1.0f, + 1.0f,-1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + + -1.0f,-1.0f,-1.0f, // -Z side + 1.0f, 1.0f,-1.0f, + 1.0f,-1.0f,-1.0f, + -1.0f,-1.0f,-1.0f, + -1.0f, 1.0f,-1.0f, + 1.0f, 1.0f,-1.0f, + + }; + #endregion + + void generateBRDFLUT (Queue staggingQ, CommandPool cmdPool) { + const VkFormat format = VkFormat.R16g16Sfloat; + const int dim = 512; + + lutBrdf = new Image (Dev, format, VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.Sampled, + VkMemoryPropertyFlags.DeviceLocal, dim, dim); + lutBrdf.SetName ("lutBrdf"); + + lutBrdf.CreateView (); + lutBrdf.CreateSampler (VkSamplerAddressMode.ClampToEdge); + + GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false); + + cfg.Layout = new PipelineLayout (Dev, new DescriptorSetLayout (Dev)); + cfg.RenderPass = new RenderPass (Dev); + cfg.RenderPass.AddAttachment (format, VkImageLayout.ShaderReadOnlyOptimal); + cfg.RenderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0, 0, 0) }); + cfg.RenderPass.AddSubpass (new SubPass (VkImageLayout.ColorAttachmentOptimal)); + cfg.AddShader (VkShaderStageFlags.Vertex, "#deferred.genbrdflut.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "#deferred.genbrdflut.frag.spv"); + + using (GraphicPipeline pl = new GraphicPipeline (cfg)) { + using (FrameBuffer fb = new FrameBuffer (cfg.RenderPass, dim, dim, lutBrdf)) { + CommandBuffer cmd = cmdPool.AllocateCommandBuffer (); + cmd.Start (VkCommandBufferUsageFlags.OneTimeSubmit); + pl.RenderPass.Begin (cmd, fb); + cmd.SetViewport (dim, dim); + cmd.SetScissor (dim, dim); + pl.Bind (cmd); + cmd.Draw (3, 1, 0, 0); + pl.RenderPass.End (cmd); + cmd.End (); + + staggingQ.Submit (cmd); + staggingQ.WaitIdle (); + + cmd.Free (); + } + } + lutBrdf.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + } + + public enum CBTarget { IRRADIANCE = 0, PREFILTEREDENV = 1 }; + + public Image generateCubeMap (Queue staggingQ, CommandPool cmdPool, CBTarget target) { + const float deltaPhi = (2.0f * (float)Math.PI) / 180.0f; + const float deltaTheta = (0.5f * (float)Math.PI) / 64.0f; + + VkFormat format = VkFormat.R32g32b32a32Sfloat; + uint dim = 64; + + if (target == CBTarget.PREFILTEREDENV) { + format = VkFormat.R16g16b16a16Sfloat; + dim = 512; + } + + uint numMips = (uint)Math.Floor (Math.Log (dim, 2)) + 1; + + Image imgFbOffscreen = new Image (Dev, format, VkImageUsageFlags.TransferSrc | VkImageUsageFlags.ColorAttachment, + VkMemoryPropertyFlags.DeviceLocal, dim, dim); + imgFbOffscreen.SetName ("offscreenfb"); + imgFbOffscreen.CreateView (); + + Image cmap = new Image (Dev, format, VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled, + VkMemoryPropertyFlags.DeviceLocal, dim, dim, VkImageType.Image2D, VkSampleCountFlags.SampleCount1, VkImageTiling.Optimal, + numMips, 6, 1, VkImageCreateFlags.CubeCompatible); + if (target == CBTarget.PREFILTEREDENV) + cmap.SetName ("prefilterenvmap"); + else + cmap.SetName ("irradianceCube"); + cmap.CreateView (VkImageViewType.Cube, VkImageAspectFlags.Color, 6, 0); + cmap.CreateSampler (VkSamplerAddressMode.ClampToEdge); + + DescriptorPool dsPool = new DescriptorPool (Dev, 2, new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler)); + + DescriptorSetLayout dsLayout = new DescriptorSetLayout (Dev, + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler)); + + + GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false); + cfg.Layout = new PipelineLayout (Dev, dsLayout); + cfg.Layout.AddPushConstants ( + new VkPushConstantRange (VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, (uint)Marshal.SizeOf () + 8)); + + cfg.RenderPass = new RenderPass (Dev); + cfg.RenderPass.AddAttachment (format, VkImageLayout.ColorAttachmentOptimal); + cfg.RenderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0, 0, 0) }); + cfg.RenderPass.AddSubpass (new SubPass (VkImageLayout.ColorAttachmentOptimal)); + + cfg.AddVertexBinding (0, 3 * sizeof (float)); + cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat); + + cfg.AddShader (VkShaderStageFlags.Vertex, "#deferred.filtercube.vert.spv"); + if (target == CBTarget.PREFILTEREDENV) + cfg.AddShader (VkShaderStageFlags.Fragment, "#deferred.prefilterenvmap.frag.spv"); + else + cfg.AddShader (VkShaderStageFlags.Fragment, "#deferred.irradiancecube.frag.spv"); + + Matrix4x4[] matrices = { + // POSITIVE_X + Matrix4x4.CreateRotationX(Utils.DegreesToRadians(180)) * Matrix4x4.CreateRotationY(Utils.DegreesToRadians(90)), + // NEGATIVE_X + Matrix4x4.CreateRotationX(Utils.DegreesToRadians(180)) * Matrix4x4.CreateRotationY(Utils.DegreesToRadians(-90)), + // POSITIVE_Y + Matrix4x4.CreateRotationX(Utils.DegreesToRadians(-90)), + // NEGATIVE_Y + Matrix4x4.CreateRotationX(Utils.DegreesToRadians(90)), + // POSITIVE_Z + Matrix4x4.CreateRotationX(Utils.DegreesToRadians(180)), + // NEGATIVE_Z + Matrix4x4.CreateRotationZ(Utils.DegreesToRadians(180)) + }; + + 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); + + cmap.SetLayout (cmd, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, subRes); + + float roughness = 0; + + cmd.SetScissor (dim, dim); + cmd.SetViewport ((float)(dim), (float)dim); + + for (int m = 0; m < numMips; m++) { + roughness = (float)m / ((float)numMips - 1f); + + for (int f = 0; f < 6; f++) { + pl.RenderPass.Begin (cmd, fb); + + pl.Bind (cmd); + + float viewPortSize = (float)Math.Pow (0.5, m) * dim; + cmd.SetViewport (viewPortSize, viewPortSize); + cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, + matrices[f] * Matrix4x4.CreatePerspectiveFieldOfView (Utils.DegreesToRadians (90), 1f, 0.1f, 512f)); + if (target == CBTarget.IRRADIANCE) { + cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, deltaPhi, (uint)Marshal.SizeOf ()); + cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, deltaTheta, (uint)Marshal.SizeOf () + 4); + } else { + cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, roughness, (uint)Marshal.SizeOf ()); + cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, 64u, (uint)Marshal.SizeOf () + 4); + } + + cmd.BindDescriptorSet (pl.Layout, dset); + cmd.BindVertexBuffer (vboSkybox); + cmd.Draw (36); + + pl.RenderPass.End (cmd); + + imgFbOffscreen.SetLayout (cmd, VkImageAspectFlags.Color, + VkImageLayout.ColorAttachmentOptimal, VkImageLayout.TransferSrcOptimal); + + VkImageCopy region = new VkImageCopy (); + region.srcSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, 1); + region.dstSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, 1, (uint)m, (uint)f); + region.extent = new VkExtent3D { width = (uint)viewPortSize, height = (uint)viewPortSize, depth = 1 }; + + Vk.vkCmdCopyImage (cmd.Handle, + imgFbOffscreen.Handle, VkImageLayout.TransferSrcOptimal, + cmap.Handle, VkImageLayout.TransferDstOptimal, + 1, region.Pin ()); + region.Unpin (); + + imgFbOffscreen.SetLayout (cmd, VkImageAspectFlags.Color, + VkImageLayout.TransferSrcOptimal, VkImageLayout.ColorAttachmentOptimal); + + } + } + + cmap.SetLayout (cmd, VkImageLayout.TransferDstOptimal, VkImageLayout.ShaderReadOnlyOptimal, subRes); + + cmd.End (); + + staggingQ.Submit (cmd); + staggingQ.WaitIdle (); + + cmd.Free (); + } + } + cmap.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + + dsLayout.Dispose (); + imgFbOffscreen.Dispose (); + dsPool.Dispose (); + + return cmap; + } + + void generateCubemaps (Queue staggingQ, CommandPool cmdPool) { + irradianceCube = generateCubeMap (staggingQ, cmdPool, CBTarget.IRRADIANCE); + prefilterCube = generateCubeMap (staggingQ, cmdPool, CBTarget.PREFILTEREDENV); + } + + protected override void Dispose (bool disposing) { + vboSkybox.Dispose (); + cubemap.Dispose (); + lutBrdf.Dispose (); + irradianceCube.Dispose (); + prefilterCube.Dispose (); + + base.Dispose (disposing); + } + } + +} diff --git a/samples/RayTests/RayTests.csproj b/samples/RayTests/RayTests.csproj new file mode 100644 index 0000000..ba6ec6a --- /dev/null +++ b/samples/RayTests/RayTests.csproj @@ -0,0 +1,36 @@ + + + + false + + + + 4 + full + false + true + TRACE;MEMORY_POOLS;_WITH_VKVG;DEBUG;NETFRAMEWORK;NET472 + + + TRACE;DEBUG;NETSTANDARD;NETSTANDARD2_0;MEMORY_POOLS;WITH_SHADOWS;_WITH_VKVG + + + + + deferred.%(Filename)%(Extension) + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/RayTests/main-crow.cs b/samples/RayTests/main-crow.cs new file mode 100644 index 0000000..20f6566 --- /dev/null +++ b/samples/RayTests/main-crow.cs @@ -0,0 +1,403 @@ +using System; +using System.Numerics; +using Glfw; +using Vulkan; +using vke; +using System.Collections.Generic; +using System.Linq; + +namespace deferred { + class Program : Crow.CrowWin { + static void Main (string[] args) { +#if DEBUG + Instance.VALIDATION = true; + Instance.DEBUG_UTILS = true; + Instance.RENDER_DOC_CAPTURE = false; +#endif + DeferredPbrRenderer.TEXTURE_ARRAY = true; + DeferredPbrRenderer.NUM_SAMPLES = VkSampleCountFlags.SampleCount1; + DeferredPbrRenderer.HDR_FORMAT = VkFormat.R32g32b32a32Sfloat; + DeferredPbrRenderer.MRT_FORMAT = VkFormat.R16g16b16a16Sfloat; + + PbrModelTexArray.TEXTURE_DIM = 1024; + + using (Program vke = new Program ()) { + vke.Run (); + } + } + + #region crow ui + public Crow.Command CMDViewScenes, CMDViewEditor, CMDViewDebug, CMDViewMaterials; + void init_crow_commands () { + CMDViewScenes = new Crow.Command (new Action (() => loadWindow ("#deferred.main.crow", this))) { Caption = "Lighting", Icon = new Crow.SvgPicture ("#deferred.crow.svg"), CanExecute = true }; + CMDViewEditor = new Crow.Command (new Action (() => loadWindow ("#deferred.scenes.crow", this))) { Caption = "Scenes", Icon = new Crow.SvgPicture ("#deferred.crow.svg"), CanExecute = true }; + CMDViewDebug = new Crow.Command (new Action (() => loadWindow ("#deferred.debug.crow", this))) { Caption = "Debug", Icon = new Crow.SvgPicture ("#deferred.crow.svg"), CanExecute = true }; + CMDViewMaterials = new Crow.Command (new Action (() => loadWindow ("#deferred.materials.crow", this))) { Caption = "Materials", Icon = new Crow.SvgPicture ("#deferred.crow.svg"), CanExecute = true }; + } + + public DeferredPbrRenderer.DebugView CurrentDebugView { + get { return renderer.currentDebugView; } + set { + if (value == renderer.currentDebugView) + return; + lock(crow.UpdateMutex) + renderer.currentDebugView = value; + rebuildBuffers = true; + NotifyValueChanged ("CurrentDebugView", renderer.currentDebugView); + } + } + + public float Gamma { + get { return renderer.matrices.gamma; } + set { + if (value == renderer.matrices.gamma) + return; + renderer.matrices.gamma = value; + NotifyValueChanged ("Gamma", value); + updateViewRequested = true; + } + } + public float Exposure { + get { return renderer.matrices.exposure; } + set { + if (value == renderer.matrices.exposure) + return; + renderer.matrices.exposure = value; + NotifyValueChanged ("Exposure", value); + updateViewRequested = true; + } + } + public float LightStrength { + get { return renderer.lights[renderer.lightNumDebug].color.X; } + set { + if (value == renderer.lights[renderer.lightNumDebug].color.X) + return; + renderer.lights[renderer.lightNumDebug].color = new Vector4(value); + NotifyValueChanged ("LightStrength", value); + renderer.uboLights.Update (renderer.lights); + } + } + public List Lights => renderer.lights.ToList (); + public List Scenes => renderer.model.Scenes; + #endregion + + public override string[] EnabledDeviceExtensions => new string[] { + Ext.D.VK_KHR_swapchain, + Ext.D.VK_EXT_debug_marker + }; + + 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; + features.pipelineStatisticsQuery = true; + + if (available_features.textureCompressionETC2) { + features.textureCompressionETC2 = true; + Image.DefaultTextureFormat = VkFormat.Etc2R8g8b8a8UnormBlock; + }else if (available_features.textureCompressionBC) { + //features.textureCompressionBC = true; + //Image.DefaultTextureFormat = VkFormat.Bc3UnormBlock; + } + + + } + + protected override void createQueues () { + base.createQueues (); + transferQ = new Queue (dev, VkQueueFlags.Transfer); + } + + string[] cubemapPathes = { + Utils.DataDirectory + "textures/papermill.ktx", + Utils.DataDirectory + "textures/cubemap_yokohama_bc3_unorm.ktx", + Utils.DataDirectory + "textures/gcanyon_cube.ktx", + Utils.DataDirectory + "textures/pisa_cube.ktx", + Utils.DataDirectory + "textures/uffizi_cube.ktx", + }; + string[] modelPathes = { + //"/mnt/devel/gts/vkChess.net/data/models/chess.glb", + //"/home/jp/gltf/jaguar/scene.gltf", + Utils.DataDirectory + "models/DamagedHelmet/glTF/DamagedHelmet.gltf", + Utils.DataDirectory + "models/shadow.glb", + Utils.DataDirectory + "models/Hubble.glb", + Utils.DataDirectory + "models/MER_static.glb", + Utils.DataDirectory + "models/ISS_stationary.glb", + }; + + int curModelIndex = 0; + bool reloadModel; + + Queue transferQ; + DeferredPbrRenderer renderer; + PipelineStatisticsQueryPool statPool; + TimestampQueryPool timestampQPool; + ulong[] results; + + DebugReport dbgRepport; + + Program () : base() { + + if (Instance.DEBUG_UTILS) + dbgRepport = new DebugReport (instance, + VkDebugReportFlagsEXT.ErrorEXT + | VkDebugReportFlagsEXT.DebugEXT + | VkDebugReportFlagsEXT.WarningEXT + | VkDebugReportFlagsEXT.PerformanceWarningEXT + ); + + camera = new Camera (Utils.DegreesToRadians (45f), 1f, 0.1f, 16f); + camera.SetPosition (0, 0, 2); + + renderer = new DeferredPbrRenderer (dev, swapChain, presentQueue, cubemapPathes[2], camera.NearPlane, camera.FarPlane); + renderer.LoadModel (transferQ, modelPathes[curModelIndex]); + camera.Model = Matrix4x4.CreateScale (1f / Math.Max (Math.Max (renderer.modelAABB.Width, renderer.modelAABB.Height), renderer.modelAABB.Depth)); + + statPool = new PipelineStatisticsQueryPool (dev, + VkQueryPipelineStatisticFlags.InputAssemblyVertices | + VkQueryPipelineStatisticFlags.InputAssemblyPrimitives | + VkQueryPipelineStatisticFlags.ClippingInvocations | + VkQueryPipelineStatisticFlags.ClippingPrimitives | + VkQueryPipelineStatisticFlags.FragmentShaderInvocations); + + timestampQPool = new TimestampQueryPool (dev); + + init_crow_commands (); + + crow.Load ("#deferred.menu.crow").DataSource = this; + + } + + protected override void recordDraw (CommandBuffer cmd, int imageIndex) { + statPool.Begin (cmd); + renderer.buildCommandBuffers (cmd, imageIndex); + statPool.End (cmd); + } + + public override void UpdateView () { + renderer.UpdateView (camera); + updateViewRequested = false; +#if WITH_SHADOWS + if (renderer.shadowMapRenderer.updateShadowMap) + renderer.shadowMapRenderer.update_shadow_map (cmdPool); +#endif + } + + int frameCount = 0; + public override void Update () { + if (reloadModel) { + renderer.LoadModel (transferQ, modelPathes[curModelIndex]); + reloadModel = false; + 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 + } + + base.Update (); + + if (++frameCount > 20) { + NotifyValueChanged ("fps", fps); + frameCount = 0; + } + + results = statPool.GetResults (); + } + protected override void OnResize () { + renderer.Resize (); + base.OnResize (); + } + + #region Mouse and keyboard + protected override void onMouseMove (double xPos, double yPos) { + if (crow.ProcessMouseMove ((int)xPos, (int)yPos)) + return; + + double diffX = lastMouseX - xPos; + double diffY = lastMouseY - yPos; + if (MouseButton[0]) { + camera.Rotate ((float)-diffX, (float)-diffY); + } else if (MouseButton[1]) { + camera.SetZoom ((float)diffY); + } else + return; + + updateViewRequested = true; + } + protected override void onMouseButtonDown (Glfw.MouseButton button) { + if (crow.ProcessMouseButtonDown ((Crow.MouseButton)button)) + return; + base.onMouseButtonDown (button); + } + protected override void onMouseButtonUp (Glfw.MouseButton button) { + if (crow.ProcessMouseButtonUp ((Crow.MouseButton)button)) + return; + base.onMouseButtonUp (button); + } + protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) { + if (crow.ProcessKeyDown ((Crow.Key)key)) + return; + switch (key) { + case Key.F: + if (modifiers.HasFlag (Modifier.Shift)) { + renderer.debugFace--; + if (renderer.debugFace < 0) + renderer.debugFace = 5; + } else { + renderer.debugFace++; + if (renderer.debugFace >= 5) + renderer.debugFace = 0; + } + rebuildBuffers = true; + break; + case Key.M: + if (modifiers.HasFlag (Modifier.Shift)) { + renderer.debugMip--; + if (renderer.debugMip < 0) + renderer.debugMip = (int)renderer.envCube.prefilterCube.CreateInfo.mipLevels - 1; + } else { + renderer.debugMip++; + if (renderer.debugMip >= renderer.envCube.prefilterCube.CreateInfo.mipLevels) + renderer.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: + case Key.Keypad3: + case Key.Keypad4: + case Key.Keypad5: + case Key.Keypad6: + case Key.Keypad7: + case Key.Keypad8: + case Key.Keypad9: + renderer.currentDebugView = (DeferredPbrRenderer.DebugView)(int)key-320; + rebuildBuffers = true; + break; + case Key.KeypadDivide: + 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.MoveLight(-Vector4.UnitZ); + else + camera.Move (0, 0, 1); + break; + case Key.Down: + if (modifiers.HasFlag (Modifier.Shift)) + renderer.MoveLight (Vector4.UnitZ); + else + camera.Move (0, 0, -1); + break; + case Key.Left: + if (modifiers.HasFlag (Modifier.Shift)) + renderer.MoveLight (-Vector4.UnitX); + else + camera.Move (1, 0, 0); + break; + case Key.Right: + if (modifiers.HasFlag (Modifier.Shift)) + renderer.MoveLight (Vector4.UnitX); + else + camera.Move (-1, 0, 0); + break; + case Key.PageUp: + if (modifiers.HasFlag (Modifier.Shift)) + renderer.MoveLight (Vector4.UnitY); + else + camera.Move (0, 1, 0); + break; + case Key.PageDown: + if (modifiers.HasFlag (Modifier.Shift)) + renderer.MoveLight (-Vector4.UnitY); + else + camera.Move (0, -1, 0); + break; + case Key.F2: + if (modifiers.HasFlag (Modifier.Shift)) + renderer.matrices.exposure -= 0.3f; + else + renderer.matrices.exposure += 0.3f; + break; + case Key.F3: + if (modifiers.HasFlag (Modifier.Shift)) + renderer.matrices.gamma -= 0.1f; + else + renderer.matrices.gamma += 0.1f; + break; + case Key.F4: + if (camera.Type == Camera.CamType.FirstPerson) + camera.Type = Camera.CamType.LookAt; + else + camera.Type = Camera.CamType.FirstPerson; + Console.WriteLine ($"camera type = {camera.Type}"); + break; + case Key.KeypadAdd: + curModelIndex++; + if (curModelIndex >= modelPathes.Length) + curModelIndex = 0; + reloadModel = true; + break; + case Key.KeypadSubtract: + curModelIndex--; + if (curModelIndex < 0) + curModelIndex = modelPathes.Length -1; + reloadModel = true; + break; + default: + base.onKeyDown (key, scanCode, modifiers); + return; + } + updateViewRequested = true; + } + protected override void onKeyUp (Key key, int scanCode, Modifier modifiers) { + if (crow.ProcessKeyUp ((Crow.Key)key)) + return; + } + protected override void onChar (CodePoint cp) { + if (crow.ProcessKeyPress (cp.ToChar ())) + return; + } + #endregion + + protected override void Dispose (bool disposing) { + if (disposing) { + if (!isDisposed) { + renderer.Dispose (); + statPool.Dispose (); + timestampQPool.Dispose (); + dbgRepport?.Dispose (); + } + } + + base.Dispose (disposing); + } + } +} diff --git a/samples/RayTests/main.cs b/samples/RayTests/main.cs new file mode 100644 index 0000000..e3c687a --- /dev/null +++ b/samples/RayTests/main.cs @@ -0,0 +1,633 @@ +using System; +using System.Numerics; +using System.Runtime.InteropServices; +using vke; +using vke.glTF; +using Glfw; +using Vulkan; +using vke.Environment; + +namespace deferred { + class Deferred : VkWindow { + static VkSampleCountFlags NUM_SAMPLES = VkSampleCountFlags.SampleCount4; + static VkFormat HDR_FORMAT = VkFormat.R16g16b16a16Sfloat; + static VkFormat MRT_FORMAT = VkFormat.R16g16b16a16Sfloat; + static int MAX_MATERIAL_COUNT = 4; + + + static void Main (string[] args) { +#if DEBUG + Instance.VALIDATION = true; + //Instance.RENDER_DOC_CAPTURE = true; +#endif + SwapChain.PREFERED_FORMAT = VkFormat.B8g8r8a8Srgb; + PbrModelTexArray.TEXTURE_DIM = 1024; + + using (Deferred vke = new Deferred ()) { + vke.Run (); + } + } + + public override string[] EnabledInstanceExtensions => new string[] { + Ext.I.VK_EXT_debug_utils, + }; + + public override string[] EnabledDeviceExtensions => new string[] { + Ext.D.VK_KHR_swapchain, + }; + + protected override void configureEnabledFeatures (VkPhysicalDeviceFeatures available_features, ref VkPhysicalDeviceFeatures enabled_features) { + base.configureEnabledFeatures (available_features, ref enabled_features); + + enabled_features.samplerAnisotropy = available_features.samplerAnisotropy; + enabled_features.sampleRateShading = available_features.sampleRateShading; + enabled_features.geometryShader = available_features.geometryShader; + + enabled_features.textureCompressionBC = available_features.textureCompressionBC; + } + + protected override void createQueues () { + base.createQueues (); + transferQ = new Queue (dev, VkQueueFlags.Transfer); + computeQ = new Queue (dev, VkQueueFlags.Compute); + } + string[] cubemapPathes = { + Utils.DataDirectory + "textures/papermill.ktx", + Utils.DataDirectory + "textures/cubemap_yokohama_bc3_unorm.ktx", + Utils.DataDirectory + "textures/gcanyon_cube.ktx", + Utils.DataDirectory + "textures/pisa_cube.ktx", + Utils.DataDirectory + "textures/uffizi_cube.ktx", + }; + string[] modelPathes = { + "/mnt/devel/vkPinball/data/models/pinball.gltf", + Utils.DataDirectory + "models/DamagedHelmet/glTF/DamagedHelmet.gltf", + Utils.DataDirectory + "models/shadow.glb", + Utils.DataDirectory + "models/Hubble.glb", + Utils.DataDirectory + "models/MER_static.glb", + Utils.DataDirectory + "models/ISS_stationary.glb", + }; + + public enum DebugView { + none, + color, + normal, + pos, + occlusion, + emissive, + metallic, + roughness, + depth, + prefill, + irradiance, + shadowMap + } + DebugView currentDebugView = DebugView.none; + int lightNumDebug = 0; + int debugMip = 0; + int debugFace = 0; + + const float lightMoveSpeed = 0.1f; + float exposure = 2.0f; + float gamma = 1.2f; + + public struct Matrices { + public Matrix4x4 projection; + public Matrix4x4 model; + public Matrix4x4 view; + public Vector4 camPos; + public float prefilteredCubeMipLevels; + public float scaleIBLAmbient; + } + public struct Light { + public Vector4 position; + public Vector4 color; + public Matrix4x4 mvp; + } + + public Matrices matrices = new Matrices { + scaleIBLAmbient = 0.5f, + }; + + public Light [] lights = { + new Light { + position = new Vector4(2.5f,5.5f,2,0f), + color = new Vector4(1,1.0f,1.0f,1) + }, + /*new Light { + position = new Vector4(-2.5f,5.5f,2,0f), + color = new Vector4(0.8f,0.8f,1,1) + }*/ + }; + + int curModelIndex = 0; + bool reloadModel; + bool rebuildBuffers; + + vke.DebugUtils.Messenger dbgmsg; + Queue transferQ, computeQ; + PipelineCache pipelineCache; + + + GraphicPipeline plGBuff, plLighting; + + FrameBuffers fbsMain; + + RenderPass rpGBuff; + FrameBuffer fbGBuff; + Image gbColorRough, gbEmitMetal, gbN_AO, gbPos; + + + DescriptorPool descriptorPool; + DescriptorSetLayout dslMain, dslMaterial, dslLighting; + DescriptorSet dsMain, dsMaterial, dsLighting; + + HostBuffer uboLights; + HostBuffer uboMatrices; + + EnvironmentCube envCube; + PbrModel model; + BoundingBox modelAABB; + + + Deferred () : base("deferred") { + dbgmsg = new vke.DebugUtils.Messenger (instance, VkDebugUtilsMessageTypeFlagsEXT.PerformanceEXT | VkDebugUtilsMessageTypeFlagsEXT.ValidationEXT | VkDebugUtilsMessageTypeFlagsEXT.GeneralEXT, + VkDebugUtilsMessageSeverityFlagsEXT.InfoEXT | + VkDebugUtilsMessageSeverityFlagsEXT.WarningEXT | VkDebugUtilsMessageSeverityFlagsEXT.ErrorEXT | VkDebugUtilsMessageSeverityFlagsEXT.VerboseEXT); + + //pipelineCache = new PipelineCache (dev); + + camera = new Camera (Utils.DegreesToRadians (45f), 1f, 0.1f, 16f); + camera.SetPosition (0, -0.1f, -1); + + init (); + + LoadModel (transferQ, modelPathes [curModelIndex]); + + //dev.WaitIdle (); + } + + + void LoadModel (Queue transferQ, string path) + { + dev.WaitIdle (); + model?.Dispose (); + + PbrModelTexArray mod = new PbrModelTexArray (transferQ, path); + if (mod.texArray != null) { + DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsMaterial, dslMaterial); + uboUpdate.Write (dev, mod.materialUBO.Descriptor, mod.texArray.Descriptor); + } + model = mod; + + modelAABB = model.DefaultScene.AABB; + + camera.Model = Matrix4x4.CreateScale (1f / Math.Max (Math.Max (modelAABB.Width, modelAABB.Height), modelAABB.Depth)); + + reloadModel = false; + } + + + void create_gbuff_pipeline () + { + rpGBuff = new RenderPass (dev, NUM_SAMPLES); + rpGBuff.AddAttachment (dev.GetSuitableDepthFormat (), VkImageLayout.DepthStencilAttachmentOptimal, NUM_SAMPLES); + rpGBuff.AddAttachment (VkFormat.R8g8b8a8Unorm, VkImageLayout.ShaderReadOnlyOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.Store, VkImageLayout.ShaderReadOnlyOptimal);//GBuff0 (color + roughness) and final color before resolve + rpGBuff.AddAttachment (VkFormat.R8g8b8a8Unorm, VkImageLayout.ShaderReadOnlyOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.Store, VkImageLayout.ShaderReadOnlyOptimal);//GBuff1 (emit + metal) + rpGBuff.AddAttachment (MRT_FORMAT, VkImageLayout.ShaderReadOnlyOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.Store, VkImageLayout.ShaderReadOnlyOptimal);//GBuff2 (normals + AO) + rpGBuff.AddAttachment (MRT_FORMAT, VkImageLayout.ShaderReadOnlyOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.Store, VkImageLayout.ShaderReadOnlyOptimal);//GBuff3 (Pos + depth) + + rpGBuff.ClearValues.Add (new VkClearValue { depthStencil = new VkClearDepthStencilValue (1.0f, 0) }); + rpGBuff.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); + rpGBuff.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); + rpGBuff.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); + rpGBuff.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); + + rpGBuff.AddSubpass (new SubPass ()); + rpGBuff.SubPasses [0].SetDepthReference (0, VkImageLayout.DepthStencilAttachmentOptimal); + rpGBuff.SubPasses [0].AddColorReference ( + new VkAttachmentReference (1, VkImageLayout.ColorAttachmentOptimal), + new VkAttachmentReference (2, VkImageLayout.ColorAttachmentOptimal), + new VkAttachmentReference (3, VkImageLayout.ColorAttachmentOptimal), + new VkAttachmentReference (4, VkImageLayout.ColorAttachmentOptimal)); + + rpGBuff.AddDependency (Vk.SubpassExternal, 0, + VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.ColorAttachmentOutput, + VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentWrite); + rpGBuff.AddDependency (0, Vk.SubpassExternal, + VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe, + VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead); + + 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; + } + cfg.Cache = pipelineCache; + cfg.Layout = new PipelineLayout (dev, dslMain, dslMaterial); + cfg.Layout.AddPushConstants ( + new VkPushConstantRange (VkShaderStageFlags.Vertex, 64), + new VkPushConstantRange (VkShaderStageFlags.Fragment, sizeof (int), 64) + ); + cfg.RenderPass = rpGBuff; + cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); + cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); + cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); + //cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); + + cfg.AddVertex (); + using (SpecializationInfo constants = new SpecializationInfo ( + new SpecializationConstant (0, camera.NearPlane), + new SpecializationConstant (1, camera.FarPlane), + new SpecializationConstant (2, MAX_MATERIAL_COUNT))) { + + cfg.AddShader (VkShaderStageFlags.Vertex, "#RayTests.GBuffPbr.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "#RayTests.GBuffPbrTexArray.frag.spv", constants); + + plGBuff = new GraphicPipeline (cfg); + } + } + + void create_lighting_pipeline () + { + GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, NUM_SAMPLES); + cfg.rasterizationState.cullMode = VkCullModeFlags.Front; + if (NUM_SAMPLES != VkSampleCountFlags.SampleCount1) { + cfg.multisampleState.sampleShadingEnable = true; + cfg.multisampleState.minSampleShading = 0.5f; + } + cfg.Cache = pipelineCache; + cfg.Layout = new PipelineLayout (dev, dslMain, dslLighting); + cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, NUM_SAMPLES); + //cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); + cfg.depthStencilState.depthTestEnable = false; + cfg.depthStencilState.depthWriteEnable = false; + + using (SpecializationInfo constants = new SpecializationInfo ( + new SpecializationConstant (0, (uint)lights.Length))) { + cfg.AddShader (VkShaderStageFlags.Vertex, "#vke.FullScreenQuad.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "#RayTests.compose.frag.spv", constants); + plLighting = new GraphicPipeline (cfg); + } + } + + void init() { + descriptorPool = new DescriptorPool (dev, 3, + new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer, 3), + new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, 8) + ); + + dslMain = new DescriptorSetLayout (dev, + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer));//matrices and params + dslMaterial = new DescriptorSetLayout (dev, + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer),//materials + new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler));//texture array) + dslLighting = new DescriptorSetLayout (dev, + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler),//color + roughness + new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler),//emit + metal + new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler),//normals + AO + new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler),//Pos + depth + new VkDescriptorSetLayoutBinding (4, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler),//irradiance + new VkDescriptorSetLayoutBinding (5, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler),//prefiltCube + new VkDescriptorSetLayoutBinding (6, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler),//lutBRDF + new VkDescriptorSetLayoutBinding (7, VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer));//lights + + uboMatrices = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, matrices, true); + uboLights = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, lights, true); + + create_gbuff_pipeline (); + + create_lighting_pipeline (); + + dsMain = descriptorPool.Allocate (dslMain); + dsMain.Handle.SetDebugMarkerName (dev, "dsMain"); + dsMaterial = descriptorPool.Allocate (dslMaterial); + dsMain.Handle.SetDebugMarkerName (dev, "dsMaterial"); + dsLighting = descriptorPool.Allocate (dslLighting); + dsMain.Handle.SetDebugMarkerName (dev, "dsLighting"); + + EnvironmentCube.STR_FRAG_PATH = "#RayTests.skybox.frag.spv"; + envCube = new EnvironmentCube (cubemapPathes[2], plLighting.Layout, presentQueue, plLighting.RenderPass); + + matrices.prefilteredCubeMipLevels = envCube.prefilterCube.CreateInfo.mipLevels; + + DescriptorSetWrites dsWrite = new DescriptorSetWrites (dsLighting, dslLighting.Bindings.GetRange (4, 4).ToArray()); + dsWrite.Write (dev, + envCube.irradianceCube.Descriptor, + envCube.prefilterCube.Descriptor, + envCube.lutBrdf.Descriptor, + uboLights.Descriptor); + + dsWrite = new DescriptorSetWrites (dsMain, dslMain); + dsWrite.Write (dev, uboMatrices.Descriptor); + } + + + void createGBuff () + { + fbGBuff?.Dispose (); + + gbColorRough?.Dispose (); + gbEmitMetal?.Dispose (); + gbN_AO?.Dispose (); + gbPos?.Dispose (); + + gbColorRough = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.Sampled | VkImageUsageFlags.ColorAttachment , VkMemoryPropertyFlags.DeviceLocal, Width, Height, VkImageType.Image2D, NUM_SAMPLES); + gbEmitMetal = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.Sampled | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, Width, Height, VkImageType.Image2D, NUM_SAMPLES); + gbN_AO = new Image (dev, MRT_FORMAT, VkImageUsageFlags.Sampled | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, Width, Height, VkImageType.Image2D, NUM_SAMPLES); + gbPos = new Image (dev, MRT_FORMAT, VkImageUsageFlags.Sampled | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, Width, Height, VkImageType.Image2D, NUM_SAMPLES); + + + gbColorRough.CreateView (); gbColorRough.CreateSampler (); + gbColorRough.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + gbEmitMetal.CreateView (); gbEmitMetal.CreateSampler (); + gbEmitMetal.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + gbN_AO.CreateView (); gbN_AO.CreateSampler (); + gbN_AO.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + gbPos.CreateView (); gbPos.CreateSampler (); + gbPos.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + + DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsLighting, dslLighting.Bindings.GetRange (0, 4).ToArray()); + uboUpdate.Write (dev, + gbColorRough.Descriptor, + gbEmitMetal.Descriptor, + gbN_AO.Descriptor, + gbPos.Descriptor); + + gbColorRough.SetName ("GBuffColorRough"); + gbEmitMetal.SetName ("GBuffEmitMetal"); + gbN_AO.SetName ("GBuffN"); + gbPos.SetName ("GBuffPos"); + + fbGBuff = new FrameBuffer (rpGBuff, Width, Height, new Image [] { + null, gbColorRough, gbEmitMetal, gbN_AO, gbPos}); + } + + void buildCommandBuffers () { + for (int i = 0; i < swapChain.ImageCount; ++i) { + cmds[i]?.Free (); + cmds[i] = cmdPool.AllocateAndStart (); + CommandBuffer cmd = cmds [i]; + + rpGBuff.Begin (cmd, fbGBuff); + + cmd.BindDescriptorSets (VkPipelineBindPoint.Graphics, plGBuff.Layout, 0, dsMain, dsMaterial); + + cmd.SetViewport (fbsMain [i].Width, fbsMain [i].Height); + cmd.SetScissor (fbsMain [i].Width, fbsMain [i].Height); + + if (model != null) { + plGBuff.Bind (cmd); + model.Bind (cmd); + model.DrawAll (cmd, plGBuff.Layout); + } + + rpGBuff.End (cmd); + + plLighting.RenderPass.Begin (cmd, fbsMain [i]); + + cmd.SetViewport (fbsMain [i].Width, fbsMain [i].Height); + cmd.SetScissor (fbsMain [i].Width, fbsMain [i].Height); + + plLighting.Bind (cmd); + plLighting.BindDescriptorSet (cmd, dsLighting, 1); + + cmd.Draw (3, 1, 0, 0); + + plLighting.RenderPass.End (cmd); + + cmd.End (); + } + } + + public override void UpdateView () { + camera.AspectRatio = (float)Width / Height; + + matrices.projection = camera.Projection; + matrices.view = camera.View; + matrices.model = camera.Model; + Matrix4x4.Invert (camera.View, out Matrix4x4 inv); + matrices.camPos = new Vector4 (inv.M41, inv.M42, inv.M43, 0); + + uboMatrices.Update (matrices, (uint)Marshal.SizeOf ()); + + updateViewRequested = false; + } + + public override void Update () { + if (reloadModel) { + LoadModel (transferQ, modelPathes[curModelIndex]); + + updateViewRequested = true; + rebuildBuffers = true; + } + + if (rebuildBuffers) { + buildCommandBuffers (); + rebuildBuffers = false; + } + + } + + protected override void OnResize () { + base.OnResize (); + + dev.WaitIdle (); + + UpdateView (); + + createGBuff (); + + fbsMain?.Dispose(); + fbsMain = plLighting.RenderPass.CreateFrameBuffers(swapChain); + + rebuildBuffers = true; + + dev.WaitIdle (); + } + + #region Mouse and keyboard + protected override void onScroll (double xOffset, double yOffset) { + } + protected override void onMouseMove (double xPos, double yPos) { + double diffX = lastMouseX - xPos; + double diffY = lastMouseY - yPos; + if (MouseButton[0]) { + camera.Rotate ((float)-diffX, (float)-diffY); + } else if (MouseButton[1]) { + camera.SetZoom ((float)diffY); + } else + return; + + updateViewRequested = true; + } + + protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) { + //switch (key) { + // case Key.F: + // if (modifiers.HasFlag (Modifier.Shift)) { + // renderer.debugFace--; + // if (renderer.debugFace < 0) + // renderer.debugFace = 5; + // } else { + // renderer.debugFace++; + // if (renderer.debugFace >= 5) + // renderer.debugFace = 0; + // } + // rebuildBuffers = true; + // break; + // case Key.M: + // if (modifiers.HasFlag (Modifier.Shift)) { + // renderer.debugMip--; + // if (renderer.debugMip < 0) + // renderer.debugMip = (int)renderer.envCube.prefilterCube.CreateInfo.mipLevels - 1; + // } else { + // renderer.debugMip++; + // if (renderer.debugMip >= renderer.envCube.prefilterCube.CreateInfo.mipLevels) + // renderer.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: + // case Key.Keypad3: + // case Key.Keypad4: + // case Key.Keypad5: + // case Key.Keypad6: + // case Key.Keypad7: + // case Key.Keypad8: + // case Key.Keypad9: + // renderer.currentDebugView = (DeferredPbrRenderer.DebugView)(int)key-320; + // rebuildBuffers = true; + // break; + // case Key.KeypadDivide: + // 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.MoveLight(-Vector4.UnitZ); + // else + // camera.Move (0, 0, 1); + // break; + // case Key.Down: + // if (modifiers.HasFlag (Modifier.Shift)) + // renderer.MoveLight (Vector4.UnitZ); + // else + // camera.Move (0, 0, -1); + // break; + // case Key.Left: + // if (modifiers.HasFlag (Modifier.Shift)) + // renderer.MoveLight (-Vector4.UnitX); + // else + // camera.Move (1, 0, 0); + // break; + // case Key.Right: + // if (modifiers.HasFlag (Modifier.Shift)) + // renderer.MoveLight (Vector4.UnitX); + // else + // camera.Move (-1, 0, 0); + // break; + // case Key.PageUp: + // if (modifiers.HasFlag (Modifier.Shift)) + // renderer.MoveLight (Vector4.UnitY); + // else + // camera.Move (0, 1, 0); + // break; + // case Key.PageDown: + // if (modifiers.HasFlag (Modifier.Shift)) + // renderer.MoveLight (-Vector4.UnitY); + // else + // camera.Move (0, -1, 0); + // break; + // case Key.F2: + // if (modifiers.HasFlag (Modifier.Shift)) + // renderer.exposure -= 0.3f; + // else + // renderer.exposure += 0.3f; + // rebuildBuffers = true; + // break; + // case Key.F3: + // if (modifiers.HasFlag (Modifier.Shift)) + // renderer.gamma -= 0.1f; + // else + // renderer.gamma += 0.1f; + // rebuildBuffers = true; + // break; + // case Key.D: + // finalDebug = -finalDebug; + // rebuildBuffers = true; + // break; + + // case Key.KeypadAdd: + // curModelIndex++; + // if (curModelIndex >= modelPathes.Length) + // curModelIndex = 0; + // reloadModel = true; + // break; + // case Key.KeypadSubtract: + // curModelIndex--; + // if (curModelIndex < 0) + // curModelIndex = modelPathes.Length -1; + // reloadModel = true; + // break; + // default: + // base.onKeyDown (key, scanCode, modifiers); + // return; + //} + updateViewRequested = true; + } + #endregion + + protected override void Dispose (bool disposing) { + dev.WaitIdle (); + if (disposing) { + if (!isDisposed) { + fbsMain?.Dispose(); + fbGBuff?.Dispose (); + + gbColorRough.Dispose (); + gbEmitMetal.Dispose (); + gbN_AO.Dispose (); + gbPos.Dispose (); + + plGBuff.Dispose (); + plLighting.Dispose (); + + uboMatrices.Dispose (); + uboLights.Dispose (); + model.Dispose (); + envCube.Dispose (); + + descriptorPool.Dispose (); + dbgmsg.Dispose (); + + pipelineCache.Dispose (); + } + } + base.Dispose (disposing); + } + } +} diff --git a/samples/RayTests/mainShadow.cs b/samples/RayTests/mainShadow.cs new file mode 100644 index 0000000..0bc3103 --- /dev/null +++ b/samples/RayTests/mainShadow.cs @@ -0,0 +1,415 @@ +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Runtime.InteropServices; +using Glfw; +using VK; +using CVKL; + +namespace deferredShadow { + class Program : VkWindow{ + static void Main (string[] args) { + using (Program vke = new Program ()) { + vke.Run (); + } + } + + VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1; + + public struct Matrices { + public Matrix4x4 projection; + public Matrix4x4 view; + public Matrix4x4 model; + public Vector4 lightPos; + public float gamma; + public float exposure; + } + + public Matrices matrices = new Matrices { + lightPos = new Vector4 (1.0f, 0.0f, 0.0f, 1.0f), + gamma = 1.0f, + exposure = 2.0f, + }; + + const uint SHADOW_MAP_SIZE = 4096; + +#if DEBUG + PipelineStatisticsQueryPool statPool; + TimestampQueryPool timestampQPool; + ulong[] results; +#endif + + protected override void configureEnabledFeatures (ref VkPhysicalDeviceFeatures features) { + base.configureEnabledFeatures (ref features); +#if DEBUG + features.pipelineStatisticsQuery = true; +#endif + } + + Program () : base(true) { + //camera.Model = Matrix4x4.CreateRotationX (Utils.DegreesToRadians (-90)) * Matrix4x4.CreateRotationY (Utils.DegreesToRadians (180)); + //camera.SetRotation (-0.1f,-0.4f); + camera.SetPosition (0, 0, -3); + + init (); + +#if DEBUG + statPool = new PipelineStatisticsQueryPool (dev, + VkQueryPipelineStatisticFlags.InputAssemblyVertices | + VkQueryPipelineStatisticFlags.InputAssemblyPrimitives | + VkQueryPipelineStatisticFlags.ClippingInvocations | + VkQueryPipelineStatisticFlags.ClippingPrimitives | + VkQueryPipelineStatisticFlags.FragmentShaderInvocations); + + timestampQPool = new TimestampQueryPool (dev); +#endif + } + + Framebuffer[] frameBuffers; + Image gbColorRough, gbEmitMetal, gbN, gbPos; + + DescriptorPool descriptorPool; + DescriptorSetLayout descLayoutMain, descLayoutModelTextures, descLayoutGBuff; + DescriptorSet dsMain, dsGBuff; + + Pipeline gBuffPipeline, composePipeline; + + HostBuffer uboMats; + + RenderPass renderPass; + + Model model; + EnvironmentCube envCube; + + DebugDrawPipeline debugDraw; + Framebuffer[] debugFB; + + void init () { + VkFormat depthFormat = dev.GetSuitableDepthFormat (); + renderPass = new RenderPass (dev); + + renderPass.AddAttachment (swapChain.ColorFormat, VkImageLayout.ColorAttachmentOptimal, VkSampleCountFlags.SampleCount1); + renderPass.AddAttachment (depthFormat, VkImageLayout.DepthStencilAttachmentOptimal, samples); + renderPass.AddAttachment (VkFormat.R8g8b8a8Unorm, VkImageLayout.ColorAttachmentOptimal); + renderPass.AddAttachment (VkFormat.R8g8b8a8Unorm, VkImageLayout.ColorAttachmentOptimal); + renderPass.AddAttachment (VkFormat.R16g16b16a16Sfloat, VkImageLayout.ColorAttachmentOptimal); + renderPass.AddAttachment (VkFormat.R16g16b16a16Sfloat, VkImageLayout.ColorAttachmentOptimal); + //renderPass.AddAttachment (VkFormat.R16g16b16a16Sfloat, VkImageLayout.DepthStencilReadOnlyOptimal); + + 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) }); + renderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); + renderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); + renderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); + renderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); + + SubPass[] subpass = { new SubPass (), new SubPass (), new SubPass() }; + subpass[0].AddColorReference ( new VkAttachmentReference (2, VkImageLayout.ColorAttachmentOptimal), + new VkAttachmentReference (3, VkImageLayout.ColorAttachmentOptimal), + new VkAttachmentReference (4, VkImageLayout.ColorAttachmentOptimal), + new VkAttachmentReference (5, VkImageLayout.ColorAttachmentOptimal)); + subpass[0].SetDepthReference (1, VkImageLayout.DepthStencilAttachmentOptimal); + + subpass[1].AddColorReference (0, VkImageLayout.ColorAttachmentOptimal); + subpass[1].AddInputReference ( new VkAttachmentReference (2, VkImageLayout.ShaderReadOnlyOptimal), + new VkAttachmentReference (3, VkImageLayout.ShaderReadOnlyOptimal), + new VkAttachmentReference (4, VkImageLayout.ShaderReadOnlyOptimal), + new VkAttachmentReference (5, VkImageLayout.ShaderReadOnlyOptimal)); + renderPass.AddSubpass (subpass); + + renderPass.AddDependency (Vk.SubpassExternal, 0, + VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.ColorAttachmentOutput, + VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite); + renderPass.AddDependency (0, 1, + VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader, + VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.ShaderRead); + renderPass.AddDependency (1, Vk.SubpassExternal, + VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe, + VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead); + + + descriptorPool = new DescriptorPool (dev, 3, + new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer, 2), + new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, 3), + new VkDescriptorPoolSize (VkDescriptorType.InputAttachment, 4) + ); + + descLayoutMain = new DescriptorSetLayout (dev, + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer), + new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler)); + + descLayoutModelTextures = new DescriptorSetLayout (dev, + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (4, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler) + ); + + descLayoutGBuff = new DescriptorSetLayout (dev, + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment), + new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment), + new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment), + new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment)); + + dsMain = descriptorPool.Allocate (descLayoutMain); + dsGBuff = descriptorPool.Allocate (descLayoutGBuff); + + GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, samples); + cfg.Layout = new PipelineLayout (dev, descLayoutMain, descLayoutModelTextures, descLayoutGBuff); + cfg.Layout.AddPushConstants ( + new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf ()), + new VkPushConstantRange (VkShaderStageFlags.Fragment, (uint)Marshal.SizeOf (), 64) + ); + cfg.RenderPass = renderPass; + cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); + cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); + cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); + + cfg.AddVertexBinding (0); + cfg.SetVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat, VkFormat.R32g32Sfloat); + cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/pbrtest.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/GBuffPbr.frag.spv"); + + gBuffPipeline = new GraphicPipeline (cfg); + cfg.blendAttachments.Clear (); + cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); + cfg.ResetShadersAndVerticesInfos (); + cfg.SubpassIndex = 1; + cfg.Layout = gBuffPipeline.Layout; + cfg.depthStencilState.depthTestEnable = false; + cfg.depthStencilState.depthWriteEnable = false; + cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/FullScreenQuad.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/pbrtest.frag.spv"); + composePipeline = new GraphicPipeline (cfg); + + envCube = new EnvironmentCube (presentQueue, renderPass); + + uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, (ulong)Marshal.SizeOf () * 2); + uboMats.Map ();//permanent map + + DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descLayoutMain); + uboUpdate.Write (dev, dsMain, uboMats.Descriptor, + envCube.lutBrdf.Descriptor, + envCube.irradianceCube.Descriptor, + envCube.prefilterCube.Descriptor); + uboMats.Descriptor.offset = (ulong)Marshal.SizeOf (); + envCube.WriteDesc (uboMats.Descriptor); +#if DEBUG + debugDraw = new DebugDrawPipeline (dev, descLayoutMain, swapChain.ColorFormat); + debugDraw.AddLine (Vector3.Zero, new Vector3(matrices.lightPos.X,matrices.lightPos.Y,matrices.lightPos.Z)*3, 1, 1, 1); + debugDraw.AddLine (Vector3.Zero, Vector3.UnitX, 1, 0, 0); + debugDraw.AddLine (Vector3.Zero, Vector3.UnitY, 0, 1, 0); + debugDraw.AddLine (Vector3.Zero, Vector3.UnitZ, 0, 0, 1); +#endif + + + model = new Model (presentQueue, "../data/models/DamagedHelmet/glTF/DamagedHelmet.gltf"); + //model = new Model (presentQueue, "../data/models/chess.gltf"); + //model = new Model (presentQueue, "../data/models/Sponza/glTF/Sponza.gltf"); + //model = new Model (dev, presentQueue, "../data/models/icosphere.gltf"); + //model = new Model (dev, presentQueue, cmdPool, "../data/models/cube.gltf"); + model.WriteMaterialsDescriptorSets (descLayoutModelTextures, + VK.AttachmentType.Color, + VK.AttachmentType.Normal, + VK.AttachmentType.AmbientOcclusion, + VK.AttachmentType.PhysicalProps, + VK.AttachmentType.Emissive); + } + + void buildCommandBuffers () { + for (int i = 0; i < swapChain.ImageCount; ++i) { + cmds[i]?.Free (); + cmds[i] = cmdPool.AllocateCommandBuffer (); + cmds[i].Start (); + +#if DEBUG + statPool.Begin (cmds[i]); + recordDraw (cmds[i], frameBuffers[i]); + statPool.End (cmds[i]); + + debugDraw.RecordDraw (cmds[i], debugFB[i], camera); +#else + recordDraw (cmds[i], frameBuffers[i]); +#endif + + cmds[i].End (); + } + } + void recordDraw (CommandBuffer cmd, Framebuffer fb) { + renderPass.Begin (cmd, fb); + + cmd.SetViewport (fb.Width, fb.Height); + cmd.SetScissor (fb.Width, fb.Height); + + cmd.BindDescriptorSet (gBuffPipeline.Layout, dsMain); + gBuffPipeline.Bind (cmd); + model.Bind (cmd); + model.DrawAll (cmd, gBuffPipeline.Layout); + + renderPass.BeginSubPass (cmd); + + cmd.BindDescriptorSet (composePipeline.Layout, dsGBuff, 2); + composePipeline.Bind (cmd); + + cmd.Draw (3, 1, 0, 0); + + renderPass.End (cmd); + } + +#region update + void updateMatrices () { + camera.AspectRatio = (float)swapChain.Width / swapChain.Height; + + matrices.projection = camera.Projection; + matrices.view = camera.View; + matrices.model = camera.Model; + uboMats.Update (matrices, (uint)Marshal.SizeOf ()); + matrices.view *= Matrix4x4.CreateTranslation (-matrices.view.Translation); + matrices.model = Matrix4x4.Identity; + uboMats.Update (matrices, (uint)Marshal.SizeOf (), (uint)Marshal.SizeOf ()); + } + + public override void UpdateView () { + updateMatrices (); + updateViewRequested = false; + } + public override void Update () { +#if DEBUG + results = statPool.GetResults (); +#endif + } +#endregion + + + + void createGBuff () { + gbColorRough?.Dispose (); + gbEmitMetal?.Dispose (); + gbN?.Dispose (); + gbPos?.Dispose (); + + gbColorRough = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height); + gbEmitMetal = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height); + gbN = new Image (dev, VkFormat.R16g16b16a16Sfloat, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height); + gbPos = new Image (dev, VkFormat.R16g16b16a16Sfloat, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height); + + gbColorRough.CreateView (); + gbColorRough.CreateSampler (); + gbEmitMetal.CreateView (); + gbEmitMetal.CreateSampler (); + gbN.CreateView (); + gbN.CreateSampler (); + gbPos.CreateView (); + gbPos.CreateSampler (); + + DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descLayoutGBuff); + uboUpdate.Write (dev, dsGBuff, gbColorRough.Descriptor, + gbEmitMetal.Descriptor, + gbN.Descriptor, + gbPos.Descriptor); + gbColorRough.SetName ("GBuffColorRough"); + gbEmitMetal.SetName ("GBuffEmitMetal"); + gbN.SetName ("GBuffN"); + gbPos.SetName ("GBuffPos"); + } + + protected override void OnResize () { + updateMatrices (); + + if (frameBuffers != null) + for (int i = 0; i < swapChain.ImageCount; ++i) + frameBuffers[i]?.Dispose (); +#if DEBUG + if (debugFB != null) + for (int i = 0; i < swapChain.ImageCount; ++i) + debugFB[i]?.Dispose (); +#endif + + createGBuff (); + + frameBuffers = new Framebuffer[swapChain.ImageCount]; + debugFB = new Framebuffer[swapChain.ImageCount]; + + for (int i = 0; i < swapChain.ImageCount; ++i) { + frameBuffers[i] = new Framebuffer (renderPass, swapChain.Width, swapChain.Height, new Image[] { + swapChain.images[i], null, gbColorRough, gbEmitMetal, gbN, gbPos}); +#if DEBUG + debugFB[i] = new Framebuffer (debugDraw.RenderPass, swapChain.Width, swapChain.Height,(debugDraw.Samples == VkSampleCountFlags.SampleCount1) + ? new Image[] { swapChain.images[i] } : new Image[] { null, swapChain.images[i] }); + debugFB[i].SetName ("main FB " + i); +#endif + } + + buildCommandBuffers (); + } + + + #region Mouse and keyboard + protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) { + switch (key) { + case Key.F1: + if (modifiers.HasFlag (Modifier.Shift)) + matrices.exposure -= 0.3f; + else + matrices.exposure += 0.3f; + break; + case Key.F2: + if (modifiers.HasFlag (Modifier.Shift)) + matrices.gamma -= 0.1f; + else + matrices.gamma += 0.1f; + break; + case Key.F3: + if (camera.Type == Camera.CamType.FirstPerson) + camera.Type = Camera.CamType.LookAt; + else + camera.Type = Camera.CamType.FirstPerson; + Console.WriteLine ($"camera type = {camera.Type}"); + break; + default: + base.onKeyDown (key, scanCode, modifiers); + return; + } + updateViewRequested = true; + } +#endregion + + protected override void Dispose (bool disposing) { + if (disposing) { + if (!isDisposed) { + dev.WaitIdle (); + for (int i = 0; i < swapChain.ImageCount; ++i) + frameBuffers[i]?.Dispose (); + + gbColorRough.Dispose (); + gbEmitMetal.Dispose (); + gbN.Dispose (); + gbPos.Dispose (); + + gBuffPipeline.Dispose (); + composePipeline.Dispose (); + + descLayoutMain.Dispose (); + descLayoutModelTextures.Dispose (); + descLayoutGBuff.Dispose (); + + uboMats.Dispose (); + model.Dispose (); + envCube.Dispose (); + + descriptorPool.Dispose (); +#if DEBUG + debugDraw.Dispose (); + timestampQPool?.Dispose (); + statPool?.Dispose (); +#endif + } + } + + base.Dispose (disposing); + } + } +} diff --git a/samples/RayTests/mainWithDebugDrawer.cs b/samples/RayTests/mainWithDebugDrawer.cs new file mode 100644 index 0000000..f95ed0a --- /dev/null +++ b/samples/RayTests/mainWithDebugDrawer.cs @@ -0,0 +1,412 @@ +using System; +using System.Numerics; +using System.Runtime.InteropServices; +using Glfw; +using VK; +using CVKL; + +namespace deferredDebug { + class Program : VkWindow{ + static void Main (string[] args) { + using (Program vke = new Program ()) { + vke.Run (); + } + } + + VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1; + + public struct Matrices { + public Matrix4x4 projection; + public Matrix4x4 view; + public Matrix4x4 model; + public Vector4 lightPos; + public float gamma; + public float exposure; + } + + public Matrices matrices = new Matrices { + lightPos = new Vector4 (1.0f, 0, 0, 1.0f), + gamma = 1.0f, + exposure = 2.0f, + }; + +#if DEBUG + PipelineStatisticsQueryPool statPool; + TimestampQueryPool timestampQPool; + ulong[] results; +#endif + + protected override void configureEnabledFeatures (ref VkPhysicalDeviceFeatures features) { + base.configureEnabledFeatures (ref features); +#if DEBUG + features.pipelineStatisticsQuery = true; +#endif + } + + Program () : base(true) { + camera.Model = Matrix4x4.CreateRotationX (Utils.DegreesToRadians (-90)) * Matrix4x4.CreateRotationY (Utils.DegreesToRadians (180)); + camera.SetRotation (-0.1f,-0.4f); + camera.SetPosition (0, 0, -3); + + init (); + +#if DEBUG + statPool = new PipelineStatisticsQueryPool (dev, + VkQueryPipelineStatisticFlags.InputAssemblyVertices | + VkQueryPipelineStatisticFlags.InputAssemblyPrimitives | + VkQueryPipelineStatisticFlags.ClippingInvocations | + VkQueryPipelineStatisticFlags.ClippingPrimitives | + VkQueryPipelineStatisticFlags.FragmentShaderInvocations); + + timestampQPool = new TimestampQueryPool (dev); +#endif + } + + Framebuffer[] frameBuffers; + Image gbColorRough, gbEmitMetal, gbN, gbPos; + + DescriptorPool descriptorPool; + DescriptorSetLayout descLayoutMain, descLayoutModelTextures, descLayoutGBuff; + DescriptorSet dsMain, dsGBuff; + + Pipeline gBuffPipeline, composePipeline; + + HostBuffer uboMats; + + RenderPass renderPass; + + Model model; + EnvironmentCube envCube; + + DebugDrawPipeline debugDraw; + Framebuffer[] debugFB; + + void init () { + renderPass = new RenderPass (dev); + renderPass.AddAttachment (swapChain.ColorFormat, VkImageLayout.ColorAttachmentOptimal, VkSampleCountFlags.SampleCount1); + renderPass.AddAttachment (dev.GetSuitableDepthFormat(), VkImageLayout.DepthStencilAttachmentOptimal, samples); + renderPass.AddAttachment (VkFormat.R8g8b8a8Unorm, VkImageLayout.ColorAttachmentOptimal); + renderPass.AddAttachment (VkFormat.R8g8b8a8Unorm, VkImageLayout.ColorAttachmentOptimal); + renderPass.AddAttachment (VkFormat.R16g16b16a16Sfloat, VkImageLayout.ColorAttachmentOptimal); + renderPass.AddAttachment (VkFormat.R16g16b16a16Sfloat, VkImageLayout.ColorAttachmentOptimal); + + 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) }); + renderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); + renderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); + renderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); + renderPass.ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.0f) }); + + SubPass[] subpass = { new SubPass (), new SubPass () }; + subpass[0].AddColorReference ( new VkAttachmentReference (2, VkImageLayout.ColorAttachmentOptimal), + new VkAttachmentReference (3, VkImageLayout.ColorAttachmentOptimal), + new VkAttachmentReference (4, VkImageLayout.ColorAttachmentOptimal), + new VkAttachmentReference (5, VkImageLayout.ColorAttachmentOptimal)); + subpass[0].SetDepthReference (1, VkImageLayout.DepthStencilAttachmentOptimal); + + subpass[1].AddColorReference (0, VkImageLayout.ColorAttachmentOptimal); + subpass[1].AddInputReference ( new VkAttachmentReference (2, VkImageLayout.ShaderReadOnlyOptimal), + new VkAttachmentReference (3, VkImageLayout.ShaderReadOnlyOptimal), + new VkAttachmentReference (4, VkImageLayout.ShaderReadOnlyOptimal), + new VkAttachmentReference (5, VkImageLayout.ShaderReadOnlyOptimal)); + renderPass.AddSubpass (subpass); + + renderPass.AddDependency (Vk.SubpassExternal, 0, + VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.ColorAttachmentOutput, + VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite); + renderPass.AddDependency (0, 1, + VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader, + VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.ShaderRead); + renderPass.AddDependency (1, Vk.SubpassExternal, + VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe, + VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead); + + + descriptorPool = new DescriptorPool (dev, 3, + new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer, 2), + new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, 3), + new VkDescriptorPoolSize (VkDescriptorType.InputAttachment, 4) + ); + + descLayoutMain = new DescriptorSetLayout (dev, + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer), + new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler)); + + descLayoutModelTextures = new DescriptorSetLayout (dev, + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (4, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler) + ); + + descLayoutGBuff = new DescriptorSetLayout (dev, + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment), + new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment), + new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment), + new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment)); + + dsMain = descriptorPool.Allocate (descLayoutMain); + dsGBuff = descriptorPool.Allocate (descLayoutGBuff); + + GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, samples); + cfg.Layout = new PipelineLayout (dev, descLayoutMain, descLayoutModelTextures, descLayoutGBuff); + cfg.Layout.AddPushConstants ( + new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf ()), + new VkPushConstantRange (VkShaderStageFlags.Fragment, sizeof(int), 64) + ); + cfg.RenderPass = renderPass; + cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); + cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); + cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); + + cfg.AddVertexBinding (0); + cfg.SetVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat, VkFormat.R32g32Sfloat); + cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/pbrtest.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/GBuffPbr.frag.spv"); + + gBuffPipeline = new GraphicPipeline (cfg); + cfg.blendAttachments.Clear (); + cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); + cfg.ResetShadersAndVerticesInfos (); + cfg.SubpassIndex = 1; + cfg.Layout = gBuffPipeline.Layout; + cfg.depthStencilState.depthTestEnable = false; + cfg.depthStencilState.depthWriteEnable = false; + cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/FullScreenQuad.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/pbrtest.frag.spv"); + composePipeline = new GraphicPipeline (cfg); + + envCube = new EnvironmentCube (presentQueue, renderPass); + + uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, (ulong)Marshal.SizeOf () * 2); + uboMats.Map ();//permanent map + + DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descLayoutMain); + uboUpdate.Write (dev, dsMain, uboMats.Descriptor, + envCube.lutBrdf.Descriptor, + envCube.irradianceCube.Descriptor, + envCube.prefilterCube.Descriptor); + uboMats.Descriptor.offset = (ulong)Marshal.SizeOf (); + envCube.WriteDesc (uboMats.Descriptor); +#if DEBUG + debugDraw = new DebugDrawPipeline (dev, descLayoutMain, swapChain.ColorFormat); + debugDraw.AddLine (Vector3.Zero, new Vector3(matrices.lightPos.X,matrices.lightPos.Y,matrices.lightPos.Z)*3, 1, 1, 1); + debugDraw.AddLine (Vector3.Zero, Vector3.UnitX, 1, 0, 0); + debugDraw.AddLine (Vector3.Zero, Vector3.UnitY, 0, 1, 0); + debugDraw.AddLine (Vector3.Zero, Vector3.UnitZ, 0, 0, 1); +#endif + + + model = new Model (presentQueue, "../data/models/DamagedHelmet/glTF/DamagedHelmet.gltf"); + //model = new Model (presentQueue, "../data/models/chess.gltf"); + //model = new Model (presentQueue, "../data/models/Sponza/glTF/Sponza.gltf"); + //model = new Model (dev, presentQueue, "../data/models/icosphere.gltf"); + //model = new Model (dev, presentQueue, cmdPool, "../data/models/cube.gltf"); + model.WriteMaterialsDescriptorSets (descLayoutModelTextures, + VK.AttachmentType.Color, + VK.AttachmentType.Normal, + VK.AttachmentType.AmbientOcclusion, + VK.AttachmentType.PhysicalProps, + VK.AttachmentType.Emissive); + } + + void buildCommandBuffers () { + for (int i = 0; i < swapChain.ImageCount; ++i) { + cmds[i]?.Free (); + cmds[i] = cmdPool.AllocateCommandBuffer (); + cmds[i].Start (); + +#if DEBUG + statPool.Begin (cmds[i]); + recordDraw (cmds[i], frameBuffers[i]); + statPool.End (cmds[i]); + + debugDraw.RecordDraw (cmds[i], debugFB[i], camera); +#else + recordDraw (cmds[i], frameBuffers[i]); +#endif + + cmds[i].End (); + } + } + void recordDraw (CommandBuffer cmd, Framebuffer fb) { + renderPass.Begin (cmd, fb); + + cmd.SetViewport (fb.Width, fb.Height); + cmd.SetScissor (fb.Width, fb.Height); + + cmd.BindDescriptorSet (gBuffPipeline.Layout, dsMain); + gBuffPipeline.Bind (cmd); + model.Bind (cmd); + model.DrawAll (cmd, gBuffPipeline.Layout); + + renderPass.BeginSubPass (cmd); + + cmd.BindDescriptorSet (composePipeline.Layout, dsGBuff, 2); + composePipeline.Bind (cmd); + + cmd.Draw (3, 1, 0, 0); + + renderPass.End (cmd); + } + +#region update + void updateMatrices () { + camera.AspectRatio = (float)swapChain.Width / swapChain.Height; + + matrices.projection = camera.Projection; + matrices.view = camera.View; + matrices.model = camera.Model; + uboMats.Update (matrices, (uint)Marshal.SizeOf ()); + matrices.view *= Matrix4x4.CreateTranslation (-matrices.view.Translation); + matrices.model = Matrix4x4.Identity; + uboMats.Update (matrices, (uint)Marshal.SizeOf (), (uint)Marshal.SizeOf ()); + } + + public override void UpdateView () { + updateMatrices (); + updateViewRequested = false; + } + public override void Update () { +#if DEBUG + results = statPool.GetResults (); +#endif + } +#endregion + + + + void createGBuff () { + gbColorRough?.Dispose (); + gbEmitMetal?.Dispose (); + gbN?.Dispose (); + gbPos?.Dispose (); + + gbColorRough = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height); + gbEmitMetal = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height); + gbN = new Image (dev, VkFormat.R16g16b16a16Sfloat, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height); + gbPos = new Image (dev, VkFormat.R16g16b16a16Sfloat, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, swapChain.Width, swapChain.Height); + + gbColorRough.CreateView (); + gbColorRough.CreateSampler (); + gbEmitMetal.CreateView (); + gbEmitMetal.CreateSampler (); + gbN.CreateView (); + gbN.CreateSampler (); + gbPos.CreateView (); + gbPos.CreateSampler (); + + DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descLayoutGBuff); + uboUpdate.Write (dev, dsGBuff, gbColorRough.Descriptor, + gbEmitMetal.Descriptor, + gbN.Descriptor, + gbPos.Descriptor); + gbColorRough.SetName ("GBuffColorRough"); + gbEmitMetal.SetName ("GBuffEmitMetal"); + gbN.SetName ("GBuffN"); + gbPos.SetName ("GBuffPos"); + } + + protected override void OnResize () { + updateMatrices (); + + if (frameBuffers != null) + for (int i = 0; i < swapChain.ImageCount; ++i) + frameBuffers[i]?.Dispose (); +#if DEBUG + if (debugFB != null) + for (int i = 0; i < swapChain.ImageCount; ++i) + debugFB[i]?.Dispose (); +#endif + + createGBuff (); + + frameBuffers = new Framebuffer[swapChain.ImageCount]; + debugFB = new Framebuffer[swapChain.ImageCount]; + + for (int i = 0; i < swapChain.ImageCount; ++i) { + frameBuffers[i] = new Framebuffer (renderPass, swapChain.Width, swapChain.Height, new Image[] { + swapChain.images[i], null, gbColorRough, gbEmitMetal, gbN, gbPos}); +#if DEBUG + debugFB[i] = new Framebuffer (debugDraw.RenderPass, swapChain.Width, swapChain.Height,(debugDraw.Samples == VkSampleCountFlags.SampleCount1) + ? new Image[] { swapChain.images[i] } : new Image[] { null, swapChain.images[i] }); + debugFB[i].SetName ("main FB " + i); +#endif + } + + buildCommandBuffers (); + } + + + #region Mouse and keyboard + protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) { + switch (key) { + case Key.F1: + if (modifiers.HasFlag (Modifier.Shift)) + matrices.exposure -= 0.3f; + else + matrices.exposure += 0.3f; + break; + case Key.F2: + if (modifiers.HasFlag (Modifier.Shift)) + matrices.gamma -= 0.1f; + else + matrices.gamma += 0.1f; + break; + case Key.F3: + if (camera.Type == Camera.CamType.FirstPerson) + camera.Type = Camera.CamType.LookAt; + else + camera.Type = Camera.CamType.FirstPerson; + Console.WriteLine ($"camera type = {camera.Type}"); + break; + default: + base.onKeyDown (key, scanCode, modifiers); + return; + } + updateViewRequested = true; + } +#endregion + + protected override void Dispose (bool disposing) { + if (disposing) { + if (!isDisposed) { + dev.WaitIdle (); + for (int i = 0; i < swapChain.ImageCount; ++i) + frameBuffers[i]?.Dispose (); + + gbColorRough.Dispose (); + gbEmitMetal.Dispose (); + gbN.Dispose (); + gbPos.Dispose (); + + gBuffPipeline.Dispose (); + composePipeline.Dispose (); + + descLayoutMain.Dispose (); + descLayoutModelTextures.Dispose (); + descLayoutGBuff.Dispose (); + + uboMats.Dispose (); + model.Dispose (); + envCube.Dispose (); + + descriptorPool.Dispose (); +#if DEBUG + foreach (Framebuffer fb in debugFB) + fb.Dispose (); + + debugDraw.Dispose (); + timestampQPool?.Dispose (); + statPool?.Dispose (); +#endif + } + } + + base.Dispose (disposing); + } + } +} diff --git a/samples/RayTests/modelWithVkvgStats.cs b/samples/RayTests/modelWithVkvgStats.cs new file mode 100644 index 0000000..f4ea123 --- /dev/null +++ b/samples/RayTests/modelWithVkvgStats.cs @@ -0,0 +1,359 @@ +using System; +using System.Numerics; +using System.Runtime.InteropServices; +using Glfw; +using CVKL; +using VK; +using static CVKL.Camera; + +namespace modelWithVkvgStats { + class Program : VkWindow { + + PipelineStatisticsQueryPool statPool; + TimestampQueryPool timestampQPool; + + ulong[] results; + + protected override void configureEnabledFeatures (ref VkPhysicalDeviceFeatures features) { + base.configureEnabledFeatures (ref features); + features.pipelineStatisticsQuery = true; + } + public struct Matrices { + public Matrix4x4 projection; + public Matrix4x4 view; + public Matrix4x4 model; + public Vector4 lightPos; + public float gamma; + public float exposure; + } + + public Matrices matrices = new Matrices { + lightPos = new Vector4 (0.0f, 0.0f, -2.0f, 1.0f), + gamma = 1.0f, + exposure = 2.0f, + }; + + HostBuffer uboMats; + + DescriptorPool descriptorPool; + DescriptorSetLayout descLayoutMatrix; + DescriptorSetLayout descLayoutTextures; + DescriptorSet dsMats; + + GraphicPipeline pipeline; + GraphicPipeline uiPipeline; + Framebuffer[] frameBuffers; + + Model model; + + vkvg.Device vkvgDev; + vkvg.Surface vkvgSurf; + Image vkvgImage; + + void vkvgDraw () { + + using (vkvg.Context ctx = new vkvg.Context (vkvgSurf)) { + ctx.Operator = vkvg.Operator.Clear; + ctx.Paint (); + ctx.Operator = vkvg.Operator.Over; + + ctx.LineWidth = 1; + ctx.SetSource (0.1, 0.1, 0.1, 0.3); + ctx.Rectangle (5.5, 5.5, 400, 250); + ctx.FillPreserve (); + ctx.Flush (); + ctx.SetSource (0.8, 0.8, 0.8); + ctx.Stroke (); + + ctx.FontFace = "mono"; + ctx.FontSize = 10; + int x = 16; + int y = 40, dy = 16; + ctx.MoveTo (x, y); + ctx.ShowText (string.Format ($"fps: {fps,5} ")); + ctx.MoveTo (x + 200, y - 0.5); + ctx.Rectangle (x + 200, y - 8.5, 0.1 * fps, 10); + ctx.SetSource (0.1, 0.9, 0.1); + ctx.Fill (); + ctx.SetSource (0.8, 0.8, 0.8); + y += dy; + ctx.MoveTo (x, y); + ctx.ShowText (string.Format ($"Exposure:{matrices.exposure,5} ")); + y += dy; + ctx.MoveTo (x, y); + ctx.ShowText (string.Format ($"Gamma: {matrices.gamma,5} ")); + if (results == null) + return; + + y += dy*2; + ctx.MoveTo (x, y); + ctx.ShowText ("Pipeline Statistics"); + ctx.MoveTo (x-2, 2.5+y); + ctx.LineTo (x+160, 2.5+y); + ctx.Stroke (); + y += 4; + x += 20; + + for (int i = 0; i < statPool.RequestedStats.Length; i++) { + y += dy; + ctx.MoveTo (x, y); + ctx.ShowText (string.Format ($"{statPool.RequestedStats[i].ToString(),-30} :{results[i],12:0,0} ")); + } + + y += dy; + ctx.MoveTo (x, y); + ctx.ShowText (string.Format ($"{"Elapsed microsecond",-20} :{timestampQPool.ElapsedMiliseconds:0.0000} ")); + } + } + + Program () : base () { + vkvgDev = new vkvg.Device (instance.Handle, phy.Handle, dev.VkDev.Handle, presentQueue.qFamIndex, + vkvg.SampleCount.Sample_4, presentQueue.index); + + camera.Type = CamType.FirstPerson; + camera.Model = Matrix4x4.CreateScale (0.05f) * Matrix4x4.CreateRotationX((float)Math.PI); + //Camera.SetRotation (-0.1f,-0.4f); + camera.SetPosition (0, 2, -3); + + init (); + + model = new Model (presentQueue, "../data/models/Sponza/glTF/Sponza.gltf"); + model.WriteMaterialsDescriptorSets (descLayoutTextures, + VK.AttachmentType.Color, + VK.AttachmentType.Normal, + VK.AttachmentType.AmbientOcclusion, + VK.AttachmentType.PhysicalProps, + VK.AttachmentType.Emissive); + } + + void init (VkSampleCountFlags samples = VkSampleCountFlags.SampleCount4) { + descriptorPool = new DescriptorPool (dev, 2, + new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer), + new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler) + ); + + descLayoutMatrix = new DescriptorSetLayout (dev, + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Vertex|VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer), + new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler) + ); + + descLayoutTextures = new DescriptorSetLayout (dev, + new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (4, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler) + ); + + dsMats = descriptorPool.Allocate (descLayoutMatrix); + + GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, samples); + + cfg.Layout = new PipelineLayout (dev, descLayoutMatrix, descLayoutTextures); + cfg.Layout.AddPushConstants ( + new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf ()), + new VkPushConstantRange (VkShaderStageFlags.Fragment, (uint)Marshal.SizeOf (), 64) + ); + cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, dev.GetSuitableDepthFormat (), samples); + + cfg.AddVertexBinding (0); + cfg.SetVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat, VkFormat.R32g32Sfloat); + + cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/pbrtest.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/pbrtest.frag.spv"); + + pipeline = new GraphicPipeline (cfg); + + cfg.ResetShadersAndVerticesInfos (); + cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/FullScreenQuad.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/simpletexture.frag.spv"); + + cfg.blendAttachments[0] = new VkPipelineColorBlendAttachmentState (true); + + uiPipeline = new GraphicPipeline (cfg); + + uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, (ulong)Marshal.SizeOf()); + uboMats.Map ();//permanent map + + DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsMats, descLayoutMatrix.Bindings[0]); + uboUpdate.Write (dev, uboMats.Descriptor); + + cfg.Layout.SetName ("Main Pipeline layout"); + uboMats.SetName ("uboMats"); + descriptorPool.SetName ("main pool"); + descLayoutTextures.SetName ("descLayoutTextures"); + + statPool = new PipelineStatisticsQueryPool (dev, + VkQueryPipelineStatisticFlags.InputAssemblyVertices | + VkQueryPipelineStatisticFlags.InputAssemblyPrimitives | + VkQueryPipelineStatisticFlags.ClippingInvocations | + VkQueryPipelineStatisticFlags.ClippingPrimitives | + VkQueryPipelineStatisticFlags.FragmentShaderInvocations); + + timestampQPool = new TimestampQueryPool (dev); + + } + + void buildCommandBuffers () { + for (int i = 0; i < swapChain.ImageCount; ++i) { + cmds[i]?.Free (); + + cmds[i] = cmdPool.AllocateCommandBuffer (); + cmds[i].Start (); + + statPool.Begin (cmds[i]); + cmds[i].BeginRegion ("draw" + i, 0.5f, 1f, 0f); + cmds[i].Handle.SetDebugMarkerName (dev, "cmd Draw" + i); + recordDraw (cmds[i], frameBuffers[i]); + cmds[i].EndRegion (); + statPool.End (cmds[i]); + cmds[i].End (); + } + } + void recordDraw (CommandBuffer cmd, Framebuffer fb) { + cmd.BeginRegion ("models", 0.5f, 1f, 0f); + pipeline.RenderPass.Begin (cmd, fb); + + cmd.SetViewport (fb.Width, fb.Height); + cmd.SetScissor (fb.Width, fb.Height); + + cmd.BindDescriptorSet (pipeline.Layout, dsMats); + pipeline.Bind (cmd); + model.Bind (cmd); + model.DrawAll (cmd, pipeline.Layout); + + cmd.EndRegion (); + cmd.BeginRegion ("vkvg", 0.5f, 1f, 0f); + uiPipeline.Bind (cmd); + + timestampQPool.Start (cmd); + + vkvgImage.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.ColorAttachmentOptimal, VkImageLayout.ShaderReadOnlyOptimal, + VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader); + + cmd.Draw (3, 1, 0, 0); + + vkvgImage.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.ShaderReadOnlyOptimal, VkImageLayout.ColorAttachmentOptimal, + VkPipelineStageFlags.FragmentShader, VkPipelineStageFlags.BottomOfPipe); + + timestampQPool.End (cmd); + + pipeline.RenderPass.End (cmd); + cmd.EndRegion (); + } + + #region update + void updateMatrices () { + + camera.AspectRatio = (float)swapChain.Width / swapChain.Height; + + matrices.projection = camera.Projection; + matrices.view = camera.View; + matrices.model = camera.Model; + uboMats.Update (matrices, (uint)Marshal.SizeOf ()); + } + + public override void UpdateView () { + updateMatrices (); + updateViewRequested = false; + } + public override void Update () { + results = statPool.GetResults (); + vkvgDraw (); + } + #endregion + + #region mouse and keyboard + protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) { + switch (key) { + case Key.F1: + if (modifiers.HasFlag (Modifier.Shift)) + matrices.exposure -= 0.3f; + else + matrices.exposure += 0.3f; + break; + case Key.F2: + if (modifiers.HasFlag (Modifier.Shift)) + matrices.gamma -= 0.1f; + else + matrices.gamma += 0.1f; + break; + case Key.F3: + if (camera.Type == CamType.FirstPerson) + camera.Type = CamType.LookAt; + else + camera.Type = CamType.FirstPerson; + break; + default: + base.onKeyDown (key, scanCode, modifiers); + return; + } + updateViewRequested = true; + } + #endregion + + protected override void OnResize () { + + vkvgImage?.Dispose (); + vkvgSurf?.Dispose (); + vkvgSurf = new vkvg.Surface (vkvgDev, (int)swapChain.Width, (int)swapChain.Height); + vkvgImage = new Image (dev, new VkImage ((ulong)vkvgSurf.VkImage.ToInt64 ()), VkFormat.B8g8r8a8Unorm, + VkImageUsageFlags.ColorAttachment, (uint)vkvgSurf.Width, (uint)vkvgSurf.Height); + vkvgImage.CreateView (VkImageViewType.ImageView2D, VkImageAspectFlags.Color); + vkvgImage.CreateSampler (VkFilter.Nearest,VkFilter.Nearest, VkSamplerMipmapMode.Nearest, VkSamplerAddressMode.ClampToBorder); + + vkvgImage.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsMats, descLayoutMatrix.Bindings[1]); + uboUpdate.Write (dev, vkvgImage.Descriptor); + + updateMatrices (); + + if (frameBuffers!=null) + for (int i = 0; i < swapChain.ImageCount; ++i) + frameBuffers[i]?.Dispose (); + + frameBuffers = new Framebuffer[swapChain.ImageCount]; + + for (int i = 0; i < swapChain.ImageCount; ++i) { + frameBuffers[i] = new Framebuffer (pipeline.RenderPass, swapChain.Width, swapChain.Height, + (pipeline.Samples == VkSampleCountFlags.SampleCount1) ? new Image[] { + swapChain.images[i], + null + } : new Image[] { + null, + null, + swapChain.images[i] + }); + frameBuffers[i].SetName ("main FB " + i); + + } + + buildCommandBuffers (); + } + + protected override void Dispose (bool disposing) { + if (disposing) { + if (!isDisposed) { + dev.WaitIdle (); + for (int i = 0; i < swapChain.ImageCount; ++i) + frameBuffers[i]?.Dispose (); + model.Dispose (); + pipeline.Dispose (); + descLayoutMatrix.Dispose (); + descLayoutTextures.Dispose (); + descriptorPool.Dispose (); + + uboMats.Dispose (); + + vkvgSurf?.Dispose (); + vkvgDev.Dispose (); + + timestampQPool.Dispose (); + statPool.Dispose (); + } + } + + base.Dispose (disposing); + } + } +} diff --git a/samples/RayTests/shaders/GBuffPbr.vert b/samples/RayTests/shaders/GBuffPbr.vert new file mode 100644 index 0000000..7cafe49 --- /dev/null +++ b/samples/RayTests/shaders/GBuffPbr.vert @@ -0,0 +1,37 @@ +#version 450 + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec3 inNormal; +layout (location = 2) in vec2 inUV0; +layout (location = 3) in vec2 inUV1; + +layout (set = 0, binding = 0) uniform UBO { + mat4 projection; + mat4 model; + mat4 view; +} ubo; + +layout(push_constant) uniform PushConsts { + mat4 model; +} pc; + +layout (location = 0) out vec3 outWorldPos; +layout (location = 1) out vec3 outNormal; +layout (location = 2) out vec2 outUV0; +layout (location = 3) out vec2 outUV1; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + +void main() +{ + vec4 locPos = ubo.model * pc.model * vec4(inPos, 1.0); + outNormal = normalize(transpose(inverse(mat3(ubo.model * pc.model))) * inNormal); + + outWorldPos = locPos.xyz; + outUV0 = inUV0; + outUV1 = inUV1; + gl_Position = ubo.projection * ubo.view * vec4(outWorldPos, 1.0); +} diff --git a/samples/RayTests/shaders/GBuffPbrCommon.inc b/samples/RayTests/shaders/GBuffPbrCommon.inc new file mode 100644 index 0000000..a56e65c --- /dev/null +++ b/samples/RayTests/shaders/GBuffPbrCommon.inc @@ -0,0 +1,56 @@ +layout (constant_id = 0) const float NEAR_PLANE = 0.1f; +layout (constant_id = 1) const float FAR_PLANE = 256.0f; +layout (constant_id = 2) const int MAT_COUNT = 1; + +const float M_PI = 3.141592653589793; +const float c_MinRoughness = 0.04; + +const float PBR_WORKFLOW_METALLIC_ROUGHNESS = 1.0; +const float PBR_WORKFLOW_SPECULAR_GLOSINESS = 2.0f; + +const uint MAP_COLOR = 0x1; +const uint MAP_NORMAL = 0x2; +const uint MAP_AO = 0x4; +const uint MAP_METAL = 0x8; +const uint MAP_ROUGHNESS = 0x10; +const uint MAP_METALROUGHNESS = 0x20; +const uint MAP_EMISSIVE = 0x40; + +layout (location = 0) in vec3 inWorldPos; +layout (location = 1) in vec3 inNormal; +layout (location = 2) in vec2 inUV0; +layout (location = 3) in vec2 inUV1; + +layout (set = 1, binding = 0) uniform UBOMaterials { + Material materials[MAT_COUNT]; +}; + +layout (push_constant) uniform PushCsts { + layout(offset = 64) + int materialIdx; +}; + +layout (location = 0) out vec4 outColorRough; +layout (location = 1) out vec4 outEmitMetal; +layout (location = 2) out vec4 outN_AO; +layout (location = 3) out vec4 outPos; + +// 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 linearDepth(float depth) +{ + float z = depth * 2.0f - 1.0f; + return (2.0f * NEAR_PLANE * FAR_PLANE) / (FAR_PLANE + NEAR_PLANE - z * (FAR_PLANE - NEAR_PLANE)); +} \ No newline at end of file diff --git a/samples/RayTests/shaders/GBuffPbrTexArray.frag b/samples/RayTests/shaders/GBuffPbrTexArray.frag new file mode 100644 index 0000000..7334609 --- /dev/null +++ b/samples/RayTests/shaders/GBuffPbrTexArray.frag @@ -0,0 +1,142 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +#define MANUAL_SRGB 0 + +struct Material { + vec4 baseColorFactor; + vec4 emissiveFactor; + vec4 diffuseFactor; + vec4 specularFactor; + + float workflow; + uint tex0; + uint tex1; + int baseColorTex; + + int physicalDescTex; + int normalTex; + int occlusionTex; + int emissiveTex; + + float metallicFactor; + float roughnessFactor; + float alphaMask; + float alphaMaskCutoff; +}; + +#include "GBuffPbrCommon.inc" +#include "tonemap.inc" + +layout (set = 1, binding = 1) uniform sampler2DArray texArray; + +// Find the normal for this fragment, pulling either from a predefined normal map +// or from the interpolated mesh normal and tangent attributes. +vec3 getNormal() +{ + vec3 tangentNormal; + // Perturb normal, see http://www.thetenthplanet.de/archives/1180 + if ((materials[materialIdx].tex0 & MAP_NORMAL) == MAP_NORMAL) + tangentNormal = texture(texArray, vec3(inUV0, materials[materialIdx].normalTex)).xyz * 2.0 - 1.0; + else if ((materials[materialIdx].tex1 & MAP_NORMAL) == MAP_NORMAL) + tangentNormal = texture(texArray, vec3(inUV1, materials[materialIdx].normalTex)).xyz * 2.0 - 1.0; + else + return normalize(inNormal); + + vec3 q1 = dFdx(inWorldPos); + vec3 q2 = dFdy(inWorldPos); + vec2 st1 = dFdx(inUV0); + vec2 st2 = dFdy(inUV0); + + vec3 N = normalize(inNormal); + vec3 T = normalize(q1 * st2.t - q2 * st1.t); + vec3 B = -normalize(cross(N, T)); + mat3 TBN = mat3(T, B, N); + + return normalize(TBN * tangentNormal); +} + +void main() +{ + float perceptualRoughness; + float metallic; + vec4 baseColor; + vec3 emissive = vec3(0); + + baseColor = materials[materialIdx].baseColorFactor; + + if (materials[materialIdx].workflow == PBR_WORKFLOW_METALLIC_ROUGHNESS) { + perceptualRoughness = materials[materialIdx].roughnessFactor; + metallic = materials[materialIdx].metallicFactor; + // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel. + // This layout intentionally reserves the 'r' channel for (optional) occlusion map data + if ((materials[materialIdx].tex0 & MAP_METALROUGHNESS) == MAP_METALROUGHNESS){ + perceptualRoughness *= texture(texArray, vec3(inUV0, materials[materialIdx].physicalDescTex)).g; + metallic *= texture(texArray, vec3(inUV0, materials[materialIdx].physicalDescTex)).b; + }else if ((materials[materialIdx].tex1 & MAP_METALROUGHNESS) == MAP_METALROUGHNESS){ + perceptualRoughness *= texture(texArray, vec3(inUV1, materials[materialIdx].physicalDescTex)).g; + metallic *= texture(texArray, vec3(inUV1, materials[materialIdx].physicalDescTex)).b; + } + perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0); + metallic = clamp(metallic, 0.0, 1.0); + + // The albedo may be defined from a base texture or a flat color + if ((materials[materialIdx].tex0 & MAP_COLOR) == MAP_COLOR) + baseColor *= SRGBtoLINEAR(texture(texArray, vec3(inUV0, materials[materialIdx].baseColorTex))); + else if ((materials[materialIdx].tex1 & MAP_COLOR) == MAP_COLOR) + baseColor *= SRGBtoLINEAR(texture(texArray, vec3(inUV1, materials[materialIdx].baseColorTex))); + } + + if (materials[materialIdx].alphaMask == 1.0f) { + if (baseColor.a < materials[materialIdx].alphaMaskCutoff) + discard; + } + + if (materials[materialIdx].workflow == PBR_WORKFLOW_SPECULAR_GLOSINESS) { + // Values from specular glossiness workflow are converted to metallic roughness + if ((materials[materialIdx].tex0 & MAP_METALROUGHNESS) == MAP_METALROUGHNESS) + perceptualRoughness = 1.0 - texture(texArray, vec3(inUV0, materials[materialIdx].physicalDescTex)).a; + else if ((materials[materialIdx].tex1 & MAP_METALROUGHNESS) == MAP_METALROUGHNESS) + perceptualRoughness = 1.0 - texture(texArray, vec3(inUV1, materials[materialIdx].physicalDescTex)).a; + else + perceptualRoughness = 0.0; + + const float epsilon = 1e-6; + + vec4 diffuse = SRGBtoLINEAR(texture(texArray, vec3(inUV0, materials[materialIdx].baseColorTex))); + vec3 specular = SRGBtoLINEAR(texture(texArray, vec3(inUV0, materials[materialIdx].physicalDescTex))).rgb; + + float maxSpecular = max(max(specular.r, specular.g), specular.b); + + // Convert metallic value from specular glossiness inputs + metallic = convertMetallic(diffuse.rgb, specular, maxSpecular); + + vec3 baseColorDiffusePart = diffuse.rgb * ((1.0 - maxSpecular) / (1 - c_MinRoughness) / max(1 - metallic, epsilon)) * materials[materialIdx].diffuseFactor.rgb; + vec3 baseColorSpecularPart = specular - (vec3(c_MinRoughness) * (1 - metallic) * (1 / max(metallic, epsilon))) * materials[materialIdx].specularFactor.rgb; + baseColor = vec4(mix(baseColorDiffusePart, baseColorSpecularPart, metallic * metallic), diffuse.a); + + } + + const float u_OcclusionStrength = 1.0f; + const float u_EmissiveFactor = 1.0f; + float ao = 1.0f; + + if ((materials[materialIdx].tex0 & MAP_EMISSIVE) == MAP_EMISSIVE) + emissive = SRGBtoLINEAR(texture(texArray, vec3(inUV0, materials[materialIdx].emissiveTex))).rgb * u_EmissiveFactor; + else if ((materials[materialIdx].tex1 & MAP_EMISSIVE) == MAP_EMISSIVE) + emissive = SRGBtoLINEAR(texture(texArray, vec3(inUV1, materials[materialIdx].emissiveTex))).rgb * u_EmissiveFactor; + + if ((materials[materialIdx].tex0 & MAP_AO) == MAP_AO) + ao = texture(texArray, vec3(inUV0, materials[materialIdx].occlusionTex)).r; + else if ((materials[materialIdx].tex1 & MAP_AO) == MAP_AO) + ao = texture(texArray, vec3(inUV1, materials[materialIdx].occlusionTex)).r; + + vec3 n = getNormal(); + vec3 p = inWorldPos; + + outColorRough = vec4 (baseColor.rgb, perceptualRoughness); + outEmitMetal = vec4 (emissive, metallic); + outN_AO = vec4 (n, ao); + outPos = vec4 (p, linearDepth(gl_FragCoord.z)); +} \ No newline at end of file diff --git a/samples/RayTests/shaders/compose.frag b/samples/RayTests/shaders/compose.frag new file mode 100644 index 0000000..64c8e48 --- /dev/null +++ b/samples/RayTests/shaders/compose.frag @@ -0,0 +1,158 @@ +#include "preamble.inc" + +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 = 1, binding = 7) uniform UBOLights { + Light lights[NUM_LIGHTS]; +}; + +const float M_PI = 3.141592653589793; +const float c_MinRoughness = 0.04; + +layout (set = 1, binding = 0) uniform sampler2D samplerColorRough; +layout (set = 1, binding = 1) uniform sampler2D samplerEmitMetal; +layout (set = 1, binding = 2) uniform sampler2D samplerN_AO; +layout (set = 1, binding = 3) uniform sampler2D samplerPos; + +layout (set = 1, binding = 4) uniform samplerCube samplerIrradiance; +layout (set = 1, binding = 5) uniform samplerCube prefilteredMap; +layout (set = 1, binding = 6) uniform sampler2D samplerBRDFLUT; + +layout (location = 0) in vec2 inUV; + +layout (location = 0) out vec4 outColor; + +#include "pbr.inc" +#include "tonemap.inc" + +// 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; +} + +void main() +{ + if (texture(samplerPos, inUV).a == 1.0f) + discard; + + float perceptualRoughness = texture(samplerColorRough, inUV).a; + float metallic = texture(samplerEmitMetal, inUV).a; + vec3 diffuseColor; + vec4 baseColor = vec4(texture(samplerColorRough, inUV).rgb, 1); + vec3 emissive = texture (samplerEmitMetal, inUV).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 = texture(samplerN_AO, inUV).rgb; + vec3 pos = texture(samplerPos, inUV).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 ()) + ); + + cfg.AddVertexBinding (0); + cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat); + + cfg.AddShader (VkShaderStageFlags.Vertex, "#RayTests.shadow.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Geometry, "#RayTests.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); + + gQueue.EndSubmitAndWait (cmd); + updateShadowMap = false; + } + + + public void Dispose () { + shadowPipeline?.Dispose (); + fbShadowMap?.Dispose (); + shadowMap?.Dispose (); + descriptorPool?.Dispose (); + } + } +} diff --git a/samples/RayTests/ui/debug.crow b/samples/RayTests/ui/debug.crow new file mode 100644 index 0000000..4d78bf1 --- /dev/null +++ b/samples/RayTests/ui/debug.crow @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/samples/RayTests/ui/deferred.style b/samples/RayTests/ui/deferred.style new file mode 100644 index 0000000..c21ffb6 --- /dev/null +++ b/samples/RayTests/ui/deferred.style @@ -0,0 +1,61 @@ +icon { + Width="14"; + Height="14"; +} +MemberViewLabel { + Margin="1"; + Height="Fit"; + Width="50%"; + Background="White"; +} +MemberViewHStack { + Focusable="true"; + Height="Fit"; + Spacing="1"; + MouseEnter="{Background=SteelBlue}"; + MouseLeave="{Background=Transparent}"; +} + +IcoBut { + Template = "#Crow.Coding.ui.IcoBut.template"; + MinimumSize = "10,10"; + Width = "8"; + Height = "14"; + Background = "White"; +} + +WinSchema { + Template="#Crow.Coding.ui.DockWindows.WinSchemaItem.template"; + Focusable = "true"; + MinimumSize="150,50"; + Width = "Fit"; + Height = "Fit"; +} +TabItem { + AllowDrag="false"; + Background="Jet"; +} +TreeItemBorder { + CornerRadius="2"; + Margin="0"; + Focusable="true"; + Height="Fit"; + Width="Stretched"; + Foreground="Transparent"; + MouseEnter="{Foreground=DimGrey}"; + MouseLeave="{Foreground=Transparent}"; +} +TreeIcon { + Margin="0"; + Width="14"; + Height="14"; +} +NormalizedFloat { + Minimum="0.0"; + Maximum="1.0"; + SmallIncrement="0.01"; + LargeIncrement="0.1"; + Decimals="2"; + Width="60"; + Foreground="Black"; +} diff --git a/samples/RayTests/ui/main.crow b/samples/RayTests/ui/main.crow new file mode 100644 index 0000000..14e6082 --- /dev/null +++ b/samples/RayTests/ui/main.crow @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/RayTests/ui/materials.crow b/samples/RayTests/ui/materials.crow new file mode 100644 index 0000000..b4c5432 --- /dev/null +++ b/samples/RayTests/ui/materials.crow @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + +