diff options
| author | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2019-04-13 16:59:32 +0200 |
|---|---|---|
| committer | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2019-04-13 16:59:32 +0200 |
| commit | 72b70df09efbb32cd4d21529dffbf786fd180af8 (patch) | |
| tree | da881b195f61f90e159bc502d1f33e850c6478b7 /samples | |
| parent | 8efa7490d87e35853944c331c2944fdc41cb594a (diff) | |
pbr test with crow cairo backend
Diffstat (limited to 'samples')
28 files changed, 2132 insertions, 14 deletions
diff --git a/samples/Pbr/main.cs b/samples/Pbr/main.cs index c62d542..90adff9 100644 --- a/samples/Pbr/main.cs +++ b/samples/Pbr/main.cs @@ -12,8 +12,12 @@ namespace PbrSample { vke.Run (); } } - - public struct Matrices { + +#if DEBUG && DEBUG_MARKER + public override string[] EnabledExtensions => new string[] { "VK_KHR_swapchain", "VK_EXT_debug_marker" }; +#endif + + public struct Matrices { public Matrix4x4 projection; public Matrix4x4 view; public Matrix4x4 model; @@ -109,6 +113,7 @@ namespace PbrSample { init (); + //model = new Model (dev, presentQueue, cmdPool, "/mnt/devel/vkChess/data/chess.gltf"); model = new Model (dev, presentQueue, cmdPool, "../data/models/DamagedHelmet/glTF/DamagedHelmet.gltf"); model.WriteMaterialsDescriptorSets (descLayoutTextures, ShaderBinding.Color, diff --git a/samples/Pbr/packages.config b/samples/Pbr/packages.config index 9464e04..713c52d 100644 --- a/samples/Pbr/packages.config +++ b/samples/Pbr/packages.config @@ -6,5 +6,5 @@ <package id="System.Memory" version="4.5.2" targetFramework="net471" /> <package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net471" /> <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net471" /> - <package id="Vulkan" version="0.1.1-alpha" targetFramework="net471" /> + <package id="Vulkan" version="0.1.2.2-alpha" targetFramework="net471" /> </packages>
\ No newline at end of file diff --git a/samples/Pbr/pbr.csproj b/samples/Pbr/pbr.csproj index b1209c0..11aedb7 100644 --- a/samples/Pbr/pbr.csproj +++ b/samples/Pbr/pbr.csproj @@ -13,7 +13,7 @@ <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> - <DefineConstants>DEBUG;</DefineConstants> + <DefineConstants>DEBUG;DEBUG_MARKER</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> @@ -54,7 +54,7 @@ <HintPath>..\..\packages\System.Memory.4.5.2\lib\netstandard2.0\System.Memory.dll</HintPath> </Reference> <Reference Include="VK"> - <HintPath>..\..\packages\Vulkan.0.1.1-alpha\lib\netstandard2.0\VK.dll</HintPath> + <HintPath>..\..\packages\Vulkan.0.1.2.2-alpha\lib\netstandard2.0\VK.dll</HintPath> </Reference> </ItemGroup> <ItemGroup> diff --git a/samples/SashaWillemPbr/SachaWillemPbr.csproj b/samples/SashaWillemPbr/SachaWillemPbr.csproj new file mode 100644 index 0000000..5fc3162 --- /dev/null +++ b/samples/SashaWillemPbr/SachaWillemPbr.csproj @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <ProjectGuid>{1F18E74F-BCC9-481C-8FDF-89D81CBB30BE}</ProjectGuid> + <OutputType>Exe</OutputType> + <RootNamespace>SachaWillemPbr</RootNamespace> + <AssemblyName>SachaWillemPbr</AssemblyName> + <TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion> + <OutputPath>$(SolutionDir)build\$(Configuration)\samples\SachaWillemPbr</OutputPath> + <IntermediateOutputPath>$(SolutionDir)build\obj\$(Configuration)</IntermediateOutputPath> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <DefineConstants>DEBUG;DEBUG_MARKER</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <Optimize>true</Optimize> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <ItemGroup> + <Compile Include="*.cs" /> + <GLSLShader Include="shaders\**\*.frag;shaders\**\*.vert" /> + <Datas Include="..\data\**\*.*"> + <Link>data\%(RecursiveDir)%(Filename)%(Extension)</Link> + </Datas> + </ItemGroup> + <ItemGroup> + <Reference Include="System.Numerics" /> + <Reference Include="System" /> + <Reference Include="System.Numerics.Vectors"> + <HintPath>..\..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath> + </Reference> + <Reference Include="mscorlib" /> + <Reference Include="Newtonsoft.Json"> + <HintPath>..\..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> + </Reference> + <Reference Include="glTFLoader"> + <HintPath>..\..\packages\glTF2Loader.1.1.3-alpha\lib\net35\glTFLoader.dll</HintPath> + </Reference> + <Reference Include="System.Buffers"> + <HintPath>..\..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll</HintPath> + </Reference> + <Reference Include="System.Runtime.CompilerServices.Unsafe"> + <HintPath>..\..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath> + </Reference> + <Reference Include="System.Memory"> + <HintPath>..\..\packages\System.Memory.4.5.2\lib\netstandard2.0\System.Memory.dll</HintPath> + </Reference> + <Reference Include="VK"> + <HintPath>..\..\packages\Vulkan.0.1.2.2-alpha\lib\netstandard2.0\VK.dll</HintPath> + </Reference> + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + <None Include="ui\fps.crow"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\vke\VKE.csproj"> + <Project>{32B7E80D-BEA7-4811-B82D-CC2533069F0A}</Project> + <Name>VKE</Name> + </ProjectReference> + <ProjectReference Include="..\..\crow\Crow\Crow.csproj"> + <Project>{C2980F9B-4798-4C05-99E2-E174810F7C7B}</Project> + <Name>Crow</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <Folder Include="ui\" /> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <Import Project="$(SolutionDir)spirv.targets" /> +</Project> diff --git a/samples/SashaWillemPbr/main.cs b/samples/SashaWillemPbr/main.cs new file mode 100644 index 0000000..30a50e9 --- /dev/null +++ b/samples/SashaWillemPbr/main.cs @@ -0,0 +1,709 @@ +using System; +using System.Numerics; +using System.Runtime.InteropServices; +using Glfw; +using VK; +using VKE; + +namespace PbrSample { + class Program : VkWindow, Crow.IValueChange { + #region IValueChange implementation + public event EventHandler<Crow.ValueChangeEventArgs> ValueChanged; + public virtual void NotifyValueChanged(string MemberName, object _value) + { + if (ValueChanged != null) + ValueChanged.Invoke(this, new Crow.ValueChangeEventArgs(MemberName, _value)); + } + #endregion + Crow.Interface crow = new Crow.Interface (); + + static void Main (string[] args) { + using (Program vke = new Program ()) { + vke.Run (); + } + } + +#if DEBUG && DEBUG_MARKER + public override string[] EnabledExtensions => new string[] { "VK_KHR_swapchain", "VK_EXT_debug_marker" }; +#endif + + public struct Matrices { + public Matrix4x4 projection; + public Matrix4x4 view; + public Matrix4x4 model; + public Vector4 lightPos; + public float gamma; + public float exposure; + } + + Matrices matrices = new Matrices { + lightPos = new Vector4 (1.0f, 0.0f, 0.0f, 1.0f), + gamma = 1.0f, + exposure = 2.0f, + }; + + public float Gamma { + get { return matrices.gamma; } + set { + if (value == matrices.gamma) + return; + matrices.gamma = value; + NotifyValueChanged ("Gamma", value); + updateViewRequested = true; + } + } + public float Exposure { + get { return matrices.exposure; } + set { + if (value == matrices.exposure) + return; + matrices.exposure = value; + NotifyValueChanged ("Exposure", value); + updateViewRequested = true; + } + } + + Framebuffer[] frameBuffers; + + HostBuffer uboMats; + + DescriptorPool descriptorPool; + DescriptorSetLayout descLayoutMain; + DescriptorSetLayout descLayoutTextures; + + DescriptorSet dsSkybox; + DescriptorSet dsMain; + + Pipeline pipeline; + Pipeline skyboxPL; + + Pipeline uiPipeline; + Image uiImage; + + Image lutBrdf; + Image irradianceCube; + Image prefilterCube; + + Model model; + + #region skybox + GPUBuffer vboSkybox; + Image cubemap; + string[] cubemapPathes = { + "../data/textures/papermill.ktx", + "../data/textures/cubemap_yokohama_bc3_unorm.ktx", + "../data/textures/gcanyon_cube.ktx", + "../data/textures/pisa_cube.ktx", + "../data/textures/uffizi_cube.ktx", + }; + static float[] box_vertices = { + -1.0f,-1.0f,-1.0f, 0.0f, 1.0f, // -X side + -1.0f,-1.0f, 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 1.0f, 1.0f, 0.0f, + -1.0f, 1.0f,-1.0f, 0.0f, 0.0f, + -1.0f,-1.0f,-1.0f, 0.0f, 1.0f, + + -1.0f,-1.0f,-1.0f, 1.0f, 1.0f, // -Z side + 1.0f, 1.0f,-1.0f, 0.0f, 0.0f, + 1.0f,-1.0f,-1.0f, 0.0f, 1.0f, + -1.0f,-1.0f,-1.0f, 1.0f, 1.0f, + -1.0f, 1.0f,-1.0f, 1.0f, 0.0f, + 1.0f, 1.0f,-1.0f, 0.0f, 0.0f, + + -1.0f,-1.0f,-1.0f, 1.0f, 0.0f, // -Y side + 1.0f,-1.0f,-1.0f, 1.0f, 1.0f, + 1.0f,-1.0f, 1.0f, 0.0f, 1.0f, + -1.0f,-1.0f,-1.0f, 1.0f, 0.0f, + 1.0f,-1.0f, 1.0f, 0.0f, 1.0f, + -1.0f,-1.0f, 1.0f, 0.0f, 0.0f, + + -1.0f, 1.0f,-1.0f, 1.0f, 0.0f, // +Y side + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, + -1.0f, 1.0f,-1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, + + 1.0f, 1.0f,-1.0f, 1.0f, 0.0f, // +X side + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, + 1.0f,-1.0f, 1.0f, 0.0f, 1.0f, + 1.0f,-1.0f, 1.0f, 0.0f, 1.0f, + 1.0f,-1.0f,-1.0f, 1.0f, 1.0f, + 1.0f, 1.0f,-1.0f, 1.0f, 0.0f, + + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, // +Z side + -1.0f,-1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, + -1.0f,-1.0f, 1.0f, 0.0f, 1.0f, + 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, + }; + #endregion + + Camera Camera = new Camera (Utils.DegreesToRadians (60f), 1f); + + Program () : base () { + UpdateFrequency = 20; + vboSkybox = new GPUBuffer<float> (presentQueue, cmdPool, VkBufferUsageFlags.VertexBuffer, box_vertices); + + cubemap = KTX.KTX.Load (presentQueue, cmdPool, cubemapPathes[1], + VkImageUsageFlags.Sampled, VkMemoryPropertyFlags.DeviceLocal, true); + cubemap.CreateView (VkImageViewType.Cube, VkImageAspectFlags.Color, 6); + cubemap.CreateSampler (); + cubemap.SetName ("skybox Texture"); + + init (); + + model = new Model (dev, presentQueue, cmdPool, "../data/models/DamagedHelmet/glTF/DamagedHelmet.gltf"); + //model = new Model (dev, presentQueue, cmdPool, "../data/models/icosphere.gltf"); + //model = new Model (dev, presentQueue, cmdPool, "../data/models/cube.gltf"); + model.WriteMaterialsDescriptorSets (descLayoutTextures, + ShaderBinding.Color, + ShaderBinding.Normal, + ShaderBinding.AmbientOcclusion, + ShaderBinding.MetalRoughness, + ShaderBinding.Emissive); + + //Camera.Model = Matrix4x4.CreateRotationX (Utils.DegreesToRadians (-90)) * Matrix4x4.CreateTranslation (5,-5, 5); + Camera.Model = Matrix4x4.CreateRotationX (Utils.DegreesToRadians (-90)); + + //crow.LoadIMLFragment ("<Window Width='400' Height='400'><Widget Width='100' Height='100' MouseEnter='{Background=Red}' MouseLeave='{Background=White}'/></Window>"); + crow.Load ("ui/fps.crow").DataSource = this; + //crow.LoadIMLFragment ("<Widget Background='Green' Width='400' Height='400'/>"); + } + + void createUIImage () { + uiImage?.Dispose (); + uiImage = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.Sampled, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, + swapChain.Width, swapChain.Height, VkImageType.Image2D, VkSampleCountFlags.SampleCount1, VkImageTiling.Linear); + uiImage.CreateView (VkImageViewType.ImageView2D, VkImageAspectFlags.Color, 1, 0, 1, 0, + VkComponentSwizzle.B, VkComponentSwizzle.G, VkComponentSwizzle.R, VkComponentSwizzle.A); + uiImage.CreateSampler (); + uiImage.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + uiImage.Map (); + + DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings[5]); + uboUpdate.Write (dev, uiImage.Descriptor); + } + + void init (VkSampleCountFlags samples = VkSampleCountFlags.SampleCount8) { + descriptorPool = new DescriptorPool (dev, 2, + new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer, 2), + new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, 10) + ); + + 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), + new VkDescriptorSetLayoutBinding (4, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler), + new VkDescriptorSetLayoutBinding (5, 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) + ); + + dsMain = descriptorPool.Allocate (descLayoutMain); + dsSkybox = descriptorPool.Allocate (descLayoutMain); + + PipelineConfig cfg = PipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, samples); + + cfg.Layout = new PipelineLayout (dev, descLayoutMain, descLayoutTextures); + cfg.Layout.AddPushConstants ( + new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf<Matrix4x4> ()), + new VkPushConstantRange (VkShaderStageFlags.Fragment, (uint)Marshal.SizeOf<Model.PbrMaterial> (), 64) + ); + cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, dev.GetSuitableDepthFormat (), samples); + cfg.AddVertexBinding<Model.Vertex> (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 Pipeline (cfg); + + #region skybox pipeline + cfg.ResetShadersAndVerticesInfos (); + + cfg.AddVertexBinding (0, 5 * sizeof (float)); + cfg.SetVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32Sfloat); + cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/skybox.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/skybox.frag.spv"); + cfg.depthStencilState.depthTestEnable = false; + cfg.depthStencilState.depthWriteEnable = false; + + skyboxPL = new Pipeline (cfg); + #endregion + + 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 Pipeline (cfg); + + uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, (ulong)Marshal.SizeOf<Matrices> () * 2); + uboMats.Map ();//permanent map + + generateBRDFLUT (); + generateCubemaps (); + + createUIImage (); + + DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descLayoutMain); + uboUpdate.Write (dev, dsMain, uboMats.Descriptor, cubemap.Descriptor, lutBrdf.Descriptor, irradianceCube.Descriptor, prefilterCube.Descriptor, uiImage.Descriptor); + uboMats.Descriptor.offset = (ulong)Marshal.SizeOf<Matrices> (); + uboUpdate.Write (dev, dsSkybox, uboMats.Descriptor, cubemap.Descriptor); + } + + #region command buffers + void buildCommandBuffers () { + for (int i = 0; i < swapChain.ImageCount; ++i) { + cmds[i]?.Free (); + cmds[i] = cmdPool.AllocateCommandBuffer (); + cmds[i].Start (); + + recordDraw (cmds[i], frameBuffers[i]); + + cmds[i].End (); + } + } + void recordDraw (CommandBuffer cmd, Framebuffer fb) { + pipeline.RenderPass.Begin (cmd, fb); + + cmd.SetViewport (fb.Width, fb.Height); + cmd.SetScissor (fb.Width, fb.Height); + + skyboxPL.Bind (cmd); + cmd.BindDescriptorSet (skyboxPL.Layout, dsSkybox); + cmd.BindVertexBuffer (vboSkybox); + cmd.Draw (36); + + drawModel (cmd); + //drawShadedModelArray (cmd); + + uiPipeline.Bind (cmd); + cmd.Draw (3, 1, 0, 0); + + pipeline.RenderPass.End (cmd); + } + void drawModel (CommandBuffer cmd) { + pipeline.Bind (cmd); + cmd.BindDescriptorSet (pipeline.Layout, dsMain); + model.Bind (cmd); + model.DrawAll (cmd, pipeline.Layout); + } + void drawShadedModelArray (CommandBuffer cmd) { + pipeline.Bind (cmd); + cmd.BindDescriptorSet (pipeline.Layout, dsMain); + model.Bind (cmd); + model.DrawAll (cmd, pipeline.Layout); + + + Matrix4x4 modelMat = Matrix4x4.Identity; + Model.PbrMaterial material = new Model.PbrMaterial (1, 0, Model.AlphaMode.Opaque, 0.5f, ShaderBinding.None); + Model.Primitive p = model.Scenes[0].Root.Children[0].Mesh.Primitives[0]; + + for (int metalFact = 0; metalFact < 10; metalFact++) { + + material.metallicFactor = (float)metalFact / 10; + + for (int roughFact = 0; roughFact < 10; roughFact++) { + + material.roughnessFactor = (float)roughFact / 10; + + modelMat = Matrix4x4.CreateTranslation (-roughFact, metalFact, 0); + + + cmd.PushConstant (pipeline.Layout, VkShaderStageFlags.Vertex, modelMat); + cmd.PushConstant (pipeline.Layout, VkShaderStageFlags.Fragment, material, (uint)Marshal.SizeOf<Matrix4x4> ()); + + cmd.DrawIndexed (p.indexCount, 1, p.indexBase, p.vertexBase, 0); + } + } + + + } + #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<Matrices> ()); + matrices.view *= Matrix4x4.CreateTranslation (-matrices.view.Translation); + matrices.model = Matrix4x4.Identity; + uboMats.Update (matrices, (uint)Marshal.SizeOf<Matrices> (), (uint)Marshal.SizeOf<Matrices> ()); + } + + public override void UpdateView () { + updateMatrices (); + updateViewRequested = false; + } + public override void Update () { + NotifyValueChanged ("fps", fps); + crow.Update (); + + uiImage.Update (crow.bmp, (ulong)crow.bmp.Length); + } + #endregion + + protected override void OnResize () { + crow.ProcessResize (new Crow.Rectangle (0,0,(int)swapChain.Width, (int)swapChain.Height)); + createUIImage (); + + 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] + }); + } + + buildCommandBuffers (); + } + + #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.Zoom ((float)diffY); + } + + updateViewRequested = true; + } + protected override void onMouseButtonDown (MouseButton button) { + if (crow.ProcessMouseButtonDown ((Crow.MouseButton)button)) + return; + base.onMouseButtonDown (button); + } + protected override void onMouseButtonUp (MouseButton button) { + if (crow.ProcessMouseButtonUp ((Crow.MouseButton)button)) + return; + base.onMouseButtonUp (button); + } + + protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) { + switch (key) { + case Key.Up: + if (modifiers.HasFlag (Modifier.Shift)) + matrices.lightPos += new Vector4 (0, 0, 1, 0); + else + Camera.Move (0, 0, 1); + break; + case Key.Down: + if (modifiers.HasFlag (Modifier.Shift)) + matrices.lightPos += new Vector4 (0, 0, -1, 0); + else + Camera.Move (0, 0, -1); + break; + case Key.Left: + if (modifiers.HasFlag (Modifier.Shift)) + matrices.lightPos += new Vector4 (1, 0, 0, 0); + else + Camera.Move (1, 0, 0); + break; + case Key.Right: + if (modifiers.HasFlag (Modifier.Shift)) + matrices.lightPos += new Vector4 (-1, 0, 0, 0); + else + Camera.Move (-1, 0, 0); + break; + case Key.PageUp: + if (modifiers.HasFlag (Modifier.Shift)) + matrices.lightPos += new Vector4 (0, 1, 0, 0); + else + Camera.Move (0, 1, 0); + break; + case Key.PageDown: + if (modifiers.HasFlag (Modifier.Shift)) + matrices.lightPos += new Vector4 (0, -1, 0, 0); + else + Camera.Move (0, -1, 0); + break; + 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 (); + model.Dispose (); + vboSkybox.Dispose (); + pipeline.Dispose (); + uiPipeline.Dispose (); + skyboxPL.Dispose (); + descLayoutMain.Dispose (); + descLayoutTextures.Dispose (); + descriptorPool.Dispose (); + cubemap.Dispose (); + + lutBrdf.Dispose (); + irradianceCube.Dispose (); + prefilterCube.Dispose (); + uiImage.Dispose (); + + uboMats.Dispose (); + } + } + + base.Dispose (disposing); + } + + void generateBRDFLUT () { + 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); + + PipelineConfig cfg = PipelineConfig.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, "shaders/genbrdflut.vert.spv"); + cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/genbrdflut.frag.spv"); + + using (Pipeline pl = new Pipeline (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 (); + + presentQueue.Submit (cmd); + presentQueue.WaitIdle (); + + cmd.Free (); + } + } + lutBrdf.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + } + + enum CBTarget { IRRADIANCE = 0, PREFILTEREDENV = 1 }; + + Image generateCubeMap (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)) + 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, numMips); + 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)); + + DescriptorSet dset = dsPool.Allocate (dsLayout); + + PipelineConfig cfg = PipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false); + + DescriptorSetWrites dsUpdate = new DescriptorSetWrites (dsLayout); + dsUpdate.Write (dev, dset, cubemap.Descriptor); + + + cfg.Layout = new PipelineLayout (dev, dsLayout); + cfg.Layout.AddPushConstants ( + new VkPushConstantRange (VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, (uint)Marshal.SizeOf<Matrix4x4> () + 8)); + + 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, 5 * sizeof (float)); + cfg.SetVertexAttributes (0, VkFormat.R32g32b32Sfloat); + + cfg.AddShader (VkShaderStageFlags.Vertex, "shaders/filtercube.vert.spv"); + if (target == CBTarget.PREFILTEREDENV) + cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/prefilterenvmap.frag.spv"); + else + cfg.AddShader (VkShaderStageFlags.Fragment, "shaders/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 (Pipeline pl = new Pipeline (cfg)) { + 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 / (numMips - 1); + 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<Matrix4x4> ()); + cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, deltaTheta, (uint)Marshal.SizeOf<Matrix4x4> () + 4); + } else { + cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, roughness, (uint)Marshal.SizeOf<Matrix4x4> ()); + cmd.PushConstant (pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, 32u, (uint)Marshal.SizeOf<Matrix4x4> () + 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 (); + + presentQueue.Submit (cmd); + presentQueue.WaitIdle (); + + cmd.Free (); + } + } + cmap.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; + return cmap; + } + + void generateCubemaps () { + irradianceCube = generateCubeMap (CBTarget.IRRADIANCE); + prefilterCube = generateCubeMap (CBTarget.PREFILTEREDENV); + } + } +} diff --git a/samples/SashaWillemPbr/packages.config b/samples/SashaWillemPbr/packages.config new file mode 100644 index 0000000..713c52d --- /dev/null +++ b/samples/SashaWillemPbr/packages.config @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="glTF2Loader" version="1.1.3-alpha" targetFramework="net471" /> + <package id="Newtonsoft.Json" version="12.0.1" targetFramework="net471" /> + <package id="System.Buffers" version="4.5.0" targetFramework="net471" /> + <package id="System.Memory" version="4.5.2" targetFramework="net471" /> + <package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net471" /> + <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net471" /> + <package id="Vulkan" version="0.1.2.2-alpha" targetFramework="net471" /> +</packages>
\ No newline at end of file diff --git a/samples/SashaWillemPbr/shaders/FullScreenQuad.vert b/samples/SashaWillemPbr/shaders/FullScreenQuad.vert new file mode 100644 index 0000000..826720b --- /dev/null +++ b/samples/SashaWillemPbr/shaders/FullScreenQuad.vert @@ -0,0 +1,10 @@ +#version 450 + +layout (location = 0) out vec2 outUV; + +void main() +{ + outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); + gl_Position = vec4(outUV * 2.0f + -1.0f, 0.0f, 1.0f); + //gl_Position = vec4(outUV -1.0f, 0.0f, 1.0f); +} diff --git a/samples/SashaWillemPbr/shaders/filtercube.vert b/samples/SashaWillemPbr/shaders/filtercube.vert new file mode 100644 index 0000000..1226e28 --- /dev/null +++ b/samples/SashaWillemPbr/shaders/filtercube.vert @@ -0,0 +1,19 @@ +#version 450 + +layout (location = 0) in vec3 inPos; + +layout(push_constant) uniform PushConsts { + layout (offset = 0) mat4 mvp; +} pushConsts; + +layout (location = 0) out vec3 outUVW; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() +{ + outUVW = inPos; + gl_Position = pushConsts.mvp * vec4(inPos.xyz, 1.0); +} diff --git a/samples/SashaWillemPbr/shaders/genbrdflut.frag b/samples/SashaWillemPbr/shaders/genbrdflut.frag new file mode 100644 index 0000000..b6290dd --- /dev/null +++ b/samples/SashaWillemPbr/shaders/genbrdflut.frag @@ -0,0 +1,90 @@ +#version 450 + +layout (location = 0) in vec2 inUV; +layout (location = 0) out vec4 outColor; +layout (constant_id = 0) const uint NUM_SAMPLES = 1024u; + +const float PI = 3.1415926536; + +// Based omn http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/ +float random(vec2 co) +{ + float a = 12.9898; + float b = 78.233; + float c = 43758.5453; + float dt= dot(co.xy ,vec2(a,b)); + float sn= mod(dt,3.14); + return fract(sin(sn) * c); +} + +vec2 hammersley2d(uint i, uint N) +{ + // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + uint bits = (i << 16u) | (i >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + float rdi = float(bits) * 2.3283064365386963e-10; + return vec2(float(i) /float(N), rdi); +} + +// Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf +vec3 importanceSample_GGX(vec2 Xi, float roughness, vec3 normal) +{ + // Maps a 2D point to a hemisphere with spread based on roughness + float alpha = roughness * roughness; + float phi = 2.0 * PI * Xi.x + random(normal.xz) * 0.1; + float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha*alpha - 1.0) * Xi.y)); + float sinTheta = sqrt(1.0 - cosTheta * cosTheta); + vec3 H = vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); + + // Tangent space + vec3 up = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangentX = normalize(cross(up, normal)); + vec3 tangentY = normalize(cross(normal, tangentX)); + + // Convert to world Space + return normalize(tangentX * H.x + tangentY * H.y + normal * H.z); +} + +// Geometric Shadowing function +float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness) +{ + float k = (roughness * roughness) / 2.0; + float GL = dotNL / (dotNL * (1.0 - k) + k); + float GV = dotNV / (dotNV * (1.0 - k) + k); + return GL * GV; +} + +vec2 BRDF(float NoV, float roughness) +{ + // Normal always points along z-axis for the 2D lookup + const vec3 N = vec3(0.0, 0.0, 1.0); + vec3 V = vec3(sqrt(1.0 - NoV*NoV), 0.0, NoV); + + vec2 LUT = vec2(0.0); + for(uint i = 0u; i < NUM_SAMPLES; i++) { + vec2 Xi = hammersley2d(i, NUM_SAMPLES); + vec3 H = importanceSample_GGX(Xi, roughness, N); + vec3 L = 2.0 * dot(V, H) * H - V; + + float dotNL = max(dot(N, L), 0.0); + float dotNV = max(dot(N, V), 0.0); + float dotVH = max(dot(V, H), 0.0); + float dotNH = max(dot(H, N), 0.0); + + if (dotNL > 0.0) { + float G = G_SchlicksmithGGX(dotNL, dotNV, roughness); + float G_Vis = (G * dotVH) / (dotNH * dotNV); + float Fc = pow(1.0 - dotVH, 5.0); + LUT += vec2((1.0 - Fc) * G_Vis, Fc * G_Vis); + } + } + return LUT / float(NUM_SAMPLES); +} + +void main() +{ + outColor = vec4(BRDF(inUV.s, 1.0-inUV.t), 0.0, 1.0); +}
\ No newline at end of file diff --git a/samples/SashaWillemPbr/shaders/genbrdflut.vert b/samples/SashaWillemPbr/shaders/genbrdflut.vert new file mode 100644 index 0000000..f3dd233 --- /dev/null +++ b/samples/SashaWillemPbr/shaders/genbrdflut.vert @@ -0,0 +1,9 @@ +#version 450 + +layout (location = 0) out vec2 outUV; + +void main() +{ + outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); + gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f); +}
\ No newline at end of file diff --git a/samples/SashaWillemPbr/shaders/irradiancecube.frag b/samples/SashaWillemPbr/shaders/irradiancecube.frag new file mode 100644 index 0000000..340d679 --- /dev/null +++ b/samples/SashaWillemPbr/shaders/irradiancecube.frag @@ -0,0 +1,37 @@ +// Generates an irradiance cube from an environment map using convolution + +#version 450 + +layout (location = 0) in vec3 inPos; +layout (location = 0) out vec4 outColor; +layout (binding = 0) uniform samplerCube samplerEnv; + +layout(push_constant) uniform PushConsts { + layout (offset = 64) float deltaPhi; + layout (offset = 68) float deltaTheta; +} consts; + +#define PI 3.1415926535897932384626433832795 + +void main() +{ + vec3 N = normalize(inPos); + vec3 up = vec3(0.0, 1.0, 0.0); + vec3 right = normalize(cross(up, N)); + up = cross(N, right); + + const float TWO_PI = PI * 2.0; + const float HALF_PI = PI * 0.5; + + vec3 color = vec3(0.0); + uint sampleCount = 0u; + for (float phi = 0.0; phi < TWO_PI; phi += consts.deltaPhi) { + for (float theta = 0.0; theta < HALF_PI; theta += consts.deltaTheta) { + vec3 tempVec = cos(phi) * right + sin(phi) * up; + vec3 sampleVector = cos(theta) * N + sin(theta) * tempVec; + color += texture(samplerEnv, sampleVector).rgb * cos(theta) * sin(theta); + sampleCount++; + } + } + outColor = vec4(PI * color / float(sampleCount), 1.0);//texture(samplerEnv, inPos).rgba; +} diff --git a/samples/SashaWillemPbr/shaders/pbr.vert b/samples/SashaWillemPbr/shaders/pbr.vert new file mode 100644 index 0000000..03d24da --- /dev/null +++ b/samples/SashaWillemPbr/shaders/pbr.vert @@ -0,0 +1,58 @@ +#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 (location = 4) in vec4 inJoint0; +layout (location = 5) in vec4 inWeight0; + +layout (set = 0, binding = 0) uniform UBO +{ + mat4 projection; + mat4 model; + mat4 view; + vec3 camPos; +} ubo; + +#define MAX_NUM_JOINTS 128 + +layout (set = 2, binding = 0) uniform UBONode { + mat4 matrix; + mat4 jointMatrix[MAX_NUM_JOINTS]; + float jointCount; +} node; + +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; + if (node.jointCount > 0.0) { + // Mesh is skinned + mat4 skinMat = + inWeight0.x * node.jointMatrix[int(inJoint0.x)] + + inWeight0.y * node.jointMatrix[int(inJoint0.y)] + + inWeight0.z * node.jointMatrix[int(inJoint0.z)] + + inWeight0.w * node.jointMatrix[int(inJoint0.w)]; + + locPos = ubo.model * node.matrix * skinMat * vec4(inPos, 1.0); + outNormal = normalize(transpose(inverse(mat3(ubo.model * node.matrix * skinMat))) * inNormal); + } else { + locPos = ubo.model * node.matrix * vec4(inPos, 1.0); + outNormal = normalize(transpose(inverse(mat3(ubo.model * node.matrix))) * inNormal); + } + locPos.y = -locPos.y; + outWorldPos = locPos.xyz / locPos.w; + outUV0 = inUV0; + outUV1 = inUV1; + gl_Position = ubo.projection * ubo.view * vec4(outWorldPos, 1.0); +} diff --git a/samples/SashaWillemPbr/shaders/pbr_khr.frag b/samples/SashaWillemPbr/shaders/pbr_khr.frag new file mode 100644 index 0000000..bdf9fce --- /dev/null +++ b/samples/SashaWillemPbr/shaders/pbr_khr.frag @@ -0,0 +1,415 @@ +// PBR shader based on the Khronos WebGL PBR implementation +// See https://github.com/KhronosGroup/glTF-WebGL-PBR +// Supports both metallic roughness and specular glossiness inputs + +#version 450 + +layout (location = 0) in vec3 inWorldPos; +layout (location = 1) in vec3 inNormal; +layout (location = 2) in vec2 inUV0; +layout (location = 3) in vec2 inUV1; + +// Scene bindings + +layout (set = 0, binding = 0) uniform UBO { + mat4 projection; + mat4 model; + mat4 view; + vec3 camPos; +} ubo; + +layout (set = 0, binding = 1) uniform UBOParams { + vec4 lightDir; + float exposure; + float gamma; + float prefilteredCubeMipLevels; + float scaleIBLAmbient; + float debugViewInputs; + float debugViewEquation; +} uboParams; + +layout (set = 0, binding = 2) uniform samplerCube samplerIrradiance; +layout (set = 0, binding = 3) uniform samplerCube prefilteredMap; +layout (set = 0, binding = 4) uniform sampler2D samplerBRDFLUT; + +// Material bindings + +layout (set = 1, binding = 0) uniform sampler2D colorMap; +layout (set = 1, binding = 1) uniform sampler2D physicalDescriptorMap; +layout (set = 1, binding = 2) uniform sampler2D normalMap; +layout (set = 1, binding = 3) uniform sampler2D aoMap; +layout (set = 1, binding = 4) uniform sampler2D emissiveMap; + +layout (push_constant) uniform Material { + vec4 baseColorFactor; + vec4 emissiveFactor; + vec4 diffuseFactor; + vec4 specularFactor; + float workflow; + int baseColorTextureSet; + int physicalDescriptorTextureSet; + int normalTextureSet; + int occlusionTextureSet; + int emissiveTextureSet; + float metallicFactor; + float roughnessFactor; + float alphaMask; + float alphaMaskCutoff; +} material; + +layout (location = 0) out vec4 outColor; + +// Encapsulate the various inputs used by the various functions in the shading equation +// We store values in this struct to simplify the integration of alternative implementations +// of the shading terms, outlined in the Readme.MD Appendix. +struct PBRInfo +{ + float NdotL; // cos angle between normal and light direction + float NdotV; // cos angle between normal and view direction + float NdotH; // cos angle between normal and half vector + float LdotH; // cos angle between light direction and half vector + float VdotH; // cos angle between view direction and half vector + float perceptualRoughness; // roughness value, as authored by the model creator (input to shader) + float metalness; // metallic value at the surface + vec3 reflectance0; // full reflectance color (normal incidence angle) + vec3 reflectance90; // reflectance color at grazing angle + float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2]) + vec3 diffuseColor; // color contribution from diffuse lighting + vec3 specularColor; // color contribution from specular lighting +}; + +const float M_PI = 3.141592653589793; +const float c_MinRoughness = 0.04; + +const float PBR_WORKFLOW_METALLIC_ROUGHNESS = 0.0; +const float PBR_WORKFLOW_SPECULAR_GLOSINESS = 1.0f; + +#define MANUAL_SRGB 1 + +vec3 Uncharted2Tonemap(vec3 color) +{ + float A = 0.15; + float B = 0.50; + float C = 0.10; + float D = 0.20; + float E = 0.02; + float F = 0.30; + float W = 11.2; + return ((color*(A*color+C*B)+D*E)/(color*(A*color+B)+D*F))-E/F; +} + +vec4 tonemap(vec4 color) +{ + vec3 outcol = Uncharted2Tonemap(color.rgb * uboParams.exposure); + outcol = outcol * (1.0f / Uncharted2Tonemap(vec3(11.2f))); + return vec4(pow(outcol, vec3(1.0f / uboParams.gamma)), color.a); +} + +vec4 SRGBtoLINEAR(vec4 srgbIn) +{ + #ifdef MANUAL_SRGB + #ifdef SRGB_FAST_APPROXIMATION + vec3 linOut = pow(srgbIn.xyz,vec3(2.2)); + #else //SRGB_FAST_APPROXIMATION + vec3 bLess = step(vec3(0.04045),srgbIn.xyz); + vec3 linOut = mix( srgbIn.xyz/vec3(12.92), pow((srgbIn.xyz+vec3(0.055))/vec3(1.055),vec3(2.4)), bLess ); + #endif //SRGB_FAST_APPROXIMATION + return vec4(linOut,srgbIn.w);; + #else //MANUAL_SRGB + return srgbIn; + #endif //MANUAL_SRGB +} + +// Find the normal for this fragment, pulling either from a predefined normal map +// or from the interpolated mesh normal and tangent attributes. +vec3 getNormal() +{ + // Perturb normal, see http://www.thetenthplanet.de/archives/1180 + vec3 tangentNormal = texture(normalMap, material.normalTextureSet == 0 ? inUV0 : inUV1).xyz * 2.0 - 1.0; + + 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); +} + +// 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 * uboParams.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 = SRGBtoLINEAR(tonemap(texture(samplerIrradiance, n))).rgb; + + vec3 specularLight = SRGBtoLINEAR(tonemap(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 *= uboParams.scaleIBLAmbient; + specular *= uboParams.scaleIBLAmbient; + + return diffuse + specular; +} + +// Basic Lambertian diffuse +// Implementation from Lambert's Photometria https://archive.org/details/lambertsphotome00lambgoog +// See also [1], Equation 1 +vec3 diffuse(PBRInfo pbrInputs) +{ + return pbrInputs.diffuseColor / M_PI; +} + +// The following equation models the Fresnel reflectance term of the spec equation (aka F()) +// Implementation of fresnel from [4], Equation 15 +vec3 specularReflection(PBRInfo pbrInputs) +{ + return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0); +} + +// This calculates the specular geometric attenuation (aka G()), +// where rougher material will reflect less light back to the viewer. +// This implementation is based on [1] Equation 4, and we adopt their modifications to +// alphaRoughness as input as originally proposed in [2]. +float geometricOcclusion(PBRInfo pbrInputs) +{ + float NdotL = pbrInputs.NdotL; + float NdotV = pbrInputs.NdotV; + float r = pbrInputs.alphaRoughness; + + float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL))); + float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV))); + return attenuationL * attenuationV; +} + +// The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D()) +// Implementation from "Average Irregularity Representation of a Roughened Surface for Ray Reflection" by T. S. Trowbridge, and K. P. Reitz +// Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games [1], Equation 3. +float microfacetDistribution(PBRInfo pbrInputs) +{ + float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness; + float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0; + return roughnessSq / (M_PI * f * f); +} + +// Gets metallic factor from specular glossiness workflow inputs +float convertMetallic(vec3 diffuse, vec3 specular, float maxSpecular) { + float perceivedDiffuse = sqrt(0.299 * diffuse.r * diffuse.r + 0.587 * diffuse.g * diffuse.g + 0.114 * diffuse.b * diffuse.b); + float perceivedSpecular = sqrt(0.299 * specular.r * specular.r + 0.587 * specular.g * specular.g + 0.114 * specular.b * specular.b); + if (perceivedSpecular < c_MinRoughness) { + return 0.0; + } + float a = c_MinRoughness; + float b = perceivedDiffuse * (1.0 - maxSpecular) / (1.0 - c_MinRoughness) + perceivedSpecular - 2.0 * c_MinRoughness; + float c = c_MinRoughness - perceivedSpecular; + float D = max(b * b - 4.0 * a * c, 0.0); + return clamp((-b + sqrt(D)) / (2.0 * a), 0.0, 1.0); +} + +void main() +{ + float perceptualRoughness; + float metallic; + vec3 diffuseColor; + vec4 baseColor; + + vec3 f0 = vec3(0.04); + + if (material.alphaMask == 1.0f) { + if (material.baseColorTextureSet > -1) { + baseColor = SRGBtoLINEAR(texture(colorMap, material.baseColorTextureSet == 0 ? inUV0 : inUV1)) * material.baseColorFactor; + } else { + baseColor = material.baseColorFactor; + } + if (baseColor.a < material.alphaMaskCutoff) { + discard; + } + } + + if (material.workflow == PBR_WORKFLOW_METALLIC_ROUGHNESS) { + // Metallic and Roughness material properties are packed together + // In glTF, these factors can be specified by fixed scalar values + // or from a metallic-roughness map + perceptualRoughness = material.roughnessFactor; + metallic = material.metallicFactor; + if (material.physicalDescriptorTextureSet > -1) { + // 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 + vec4 mrSample = texture(physicalDescriptorMap, material.physicalDescriptorTextureSet == 0 ? inUV0 : inUV1); + perceptualRoughness = mrSample.g * perceptualRoughness; + metallic = mrSample.b * metallic; + } else { + perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0); + metallic = clamp(metallic, 0.0, 1.0); + } + // Roughness is authored as perceptual roughness; as is convention, + // convert to material roughness by squaring the perceptual roughness [2]. + + // The albedo may be defined from a base texture or a flat color + if (material.baseColorTextureSet > -1) { + baseColor = SRGBtoLINEAR(texture(colorMap, material.baseColorTextureSet == 0 ? inUV0 : inUV1)) * material.baseColorFactor; + } else { + baseColor = material.baseColorFactor; + } + } + + if (material.workflow == PBR_WORKFLOW_SPECULAR_GLOSINESS) { + // Values from specular glossiness workflow are converted to metallic roughness + if (material.physicalDescriptorTextureSet > -1) { + perceptualRoughness = 1.0 - texture(physicalDescriptorMap, material.physicalDescriptorTextureSet == 0 ? inUV0 : inUV1).a; + } else { + perceptualRoughness = 0.0; + } + + const float epsilon = 1e-6; + + vec4 diffuse = SRGBtoLINEAR(texture(colorMap, inUV0)); + vec3 specular = SRGBtoLINEAR(texture(physicalDescriptorMap, inUV0)).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)) * material.diffuseFactor.rgb; + vec3 baseColorSpecularPart = specular - (vec3(c_MinRoughness) * (1 - metallic) * (1 / max(metallic, epsilon))) * material.specularFactor.rgb; + baseColor = vec4(mix(baseColorDiffusePart, baseColorSpecularPart, metallic * metallic), diffuse.a); + + } + + 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, 1.0, 1.0) * reflectance90; + + vec3 n = (material.normalTextureSet > -1) ? getNormal() : normalize(inNormal); + vec3 v = normalize(ubo.camPos - inWorldPos); // Vector from surface point to camera + vec3 l = normalize(uboParams.lightDir.xyz); // Vector from surface point to light + vec3 h = normalize(l+v); // Half vector between both l and v + vec3 reflection = -normalize(reflect(v, n)); + reflection.y *= -1.0f; + + float NdotL = clamp(dot(n, l), 0.001, 1.0); + float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0); + float NdotH = clamp(dot(n, h), 0.0, 1.0); + float LdotH = clamp(dot(l, h), 0.0, 1.0); + float VdotH = clamp(dot(v, h), 0.0, 1.0); + + PBRInfo pbrInputs = PBRInfo( + NdotL, + NdotV, + NdotH, + LdotH, + VdotH, + perceptualRoughness, + metallic, + specularEnvironmentR0, + specularEnvironmentR90, + alphaRoughness, + diffuseColor, + specularColor + ); + + // Calculate the shading terms for the microfacet specular shading model + vec3 F = specularReflection(pbrInputs); + float G = geometricOcclusion(pbrInputs); + float D = microfacetDistribution(pbrInputs); + + const vec3 u_LightColor = vec3(1.0); + + // Calculation of analytical lighting contribution + vec3 diffuseContrib = (1.0 - F) * diffuse(pbrInputs); + vec3 specContrib = F * G * D / (4.0 * NdotL * NdotV); + // Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law) + vec3 color = NdotL * u_LightColor * (diffuseContrib + specContrib); + + // Calculate lighting contribution from image based lighting source (IBL) + color += getIBLContribution(pbrInputs, n, reflection); + + const float u_OcclusionStrength = 1.0f; + // Apply optional PBR terms for additional (optional) shading + if (material.occlusionTextureSet > -1) { + float ao = texture(aoMap, (material.occlusionTextureSet == 0 ? inUV0 : inUV1)).r; + color = mix(color, color * ao, u_OcclusionStrength); + } + + const float u_EmissiveFactor = 1.0f; + if (material.emissiveTextureSet > -1) { + vec3 emissive = SRGBtoLINEAR(texture(emissiveMap, material.emissiveTextureSet == 0 ? inUV0 : inUV1)).rgb * u_EmissiveFactor; + color += emissive; + } + + outColor = vec4(color, baseColor.a); + + // Shader inputs debug visualization + if (uboParams.debugViewInputs > 0.0) { + int index = int(uboParams.debugViewInputs); + switch (index) { + case 1: + outColor.rgba = material.baseColorTextureSet > -1 ? texture(colorMap, material.baseColorTextureSet == 0 ? inUV0 : inUV1) : vec4(1.0f); + break; + case 2: + outColor.rgb = (material.normalTextureSet > -1) ? texture(normalMap, material.normalTextureSet == 0 ? inUV0 : inUV1).rgb : normalize(inNormal); + break; + case 3: + outColor.rgb = (material.occlusionTextureSet > -1) ? texture(aoMap, material.occlusionTextureSet == 0 ? inUV0 : inUV1).rrr : vec3(0.0f); + break; + case 4: + outColor.rgb = (material.emissiveTextureSet > -1) ? texture(emissiveMap, material.emissiveTextureSet == 0 ? inUV0 : inUV1).rgb : vec3(0.0f); + break; + case 5: + outColor.rgb = texture(physicalDescriptorMap, inUV0).bbb; + break; + case 6: + outColor.rgb = texture(physicalDescriptorMap, inUV0).ggg; + break; + } + outColor = SRGBtoLINEAR(outColor); + } + + // PBR equation debug visualization + // "none", "Diff (l,n)", "F (l,h)", "G (l,v,h)", "D (h)", "Specular" + if (uboParams.debugViewEquation > 0.0) { + int index = int(uboParams.debugViewEquation); + switch (index) { + case 1: + outColor.rgb = diffuseContrib; + break; + case 2: + outColor.rgb = F; + break; + case 3: + outColor.rgb = vec3(G); + break; + case 4: + outColor.rgb = vec3(D); + break; + case 5: + outColor.rgb = specContrib; + break; + } + } + +} diff --git a/samples/SashaWillemPbr/shaders/pbrtest.frag b/samples/SashaWillemPbr/shaders/pbrtest.frag new file mode 100644 index 0000000..3ff79ef --- /dev/null +++ b/samples/SashaWillemPbr/shaders/pbrtest.frag @@ -0,0 +1,209 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (binding = 0) uniform UBO +{ + mat4 projectionMatrix; + mat4 viewMatrix; + mat4 modelMatrix; + vec4 lightPos; + float gamma; + float exposure; +} ubo; + +layout (set = 0, binding = 1) uniform samplerCube samplerCubemap; +layout (set = 0, binding = 2) uniform sampler2D samplerBRDFLUT; +layout (set = 0, binding = 3) uniform samplerCube samplerIrradiance; +layout (set = 0, binding = 4) uniform samplerCube prefilteredMap; + +layout (set = 1, binding = 0) uniform sampler2D samplerColor; +layout (set = 1, binding = 1) uniform sampler2D samplerNormal; +layout (set = 1, binding = 2) uniform sampler2D samplerOcclusion; +layout (set = 1, binding = 3) uniform sampler2D samplerMetalRoughness; +layout (set = 1, binding = 4) uniform sampler2D samplerEmissive; + +layout (location = 0) in vec2 inUV; +layout (location = 1) in vec3 inN; +layout (location = 2) in vec3 inV; +layout (location = 3) in vec3 inWorldPos; + +layout (location = 0) out vec4 outFragColor; + +layout(push_constant) uniform PushConsts { + layout(offset = 64) + vec4 baseColorFactor; + vec4 emissiveFactor; + uint availableAttachments; + uint alphaMode; + float alphaCutoff; + float metallicFactor; + float roughnessFactor; +} pc; + +const uint MAP_COLOR = 0x1; +const uint MAP_NORMAL = 0x2; +const uint MAP_AO = 0x4; +const uint MAP_METAL = 0x8; +const uint MAP_ROUGHNESS = 0x16; +const uint MAP_METALROUGHNESS = 0x32; +const uint MAP_EMISSIVE = 0x64; + +const float PI = 3.141592653589793; + +// From http://filmicgames.com/archives/75 +vec3 Uncharted2Tonemap(vec3 x) +{ + float A = 0.15; + float B = 0.50; + float C = 0.10; + float D = 0.20; + float E = 0.02; + float F = 0.30; + return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F; +} + +// Normal Distribution function -------------------------------------- +float D_GGX(float dotNH, float roughness) +{ + float alpha = roughness * roughness; + float alpha2 = alpha * alpha; + float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0; + return (alpha2)/(PI * denom*denom); +} + +// Geometric Shadowing function -------------------------------------- +float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness) +{ + float r = (roughness + 1.0); + float k = (r*r) / 8.0; + float GL = dotNL / (dotNL * (1.0 - k) + k); + float GV = dotNV / (dotNV * (1.0 - k) + k); + return GL * GV; +} + +// Fresnel function ---------------------------------------------------- +vec3 F_Schlick(float cosTheta, vec3 F0) +{ + return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); +} +vec3 F_SchlickR(float cosTheta, vec3 F0, float roughness) +{ + return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0); +} + +vec3 specularContribution(vec3 L, vec3 V, vec3 N, vec3 F0, float metallic, float roughness, vec3 albedo) +{ + // Precalculate vectors and dot products + vec3 H = normalize (V + L); + float dotNH = clamp(dot(N, H), 0.0, 1.0); + float dotNV = clamp(dot(N, V), 0.0, 1.0); + float dotNL = clamp(dot(N, L), 0.0, 1.0); + + // Light color fixed + vec3 lightColor = vec3(1.0); + + vec3 color = vec3(0.0); + + if (dotNL > 0.0) { + // D = Normal distribution (Distribution of the microfacets) + float D = D_GGX(dotNH, roughness); + // G = Geometric shadowing term (Microfacets shadowing) + float G = G_SchlicksmithGGX(dotNL, dotNV, roughness); + // F = Fresnel factor (Reflectance depending on angle of incidence) + vec3 F = F_Schlick(dotNV, F0); + vec3 spec = D * F * G / (4.0 * dotNL * dotNV + 0.001); + vec3 kD = (vec3(1.0) - F) * (1.0 - metallic); + color += (kD * albedo / PI + spec) * dotNL; + } + + return color; +} + +// See http://www.thetenthplanet.de/archives/1180 +vec3 perturbNormal(vec3 inNormal, vec3 tangentNormal) +{ + + + vec3 q1 = dFdx(inWorldPos); + vec3 q2 = dFdy(inWorldPos); + vec2 st1 = dFdx(inUV); + vec2 st2 = dFdy(inUV); + + 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); +} + +vec3 prefilteredReflection(vec3 R, float roughness) +{ + const float MAX_REFLECTION_LOD = 9.0; // todo: param/const + float lod = roughness * MAX_REFLECTION_LOD; + float lodf = floor(lod); + float lodc = ceil(lod); + vec3 a = textureLod(prefilteredMap, R, lodf).rgb; + vec3 b = textureLod(prefilteredMap, R, lodc).rgb; + return mix(a, b, lod - lodf); +} + +void main() +{ + vec3 emit = vec3(0); + vec4 base_color = pc.baseColorFactor; + float rough = pc.roughnessFactor; + float metallic = pc.metallicFactor; + + if ((pc.availableAttachments & MAP_COLOR) == MAP_COLOR) + base_color *= texture(samplerColor, inUV); + if ((pc.availableAttachments & MAP_METALROUGHNESS) == MAP_METALROUGHNESS) { + rough *= clamp(texture(samplerMetalRoughness, inUV).g, 0.04, 1.0); + metallic *= texture(samplerMetalRoughness, inUV).b; + } + if ((pc.availableAttachments & MAP_EMISSIVE) == MAP_EMISSIVE) + emit = pc.emissiveFactor.rgb * texture(samplerEmissive, inUV).rgb; + + + vec3 N = ((pc.availableAttachments & MAP_NORMAL) == MAP_NORMAL) ? + perturbNormal(inN, texture(samplerNormal, inUV).xyz * 2.0 - 1.0) : + normalize(inN); + vec3 V = normalize(inV); + vec3 R = -normalize(reflect(V, N)); + + vec3 F0 = vec3(0.04); + F0 = mix(F0, base_color.rgb, metallic); + float alpha = pow(rough, 2.0); + + vec3 L = normalize(ubo.lightPos.xyz); + vec3 Lo = specularContribution(L, V, N, F0, metallic, rough, base_color.rgb); + + vec2 brdf = texture(samplerBRDFLUT, vec2(max(dot(N, V), 0.0), rough)).rg; + vec3 reflection = prefilteredReflection(R, rough).rgb; //texture(samplerCubemap, R).rgb * (1.0-rough); + vec3 irradiance = texture(samplerIrradiance, N).rgb; + + // Diffuse based on irradiance + vec3 diffuse = base_color.rgb;// * irradiance; + + vec3 F = F_SchlickR(max(dot(N, V), 0.0), F0, rough); + + vec3 specular = reflection * (F * brdf.x + brdf.y); + + // Ambient part + vec3 kD = 1.0 - F; + kD *= 1.0 - metallic; + + float ao = ((pc.availableAttachments & MAP_AO) == MAP_AO) ? texture(samplerOcclusion, inUV).r : 1.0f; + vec3 ambient = (kD * diffuse + specular) * ao; + vec3 color = ambient + Lo; + + // Tone mapping + color = Uncharted2Tonemap(color * ubo.exposure); + color = color * (1.0f / Uncharted2Tonemap(vec3(11.2f))); + // Gamma correction + color = pow(color, vec3(1.0f / ubo.gamma)) + emit; + + outFragColor = vec4(color, base_color.a); +}
\ No newline at end of file diff --git a/samples/SashaWillemPbr/shaders/pbrtest.vert b/samples/SashaWillemPbr/shaders/pbrtest.vert new file mode 100644 index 0000000..25907bb --- /dev/null +++ b/samples/SashaWillemPbr/shaders/pbrtest.vert @@ -0,0 +1,49 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec3 inNormal; +layout (location = 2) in vec2 inUV; + +layout (binding = 0) uniform UBO +{ + mat4 projectionMatrix; + mat4 viewMatrix; + mat4 modelMatrix; + vec4 lightPos; + float gamma; + float exposure; +} ubo; + +layout (location = 0) out vec2 outUV; +layout (location = 1) out vec3 outN; +layout (location = 2) out vec3 outV;//ViewDir +layout (location = 3) out vec3 outWorldPos; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + +layout(push_constant) uniform PushConsts { + mat4 model; +} pc; + +void main() +{ + outUV = inUV; + + mat4 mod = ubo.modelMatrix * pc.model; + vec4 pos = mod * vec4(inPos.xyz, 1.0); + + outN = normalize(transpose(inverse(mat3(mod))) * inNormal); + //outN = normalize(mat3(mod)* inNormal); + + mat4 viewInv = inverse(ubo.viewMatrix); + //outV = -(ubo.viewMatrix * pos).xyz; + outV = normalize(vec3(viewInv * vec4(0.0, 0.0, 0.0, 1.0) - pos)); + outWorldPos = pos.xyz; + gl_Position = ubo.projectionMatrix * ubo.viewMatrix * pos; +} diff --git a/samples/SashaWillemPbr/shaders/prefilterenvmap.frag b/samples/SashaWillemPbr/shaders/prefilterenvmap.frag new file mode 100644 index 0000000..ae1212e --- /dev/null +++ b/samples/SashaWillemPbr/shaders/prefilterenvmap.frag @@ -0,0 +1,105 @@ +#version 450 + +layout (location = 0) in vec3 inPos; +layout (location = 0) out vec4 outColor; + +layout (binding = 0) uniform samplerCube samplerEnv; + +layout(push_constant) uniform PushConsts { + layout (offset = 64) float roughness; + layout (offset = 68) uint numSamples; +} consts; + +const float PI = 3.1415926536; + +// Based omn http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/ +float random(vec2 co) +{ + float a = 12.9898; + float b = 78.233; + float c = 43758.5453; + float dt= dot(co.xy ,vec2(a,b)); + float sn= mod(dt,3.14); + return fract(sin(sn) * c); +} + +vec2 hammersley2d(uint i, uint N) +{ + // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + uint bits = (i << 16u) | (i >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + float rdi = float(bits) * 2.3283064365386963e-10; + return vec2(float(i) /float(N), rdi); +} + +// Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf +vec3 importanceSample_GGX(vec2 Xi, float roughness, vec3 normal) +{ + // Maps a 2D point to a hemisphere with spread based on roughness + float alpha = roughness * roughness; + float phi = 2.0 * PI * Xi.x + random(normal.xz) * 0.1; + float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha*alpha - 1.0) * Xi.y)); + float sinTheta = sqrt(1.0 - cosTheta * cosTheta); + vec3 H = vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); + + // Tangent space + vec3 up = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangentX = normalize(cross(up, normal)); + vec3 tangentY = normalize(cross(normal, tangentX)); + + // Convert to world Space + return normalize(tangentX * H.x + tangentY * H.y + normal * H.z); +} + +// Normal Distribution function +float D_GGX(float dotNH, float roughness) +{ + float alpha = roughness * roughness; + float alpha2 = alpha * alpha; + float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0; + return (alpha2)/(PI * denom*denom); +} + +vec3 prefilterEnvMap(vec3 R, float roughness) +{ + vec3 N = R; + vec3 V = R; + vec3 color = vec3(0.0); + float totalWeight = 0.0; + float envMapDim = float(textureSize(samplerEnv, 0).s); + for(uint i = 0u; i < consts.numSamples; i++) { + vec2 Xi = hammersley2d(i, consts.numSamples); + vec3 H = importanceSample_GGX(Xi, roughness, N); + vec3 L = 2.0 * dot(V, H) * H - V; + float dotNL = clamp(dot(N, L), 0.0, 1.0); + if(dotNL > 0.0) { + // Filtering based on https://placeholderart.wordpress.com/2015/07/28/implementation-notes-runtime-environment-map-filtering-for-image-based-lighting/ + + float dotNH = clamp(dot(N, H), 0.0, 1.0); + float dotVH = clamp(dot(V, H), 0.0, 1.0); + + // Probability Distribution Function + float pdf = D_GGX(dotNH, roughness) * dotNH / (4.0 * dotVH) + 0.0001; + // Slid angle of current smple + float omegaS = 1.0 / (float(consts.numSamples) * pdf); + // Solid angle of 1 pixel across all cube faces + float omegaP = 4.0 * PI / (6.0 * envMapDim * envMapDim); + // Biased (+1.0) mip level for better result + float mipLevel = roughness == 0.0 ? 0.0 : max(0.5 * log2(omegaS / omegaP) + 1.0, 0.0f); + color += textureLod(samplerEnv, L, mipLevel).rgb * dotNL; + totalWeight += dotNL; + + } + } + return (color / totalWeight); +} + + +void main() +{ + vec3 N = normalize(inPos); + outColor = vec4(prefilterEnvMap(N, consts.roughness), 1.0); +} diff --git a/samples/SashaWillemPbr/shaders/simpletexture.frag b/samples/SashaWillemPbr/shaders/simpletexture.frag new file mode 100644 index 0000000..d5bcf79 --- /dev/null +++ b/samples/SashaWillemPbr/shaders/simpletexture.frag @@ -0,0 +1,15 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (set = 0, binding = 5) uniform sampler2D samplerColor; + +layout (location = 0) in vec2 inUV; + +layout (location = 0) out vec4 outFragColor; + +void main() +{ + outFragColor = texture(samplerColor, inUV); +} diff --git a/samples/SashaWillemPbr/shaders/skybox.frag b/samples/SashaWillemPbr/shaders/skybox.frag new file mode 100644 index 0000000..fa10f82 --- /dev/null +++ b/samples/SashaWillemPbr/shaders/skybox.frag @@ -0,0 +1,15 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (binding = 1) uniform samplerCube skybox; + +layout (location = 0) in vec3 TexCoords; + +layout (location = 0) out vec4 outFragColor; + +void main() +{ + outFragColor = texture(skybox, TexCoords); +} diff --git a/samples/SashaWillemPbr/shaders/skybox.vert b/samples/SashaWillemPbr/shaders/skybox.vert new file mode 100644 index 0000000..1925ec9 --- /dev/null +++ b/samples/SashaWillemPbr/shaders/skybox.vert @@ -0,0 +1,30 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec2 inUV; + +layout (location = 0) out vec3 outUVW; + +layout (binding = 0) uniform UBO +{ + mat4 projection; + mat4 view; + mat4 model; + vec4 lightPos; + float gamma; + float exposure; +} ubo; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + +void main() +{ + outUVW = inPos; + gl_Position = ubo.projection * ubo.view * vec4(inPos, 1.0); +} diff --git a/samples/SashaWillemPbr/shaders/skybox_sw.frag b/samples/SashaWillemPbr/shaders/skybox_sw.frag new file mode 100644 index 0000000..a861ec4 --- /dev/null +++ b/samples/SashaWillemPbr/shaders/skybox_sw.frag @@ -0,0 +1,55 @@ +#version 450 + +layout (binding = 2) uniform samplerCube samplerEnv; + +layout (location = 0) in vec3 inUVW; +layout (location = 0) out vec4 outColor; + +layout (set = 0, binding = 1) uniform UBOParams { + vec4 _pad0; + float exposure; + float gamma; +} uboParams; + +// From http://filmicworlds.com/blog/filmic-tonemapping-operators/ +vec3 Uncharted2Tonemap(vec3 color) +{ + float A = 0.15; + float B = 0.50; + float C = 0.10; + float D = 0.20; + float E = 0.02; + float F = 0.30; + float W = 11.2; + return ((color*(A*color+C*B)+D*E)/(color*(A*color+B)+D*F))-E/F; +} + +vec4 tonemap(vec4 color) +{ + vec3 outcol = Uncharted2Tonemap(color.rgb * uboParams.exposure); + outcol = outcol * (1.0f / Uncharted2Tonemap(vec3(11.2f))); + return vec4(pow(outcol, vec3(1.0f / uboParams.gamma)), color.a); +} + +#define MANUAL_SRGB 1 + +vec4 SRGBtoLINEAR(vec4 srgbIn) +{ + #ifdef MANUAL_SRGB + #ifdef SRGB_FAST_APPROXIMATION + vec3 linOut = pow(srgbIn.xyz,vec3(2.2)); + #else //SRGB_FAST_APPROXIMATION + vec3 bLess = step(vec3(0.04045),srgbIn.xyz); + vec3 linOut = mix( srgbIn.xyz/vec3(12.92), pow((srgbIn.xyz+vec3(0.055))/vec3(1.055),vec3(2.4)), bLess ); + #endif //SRGB_FAST_APPROXIMATION + return vec4(linOut,srgbIn.w);; + #else //MANUAL_SRGB + return srgbIn; + #endif //MANUAL_SRGB +} + +void main() +{ + vec3 color = SRGBtoLINEAR(tonemap(textureLod(samplerEnv, inUVW, 1.5))).rgb; + outColor = vec4(color * 1.0, 1.0); +}
\ No newline at end of file diff --git a/samples/SashaWillemPbr/shaders/skybox_sw.vert b/samples/SashaWillemPbr/shaders/skybox_sw.vert new file mode 100644 index 0000000..c51c4b5 --- /dev/null +++ b/samples/SashaWillemPbr/shaders/skybox_sw.vert @@ -0,0 +1,28 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec3 inNormal; +layout (location = 2) in vec2 inUV; + +layout (binding = 0) uniform UBO +{ + mat4 projection; + mat4 pad; + mat4 model; +} ubo; + +layout (location = 0) out vec3 outUVW; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + +void main() +{ + outUVW = inPos; + gl_Position = ubo.projection * ubo.model * vec4(inPos.xyz, 1.0); +} diff --git a/samples/SashaWillemPbr/shaders/ui.frag b/samples/SashaWillemPbr/shaders/ui.frag new file mode 100644 index 0000000..e0d7995 --- /dev/null +++ b/samples/SashaWillemPbr/shaders/ui.frag @@ -0,0 +1,13 @@ +#version 450 + +layout (binding = 0) uniform sampler2D fontSampler; + +layout (location = 0) in vec2 inUV; +layout (location = 1) in vec4 inColor; + +layout (location = 0) out vec4 outColor; + +void main() +{ + outColor = inColor * texture(fontSampler, inUV); +}
\ No newline at end of file diff --git a/samples/SashaWillemPbr/shaders/ui.vert b/samples/SashaWillemPbr/shaders/ui.vert new file mode 100644 index 0000000..ddb63a4 --- /dev/null +++ b/samples/SashaWillemPbr/shaders/ui.vert @@ -0,0 +1,25 @@ +#version 450 + +layout (location = 0) in vec2 inPos; +layout (location = 1) in vec2 inUV; +layout (location = 2) in vec4 inColor; + +layout (push_constant) uniform PushConstants { + vec2 scale; + vec2 translate; +} pushConstants; + +layout (location = 0) out vec2 outUV; +layout (location = 1) out vec4 outColor; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + +void main() +{ + outUV = inUV; + outColor = inColor; + gl_Position = vec4(inPos * pushConstants.scale + pushConstants.translate, 0.0, 1.0); +}
\ No newline at end of file diff --git a/samples/SashaWillemPbr/skybox.cs b/samples/SashaWillemPbr/skybox.cs new file mode 100644 index 0000000..4d61e55 --- /dev/null +++ b/samples/SashaWillemPbr/skybox.cs @@ -0,0 +1,93 @@ +using System; +using System.Numerics; +using System.Runtime.InteropServices; +using Glfw; +using VK; +using VKE; +using Vulkan; +using Buffer = VKE.Buffer; + +namespace VKE { + public class Skybox : IDisposable { + static float[] box_vertices = { + -1.0f,-1.0f,-1.0f, 0.0f, 1.0f, // -X side + -1.0f,-1.0f, 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 1.0f, 1.0f, 0.0f, + -1.0f, 1.0f,-1.0f, 0.0f, 0.0f, + -1.0f,-1.0f,-1.0f, 0.0f, 1.0f, + + -1.0f,-1.0f,-1.0f, 1.0f, 1.0f, // -Z side + 1.0f, 1.0f,-1.0f, 0.0f, 0.0f, + 1.0f,-1.0f,-1.0f, 0.0f, 1.0f, + -1.0f,-1.0f,-1.0f, 1.0f, 1.0f, + -1.0f, 1.0f,-1.0f, 1.0f, 0.0f, + 1.0f, 1.0f,-1.0f, 0.0f, 0.0f, + + -1.0f,-1.0f,-1.0f, 1.0f, 0.0f, // -Y side + 1.0f,-1.0f,-1.0f, 1.0f, 1.0f, + 1.0f,-1.0f, 1.0f, 0.0f, 1.0f, + -1.0f,-1.0f,-1.0f, 1.0f, 0.0f, + 1.0f,-1.0f, 1.0f, 0.0f, 1.0f, + -1.0f,-1.0f, 1.0f, 0.0f, 0.0f, + + -1.0f, 1.0f,-1.0f, 1.0f, 0.0f, // +Y side + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, + -1.0f, 1.0f,-1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, + + 1.0f, 1.0f,-1.0f, 1.0f, 0.0f, // +X side + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, + 1.0f,-1.0f, 1.0f, 0.0f, 1.0f, + 1.0f,-1.0f, 1.0f, 0.0f, 1.0f, + 1.0f,-1.0f,-1.0f, 1.0f, 1.0f, + 1.0f, 1.0f,-1.0f, 1.0f, 0.0f, + + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, // +Z side + -1.0f,-1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, + -1.0f,-1.0f, 1.0f, 0.0f, 1.0f, + 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, + }; + + GPUBuffer vboSkybox; + DescriptorSet dsSkybox; + DescriptorSetLayout dsLayoutMain; + + public Image cubemap; + string[] cubemapPathes = { + "../data/textures/papermill.ktx", + "../data/textures/cubemap_yokohama_bc3_unorm.ktx", + "../data/textures/gcanyon_cube.ktx", + "../data/textures/pisa_cube.ktx", + "../data/textures/uffizi_cube.ktx", + }; + + //string[] imgPathes = { + // "../data/textures/papermill.ktx", + // "../data/textures/cubemap_yokohama_bc3_unorm.ktx", + // "../data/textures/gcanyon_cube.ktx", + // "../data/textures/pisa_cube.ktx", + // "../data/textures/uffizi_cube.ktx", + //}; + + + public Skybox (Queue presentQueue, CommandPool cmdPool , DescriptorSetLayout dsLayout) { + dsLayoutMain = dsLayout; + + vboSkybox = new GPUBuffer<float> (presentQueue, cmdPool, VkBufferUsageFlags.VertexBuffer, box_vertices); + + cubemap = KTX.KTX.Load (presentQueue, cmdPool, cubemapPathes[0], + VkImageUsageFlags.Sampled, VkMemoryPropertyFlags.DeviceLocal, true); + cubemap.CreateView (VkImageViewType.Cube, VkImageAspectFlags.Color, 6); + cubemap.CreateSampler (); + } + + public void Dispose () { + throw new NotImplementedException (); + } + } +} diff --git a/samples/SashaWillemPbr/ui/fps.crow b/samples/SashaWillemPbr/ui/fps.crow new file mode 100755 index 0000000..ad94840 --- /dev/null +++ b/samples/SashaWillemPbr/ui/fps.crow @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<Window Caption="Showcase" Height="40%" Width="40%"> + <VerticalStack Width="90%" Height="Fit" Spacing="2" > + <HorizontalStack Height="Fit"> + <Label Text="Fps:" Width="60" Background="SteelBlue"/> + <Label Text="{fps}" /> + </HorizontalStack> + <HorizontalStack Height="Fit"> + <Label Text="Gamma:" Width="60" Background="SteelBlue" Margin="2"/> + <Slider Height="4" Value="{²Gamma}" Maximum="10.0" SmallIncrement="0.1" LargeIncrement="1.0"/> + <Label Text="{Gamma}" Width="40" TextAlignment="Right"/> + </HorizontalStack> + <HorizontalStack Height="Fit"> + <Label Text="Exposure:" Width="60" Background="SteelBlue"/> + <Slider Height="4" Value="{²Exposure}" Maximum="10.0" SmallIncrement="0.1" LargeIncrement="1.0"/> + <Label Text="{Exposure}" Width="40" TextAlignment="Right"/> + </HorizontalStack> + </VerticalStack> +</Window>
\ No newline at end of file diff --git a/samples/vkvg_overlay/main.cs b/samples/vkvg_overlay/main.cs index 11781a8..7753265 100644 --- a/samples/vkvg_overlay/main.cs +++ b/samples/vkvg_overlay/main.cs @@ -19,6 +19,8 @@ namespace ModelSample { public override string[] EnabledExtensions => new string[] {"VK_KHR_swapchain","VK_EXT_debug_marker"}; #endif PipelineStatisticsQueryPool statPool; + TimestampQueryPool timestampQPool; + ulong[] results; protected override void configureEnabledFeatures (ref VkPhysicalDeviceFeatures features) { @@ -108,17 +110,25 @@ namespace ModelSample { 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 ($"{"TimeStamp Start",-24} :{timeStamps[0],18:0,0} ")); + //y += dy; + //ctx.MoveTo (x, y); + //ctx.ShowText (string.Format ($"{"TimeStamp End ",-24} :{timeStamps[1],18: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_8, presentQueue.index); + vkvg.SampleCount.Sample_4, presentQueue.index); init (); - //model = new Model (dev, presentQueue, cmdPool, "/mnt/devel/vkChess/data/chess.gltf"); - //model = new Model (dev, presentQueue, cmdPool, "/mnt/devel/tmp/gltf-pbr-datasave/models/chess.gltf"); - model = new Model (dev, presentQueue, cmdPool, "../data/models/DamagedHelmet/glTF/DamagedHelmet.gltf"); + model = new Model (dev, presentQueue, cmdPool, "/mnt/devel/vkChess/data/chess.gltf"); + //model = new Model (dev, presentQueue, cmdPool, "../data/models/DamagedHelmet/glTF/DamagedHelmet.gltf"); model.WriteMaterialsDescriptorSets (descLayoutTextures, ShaderBinding.Color, ShaderBinding.Normal, @@ -193,6 +203,8 @@ namespace ModelSample { VkQueryPipelineStatisticFlags.ClippingPrimitives | VkQueryPipelineStatisticFlags.FragmentShaderInvocations); + timestampQPool = new TimestampQueryPool (dev); + } void buildCommandBuffers () { @@ -237,6 +249,8 @@ namespace ModelSample { #endif uiPipeline.Bind (cmd); + timestampQPool.Start (cmd); + vkvgImage.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.ColorAttachmentOptimal, VkImageLayout.ShaderReadOnlyOptimal, VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader); @@ -245,6 +259,8 @@ namespace ModelSample { vkvgImage.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.ShaderReadOnlyOptimal, VkImageLayout.ColorAttachmentOptimal, VkPipelineStageFlags.FragmentShader, VkPipelineStageFlags.BottomOfPipe); + timestampQPool.End (cmd); + pipeline.RenderPass.End (cmd); #if DEBUG && DEBUG_MARKER cmd.EndRegion (); @@ -359,9 +375,9 @@ namespace ModelSample { 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.R8g8b8a8Unorm, + vkvgImage = new Image (dev, new VkImage ((ulong)vkvgSurf.VkImage.ToInt64 ()), VkFormat.B8g8r8a8Unorm, VkImageUsageFlags.ColorAttachment, (uint)vkvgSurf.Width, (uint)vkvgSurf.Height); - vkvgImage.CreateView (); + vkvgImage.CreateView (VkImageViewType.ImageView2D, VkImageAspectFlags.Color); vkvgImage.CreateSampler (VkFilter.Nearest,VkFilter.Nearest, VkSamplerMipmapMode.Nearest, VkSamplerAddressMode.ClampToBorder); vkvgImage.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; @@ -408,6 +424,9 @@ namespace ModelSample { uboMats.Dispose (); vkvgSurf?.Dispose (); vkvgDev.Dispose (); + + timestampQPool.Dispose (); + statPool.Dispose (); } } diff --git a/samples/vkvg_overlay/packages.config b/samples/vkvg_overlay/packages.config index f37d503..d6302aa 100644 --- a/samples/vkvg_overlay/packages.config +++ b/samples/vkvg_overlay/packages.config @@ -7,5 +7,5 @@ <package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net471" /> <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net471" /> <package id="vkvg.net" version="0.2.0" targetFramework="net471" /> - <package id="Vulkan" version="0.1.1-alpha" targetFramework="net471" /> + <package id="Vulkan" version="0.1.2.2-alpha" targetFramework="net471" /> </packages>
\ No newline at end of file diff --git a/samples/vkvg_overlay/vkvg_overlay.csproj b/samples/vkvg_overlay/vkvg_overlay.csproj index 16c2df9..7423f61 100644 --- a/samples/vkvg_overlay/vkvg_overlay.csproj +++ b/samples/vkvg_overlay/vkvg_overlay.csproj @@ -12,7 +12,7 @@ <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> - <DefineConstants>DEBUG;_DEBUG_MARKER</DefineConstants> + <DefineConstants>DEBUG;DEBUG_MARKER</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> @@ -56,7 +56,7 @@ <HintPath>..\..\packages\vkvg.net.0.2.0\lib\netstandard2.0\vkvg.net.dll</HintPath> </Reference> <Reference Include="VK"> - <HintPath>..\..\packages\Vulkan.0.1.1-alpha\lib\netstandard2.0\VK.dll</HintPath> + <HintPath>..\..\packages\Vulkan.0.1.2.2-alpha\lib\netstandard2.0\VK.dll</HintPath> </Reference> </ItemGroup> <ItemGroup> |