<RestoreAdditionalProjectSources Condition="Exists('$(SolutionDir)build\$(Configuration)\')">$(SolutionDir)build\$(Configuration)\</RestoreAdditionalProjectSources>
<SpirVTasksReleaseVersion>0.1.44</SpirVTasksReleaseVersion>
<SpirVTasksPackageVersion>$(SpirVTasksReleaseVersion)-beta</SpirVTasksPackageVersion>
- <VkeReleaseVersion>0.1.18</VkeReleaseVersion>
+ <VkeReleaseVersion>0.1.20</VkeReleaseVersion>
<VkePackageVersion>$(VkeReleaseVersion)-beta</VkePackageVersion>
<LangVersion>7.2</LangVersion>
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <AssemblyName>CrowWindow</AssemblyName>
+ <PackageId>vke.CrowWindow</PackageId>
+ <AssemblyVersion>$(VkeReleaseVersion)</AssemblyVersion>
+ <Description>vke.net addon to creaet a vulkan window with crow gui support.</Description>
+ <PackageTags>vulkan gui ui c# vke.net</PackageTags>
+ <PackageVersion>$(AssemblyVersion)</PackageVersion>
+ <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
+ <PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>
+ <PackageProjectUrl>https://github.com/jpbruyere/vke.net/blob/master/README.md</PackageProjectUrl>
+ <License>MIT</License>
+ <PackageReleaseNotes></PackageReleaseNotes>
+ <SynchReleaseVersion>false</SynchReleaseVersion>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Crow" Version="0.9.2-beta" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Remove="main.cs" />
+ </ItemGroup>
+</Project>
--- /dev/null
+// Copyright (c) 2019 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Numerics;
+using vke;
+using Vulkan;
+
+namespace vke {
+
+ public class FSQPipeline : GraphicPipeline {
+ public static string FragPath = "#CrowWindow.simpletexture.frag.spv";
+ public FSQPipeline (RenderPass renderPass, PipelineLayout pipelineLayout, int attachment = 0, PipelineCache pipelineCache = null)
+ : base (renderPass, pipelineCache, "FSQ pipeline") {
+
+ GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, this.RenderPass.Samples, false);
+ cfg.RenderPass = RenderPass;
+ cfg.Layout = pipelineLayout;
+ cfg.AddShader (Dev, VkShaderStageFlags.Vertex, "#vke.FullScreenQuad.vert.spv");
+ cfg.AddShader (Dev, VkShaderStageFlags.Fragment, FragPath);
+ cfg.multisampleState.rasterizationSamples = Samples;
+
+ cfg.blendAttachments[attachment] = new VkPipelineColorBlendAttachmentState (true);
+
+ layout = cfg.Layout;
+
+ init (cfg);
+
+ cfg.DisposeShaders ();
+ }
+
+ public virtual void RecordDraw (CommandBuffer cmd) {
+ Bind (cmd);
+ cmd.Draw (3, 1, 0, 0);
+ }
+
+ protected override void Dispose (bool disposing) {
+ base.Dispose (disposing);
+ }
+ }
+
+}
--- /dev/null
+// Copyright (c) 2019 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using Glfw;
+using Vulkan;
+using Crow;
+using System.Threading;
+
+namespace vke {
+ /// <summary>
+ /// Vulkan context with Crow enabled window.
+ /// Crow vector drawing is handled with Cairo Image on an Host mapped vulkan image.
+ /// This is an easy way to have GUI in my samples with low GPU cost. Most of the ui
+ /// is cached on cpu memory images.
+ /// </summary>
+ public class CrowWindow : VkWindow, IValueChange {
+ #region IValueChange implementation
+ public event EventHandler<ValueChangeEventArgs> ValueChanged;
+ public virtual void NotifyValueChanged (string MemberName, object _value)
+ {
+ ValueChanged?.Invoke (this, new ValueChangeEventArgs (MemberName, _value));
+ }
+ #endregion
+
+ public bool MouseIsInInterface =>
+ iFace.HoverWidget != null;
+
+ protected FSQPipeline fsqPl;
+ DescriptorPool dsPool;
+ protected DescriptorSet descSet;
+ CommandPool cmdPoolCrow;
+ PrimaryCommandBuffer cmdUpdateCrow;
+ Image crowImage;
+ HostBuffer crowBuffer;
+ Interface iFace;
+ protected RenderPass renderPass;
+
+ volatile bool running;
+
+
+ VkDescriptorSetLayoutBinding dslBinding = new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler);
+
+ protected override void initVulkan () {
+ base.initVulkan ();
+
+ iFace = new Interface ((int)Width, (int)Height, WindowHandle);
+ iFace.Init ();
+
+ CreateRenderPass ();
+
+ fsqPl = new FSQPipeline (renderPass,
+ new PipelineLayout (dev, new DescriptorSetLayout (dev, dslBinding)));
+
+ cmdPoolCrow = new CommandPool (presentQueue, VkCommandPoolCreateFlags.ResetCommandBuffer);
+ cmdUpdateCrow = cmdPoolCrow.AllocateCommandBuffer ();
+
+ dsPool = new DescriptorPool (dev, 1, new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler));
+ descSet = dsPool.Allocate (fsqPl.Layout.DescriptorSetLayouts[0]);
+
+ Thread ui = new Thread (crowThread);
+ ui.IsBackground = true;
+ ui.Start ();
+ }
+ protected virtual void CreateRenderPass () {
+ renderPass = new RenderPass (dev, swapChain.ColorFormat, dev.GetSuitableDepthFormat (), VkSampleCountFlags.SampleCount1);
+ }
+
+
+ protected override void onMouseMove (double xPos, double yPos)
+ {
+ if (iFace.OnMouseMove ((int)xPos, (int)yPos))
+ return;
+ base.onMouseMove (xPos, yPos);
+ }
+ protected override void onMouseButtonDown (MouseButton button) {
+ if (iFace.OnMouseButtonDown (button))
+ return;
+ base.onMouseButtonDown (button);
+ }
+ protected override void onMouseButtonUp (MouseButton button)
+ {
+ if (iFace.OnMouseButtonUp (button))
+ return;
+ base.onMouseButtonUp (button);
+ }
+ protected override void onScroll (double xOffset, double yOffset) {
+ if (iFace.OnMouseWheelChanged ((float)yOffset))
+ return;
+ base.onScroll (xOffset, yOffset);
+ }
+ protected override void onChar (CodePoint cp) {
+ if (iFace.OnKeyPress (cp.ToChar()))
+ return;
+ base.onChar (cp);
+ }
+ protected override void onKeyUp (Key key, int scanCode, Modifier modifiers) {
+ if (iFace.OnKeyUp (key))
+ return;
+ base.onKeyUp (key, scanCode, modifiers);
+ }
+ protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) {
+ if (iFace.OnKeyDown (key))
+ return;
+ base.onKeyDown (key, scanCode, modifiers);
+ }
+
+ protected override void render () {
+
+ int idx = swapChain.GetNextImage ();
+ if (idx < 0) {
+ OnResize ();
+ return;
+ }
+
+ if (cmds[idx] == null)
+ return;
+
+ drawFence.Wait ();
+ drawFence.Reset ();
+
+ if (Monitor.IsEntered (iFace.UpdateMutex))
+ Monitor.Exit (iFace.UpdateMutex);
+
+ presentQueue.Submit (cmds[idx], swapChain.presentComplete, drawComplete[idx], drawFence);
+ presentQueue.Present (swapChain, drawComplete[idx]);
+ }
+
+ public override void Update () {
+ if (iFace.IsDirty) {
+ drawFence.Wait ();
+ drawFence.Reset ();
+ Monitor.Enter (iFace.UpdateMutex);
+ presentQueue.Submit (cmdUpdateCrow, default, default, drawFence);
+ iFace.IsDirty = false;
+ }
+
+ NotifyValueChanged ("fps", fps);
+ }
+
+ protected override void OnResize ()
+ {
+ base.OnResize ();
+ dev.WaitIdle ();
+ initCrowSurface ();
+ iFace.ProcessResize (new Rectangle (0, 0, (int)Width, (int)Height));
+ }
+
+ protected virtual void recordUICmd (CommandBuffer cmd) {
+ fsqPl.BindDescriptorSet (cmd, descSet, 0);
+ fsqPl.RecordDraw (cmd);
+ }
+
+ void crowThread () {
+ while (iFace.surf == null) {
+ Thread.Sleep (10);
+ }
+ running = true;
+ while (running) {
+ iFace.Update ();
+ Thread.Sleep (10);
+ }
+ }
+ void initCrowSurface () {
+ lock (iFace.UpdateMutex) {
+ iFace.surf?.Dispose ();
+ crowImage?.Dispose ();
+ crowBuffer?.Dispose ();
+
+ crowBuffer = new HostBuffer (dev, VkBufferUsageFlags.TransferSrc | VkBufferUsageFlags.TransferDst, Width * Height * 4, true);
+
+ crowImage = new Image (dev, VkFormat.B8g8r8a8Unorm, VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferDst,
+ VkMemoryPropertyFlags.DeviceLocal, Width, Height, VkImageType.Image2D, VkSampleCountFlags.SampleCount1, VkImageTiling.Linear);
+ crowImage.CreateView (VkImageViewType.ImageView2D, VkImageAspectFlags.Color);
+ crowImage.CreateSampler (VkFilter.Nearest, VkFilter.Nearest, VkSamplerMipmapMode.Nearest, VkSamplerAddressMode.ClampToBorder);
+ crowImage.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
+
+ DescriptorSetWrites dsw = new DescriptorSetWrites (descSet, dslBinding);
+ dsw.Write (dev, crowImage.Descriptor);
+
+ iFace.surf = new Crow.Cairo.ImageSurface (crowBuffer.MappedData, Crow.Cairo.Format.ARGB32,
+ (int)Width, (int)Height, (int)Width * 4);
+
+ PrimaryCommandBuffer cmd = cmdPoolCrow.AllocateAndStart (VkCommandBufferUsageFlags.OneTimeSubmit);
+ crowImage.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.Preinitialized, VkImageLayout.ShaderReadOnlyOptimal);
+ presentQueue.EndSubmitAndWait (cmd, true);
+
+ recordUpdateCrowCmd ();
+ }
+ }
+
+ /// <summary>
+ /// command buffer must have been reseted
+ /// </summary>
+ void recordUpdateCrowCmd () {
+ cmdPoolCrow.Reset ();
+ cmdUpdateCrow.Start ();
+ crowImage.SetLayout (cmdUpdateCrow, VkImageAspectFlags.Color,
+ VkImageLayout.ShaderReadOnlyOptimal, VkImageLayout.TransferDstOptimal,
+ VkPipelineStageFlags.FragmentShader, VkPipelineStageFlags.Transfer);
+
+ crowBuffer.CopyTo (cmdUpdateCrow, crowImage, VkImageLayout.ShaderReadOnlyOptimal);
+
+ crowImage.SetLayout (cmdUpdateCrow, VkImageAspectFlags.Color,
+ VkImageLayout.TransferDstOptimal, VkImageLayout.ShaderReadOnlyOptimal,
+ VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader);
+ cmdUpdateCrow.End ();
+ }
+
+
+ protected void loadWindow (string path, object dataSource = null) {
+ try {
+ Widget w = iFace.FindByName (path);
+ if (w != null) {
+ iFace.PutOnTop (w);
+ return;
+ }
+ w = iFace.Load (path);
+ w.Name = path;
+ w.DataSource = dataSource;
+
+ } catch (Exception ex) {
+ System.Diagnostics.Debug.WriteLine (ex.Message);
+ }
+ }
+ protected void loadIMLFragment (string imlFragment, object dataSource = null) {
+ try {
+ iFace.LoadIMLFragment (imlFragment).DataSource = dataSource;
+ } catch (Exception ex) {
+ System.Diagnostics.Debug.WriteLine (ex.Message);
+ }
+ }
+ protected void closeWindow (string path) {
+ Widget g = iFace.FindByName (path);
+ if (g != null)
+ iFace.DeleteWidget (g);
+ }
+
+
+ protected override void Dispose (bool disposing) {
+ dev.WaitIdle ();
+
+ running = false;
+ fsqPl.Dispose ();
+ dsPool.Dispose ();
+ cmdPoolCrow.Dispose ();
+ crowImage?.Dispose ();
+ crowBuffer?.Dispose ();
+ iFace.Dispose ();
+
+ base.Dispose (disposing);
+ }
+
+ }
+}
--- /dev/null
+#version 450
+
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout (set = 0, binding = 0) uniform sampler2D samplerColor;
+
+layout (location = 0) in vec2 inUV;
+layout (location = 0) out vec4 outFragColor;
+
+void main()
+{
+ outFragColor = texture(samplerColor, inUV);
+}
<AssemblyName>vke.gltfLoader</AssemblyName>
<PackageId>vke.gltfLoader</PackageId>
<AssemblyVersion>$(VkeReleaseVersion)</AssemblyVersion>
- <Description>vke.net gltf addons</Description>
- <PackageTags>C# vulkan CVKL gltf</PackageTags>
+ <Description>vke.net glTF addons</Description>
+ <PackageTags>vulkan C# gltf</PackageTags>
<PackageVersion>$(AssemblyVersion)</PackageVersion>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DefineConstants>TRACE;DEBUG;NETSTANDARD;NETSTANDARD2_0;WITH_SHADOWS;_WITH_VKVG</DefineConstants>
+ <DefineConstants>TRACE;DEBUG;NETSTANDARD;NETSTANDARD2_0;_WITH_SHADOWS;_WITH_VKVG</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DefineConstants>NETSTANDARD;NETSTANDARD2_0;WITH_SHADOWS;_WITH_VKVG</DefineConstants>
--- /dev/null
+// Copyright (c) 2013-2020 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.IO;
+using Crow;
+using vke;
+using Vulkan;
+
+namespace Model {
+ public class EditableShaderInfo : ShaderInfo, IValueChange {
+ #region IValueChange implementation
+ public event EventHandler<ValueChangeEventArgs> ValueChanged;
+ public virtual void NotifyValueChanged (string MemberName, object _value) {
+ ValueChanged?.Invoke (this, new ValueChangeEventArgs (MemberName, _value));
+ }
+ #endregion
+
+ public event EventHandler ModuleChanged;
+
+ string path;
+ string origSource;
+ string source;
+
+ public string Source {
+ get => source;
+ set {
+ if (source == value)
+ return;
+ source = value;
+
+ NotifyValueChanged (nameof (IsDirty), IsDirty);
+ NotifyValueChanged (nameof(Source), source);
+
+ Compile ();
+ }
+ }
+
+ string error;
+
+ public bool IsDirty => source != origSource;
+ public bool HasError => !string.IsNullOrEmpty (error);
+
+ public string Error {
+ get => error;
+ set {
+ if (error == value)
+ return;
+ error = value;
+ NotifyValueChanged (nameof (Error), error);
+ NotifyValueChanged ("HasError", HasError);
+ }
+ }
+
+ public EditableShaderInfo (Device dev, string shaderPath, VkShaderStageFlags stageFlags, SpecializationInfo specializationInfo = null, string entryPoint = "main") :
+ base (stageFlags, default, specializationInfo, entryPoint) {
+ this.dev = dev;
+ path = shaderPath;
+ reloadFromDisk ();
+ }
+
+ void reloadFromDisk () {
+ using (StreamReader sr = new StreamReader (path)) {
+ origSource = sr.ReadToEnd ();
+ }
+ Source = origSource;
+ }
+
+ public bool Compile () {
+ using (shaderc.Compiler comp = new shaderc.Compiler ()) {
+ using (shaderc.Result res = comp.Compile (source, path, Utils.ShaderStageToShaderKind (Stage))) {
+ if (res.Status == shaderc.Status.Success) {
+ dev.DestroyShaderModule (info.module);
+ info.module = dev.CreateShaderModule (res.CodePointer, (UIntPtr)res.CodeLength);
+ Error = null;
+ ModuleChanged.Raise (this, null);
+ return true;
+ }
+ Error = res.ErrorMessage;
+ }
+ }
+ return false;
+ }
+ }
+}
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\..\addons\gltfLoader\gltfLoader.csproj" />
+ <ProjectReference Include="..\..\addons\CrowWindow\CrowWindow.csproj" />
</ItemGroup>
<ItemGroup>
<GLSLShader Remove="shaders\**\*.frag;shaders\**\*.vert;shaders\**\*.comp;shaders\**\*.geom" />
//
// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
using System;
+using System.Collections.Generic;
+using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using vke;
using vke.glTF;
using Vulkan;
-namespace ModelSample {
- class Program : VkWindow {
+namespace Model{
+ class Program : CrowWindow {
static void Main (string[] args) {
#if DEBUG
Instance.VALIDATION = true;
FrameBuffers frameBuffers;
- GraphicPipeline pipeline;
+ GraphicPipeline modelPipeline;
VkSampleCountFlags NUM_SAMPLES = VkSampleCountFlags.SampleCount1;
DebugDrawPipeline dbgPipeline;
+ public List<ShaderInfo> Shaders {
+ get => modelPlCfg?.Shaders;
+ }
+ GraphicPipelineConfig modelPlCfg;
protected override void initVulkan () {
base.initVulkan ();
cmds = cmdPool.AllocateCommandBuffer(swapChain.ImageCount);
cmdDebug = cmdPool.AllocateSecondaryCommandBuffer ();
+ cmdUI = cmdPool.AllocateSecondaryCommandBuffer ();
descriptorPool = new DescriptorPool (dev, 2,
new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer),
new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler),
new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler)
);
-
- GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, NUM_SAMPLES);
- cfg.rasterizationState.cullMode = VkCullModeFlags.Back;
+
+ modelPlCfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, NUM_SAMPLES);
+
+ modelPlCfg.rasterizationState.cullMode = VkCullModeFlags.Back;
if (NUM_SAMPLES != VkSampleCountFlags.SampleCount1) {
- cfg.multisampleState.sampleShadingEnable = true;
- cfg.multisampleState.minSampleShading = 0.5f;
+ modelPlCfg.multisampleState.sampleShadingEnable = true;
+ modelPlCfg.multisampleState.minSampleShading = 0.5f;
}
- cfg.Layout = new PipelineLayout (dev, new VkPushConstantRange(VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf<Matrix4x4> ()), descLayoutMatrix, descLayoutTextures);
- cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, dev.GetSuitableDepthFormat (), cfg.Samples);
- cfg.AddVertexBinding<Model.Vertex> (0);
- cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat, VkFormat.R32g32Sfloat);
+ modelPlCfg.Layout = new PipelineLayout (dev, new VkPushConstantRange(VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf<Matrix4x4> ()), descLayoutMatrix, descLayoutTextures);
+ modelPlCfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, dev.GetSuitableDepthFormat (), modelPlCfg.Samples);
+ modelPlCfg.AddVertexBinding<SimpleModel.Vertex> (0);
+ modelPlCfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat, VkFormat.R32g32Sfloat);
- 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));
- }
+ modelPlCfg.AddShaders (new EditableShaderInfo (dev, "shaders/model.vert", VkShaderStageFlags.Vertex));
+ modelPlCfg.AddShaders (new EditableShaderInfo (dev, "shaders/model.frag", VkShaderStageFlags.Fragment));
- pipeline = new GraphicPipeline (cfg);
+ foreach (EditableShaderInfo esi in modelPlCfg.Shaders.OfType<EditableShaderInfo> ()) {
+ esi.Compile ();
+ esi.ModuleChanged += (sender, e) => rebuildModelPipeline = true;
+ }
- cfg.DisposeShaders ();
+ buildModelPipeline ();
helmet = new SimpleModel (presentQueue, Utils.DataDirectory + "models/DamagedHelmet/glTF/DamagedHelmet.gltf");
DescriptorSetWrites texturesUpdate = new DescriptorSetWrites (dsTextures, descLayoutTextures);
texturesUpdate.Write (dev,
helmet.textures[0].Descriptor,
- helmet.textures[1].Descriptor,
- helmet.textures[2].Descriptor);
+ helmet.textures[4].Descriptor,
+ helmet.textures[3].Descriptor);
uboMats.Map ();//permanent map
- dbgPipeline = new DebugDrawPipeline (pipeline.RenderPass);
+ dbgPipeline = new DebugDrawPipeline (modelPipeline.RenderPass);
dbgPipeline.AddLine (Vector3.Zero, Vector3.UnitX, 1, 0, 0);
dbgPipeline.AddLine (Vector3.Zero, Vector3.UnitY, 0, 1, 0);
dbgPipeline.AddLine (Vector3.Zero, Vector3.UnitZ, 0, 0, 1);
cmdPoolModel = new CommandPool (presentQueue, VkCommandPoolCreateFlags.ResetCommandBuffer);
cmdModel = cmdPoolModel.AllocateSecondaryCommandBuffer ();
+
+ UpdateFrequency = 20;
+
+ loadWindow ("#ui.main.crow", this);
}
+ void buildModelPipeline () {
+ dev.WaitIdle ();
+ GraphicPipeline newPL = new GraphicPipeline (modelPlCfg);
+ modelPipeline?.Dispose ();
+ modelPipeline = newPL;
+ }
- bool rebuildCmdBuffers, rebuildCmdModel = true;
+ bool rebuildCmdBuffers, rebuildCmdModel = true, rebuildModelPipeline;
CommandPool cmdPoolModel;
- SecondaryCommandBuffer cmdModel, cmdDebug;
+ SecondaryCommandBuffer cmdModel, cmdDebug, cmdUI;
void buildModelCmd () {
cmdPoolModel.Reset ();
- cmdModel.Start (VkCommandBufferUsageFlags.RenderPassContinue | VkCommandBufferUsageFlags.SimultaneousUse, pipeline.RenderPass, 0);
+ cmdModel.Start (VkCommandBufferUsageFlags.RenderPassContinue | VkCommandBufferUsageFlags.SimultaneousUse, modelPipeline.RenderPass, 0);
cmdModel.SetViewport (swapChain.Width, swapChain.Height);
cmdModel.SetScissor (swapChain.Width, swapChain.Height);
- cmdModel.BindDescriptorSet (pipeline.Layout, dsMatrices);
- cmdModel.BindDescriptorSet (pipeline.Layout, dsTextures, 1);
+ cmdModel.BindDescriptorSet (modelPipeline.Layout, dsMatrices);
+ cmdModel.BindDescriptorSet (modelPipeline.Layout, dsTextures, 1);
Matrix4x4 matrix = Matrix4x4.Identity;
- cmdModel.PushConstant (pipeline.Layout, VkShaderStageFlags.Vertex, matrix);
+ cmdModel.PushConstant (modelPipeline.Layout, VkShaderStageFlags.Vertex, matrix);
- cmdModel.BindPipeline (pipeline);
+ cmdModel.BindPipeline (modelPipeline);
- helmet.DrawAll (cmdModel, pipeline.Layout);
+ helmet.DrawAll (cmdModel, modelPipeline.Layout);
cmdModel.End ();
}
void buildDebugCmd () {
- cmdDebug.Start (VkCommandBufferUsageFlags.RenderPassContinue | VkCommandBufferUsageFlags.SimultaneousUse, pipeline.RenderPass);
+ cmdDebug.Start (VkCommandBufferUsageFlags.RenderPassContinue | VkCommandBufferUsageFlags.SimultaneousUse, modelPipeline.RenderPass);
float d = 0.2f;
uint dbgW = (uint)(swapChain.Width * d);
cmdDebug.End ();
}
+ protected override void recordUICmd (CommandBuffer cmd) {
+ (cmd as SecondaryCommandBuffer).Start (VkCommandBufferUsageFlags.RenderPassContinue | VkCommandBufferUsageFlags.SimultaneousUse, modelPipeline.RenderPass);
+ cmd.SetViewport (swapChain.Width, swapChain.Height);
+ cmd.SetScissor (swapChain.Width, swapChain.Height);
+ fsqPl.BindDescriptorSet (cmd, descSet, 0);
+ fsqPl.RecordDraw (cmd);
+ cmd.End ();
+ }
+
void buildCommandBuffers () {
dev.WaitIdle ();
cmdPool.Reset (VkCommandPoolResetFlags.ReleaseResources);
}
buildDebugCmd ();
+ recordUICmd (cmdUI);
for (int i = 0; i < swapChain.ImageCount; ++i) {
FrameBuffer fb = frameBuffers[i];
cmds[i].Start ();
- pipeline.RenderPass.Begin (cmds[i], fb, VkSubpassContents.SecondaryCommandBuffers);
+ modelPipeline.RenderPass.Begin (cmds[i], fb, VkSubpassContents.SecondaryCommandBuffers);
if (cmdModel != null)
cmds[i].Execute (cmdModel);
-
+
+ cmds[i].Execute (cmdUI);
cmds[i].Execute (cmdDebug);
- pipeline.RenderPass.End (cmds[i]);
+ modelPipeline.RenderPass.End (cmds[i]);
cmds[i].End ();
}
public override void Update () {
+ if (rebuildModelPipeline) {
+ buildModelPipeline ();
+ rebuildModelPipeline = false;
+ rebuildCmdModel = rebuildCmdBuffers = true;
+ }
if (rebuildCmdBuffers) {
buildCommandBuffers ();
rebuildCmdBuffers = false;
}
+ base.Update ();
}
public override void UpdateView () {
camera.AspectRatio = (float)swapChain.Width / swapChain.Height;
}
protected override void onMouseMove (double xPos, double yPos) {
- double diffX = lastMouseX - xPos;
- double diffY = lastMouseY - yPos;
- if (MouseButton[0]) {
- camera.Rotate ((float)-diffY,0, (float)diffX);
- } else if (MouseButton[1]) {
- camera.SetZoom ((float)diffY);
- } else
+ base.onMouseMove (xPos, yPos);
+ if (MouseIsInInterface)
return;
- rebuildCmdBuffers = true;
- updateViewRequested = true;
- }
-
-
+ //double diffX = lastMouseX - xPos;
+ //double diffY = lastMouseY - yPos;
+ //if (MouseButton[0]) {
+ // camera.Rotate ((float)-diffY,0, (float)diffX);
+ //} else if (MouseButton[1]) {
+ // camera.SetZoom ((float)diffY);
+ //} else
+ // return;
+ //rebuildCmdBuffers = true;
+ //updateViewRequested = true;
+ }
protected override void OnResize () {
base.OnResize();
frameBuffers?.Dispose();
- frameBuffers = pipeline.RenderPass.CreateFrameBuffers(swapChain);
+ frameBuffers = modelPipeline.RenderPass.CreateFrameBuffers(swapChain);
+ rebuildCmdModel = true;
buildCommandBuffers ();
+ updateViewRequested = true;
}
class SimpleModel : PbrModel {
if (disposing) {
if (!isDisposed) {
helmet.Dispose ();
- pipeline.Dispose ();
+ modelPipeline.Dispose ();
descLayoutMatrix.Dispose ();
descLayoutTextures.Dispose ();
frameBuffers?.Dispose();
layout (location = 0) in vec2 inUV;
layout (location = 1) in vec3 inN;
-layout (location = 2) in vec3 inV;//ViewDir
+layout (location = 2) in vec3 inV;
layout (location = 3) in vec3 inL;
+layout (location = 4) in vec3 inP;
layout (location = 0) out vec4 outFragColor;
-// http://www.thetenthplanet.de/archives/1180
-mat3 cotangent_frame(vec3 N, vec3 p, vec2 uv)
+vec3 perturb_normal(vec3 N, vec3 P, vec2 uv)
{
+ // assume N, the interpolated vertex normal and
+ // V, the view vector (vertex to eye)
+ vec3 map = texture(samplerNormal, uv).xyz * 2.0 - 1.0;
// get edge vectors of the pixel triangle
- vec3 dp1 = dFdx( p );
- vec3 dp2 = dFdy( p );
+ vec3 dp1 = dFdx( P );
+ vec3 dp2 = dFdy( P );
vec2 duv1 = dFdx( uv );
vec2 duv2 = dFdy( uv );
// construct a scale-invariant frame
float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) );
- return mat3( T * invmax, B * invmax, N );
-}
-
-vec3 perturb_normal( vec3 N, vec3 V, vec2 texcoord )
-{
- // assume N, the interpolated vertex normal and
- // V, the view vector (vertex to eye)
- vec3 map = texture(samplerNormal, texcoord).xyz;
- map = map * 255./127. - 128./127.;
- mat3 TBN = cotangent_frame(N, -V, texcoord);
+ mat3 TBN = mat3( T * invmax, B * invmax, N );
+
return normalize(TBN * map);
}
-
void main()
{
vec4 color = texture(samplerColor, inUV);
vec3 N = normalize(inN);
- vec3 L = normalize(inL);
vec3 V = normalize(inV);
+ vec3 L = normalize(inL);
+ vec3 P = normalize(inP);
+
+ N = perturb_normal(N, P, inUV);
+
vec3 R = reflect(-L, N);
- vec3 diffuse = max(dot(N, L), 0.0) * vec3(0.9);
- vec3 specular = pow(max(dot(R, V), 0.0), 16.0) * vec3(0.75);
- outFragColor = vec4(diffuse * color.rgb + specular, 1.0);
-}
-/*void main()
-{
- vec4 diff = texture(samplerColor, inUV);
+ vec3 diff = max(dot(N, L), 0.0) * texture(samplerOcclusion, inUV).rgb;
+ vec3 specular = pow(max(dot(R, V), 0.0), 16.0) * vec3(1.0);
- vec3 n = normalize(inN);
- vec3 l = normalize(-light);
- vec3 pn = perturb_normal(n, inV, inUV);
+ outFragColor = vec4(diff * color.rgb + specular, 1.0);
- float lambert = max(0.0, dot(pn, l));
+ /*float fr = dot(N,V);
+ */
- //diff.rgb *= lambert * texture(samplerOcclusion, inUV).rgb;
- vec3 spec = vec3(0);
- vec3 amb = vec3(0.1);
- if (lambert >= 0.0) {
- vec3 rd = reflect(l, pn);
- float s = dot(rd, normalize(inV));
- spec = vec3(0.9,0.9,0.9)* //light.specular.xyz * material.specular.xyz *
- pow(max(0.0, s), 10.5); //0.5 = mat shininess
- }
- //outFragColor = vec4(1.0); //
- //outFragColor = vec4(diff.rgb , 1.0); //
- outFragColor = vec4(diff.rgb + amb + spec , diff.a); //
-}*/
\ No newline at end of file
+}
layout (location = 0) out vec2 outUV;
layout (location = 1) out vec3 outN;
-layout (location = 2) out vec3 outV;//ViewDir
+layout (location = 2) out vec3 outV;
layout (location = 3) out vec3 outL;
+layout (location = 4) out vec3 outP;
out gl_PerVertex
{
//outN = normalize(transpose(inverse(mat3(mod))) * inNormal);
outN = mat3(mod)* inNormal;
- //mat4 viewInv = inverse(ubo.viewMatrix);
-
- outV = -pos.xyz;//normalize(vec3(viewInv * vec4(0.0, 0.0, 0.0, 1.0) - pos));
+ mat4 vi = inverse(ubo.viewMatrix);
+ vec4 vit = vi[3];
+ outV = vec3(vit[0],vit[1],vit[2]); //normalize(vec3(viewInv * vec4(0.0, 0.0, 0.0, 1.0) - pos));
outL = lPos - pos.xyz;
+ outP = -pos.xyz;
gl_Position = ubo.projectionMatrix * ubo.viewMatrix * pos;
}
--- /dev/null
+<?xml version="1.0"?>
+<Window Width="50%" Height="50%" Background="0.1,0.1,0.1,0.7">
+ <HorizontalStack>
+ <ListBox Name="shaders" Data="{Shaders}" Width="30%" Height="Stretched" Background="Transparent"
+ SelectionColoring="true" SelectionBackground="RoyalBlue">
+ <ItemTemplate>
+ <VerticalStack Height="Fit" Margin="5">
+ <Label Text="{Stage}" Width="Stretched" />
+ </VerticalStack>
+ </ItemTemplate>
+ </ListBox>
+ <Splitter/>
+ <VerticalStack DataSource="{../shaders.SelectedItem}">
+ <!--<TextBox Text="{²Source}" Multiline="True" Height="Stretched" TextAlignment="TopLeft" Background="0.0,0.0,0.0,0.7" Foreground="White"/>
+ <Scroller Height="Stretched" Background="White">
+ <Label Height="Fit" Text="{Error}" Visible="{HasError}" Width="Stretched" Background="DarkRed" Foreground="White" Multiline="true"/>
+ </Scroller>-->
+ <HorizontalStack>
+ <Scroller Name="scroller1" Background="White"
+ Margin="2" ScrollY="{../scrollbar1.Value}"
+ ValueChanged="./_scroller_ValueChanged">
+ <TextBox VerticalAlignment="Top"
+ Text="{²Source}" Multiline="true" TextAlignment="TopLeft"
+ Font="Courriernew 10"/>
+ </Scroller>
+ <ScrollBar Name="scrollbar1" Value="{../scroller1.ScrollY}"
+ LargeIncrement="{../scroller1.PageHeight}" SmallIncrement="30"
+ CursorSize="{../scroller1.ChildHeightRatio}"
+ Maximum="{../scroller1.MaxScrollY}" Orientation="Vertical"
+ Width="14" />
+ </HorizontalStack>
+ </VerticalStack>
+ </HorizontalStack>
+</Window>
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
- <ProjectReference Include="..\..\addons\VkvgPipeline\VkvgPipeline.csproj" />
+<!-- <ProjectReference Include="..\..\addons\VkvgPipeline\VkvgPipeline.csproj" />-->
</ItemGroup>
</Project>
namespace vke {
public class FSQPipeline : GraphicPipeline {
+ public static string FragPath = "#shaders.simpletexture.frag.spv";
public FSQPipeline (RenderPass renderPass, PipelineLayout pipelineLayout, int attachment = 0, PipelineCache pipelineCache = null)
: base (renderPass, pipelineCache, "FSQ pipeline") {
cfg.RenderPass = RenderPass;
cfg.Layout = pipelineLayout;
cfg.AddShader (Dev, VkShaderStageFlags.Vertex, "#vke.FullScreenQuad.vert.spv");
- cfg.AddShader (Dev, VkShaderStageFlags.Fragment, "#shaders.simpletexture.frag.spv");
+ cfg.AddShader (Dev, VkShaderStageFlags.Fragment, FragPath);
cfg.multisampleState.rasterizationSamples = Samples;
cfg.blendAttachments[attachment] = new VkPipelineColorBlendAttachmentState (true);
/// </summary>
public class CrowWindow : VkWindow, IValueChange {
#region IValueChange implementation
- public event EventHandler<Crow.ValueChangeEventArgs> ValueChanged;
+ public event EventHandler<ValueChangeEventArgs> ValueChanged;
public virtual void NotifyValueChanged (string MemberName, object _value)
{
ValueChanged?.Invoke (this, new ValueChangeEventArgs (MemberName, _value));
base.OnResize ();
dev.WaitIdle ();
initCrowSurface ();
- iFace.ProcessResize (new Crow.Rectangle (0, 0, (int)Width, (int)Height));
+ iFace.ProcessResize (new Rectangle (0, 0, (int)Width, (int)Height));
}
public void RecordDraw (CommandBuffer cmd) {
layout (set = 0, binding = 0) uniform sampler2D samplerColor;
layout (location = 0) in vec2 inUV;
-
layout (location = 0) out vec4 outFragColor;
void main()
static void Main (string[] args) {
#if DEBUG
Instance.VALIDATION = true;
- //Instance.RENDER_DOC_CAPTURE = true;
+ Instance.RENDER_DOC_CAPTURE = true;
#endif
SwapChain.PREFERED_FORMAT = VkFormat.B8g8r8a8Srgb;
DeferredPbrRenderer.TEXTURE_ARRAY = true;
};
string[] modelPathes = {
"/mnt/devel/vkPinball/data/models/pinball.gltf",
+ "/mnt/devel/tests/FidelityFX-SSSR/sample/media/Chess/scene.gltf",
+ "/mnt/devel/tests/FidelityFX-SSSR/sample/media/Chess/scene.bin",
"/mnt/devel/pinball.net/data/test.glb",
Utils.DataDirectory + "models/DamagedHelmet/glTF/DamagedHelmet.gltf",
//Utils.DataDirectory + "models/shadow.glb",
--- /dev/null
+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<Matrix4x4> () * 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);
+ }
+ }
+
+}
--- /dev/null
+using System;
+using System.Numerics;
+using System.Runtime.InteropServices;
+using vke;
+using vke.Environment;
+using vke.glTF;
+using Vulkan;
+
+namespace glow {
+ public class DeferredPbrRenderer : IDisposable {
+ Device dev;
+ Queue gQueue;
+ public static int MAX_MATERIAL_COUNT = 4;
+ public static VkSampleCountFlags NUM_SAMPLES = VkSampleCountFlags.SampleCount1;
+ public static VkFormat HDR_FORMAT = VkFormat.R16g16b16a16Sfloat;
+ public static VkFormat MRT_FORMAT = VkFormat.R32g32b32a32Sfloat;
+ public static bool TEXTURE_ARRAY;
+
+ public enum DebugView {
+ none,
+ color,
+ normal,
+ pos,
+ occlusion,
+ emissive,
+ metallic,
+ roughness,
+ depth,
+ prefill,
+ irradiance,
+ shadowMap
+ }
+ public DebugView currentDebugView = DebugView.none;
+ public int lightNumDebug = 0;
+ public int debugMip = 0;
+ public int debugFace = 0;
+
+ const float lightMoveSpeed = 0.1f;
+ public float exposure = 2.0f;
+ public 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 = 1.0f,
+ };
+ public Light[] lights = {
+ new Light {
+ position = new Vector4(1.5f,2.5f,1.5f,0f),
+ color = new Vector4(1,1.0f,1.0f,1)
+ },
+ new Light {
+ position = new Vector4(-1.5f,2.5f,1.5f,0f),
+ color = new Vector4(0.8f,0.8f,1,1)
+ }
+ };
+
+ FrameBuffer frameBuffer;
+ public Image gbColorRough, gbEmitMetal, gbN_AO, gbPos, hdrImgResolved;
+
+ DescriptorPool descriptorPool;
+ DescriptorSetLayout descLayoutMain, descLayoutTextures, descLayoutGBuff;
+ DescriptorSet dsMain, dsGBuff;
+
+ public PipelineCache pipelineCache;
+ Pipeline gBuffPipeline, composePipeline, debugPipeline;
+
+ public HostBuffer uboMatrices { get; private set; }
+ public HostBuffer<Light> uboLights { get; private set; }
+
+ RenderPass renderPass;
+
+ public PbrModel model { get; private set; }
+ public EnvironmentCube envCube;
+ public ShadowMapRenderer shadowMapRenderer;
+
+ public BoundingBox modelAABB;
+
+ public VkSemaphore DrawComplete;
+
+ const int SP_SKYBOX = 0;
+ const int SP_MODELS = 1;
+ const int SP_COMPOSE = 2;
+ //const int SP_TONE_MAPPING = 3;
+
+ string cubemapPath;
+
+ uint width, height;
+ public uint Width => width;
+ public uint Height => height;
+
+ public DeferredPbrRenderer (Queue gQueue, string cubemapPath, uint width, uint height, float nearPlane, float farPlane) {
+ this.gQueue = gQueue;
+ this.dev = gQueue.Dev;
+ this.cubemapPath = cubemapPath;
+ this.width = width;
+ this.height = height;
+
+ DrawComplete = dev.CreateSemaphore();
+
+ pipelineCache = new PipelineCache (dev);
+
+ descriptorPool = new DescriptorPool (dev, 5,
+ new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer, 3),
+ new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, 6),
+ new VkDescriptorPoolSize (VkDescriptorType.InputAttachment, 5),
+ new VkDescriptorPoolSize (VkDescriptorType.StorageImage, 4)
+ );
+
+ uboMatrices = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, matrices, true);
+ uboLights = new HostBuffer<Light> (dev, VkBufferUsageFlags.UniformBuffer, lights, true);
+
+#if WITH_SHADOWS
+ shadowMapRenderer = new ShadowMapRenderer (gQueue, this);
+#endif
+
+ init (nearPlane, farPlane);
+ }
+
+ void init_renderpass () {
+ renderPass = new RenderPass (dev, NUM_SAMPLES);
+
+ renderPass.AddAttachment (HDR_FORMAT, VkImageLayout.ShaderReadOnlyOptimal, NUM_SAMPLES);//final outpout
+ renderPass.AddAttachment (dev.GetSuitableDepthFormat (), VkImageLayout.DepthStencilAttachmentOptimal, NUM_SAMPLES);
+ renderPass.AddAttachment (VkFormat.R8g8b8a8Unorm, VkImageLayout.ColorAttachmentOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff0 (color + roughness) and final color before resolve
+ renderPass.AddAttachment (VkFormat.R8g8b8a8Unorm, VkImageLayout.ColorAttachmentOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff1 (emit + metal)
+ renderPass.AddAttachment (MRT_FORMAT, VkImageLayout.ColorAttachmentOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff2 (normals + AO)
+ renderPass.AddAttachment (MRT_FORMAT, VkImageLayout.ColorAttachmentOptimal, NUM_SAMPLES, VkAttachmentLoadOp.Clear, VkAttachmentStoreOp.DontCare);//GBuff3 (Pos + depth)
+
+ renderPass.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 ()};
+ //skybox
+ subpass[SP_SKYBOX].AddColorReference (0, VkImageLayout.ColorAttachmentOptimal);
+ //models
+ subpass[SP_MODELS].AddColorReference (new VkAttachmentReference (2, VkImageLayout.ColorAttachmentOptimal),
+ new VkAttachmentReference (3, VkImageLayout.ColorAttachmentOptimal),
+ new VkAttachmentReference (4, VkImageLayout.ColorAttachmentOptimal),
+ new VkAttachmentReference (5, VkImageLayout.ColorAttachmentOptimal));
+ subpass[SP_MODELS].SetDepthReference (1, VkImageLayout.DepthStencilAttachmentOptimal);
+ subpass[SP_MODELS].AddPreservedReference (0);
+
+ //compose
+ subpass[SP_COMPOSE].AddColorReference (0, VkImageLayout.ColorAttachmentOptimal);
+ subpass[SP_COMPOSE].AddInputReference (new VkAttachmentReference (2, VkImageLayout.ShaderReadOnlyOptimal),
+ new VkAttachmentReference (3, VkImageLayout.ShaderReadOnlyOptimal),
+ new VkAttachmentReference (4, VkImageLayout.ShaderReadOnlyOptimal),
+ new VkAttachmentReference (5, VkImageLayout.ShaderReadOnlyOptimal));
+ //tone mapping
+ //subpass[SP_TONE_MAPPING].AddColorReference ((NUM_SAMPLES == VkSampleCountFlags.SampleCount1) ? 0u : 2u, VkImageLayout.ColorAttachmentOptimal);
+ //subpass[SP_TONE_MAPPING].AddInputReference (new VkAttachmentReference (6, VkImageLayout.ShaderReadOnlyOptimal));
+ //if (NUM_SAMPLES != VkSampleCountFlags.SampleCount1)
+ //subpass[SP_TONE_MAPPING].AddResolveReference (0, VkImageLayout.ColorAttachmentOptimal);
+
+ renderPass.AddSubpass (subpass);
+
+ renderPass.AddDependency (Vk.SubpassExternal, SP_SKYBOX,
+ VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.ColorAttachmentOutput,
+ VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite);
+ renderPass.AddDependency (SP_SKYBOX, SP_MODELS,
+ VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader,
+ VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.ShaderRead);
+ renderPass.AddDependency (SP_MODELS, SP_COMPOSE,
+ VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader,
+ VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.ShaderRead);
+ //renderPass.AddDependency (SP_COMPOSE, Vk.SubpassExternal,
+ //VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.Transfer,
+ //VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.TransferRead);
+ //renderPass.AddDependency (SP_COMPOSE, SP_COMPOSE,
+ //VkPipelineStageFlags.Transfer, VkPipelineStageFlags.ComputeShader,
+ //VkAccessFlags.TransferWrite, VkAccessFlags.ShaderRead);
+ //renderPass.AddDependency (Vk.SubpassExternal, SP_TONE_MAPPING,
+ // VkPipelineStageFlags.ComputeShader, VkPipelineStageFlags.FragmentShader,
+ // VkAccessFlags.ShaderWrite, VkAccessFlags.ShaderRead);
+ //renderPass.AddDependency (SP_SKYBOX, SP_TONE_MAPPING,
+ //VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.FragmentShader,
+ //VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.ShaderRead);
+ renderPass.AddDependency (SP_COMPOSE, Vk.SubpassExternal,
+ VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.Transfer,
+ VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.TransferRead);
+ //renderPass.AddDependency (SP_TONE_MAPPING, Vk.SubpassExternal,
+ //VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe,
+ //VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead);
+ }
+
+ void init (float nearPlane, float farPlane) {
+ init_renderpass ();
+
+ descLayoutMain = new DescriptorSetLayout (dev,
+ new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer),//matrices and params
+ 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.UniformBuffer),//lights
+ new VkDescriptorSetLayoutBinding (5, VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer));//materials
+#if WITH_SHADOWS
+ descLayoutMain.Bindings.Add (new VkDescriptorSetLayoutBinding (6, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler));
+#endif
+
+ if (TEXTURE_ARRAY) {
+ descLayoutMain.Bindings.Add (new VkDescriptorSetLayoutBinding (7, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler));//texture array
+ //descLayoutMain.Bindings.Add (new VkDescriptorSetLayoutBinding (8, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler));//down sampled hdr
+ } else {
+ 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)
+ );
+ }
+
+ descLayoutGBuff = new DescriptorSetLayout (dev,
+ new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment),//color + roughness
+ new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment),//emit + metal
+ new VkDescriptorSetLayoutBinding (2, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment),//normals + AO
+ new VkDescriptorSetLayoutBinding (3, VkShaderStageFlags.Fragment, VkDescriptorType.InputAttachment));//Pos + depth
+
+
+
+ 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;
+ if (TEXTURE_ARRAY)
+ cfg.Layout = new PipelineLayout (dev, descLayoutMain, descLayoutGBuff);
+ else
+ cfg.Layout = new PipelineLayout (dev, descLayoutMain, descLayoutGBuff, descLayoutTextures);
+
+ cfg.Layout.AddPushConstants (
+ new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf<Matrix4x4> ()),
+ new VkPushConstantRange (VkShaderStageFlags.Fragment, sizeof (int), 64)
+ );
+ cfg.RenderPass = renderPass;
+ cfg.SubpassIndex = SP_MODELS;
+ 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<PbrModelTexArray.Vertex> ();
+
+ using (SpecializationInfo constants = new SpecializationInfo (
+ new SpecializationConstant<float> (0, nearPlane),
+ new SpecializationConstant<float> (1, farPlane),
+ new SpecializationConstant<float> (2, MAX_MATERIAL_COUNT))) {
+
+ cfg.AddShader (dev, VkShaderStageFlags.Vertex, "#shaders.GBuffPbr.vert.spv");
+ if (TEXTURE_ARRAY)
+ cfg.AddShader (dev, VkShaderStageFlags.Fragment, "#shaders.GBuffPbrTexArray.frag.spv", constants);
+ else
+ cfg.AddShader (dev, VkShaderStageFlags.Fragment, "#shaders.GBuffPbr.frag.spv", constants);
+
+ gBuffPipeline = new GraphicPipeline (cfg);
+ }
+ cfg.rasterizationState.cullMode = VkCullModeFlags.Front;
+ //COMPOSE PIPELINE
+ cfg.blendAttachments.Clear ();
+ cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+ cfg.ResetShadersAndVerticesInfos ();
+ cfg.SubpassIndex = SP_COMPOSE;
+ cfg.Layout = gBuffPipeline.Layout;
+ cfg.depthStencilState.depthTestEnable = false;
+ cfg.depthStencilState.depthWriteEnable = false;
+ using (SpecializationInfo constants = new SpecializationInfo (
+ new SpecializationConstant<uint> (0, (uint)lights.Length))) {
+ cfg.AddShader (dev, VkShaderStageFlags.Vertex, "#vke.FullScreenQuad.vert.spv");
+#if WITH_SHADOWS
+ cfg.AddShader (dev, VkShaderStageFlags.Fragment, "#shaders.compose_with_shadows.frag.spv", constants);
+#else
+ cfg.AddShader (VkShaderStageFlags.Fragment, "#shaders.compose.frag.spv", constants);
+#endif
+ composePipeline = new GraphicPipeline (cfg);
+ }
+ //DEBUG DRAW use subpass of compose
+ cfg.Shaders[1].Dispose ();
+ cfg.Shaders[1] = new ShaderInfo (dev, VkShaderStageFlags.Fragment, "#shaders.show_gbuff.frag.spv");
+ cfg.SubpassIndex = SP_COMPOSE;
+ debugPipeline = new GraphicPipeline (cfg);
+ ////TONE MAPPING
+ //cfg.shaders[1] = new ShaderInfo (VkShaderStageFlags.Fragment, "#shaders.tone_mapping.frag.spv");
+ //cfg.SubpassIndex = SP_TONE_MAPPING;
+ //toneMappingPipeline = new GraphicPipeline (cfg);
+
+ cfg.DisposeShaders ();
+
+ dsMain = descriptorPool.Allocate (descLayoutMain);
+ dsGBuff = descriptorPool.Allocate (descLayoutGBuff);
+
+ envCube = new EnvironmentCube (cubemapPath, gBuffPipeline.Layout, gQueue, renderPass);
+
+ matrices.prefilteredCubeMipLevels = envCube.prefilterCube.CreateInfo.mipLevels;
+
+ DescriptorSetWrites dsMainWrite = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings.GetRange (0, 5).ToArray ());
+ dsMainWrite.Write (dev,
+ uboMatrices.Descriptor,
+ envCube.irradianceCube.Descriptor,
+ envCube.prefilterCube.Descriptor,
+ envCube.lutBrdf.Descriptor,
+ uboLights.Descriptor);
+
+#if WITH_SHADOWS
+ dsMainWrite = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings[6]);
+ dsMainWrite.Write (dev, shadowMapRenderer.shadowMap.Descriptor);
+#endif
+ }
+
+
+ public void LoadModel (Queue transferQ, string path) {
+ dev.WaitIdle ();
+ model?.Dispose ();
+
+ if (TEXTURE_ARRAY) {
+ PbrModelTexArray mod = new PbrModelTexArray (transferQ, path);
+ if (mod.texArray != null) {
+ DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings[5], descLayoutMain.Bindings[7]);
+ uboUpdate.Write (dev, mod.materialUBO.Descriptor, mod.texArray.Descriptor);
+ }
+ model = mod;
+ } else {
+ model = new PbrModelSeparatedTextures (transferQ, path,
+ descLayoutTextures,
+ AttachmentType.Color,
+ AttachmentType.PhysicalProps,
+ AttachmentType.Normal,
+ AttachmentType.AmbientOcclusion,
+ AttachmentType.Emissive);
+
+ DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dsMain, descLayoutMain.Bindings[5]);
+ uboUpdate.Write (dev, model.materialUBO.Descriptor);
+ }
+
+
+ modelAABB = model.DefaultScene.AABB;
+ }
+ public void buildCommandBuffers (PrimaryCommandBuffer cmd) {
+
+
+ renderPass.Begin (cmd, frameBuffer);
+
+ cmd.SetViewport (frameBuffer.Width, frameBuffer.Height);
+ cmd.SetScissor (frameBuffer.Width, frameBuffer.Height);
+
+ cmd.BindDescriptorSet (gBuffPipeline.Layout, dsMain);
+
+ envCube.RecordDraw (cmd);
+
+ renderPass.BeginSubPass (cmd);
+
+ if (model != null) {
+ gBuffPipeline.Bind (cmd);
+ model.Bind (cmd);
+ model.DrawAll (cmd, gBuffPipeline.Layout);
+ }
+
+ renderPass.BeginSubPass (cmd);
+
+ //cmd.BindDescriptorSet (composePipeline.Layout, dsMain);
+ cmd.BindDescriptorSet (composePipeline.Layout, dsGBuff, 1);
+
+ if (currentDebugView == DebugView.none)
+ composePipeline.Bind (cmd);
+ else {
+ debugPipeline.Bind (cmd);
+ uint debugValue = (uint)currentDebugView - 1;
+ if (currentDebugView == DebugView.shadowMap)
+ debugValue += (uint)((lightNumDebug << 8));
+ else
+ debugValue += (uint)((debugFace << 8) + (debugMip << 16));
+ cmd.PushConstant (debugPipeline.Layout, VkShaderStageFlags.Fragment, debugValue, (uint)Marshal.SizeOf<Matrix4x4> ());
+ }
+
+ cmd.Draw (3, 1, 0, 0);
+
+ //renderPass.BeginSubPass (cmd);
+ //toneMappingPipeline.Bind (cmd);
+ //cmd.Draw (3, 1, 0, 0);
+
+ renderPass.End (cmd);
+ }
+
+ public void MoveLight (Vector4 dir) {
+ lights[lightNumDebug].position += dir * lightMoveSpeed;
+#if WITH_SHADOWS
+ shadowMapRenderer.updateShadowMap = true;
+#endif
+ }
+
+ #region update
+ public void UpdateView (Camera camera) {
+ camera.AspectRatio = (float)width / height;
+
+ matrices.projection = camera.Projection;
+ //matrices.projection = Utils.CreatePerspectiveFieldOfView (Utils.DegreesToRadians (60), 1, 0.1f, 16f);
+ matrices.view = camera.View;
+ //matrices.view = Matrix4x4.CreateLookAt (lights[0].position.ToVector3 (), Vector3.Zero, Vector3.UnitY);
+ 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<Matrices> ());
+ }
+
+ #endregion
+
+
+ void createGBuff () {
+ gbColorRough?.Dispose ();
+ gbEmitMetal?.Dispose ();
+ gbN_AO?.Dispose ();
+ gbPos?.Dispose ();
+ hdrImgResolved?.Dispose ();
+
+
+ hdrImgResolved = new Image (dev, HDR_FORMAT, VkImageUsageFlags.Sampled | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransferSrc, VkMemoryPropertyFlags.DeviceLocal, width, height, VkImageType.Image2D, NUM_SAMPLES);
+ gbColorRough = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal, width, height, VkImageType.Image2D, NUM_SAMPLES);
+ gbEmitMetal = new Image (dev, VkFormat.R8g8b8a8Unorm, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal, width, height, VkImageType.Image2D, NUM_SAMPLES);
+ gbN_AO = new Image (dev, MRT_FORMAT, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, VkMemoryPropertyFlags.DeviceLocal, width, height, VkImageType.Image2D, NUM_SAMPLES);
+ gbPos = new Image (dev, MRT_FORMAT, VkImageUsageFlags.InputAttachment | VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransientAttachment, 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;
+ hdrImgResolved.CreateView (); hdrImgResolved.CreateSampler ();
+ hdrImgResolved.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
+
+ DescriptorSetWrites uboUpdate = new DescriptorSetWrites (descLayoutGBuff);
+ uboUpdate.Write (dev, dsGBuff, gbColorRough.Descriptor,
+ gbEmitMetal.Descriptor,
+ gbN_AO.Descriptor,
+ gbPos.Descriptor);
+
+ gbColorRough.SetName ("GBuffColorRough");
+ gbEmitMetal.SetName ("GBuffEmitMetal");
+ gbN_AO.SetName ("GBuffN");
+ gbPos.SetName ("GBuffPos");
+ hdrImgResolved.SetName ("HDRimg resolved");
+ }
+
+ public void Resize (uint width, uint height) {
+ this.width = width;
+ this.height = height;
+
+ frameBuffer?.Dispose ();
+ createGBuff ();
+
+ frameBuffer = new FrameBuffer (renderPass, width, height, new Image[] {
+ hdrImgResolved, null, gbColorRough, gbEmitMetal, gbN_AO, gbPos});
+ }
+
+ public void Dispose () {
+ dev.WaitIdle ();
+
+ frameBuffer?.Dispose ();
+
+ gbColorRough.Dispose ();
+ gbEmitMetal.Dispose ();
+ gbN_AO.Dispose ();
+ gbPos.Dispose ();
+ hdrImgResolved.Dispose ();
+
+ gBuffPipeline.Dispose ();
+ composePipeline.Dispose ();
+ //toneMappingPipeline.Dispose ();
+ debugPipeline?.Dispose ();
+
+ descLayoutMain.Dispose ();
+ descLayoutTextures?.Dispose ();
+ descLayoutGBuff.Dispose ();
+
+ uboMatrices.Dispose ();
+ uboLights.Dispose ();
+ model.Dispose ();
+ envCube.Dispose ();
+
+#if WITH_SHADOWS
+ shadowMapRenderer.Dispose ();
+#endif
+
+ descriptorPool.Dispose ();
+
+ dev.DestroySemaphore (DrawComplete);
+ }
+ }
+}
--- /dev/null
+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<float> (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<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, 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<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, 64u, (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 ();
+
+ 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);
+ }
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
+ <!-- <EnableDefaultNoneItems>false</EnableDefaultNoneItems> -->
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DefineConstants>TRACE;NETSTANDARD;NETSTANDARD2_0;MEMORY_POOLS;WITH_SHADOWS;_WITH_VKVG;DEBUG;NETFRAMEWORK;NET472</DefineConstants>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugCrow|AnyCPU' ">
+ <DefineConstants>TRACE;DEBUG;NETSTANDARD;NETSTANDARD2_0;MEMORY_POOLS;WITH_SHADOWS;_WITH_VKVG</DefineConstants>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="DeferredPbrRenderer.cs;shadowMapRenderer.cs" />
+ </ItemGroup>
+ <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugCrow|AnyCPU' ">
+ <Compile Include="main-crow.cs" />
+ </ItemGroup>
+ <ItemGroup Condition="$(Configuration) != 'DebugCrow' ">
+ <Compile Include="main.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\addons\gltfLoader\gltfLoader.csproj" />
+ <ProjectReference Include="..\..\addons\EnvironmentPipeline\EnvironmentPipeline.csproj" />
+ </ItemGroup>
+</Project>
--- /dev/null
+using System;
+using System.Numerics;
+using Glfw;
+using Vulkan;
+using vke;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace glow {
+ 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<DeferredPbrRenderer.Light> Lights => renderer.lights.ToList ();
+ public List<Model.Scene> 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;
+
+ protected override void initVulkan () {
+ base.initVulkan ();
+
+#if DEBUG
+ dbgRepport = new DebugReport (instance,
+ VkDebugReportFlagsEXT.ErrorEXT
+ | VkDebugReportFlagsEXT.DebugEXT
+ | VkDebugReportFlagsEXT.WarningEXT
+ | VkDebugReportFlagsEXT.PerformanceWarningEXT
+ );
+#endif
+
+ 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 (PrimaryCommandBuffer 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);
+ }
+ }
+}
--- /dev/null
+// Copyright (c) 2020 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// 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 Glfw;
+using Vulkan;
+
+namespace glow {
+ /// <summary>
+ /// Deferred PBR rendering.
+ /// </summary>
+ class Glow : VkWindow {
+ static void Main (string[] args) {
+#if DEBUG
+ Instance.VALIDATION = true;
+ //Instance.RENDER_DOC_CAPTURE = true;
+#endif
+ SwapChain.PREFERED_FORMAT = VkFormat.B8g8r8a8Srgb;
+ DeferredPbrRenderer.TEXTURE_ARRAY = true;
+ DeferredPbrRenderer.NUM_SAMPLES = VkSampleCountFlags.SampleCount1;
+ DeferredPbrRenderer.HDR_FORMAT = VkFormat.R32g32b32a32Sfloat;
+ DeferredPbrRenderer.MRT_FORMAT = VkFormat.R32g32b32a32Sfloat;
+
+ PbrModelTexArray.TEXTURE_DIM = 1024;
+
+ using (Glow vke = new Glow ()) {
+ 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",
+ "/mnt/devel/pinball.net/data/test.glb",
+ 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 = 1;
+ bool reloadModel;
+ bool rebuildBuffers;
+
+ Queue transferQ, computeQ;
+ DeferredPbrRenderer renderer;
+
+
+ GraphicPipeline plToneMap;
+ FrameBuffers frameBuffers;
+ DescriptorPool descriptorPool;
+ DescriptorSet descriptorSet;
+
+ vke.DebugUtils.Messenger dbgmsg;
+
+ protected override void initVulkan () {
+ base.initVulkan ();
+
+#if DEBUG
+ dbgmsg = new vke.DebugUtils.Messenger (instance, VkDebugUtilsMessageTypeFlagsEXT.PerformanceEXT | VkDebugUtilsMessageTypeFlagsEXT.ValidationEXT | VkDebugUtilsMessageTypeFlagsEXT.GeneralEXT,
+ VkDebugUtilsMessageSeverityFlagsEXT.InfoEXT |
+ VkDebugUtilsMessageSeverityFlagsEXT.WarningEXT |
+ VkDebugUtilsMessageSeverityFlagsEXT.ErrorEXT |
+ VkDebugUtilsMessageSeverityFlagsEXT.VerboseEXT);
+#endif
+
+ camera = new Camera (Utils.DegreesToRadians (45f), 1f, 0.1f, 16f);
+ camera.SetPosition (0, 0, -2);
+
+ //renderer = new DeferredPbrRenderer (presentQueue, cubemapPathes[2], swapChain.Width, swapChain.Height, camera.NearPlane, camera.FarPlane);
+ renderer = new DeferredPbrRenderer (presentQueue, cubemapPathes[2], swapChain.Width, swapChain.Height, 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));
+
+ init_final_pl ();
+ }
+
+ void init_final_pl() {
+ descriptorPool = new DescriptorPool (dev, 3,
+ new VkDescriptorPoolSize (VkDescriptorType.CombinedImageSampler, 2),
+ new VkDescriptorPoolSize (VkDescriptorType.StorageImage, 4)
+ );
+
+ GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList, DeferredPbrRenderer.NUM_SAMPLES);
+ if (DeferredPbrRenderer.NUM_SAMPLES != VkSampleCountFlags.SampleCount1) {
+ cfg.multisampleState.sampleShadingEnable = true;
+ cfg.multisampleState.minSampleShading = 0.5f;
+ }
+ cfg.Layout = new PipelineLayout (dev,
+ new VkPushConstantRange (VkShaderStageFlags.Fragment, 2 * sizeof (float)),
+ new DescriptorSetLayout (dev, 0,
+ new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler)
+ ));
+
+ cfg.RenderPass = new RenderPass (dev, swapChain.ColorFormat, DeferredPbrRenderer.NUM_SAMPLES);
+
+ using (ShaderInfo vs = new ShaderInfo (dev, VkShaderStageFlags.Vertex, "#vke.FullScreenQuad.vert.spv"))
+ using (ShaderInfo fs = new ShaderInfo (dev, VkShaderStageFlags.Fragment, "#shaders.tone_mapping.frag.spv"))
+ {
+ cfg.AddShaders (vs, fs);
+
+ plToneMap = new GraphicPipeline (cfg);
+ }
+
+ descriptorSet = descriptorPool.Allocate (cfg.Layout.DescriptorSetLayouts[0]);
+ }
+
+ void buildCommandBuffers () {
+ for (int i = 0; i < swapChain.ImageCount; ++i) {
+ cmds[i]?.Free ();
+ cmds[i] = cmdPool.AllocateAndStart ();
+
+ renderer.buildCommandBuffers (cmds[i]);
+
+ plToneMap.RenderPass.Begin (cmds[i], frameBuffers[i]);
+
+ cmds[i].SetViewport (frameBuffers[i].Width, frameBuffers[i].Height);
+ cmds[i].SetScissor (frameBuffers[i].Width, frameBuffers[i].Height);
+
+ plToneMap.Bind (cmds[i]);
+ plToneMap.BindDescriptorSet (cmds[i], descriptorSet);
+
+ cmds[i].PushConstant (plToneMap.Layout, VkShaderStageFlags.Fragment, 8, new float[] { renderer.exposure, renderer.gamma }, 0);
+
+ cmds[i].Draw (3, 1, 0, 0);
+
+ plToneMap.RenderPass.End (cmds[i]);
+
+ cmds[i].End ();
+ }
+ }
+
+ public override void UpdateView () {
+ dev.WaitIdle ();
+
+ renderer.UpdateView (camera);
+ updateViewRequested = false;
+#if WITH_SHADOWS
+ if (renderer.shadowMapRenderer.updateShadowMap)
+ renderer.shadowMapRenderer.update_shadow_map (cmdPool);
+#endif
+ }
+
+ public override void Update () {
+ if (reloadModel) {
+ renderer.LoadModel (transferQ, modelPathes[curModelIndex]);
+ 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
+ }
+
+ if (rebuildBuffers) {
+ buildCommandBuffers ();
+ rebuildBuffers = false;
+ }
+
+ }
+
+ protected override void OnResize () {
+ base.OnResize ();
+
+ dev.WaitIdle ();
+
+ renderer.Resize (Width, Height);
+
+ UpdateView ();
+
+ frameBuffers?.Dispose();
+ frameBuffers = plToneMap.RenderPass.CreateFrameBuffers(swapChain);
+
+ DescriptorSetWrites dsUpdate = new DescriptorSetWrites (plToneMap.Layout.DescriptorSetLayouts[0].Bindings[0]);
+ dsUpdate.Write (dev, descriptorSet, renderer.hdrImgResolved.Descriptor);
+
+ buildCommandBuffers ();
+
+ 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)-diffY, (float)-diffX, 0);
+ } 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.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) {
+ frameBuffers?.Dispose();
+ renderer?.Dispose ();
+ plToneMap?.Dispose ();
+ descriptorPool?.Dispose ();
+ dbgmsg?.Dispose ();
+ }
+ }
+ base.Dispose (disposing);
+ }
+ }
+}
--- /dev/null
+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<Matrix4x4> ()),
+ new VkPushConstantRange (VkShaderStageFlags.Fragment, (uint)Marshal.SizeOf<Model.PbrMaterial> (), 64)
+ );
+ cfg.RenderPass = renderPass;
+ cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+ cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+ cfg.blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false));
+
+ 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/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<Matrices> () * 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<Matrices> ();
+ 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> ());
+ 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 () {
+#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);
+ }
+ }
+}
--- /dev/null
+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<Matrix4x4> ()),
+ 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<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/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<Matrices> () * 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<Matrices> ();
+ 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> ());
+ 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 () {
+#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);
+ }
+ }
+}
--- /dev/null
+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<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 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<Matrices>());
+ 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<Matrices> ());
+ }
+
+ 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);
+ }
+ }
+}
--- /dev/null
+#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;
+ float metallicFactor;
+ float roughnessFactor;
+ float alphaMask;
+ float alphaMaskCutoff;
+ int pad0;
+};
+
+#include "GBuffPbrCommon.inc"
+#include "tonemap.inc"
+
+// Material bindings
+layout (set = 2, binding = 0) uniform sampler2D colorMap;
+layout (set = 2, binding = 1) uniform sampler2D physicalDescriptorMap;
+layout (set = 2, binding = 2) uniform sampler2D normalMap;
+layout (set = 2, binding = 3) uniform sampler2D aoMap;
+layout (set = 2, binding = 4) uniform sampler2D emissiveMap;
+
+// 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(normalMap, inUV0).xyz * 2.0 - 1.0;
+ else if ((materials[materialIdx].tex1 & MAP_NORMAL) == MAP_NORMAL)
+ tangentNormal = texture(normalMap, inUV1).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(physicalDescriptorMap, inUV0).g;
+ metallic *= texture(physicalDescriptorMap, inUV0).b;
+ }else if ((materials[materialIdx].tex1 & MAP_METALROUGHNESS) == MAP_METALROUGHNESS){
+ perceptualRoughness *= texture(physicalDescriptorMap, inUV1).g;
+ metallic *= texture(physicalDescriptorMap, inUV1).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(colorMap, inUV0));
+ else if ((materials[materialIdx].tex1 & MAP_COLOR) == MAP_COLOR)
+ baseColor *= SRGBtoLINEAR(texture(colorMap, inUV1));
+ }
+
+ 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(physicalDescriptorMap, inUV0).a;
+ else if ((materials[materialIdx].tex1 & MAP_METALROUGHNESS) == MAP_METALROUGHNESS)
+ perceptualRoughness = 1.0 - texture(physicalDescriptorMap, 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)) * 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(emissiveMap, inUV0)).rgb * u_EmissiveFactor;
+ else if ((materials[materialIdx].tex1 & MAP_EMISSIVE) == MAP_EMISSIVE)
+ emissive = SRGBtoLINEAR(texture(emissiveMap, inUV1)).rgb * u_EmissiveFactor;
+
+ if ((materials[materialIdx].tex0 & MAP_AO) == MAP_AO)
+ ao = texture(aoMap, inUV0).r;
+ else if ((materials[materialIdx].tex1 & MAP_AO) == MAP_AO)
+ ao = texture(aoMap, inUV1).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
--- /dev/null
+#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);
+}
--- /dev/null
+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 = 0, binding = 5) 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
--- /dev/null
+#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 = 0, binding = 7) 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
--- /dev/null
+#version 450
+
+layout (local_size_x = 16, local_size_y = 16) in;
+layout (binding = 0, rgba16f) uniform readonly image2D inputImage;
+layout (binding = 1, rgba16f) uniform image2D resultImage;
+
+layout(push_constant) uniform PushConsts {
+ vec2 texSize;
+ int dir;
+ float scale;
+ float strength;
+} pc;
+
+void main(void)
+{
+ // From the OpenGL Super bible
+ const float weights[] = float[](0.0024499299678342,
+ 0.0043538453346397,
+ 0.0073599963704157,
+ 0.0118349786570722,
+ 0.0181026699707781,
+ 0.0263392293891488,
+ 0.0364543006660986,
+ 0.0479932050577658,
+ 0.0601029809166942,
+ 0.0715974486241365,
+ 0.0811305381519717,
+ 0.0874493212267511,
+ 0.0896631113333857,
+ 0.0874493212267511,
+ 0.0811305381519717,
+ 0.0715974486241365,
+ 0.0601029809166942,
+ 0.0479932050577658,
+ 0.0364543006660986,
+ 0.0263392293891488,
+ 0.0181026699707781,
+ 0.0118349786570722,
+ 0.0073599963704157,
+ 0.0043538453346397,
+ 0.0024499299678342);
+
+
+ float ar = 1.0;
+ vec4 color = vec4(0.0);
+
+ // Aspect ratio for vertical blur pass
+ if (pc.dir == 1)
+ ar = pc.texSize.y / pc.texSize.x;
+
+ vec2 P = gl_GlobalInvocationID.yx - vec2(0, (weights.length() >> 1) * ar * pc.scale);
+
+ for (int i = 0; i < weights.length(); i++)
+ {
+ vec2 dv = vec2(0.0, i * pc.scale) * ar;
+ color += imageLoad (inputImage, ivec2(P + dv)) * weights[i] * pc.strength;
+ }
+
+ imageStore(resultImage, ivec2(gl_GlobalInvocationID.xy), color);
+}
\ No newline at end of file
--- /dev/null
+#version 450
+
+layout (binding = 0) uniform sampler2D samplerColor0;
+layout (binding = 1) uniform sampler2D samplerColor1;
+
+layout (location = 0) in vec2 inUV;
+
+layout (location = 0) out vec4 outColor;
+
+layout (constant_id = 0) const int dir = 0;
+
+void main(void)
+{
+ // From the OpenGL Super bible
+ const float weights[] = float[](0.0024499299678342,
+ 0.0043538453346397,
+ 0.0073599963704157,
+ 0.0118349786570722,
+ 0.0181026699707781,
+ 0.0263392293891488,
+ 0.0364543006660986,
+ 0.0479932050577658,
+ 0.0601029809166942,
+ 0.0715974486241365,
+ 0.0811305381519717,
+ 0.0874493212267511,
+ 0.0896631113333857,
+ 0.0874493212267511,
+ 0.0811305381519717,
+ 0.0715974486241365,
+ 0.0601029809166942,
+ 0.0479932050577658,
+ 0.0364543006660986,
+ 0.0263392293891488,
+ 0.0181026699707781,
+ 0.0118349786570722,
+ 0.0073599963704157,
+ 0.0043538453346397,
+ 0.0024499299678342);
+
+
+ const float blurScale = 0.003;
+ const float blurStrength = 1.0;
+
+ float ar = 1.0;
+ // Aspect ratio for vertical blur pass
+ if (dir == 1)
+ {
+ vec2 ts = textureSize(samplerColor1, 0);
+ ar = ts.y / ts.x;
+ }
+
+ vec2 P = inUV.yx - vec2(0, (weights.length() >> 1) * ar * blurScale);
+
+ vec4 color = vec4(0.0);
+ for (int i = 0; i < weights.length(); i++)
+ {
+ vec2 dv = vec2(0.0, i * blurScale) * ar;
+ color += texture(samplerColor1, P + dv) * weights[i] * blurStrength;
+ }
+
+ outColor = color;
+}
\ No newline at end of file
--- /dev/null
+#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 = 0, binding = 4) uniform UBOLights {
+ Light lights[NUM_LIGHTS];
+};
+
+const float M_PI = 3.141592653589793;
+const float c_MinRoughness = 0.04;
+
+layout (input_attachment_index = 0, set = 1, binding = 0) uniform subpassInputMS samplerColorRough;
+layout (input_attachment_index = 1, set = 1, binding = 1) uniform subpassInputMS samplerEmitMetal;
+layout (input_attachment_index = 2, set = 1, binding = 2) uniform subpassInputMS samplerN_AO;
+layout (input_attachment_index = 3, set = 1, binding = 3) uniform subpassInputMS samplerPos;
+
+layout (set = 0, binding = 1) uniform samplerCube samplerIrradiance;
+layout (set = 0, binding = 2) uniform samplerCube prefilteredMap;
+layout (set = 0, binding = 3) uniform sampler2D samplerBRDFLUT;
+
+layout (location = 0) in vec2 inUV;
+
+layout (location = 0) out vec4 outColor;
+
+#include "pbr.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 (subpassLoad(samplerPos, gl_SampleID).a == 1.0f)
+ discard;
+
+ float perceptualRoughness = subpassLoad(samplerColorRough, gl_SampleID).a;
+ float metallic = subpassLoad(samplerEmitMetal, gl_SampleID).a;
+ vec3 diffuseColor;
+ vec4 baseColor = vec4(subpassLoad(samplerColorRough, gl_SampleID).rgb, 1);
+ vec3 emissive = subpassLoad (samplerEmitMetal, gl_SampleID).rgb;
+
+ vec3 f0 = vec3(0.04);
+
+ diffuseColor = baseColor.rgb * (vec3(1.0) - f0);
+ diffuseColor *= 1.0 - metallic;
+
+ float alphaRoughness = perceptualRoughness * perceptualRoughness;
+
+ vec3 specularColor = mix(f0, baseColor.rgb, metallic);
+
+ // Compute reflectance.
+ float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);
+
+ // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
+ // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
+ float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
+ vec3 specularEnvironmentR0 = specularColor.rgb;
+ vec3 specularEnvironmentR90 = vec3(1.0) * reflectance90;
+
+ vec3 n = subpassLoad(samplerN_AO, gl_SampleID).rgb;
+ vec3 pos = subpassLoad(samplerPos, gl_SampleID).rgb;
+ vec3 v = normalize(ubo.camPos.xyz - pos); // Vector from surface point to camera
+
+ vec3 colors = vec3(0);
+ vec3 lightTarget = vec3(0);
+
+ for (int i=0; i<NUM_LIGHTS; i++) {
+
+ vec3 l = normalize(lights[i].position.xyz-pos); // Vector from surface point to light
+ vec3 h = normalize(l+v); // Half vector between both l and v
+ vec3 reflection = -normalize(reflect(v, n));
+ reflection.y *= -1.0f;
+
+ float NdotL = clamp(dot(n, l), 0.001, 1.0);
+ float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
+ float NdotH = clamp(dot(n, h), 0.0, 1.0);
+ float LdotH = clamp(dot(l, h), 0.0, 1.0);
+ float VdotH = clamp(dot(v, h), 0.0, 1.0);
+
+ PBRInfo pbrInputs = PBRInfo(
+ NdotL,
+ NdotV,
+ NdotH,
+ LdotH,
+ VdotH,
+ perceptualRoughness,
+ metallic,
+ specularEnvironmentR0,
+ specularEnvironmentR90,
+ alphaRoughness,
+ diffuseColor,
+ specularColor
+ );
+
+ // Calculate the shading terms for the microfacet specular shading model
+ vec3 F = specularReflection(pbrInputs);
+ float G = geometricOcclusion(pbrInputs);
+ float D = microfacetDistribution(pbrInputs);
+
+ // Calculation of analytical lighting contribution
+ vec3 diffuseContrib = (1.0 - F) * diffuse(pbrInputs);
+ vec3 specContrib = F * G * D / (4.0 * NdotL * NdotV);
+ // Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law)
+ vec3 color = NdotL * lights[i].color.rgb * (diffuseContrib + specContrib);
+ // Calculate lighting contribution from image based lighting source (IBL)
+ colors += (color + getIBLContribution(pbrInputs, n, reflection));
+
+
+ }
+ colors /= NUM_LIGHTS;
+
+
+ const float u_OcclusionStrength = 1.0f;
+ const float u_EmissiveFactor = 1.0f;
+
+ //AO is in the alpha channel of the normalAttachment
+ colors = mix(colors, colors * subpassLoad(samplerN_AO, gl_SampleID).a, u_OcclusionStrength);
+ colors += emissive;
+
+ outColor = vec4(colors, baseColor.a);
+}
\ No newline at end of file
--- /dev/null
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout (set = 0, binding = 0) uniform UBO {
+ mat4 projection;
+ mat4 model;
+ mat4 view;
+ vec4 camPos;
+ float prefilteredCubeMipLevels;
+ float scaleIBLAmbient;
+} ubo;
+
+layout (constant_id = 0) const uint NUM_LIGHTS = 1;
+
+struct Light {
+ vec4 position;
+ vec4 color;
+ mat4 mvp;
+};
+
+layout (set = 0, binding = 4) uniform UBOLights {
+ Light lights[NUM_LIGHTS];
+};
+
+const float M_PI = 3.141592653589793;
+const float c_MinRoughness = 0.04;
+#define SHADOW_FACTOR 0.15
+
+layout (input_attachment_index = 0, set = 1, binding = 0) uniform subpassInputMS samplerColorRough;
+layout (input_attachment_index = 1, set = 1, binding = 1) uniform subpassInputMS samplerEmitMetal;
+layout (input_attachment_index = 2, set = 1, binding = 2) uniform subpassInputMS samplerN_AO;
+layout (input_attachment_index = 3, set = 1, binding = 3) uniform subpassInputMS samplerPos;
+
+layout (set = 0, binding = 1) uniform samplerCube samplerIrradiance;
+layout (set = 0, binding = 2) uniform samplerCube prefilteredMap;
+layout (set = 0, binding = 3) uniform sampler2D samplerBRDFLUT;
+layout (set = 0, binding = 6) uniform sampler2DArray samplerShadowMap;
+
+layout (location = 0) in vec2 inUV;
+
+layout (location = 0) out vec4 outColor;
+
+#include "pbr.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;
+}
+
+float textureProj(vec4 P, float layer, vec2 offset)
+{
+ float shadow = 1.0;
+ vec4 shadowCoord = P / P.w;
+ shadowCoord.st = shadowCoord.st * 0.5 + 0.5;
+
+ if (shadowCoord.z > -1.0 && shadowCoord.z < 1.0)
+ {
+ float dist = texture(samplerShadowMap, vec3(shadowCoord.st + offset, layer)).r;
+ if (shadowCoord.w > 0.0 && dist < shadowCoord.z)
+ shadow = SHADOW_FACTOR;
+ }else
+ shadow = 0.05f;//for debug view out of light proj
+
+ return shadow;
+}
+
+float filterPCF(vec4 sc, float layer)
+{
+ ivec2 texDim = textureSize(samplerShadowMap, 0).xy;
+ float scale = 1.5;
+ float dx = scale * 1.0 / float(texDim.x);
+ float dy = scale * 1.0 / float(texDim.y);
+
+ float shadowFactor = 0.0;
+ int count = 0;
+ int range = 1;
+
+ for (int x = -range; x <= range; x++)
+ {
+ for (int y = -range; y <= range; y++)
+ {
+ shadowFactor += textureProj(sc, layer, vec2(dx*x, dy*y));
+ count++;
+ }
+
+ }
+ return shadowFactor / count;
+}
+
+void main()
+{
+ if (subpassLoad(samplerPos, gl_SampleID).a == 1.0f)
+ discard;
+
+ float perceptualRoughness = subpassLoad(samplerColorRough, gl_SampleID).a;
+ float metallic = subpassLoad(samplerEmitMetal, gl_SampleID).a;
+ vec3 diffuseColor;
+ vec4 baseColor = vec4(subpassLoad(samplerColorRough, gl_SampleID).rgb, 1);
+ vec3 emissive = subpassLoad (samplerEmitMetal, gl_SampleID).rgb;
+
+ vec3 f0 = vec3(0.04);
+
+ diffuseColor = baseColor.rgb * (vec3(1.0) - f0);
+ diffuseColor *= 1.0 - metallic;
+
+ float alphaRoughness = perceptualRoughness * perceptualRoughness;
+
+ vec3 specularColor = mix(f0, baseColor.rgb, metallic);
+
+ // Compute reflectance.
+ float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);
+
+ // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
+ // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
+ float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
+ vec3 specularEnvironmentR0 = specularColor.rgb;
+ vec3 specularEnvironmentR90 = vec3(1.0) * reflectance90;
+
+ vec3 n = subpassLoad(samplerN_AO, gl_SampleID).rgb;
+ vec3 pos = subpassLoad(samplerPos, gl_SampleID).rgb;
+ vec3 v = normalize(ubo.camPos.xyz - pos); // Vector from surface point to camera
+
+ vec3 colors = vec3(0);
+ vec3 lightTarget = vec3(0);
+
+ for (int i=0; i<NUM_LIGHTS; i++) {
+
+ vec3 l = normalize(lights[i].position.xyz-pos); // Vector from surface point to light
+ vec3 h = normalize(l+v); // Half vector between both l and v
+ vec3 reflection = -normalize(reflect(v, n));
+ reflection.y *= -1.0f;
+
+ float NdotL = clamp(dot(n, l), 0.001, 1.0);
+ float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
+ float NdotH = clamp(dot(n, h), 0.0, 1.0);
+ float LdotH = clamp(dot(l, h), 0.0, 1.0);
+ float VdotH = clamp(dot(v, h), 0.0, 1.0);
+
+ PBRInfo pbrInputs = PBRInfo(
+ NdotL,
+ NdotV,
+ NdotH,
+ LdotH,
+ VdotH,
+ perceptualRoughness,
+ metallic,
+ specularEnvironmentR0,
+ specularEnvironmentR90,
+ alphaRoughness,
+ diffuseColor,
+ specularColor
+ );
+
+ // Calculate the shading terms for the microfacet specular shading model
+ vec3 F = specularReflection(pbrInputs);
+ float G = geometricOcclusion(pbrInputs);
+ float D = microfacetDistribution(pbrInputs);
+
+ // Calculation of analytical lighting contribution
+ vec3 diffuseContrib = (1.0 - F) * diffuse(pbrInputs);
+ vec3 specContrib = F * G * D / (4.0 * NdotL * NdotV);
+ // Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law)
+ vec3 color = NdotL * lights[i].color.rgb * (diffuseContrib + specContrib);
+
+ #ifdef WITH_SHADOWS
+ vec4 shadowClip = lights[i].mvp * vec4(pos, 1);
+ float shadowFactor = filterPCF(shadowClip, i);
+ // Calculate lighting contribution from image based lighting source (IBL)
+ colors += shadowFactor * (color + getIBLContribution(pbrInputs, n, reflection));
+ #else
+ colors += color + getIBLContribution(pbrInputs, n, reflection);
+ #endif
+
+
+ }
+ colors /= NUM_LIGHTS;
+
+
+ const float u_OcclusionStrength = 1.0f;
+ const float u_EmissiveFactor = 3.0f;
+
+ //AO is in the alpha channel of the normalAttachment
+ colors = mix(colors, colors * subpassLoad(samplerN_AO, gl_SampleID).a, u_OcclusionStrength);
+ colors += emissive * u_EmissiveFactor;
+
+ outColor = vec4(colors, baseColor.a);
+}
\ No newline at end of file
--- /dev/null
+#version 450
+
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout (location = 0) in vec3 inColor;
+layout (location = 0) out vec4 outFragColor;
+
+void main()
+{
+ outFragColor = vec4(inColor, 1.0);
+}
\ No newline at end of file
--- /dev/null
+#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 inColor;
+
+layout (location = 0) out vec3 outColor;
+
+layout (binding = 0) uniform UBO
+{
+ mat4 projectionMatrix;
+ mat4 viewMatrix;
+ mat4 modelMatrix;
+ float gamma;
+ float exposure;
+} ubo;
+
+layout(push_constant) uniform PushConsts {
+ mat4 projectionMatrix;
+} pc;
+
+out gl_PerVertex
+{
+ vec4 gl_Position;
+};
+
+void main()
+{
+ outColor = inColor;
+
+ gl_Position = pc.projectionMatrix * vec4 ((ubo.viewMatrix * vec4(inPos.xyz, 0.0)).xyz, 1);
+}
--- /dev/null
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout (input_attachment_index = 0, set = 2, binding = 0) uniform subpassInputMS samplerColorRough;
+layout (input_attachment_index = 1, set = 2, binding = 1) uniform subpassInputMS samplerEmitMetal;
+layout (input_attachment_index = 2, set = 2, binding = 2) uniform subpassInputMS samplerN_AO;
+layout (input_attachment_index = 3, set = 2, binding = 3) uniform subpassInputMS samplerPos;
+
+layout (location = 0) in vec2 inUV;
+
+layout (location = 0) out vec4 outColor;
+
+const float offset[5] = float[](0.0, 1.0, 2.0, 3.0, 4.0);
+const float weight[5] = float[](0.2270270270, 0.1945945946, 0.1216216216,
+ 0.0540540541, 0.0162162162);
+
+void main()
+{
+ if (subpassLoad(samplerPos, gl_SampleID).a == 1.0f)
+ discard;
+ vec3 emissive = subpassLoad (samplerEmitMetal, gl_SampleID).rgb;
+
+ outColor = vec4(emissive, 1);
+}
\ No newline at end of file
--- /dev/null
+#version 420
+
+#define NUM_LIGHTS 2
+
+layout (triangles, invocations = NUM_LIGHTS) in;
+layout (triangle_strip, max_vertices = 3) out;
+
+struct Light {
+ vec4 position;
+ vec4 color;
+ mat4 mvp;
+};
+layout (set = 0, binding = 0) uniform UBO {
+ mat4 projection;
+ mat4 model;
+ mat4 view;
+};
+layout (set = 0, binding = 1) uniform UBOLights {
+ Light lights[NUM_LIGHTS];
+};
+
+//layout (location = 0) in int inInstanceIndex[];
+
+in gl_PerVertex
+{
+ vec4 gl_Position;
+} gl_in[];
+
+void main()
+{
+ for (int i = 0; i < gl_in.length(); i++)
+ {
+ gl_Layer = gl_InvocationID;
+ gl_Position = lights[gl_InvocationID].mvp * model * gl_in[i].gl_Position;
+ EmitVertex();
+ }
+ EndPrimitive();
+}
\ No newline at end of file
--- /dev/null
+#version 450
+
+layout (location = 0) in vec3 inPos;
+
+layout(push_constant) uniform PushConsts {
+ mat4 model;
+} pc;
+
+out gl_PerVertex
+{
+ vec4 gl_Position;
+};
+
+void main()
+{
+ gl_Position = pc.model * vec4(inPos,1);
+}
\ No newline at end of file
--- /dev/null
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout (input_attachment_index = 0, set = 1, binding = 0) uniform subpassInputMS samplerColorRough;
+layout (input_attachment_index = 1, set = 1, binding = 1) uniform subpassInputMS samplerEmitMetal;
+layout (input_attachment_index = 2, set = 1, binding = 2) uniform subpassInputMS samplerN_AO;
+layout (input_attachment_index = 3, set = 1, binding = 3) uniform subpassInputMS samplerPos;
+
+layout (set = 0, binding = 1) uniform samplerCube samplerIrradiance;
+layout (set = 0, binding = 2) uniform samplerCube prefilteredMap;
+layout (set = 0, binding = 3) uniform sampler2D samplerBRDFLUT;
+layout (set = 0, binding = 6) uniform sampler2DArray samplerShadowMap;
+
+layout (push_constant) uniform PushCsts {
+ layout(offset = 64)
+ int imgIdx;
+};
+
+layout (location = 0) in vec2 inUV;
+layout (location = 0) out vec4 outColor;
+
+const uint color = 0;
+const uint normal = 1;
+const uint pos = 2;
+const uint occlusion = 3;
+const uint emissive = 4;
+const uint metallic = 5;
+const uint roughness = 6;
+const uint depth = 7;
+const uint prefill = 8;
+const uint irradiance = 9;
+const uint shadowMap = 10;
+
+vec4 sampleCubeMap (samplerCube sc, uint face, uint lod) {
+ vec2 uv = 2.0 * inUV - vec2(1.0);
+ switch (face) {
+ case 0:
+ return vec4 (textureLod (sc, vec3(1, uv.t, uv.s), lod).rgb, 1);
+ case 1:
+ return vec4 (textureLod (sc, vec3(-1, uv.t, uv.s), lod).rgb, 1);
+ case 2:
+ return vec4 (textureLod (sc, vec3(uv.s, 1, -uv.t), lod).rgb, 1);
+ case 3:
+ return vec4 (textureLod (sc, vec3(uv.s, -1, uv.t), lod).rgb, 1);
+ case 4:
+ return vec4 (textureLod (sc, vec3(uv, 1), lod).rgb, 1);
+ case 5:
+ return vec4 (textureLod (sc, vec3(-uv.s, uv.t, -1), lod).rgb, 1);
+ }
+}
+
+void main()
+{
+ uint imgNum = bitfieldExtract (imgIdx, 0, 8);
+ switch (imgNum) {
+ case color:
+ outColor = vec4(subpassLoad(samplerColorRough, gl_SampleID).rgb, 1);
+ break;
+ case normal:
+ outColor = vec4(subpassLoad(samplerN_AO, gl_SampleID).rgb, 1);
+ break;
+ case pos:
+ outColor = vec4(subpassLoad(samplerPos, gl_SampleID).rgb, 1);
+ break;
+ case occlusion:
+ outColor = vec4(subpassLoad(samplerN_AO, gl_SampleID).aaa, 1);
+ break;
+ case emissive:
+ outColor = vec4(subpassLoad(samplerEmitMetal, gl_SampleID).rgb, 1);
+ break;
+ case metallic:
+ outColor = vec4(subpassLoad(samplerEmitMetal, gl_SampleID).aaa, 1);
+ break;
+ case roughness:
+ outColor = vec4(subpassLoad(samplerColorRough, gl_SampleID).aaa, 1);
+ break;
+ case depth:
+ outColor = vec4(subpassLoad(samplerPos, gl_SampleID).aaa, 1);
+ break;
+ case shadowMap:
+ vec3 d = texture(samplerShadowMap, vec3(inUV, bitfieldExtract (imgIdx, 8, 8))).rrr;
+ outColor = vec4(d*d*d, 1);
+ break;
+ default:
+ if (imgNum == prefill)
+ outColor = sampleCubeMap (prefilteredMap, bitfieldExtract (imgIdx, 8, 8), bitfieldExtract (imgIdx, 16, 8));
+ else if (imgNum == irradiance)
+ outColor = sampleCubeMap (samplerIrradiance, bitfieldExtract (imgIdx, 8, 8), bitfieldExtract (imgIdx, 16, 8));
+ break;
+ }
+}
\ No newline at end of file
--- /dev/null
+#version 450
+
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout (set = 0, binding = 0) uniform sampler2D samplerColor;
+
+layout (location = 0) in vec2 inUV;
+
+layout (location = 0) out vec4 outFragColor;
+
+void main()
+{
+ outFragColor = texture(samplerColor, inUV);
+}
--- /dev/null
+#include "preamble.inc"
+
+layout(push_constant) uniform PushConsts {
+ float exposure;
+ float gamma;
+};
+
+#include "tonemap.inc"
+
+layout (set = 0, binding = 0) uniform sampler2DMS samplerHDR;
+
+layout (location = 0) in vec2 inUV;
+layout (location = 0) out vec4 outColor;
+
+void main()
+{
+ ivec2 ts = textureSize(samplerHDR);
+ vec4 hdrColor = texelFetch (samplerHDR, ivec2(gl_FragCoord.xy), gl_SampleID);
+ //vec4 hdrColor = texelFetch (samplerHDR, inUV);
+ //vec4 c = texture (bloom, inUV);
+ //float lum = (0.299*c.r + 0.587*c.g + 0.114*c.b);
+ //if (lum>1.0)
+ // hdrColor.rgb += c.rgb * 0.05;
+ //outColor = SRGBtoLINEAR(tonemap(hdrColor, exposure, gamma));
+ outColor = tonemap(hdrColor, exposure, gamma);
+
+
+ /*
+ outColor = vec4(SRGBtoLINEAR(tonemap(hdrColor.rgb)), hdrColor.a);;*/
+
+/* vec3 mapped = vec3(1.0) - exp(-hdrColor.rgb * pc.exposure);
+ mapped = pow(mapped, vec3(1.0 / pc.gamma));
+ outColor = vec4(mapped, hdrColor.a);*/
+}
\ No newline at end of file
--- /dev/null
+/*shadow mapping greatly inspired from:
+* Vulkan Example - Deferred shading with shadows from multiple light sources using geometry shader instancing
+* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
+* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+*/
+using System;
+using System.Numerics;
+using System.Runtime.InteropServices;
+using vke;
+using vke.glTF;
+using Vulkan;
+using static glow.DeferredPbrRenderer;
+
+namespace glow {
+ public class ShadowMapRenderer : IDisposable {
+ Device dev;
+ Queue gQueue;
+
+ public static uint SHADOWMAP_SIZE = 4096;
+ public static VkFormat SHADOWMAP_FORMAT = VkFormat.D32SfloatS8Uint;
+ public static VkSampleCountFlags SHADOWMAP_NUM_SAMPLES = VkSampleCountFlags.SampleCount1;
+ public bool updateShadowMap = true;
+
+ public float depthBiasConstant = 1.5f;
+ public float depthBiasSlope = 1.75f;
+ float lightFOV = Utils.DegreesToRadians (60);
+ float lightFarPlane;
+
+
+
+ RenderPass shadowPass;
+ FrameBuffer fbShadowMap;
+ public Image shadowMap { get; private set; }
+ Pipeline shadowPipeline;
+ DescriptorPool descriptorPool;
+ DescriptorSetLayout descLayoutShadow;
+ DescriptorSet dsShadow;
+ DeferredPbrRenderer renderer;
+
+ public ShadowMapRenderer (Queue gQueue, DeferredPbrRenderer renderer, float farPlane = 16f) {
+ this.lightFarPlane = farPlane;
+ this.gQueue = gQueue;
+ this.dev = gQueue.Dev;
+ this.renderer = renderer;
+
+ descriptorPool = new DescriptorPool (dev, 1,
+ new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer, 2)
+ );
+
+ init ();
+ }
+
+ void init () {
+
+ //Shadow map renderpass
+ shadowPass = new RenderPass (dev, VkSampleCountFlags.SampleCount1);
+ shadowPass.AddAttachment (SHADOWMAP_FORMAT, VkImageLayout.DepthStencilReadOnlyOptimal, SHADOWMAP_NUM_SAMPLES);
+ shadowPass.ClearValues.Add (new VkClearValue { depthStencil = new VkClearDepthStencilValue (1.0f, 0) });
+
+ SubPass subpass0 = new SubPass ();
+ subpass0.SetDepthReference (0);
+ shadowPass.AddSubpass (subpass0);
+
+ shadowPass.AddDependency (Vk.SubpassExternal, 0,
+ VkPipelineStageFlags.FragmentShader, VkPipelineStageFlags.EarlyFragmentTests,
+ VkAccessFlags.ShaderRead, VkAccessFlags.DepthStencilAttachmentWrite);
+ shadowPass.AddDependency (0, Vk.SubpassExternal,
+ VkPipelineStageFlags.LateFragmentTests, VkPipelineStageFlags.FragmentShader,
+ VkAccessFlags.DepthStencilAttachmentWrite, VkAccessFlags.ShaderRead);
+
+ descLayoutShadow = new DescriptorSetLayout (dev,
+ new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Geometry, VkDescriptorType.UniformBuffer),//matrices
+ new VkDescriptorSetLayoutBinding (1, VkShaderStageFlags.Geometry, VkDescriptorType.UniformBuffer));//lights
+
+ GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault (VkPrimitiveTopology.TriangleList);
+ cfg.rasterizationState.cullMode = VkCullModeFlags.Back;
+ cfg.rasterizationState.depthBiasEnable = true;
+ cfg.dynamicStates.Add (VkDynamicState.DepthBias);
+
+ cfg.RenderPass = shadowPass;
+
+ cfg.Layout = new PipelineLayout (dev, descLayoutShadow);
+ cfg.Layout.AddPushConstants (
+ new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf<Matrix4x4> ())
+ );
+
+ cfg.AddVertexBinding<PbrModelTexArray.Vertex> (0);
+ cfg.AddVertexAttributes (0, VkFormat.R32g32b32Sfloat);
+
+ using (ShaderInfo vs = new ShaderInfo (dev, VkShaderStageFlags.Vertex, "#shaders.shadow.vert.spv"))
+ using (ShaderInfo fs = new ShaderInfo (dev, VkShaderStageFlags.Geometry, "#shaders.shadow.geom.spv")) {
+ cfg.AddShaders (vs, fs);
+
+ 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 = Utils.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 ();
+
+ PrimaryCommandBuffer 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 ();
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0"?>
+<Window Caption="Debug" Icon="#deferred.crow.svg" Left="10" Top="100" Width="40%" Height="50%">
+ <VerticalStack Spacing="1" Margin="10" CacheEnabled="true">
+ <HorizontalStack Height="Fit">
+ <Label Text="Fps:" Width="80"/>
+ <Label Text="{fps}" Width="Stretched" TextAlignment="Center"/>
+ </HorizontalStack>
+ <Expandable Caption="Debug Views">
+ <EnumSelector Left="20" EnumValue="{²CurrentDebugView}" Width="50%"/>
+ </Expandable>
+ </VerticalStack>
+</Window>
+
--- /dev/null
+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";
+}
--- /dev/null
+<?xml version="1.0"?>
+<Window Caption="Lighting" Icon="#deferred.crow.svg" Left="10" Top="100" Width="40%" Height="40%" CornerRadius="10">
+ <VerticalStack Spacing="1" Margin="10" CacheEnabled="true">
+ <HorizontalStack Height="Fit" >
+ <Label Text="Exposure:" Width="80"/>
+ <Slider Height="10" Value="{²Exposure}" Maximum="10.0" SmallIncrement="0.1" LargeIncrement="1.0"/>
+ <Label Text="{Exposure}" Width="40" TextAlignment="Right" />
+ </HorizontalStack>
+ <HorizontalStack Height="Fit">
+ <Label Text="Gamma:" Width="80" />
+ <Slider Height="10" Value="{²Gamma}" Maximum="10.0" SmallIncrement="0.1" LargeIncrement="1.0"/>
+ <Label Text="{Gamma}" Width="40" TextAlignment="Right" />
+ </HorizontalStack>
+ <HorizontalStack Height="Fit">
+ <Label Text="Light Strength:" Width="100" />
+ <Slider Height="10" Value="{²LightStrength}" Maximum="50.0" SmallIncrement="0.1" LargeIncrement="5.0"/>
+ <Label Text="{LightStrength}" Width="40" TextAlignment="Right" />
+ </HorizontalStack>
+ <ListBox Name="dv" Data="{Lights}" Width="Stretched" Height="Fit">
+ <ItemTemplate>
+ <Border Height="Fit">
+ <VerticalStack>
+ <HorizontalStack>
+ <Label Text="Position" Width="50"/>
+ <Label Text="{position}"/>
+ </HorizontalStack>
+ <HorizontalStack>
+ <Label Text="Color" Width="50"/>
+ <Label Text="{color}"/>
+ </HorizontalStack>
+ </VerticalStack>
+ </Border>
+ </ItemTemplate>
+ </ListBox>
+ </VerticalStack>
+</Window>
+
--- /dev/null
+<?xml version="1.0"?>
+<Window Icon="#deferred.crow.svg" Left="10" Top="100" Width="40%" Height="40%" CornerRadius="10">
+ <VerticalStack>
+ <ListBox Data="{Materials}">
+ <ItemTemplate DataType="PbrMaterial">
+ <VerticalStack>
+ <ColorPicker Width="260" Height="Fit"/>
+ <HorizontalStack>
+ <Label Width="Stretched" Text="Metallic Factor"/>
+ <Spinner Style="NormalizedFloat" Value="{²metallicFactor}"/>
+ </HorizontalStack>
+ <HorizontalStack>
+ <Label Width="Stretched" Text="Roughness Factor"/>
+ <Spinner Style="NormalizedFloat" Value="{²roughnessFactor}"/>
+ </HorizontalStack>
+ <HorizontalStack>
+ <Label Width="Stretched" Text="Alpha Mask"/>
+ <Spinner Style="NormalizedFloat" Value="{²alphaMask}"/>
+ </HorizontalStack>
+ <HorizontalStack>
+ <Label Width="Stretched" Text="Alpha Mask Cutoff"/>
+ <Spinner Style="NormalizedFloat" Value="{²alphaMaskCutoff}"/>
+ </HorizontalStack>
+ </VerticalStack>
+ </ItemTemplate>
+ </ListBox>
+ <Button Caption="Apply" MouseClick="onApplyMaterialChanges"/>
+ </VerticalStack>
+</Window>
+
--- /dev/null
+<?xml version="1.0"?>
+<Menu>
+ <MenuItem Caption="View" Fit="true" PopWidth="150">
+ <MenuItem Command="{CMDViewScenes}"/>
+ <MenuItem Command="{CMDViewDebug}"/>
+ <MenuItem Command="{CMDViewEditor}"/>
+ <MenuItem Command="{CMDViewMaterials}"/>
+ </MenuItem>
+</Menu>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<VerticalStack>
+ <Border Style="TreeItemBorder" MouseDoubleClick="./onClickForExpand">
+ <HorizontalStack Spacing="5">
+ <Image Margin="1" Width="10" Height="10" Focusable="true" MouseDown="./onClickForExpand"
+ Path="{./Image}"
+ Visible="{./IsExpandable}"
+ SvgSub="{./IsExpanded}"
+ MouseEnter="{Background=LightGrey}"
+ MouseLeave="{Background=Transparent}"/>
+ <Image Style="TreeIcon"
+ Path="#Crow.Icons.folder.svg" SvgSub="{./IsExpanded}"/>
+ <Label Text="{./Caption}"/>
+ </HorizontalStack>
+ </Border>
+ <Container Name="Content" Visible="false"/>
+</VerticalStack>
+
--- /dev/null
+<?xml version="1.0"?>
+<Window Caption="Scenes" Icon="#deferred.crow.svg" Left="10" Top="100" Width="40%" Height="80%" CornerRadius="10">
+ <TreeView Data="{Scenes}" Width="Stretched">
+ <ItemTemplate DataType="Scene" Data="GetNodes">
+ <Expandable Caption="{Name}" Template="#deferred.sceneItem.crow" IsExpanded="{²IsExpanded}">
+ <HorizontalStack Height="Fit">
+ <Widget Width="8" Height="10"/>
+ <VerticalStack Height="Fit" Name="ItemsContainer"/>
+ </HorizontalStack>
+ </Expandable>
+ </ItemTemplate>
+ <ItemTemplate DataType="Node" Data="Children">
+ <Expandable Caption="Node" IsExpanded="{²IsExpanded}">
+ <Template>
+ <VerticalStack>
+ <Border Style="TreeItemBorder" MouseDoubleClick="./onClickForExpand">
+ <HorizontalStack Spacing="5">
+ <Image Margin="1" Width="10" Height="10" Focusable="true" MouseDown="./onClickForExpand"
+ Path="{./Image}"
+ Visible="{./IsExpandable}"
+ SvgSub="{./IsExpanded}"
+ MouseEnter="{Background=LightGrey}"
+ MouseLeave="{Background=Transparent}"/>
+ <Image Style="TreeIcon"
+ Path="#Crow.Icons.folder.svg" SvgSub="{./IsExpanded}"/>
+ <Label Text="{./Caption}"/>
+ <Label DataSource="{Mesh}" Text="{Name}"/>
+ </HorizontalStack>
+ </Border>
+ <Container Name="Content" Visible="false"/>
+ </VerticalStack>
+ </Template>>
+ <HorizontalStack Height="Fit">
+ <Widget Width="8" Height="10"/>
+ <VerticalStack Height="Fit" Name="ItemsContainer"/>
+ </HorizontalStack>
+ </Expandable>
+ </ItemTemplate>
+ </TreeView>
+</Window>
+
--- /dev/null
+<?xml version="1.0"?>
+<EnumSelector Height="300" EnumValue="{²CurrentDebugView}"/>
+
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "pbr", "samples\pbr\pbr.csproj", "{7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "glow", "samples\glow\glow.csproj", "{82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "crowWin", "samples\crowWin\crowWin.csproj", "{A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrowWindow", "addons\CrowWindow\CrowWindow.csproj", "{5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
{1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.ReleaseSpirVTasks|Any CPU.ActiveCfg = Debug|Any CPU
{1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.BuildPackages|Any CPU.ActiveCfg = Release|Any CPU
{1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.BuildPackages|Any CPU.Build.0 = Release|Any CPU
+ {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.DebugCrow|Any CPU.ActiveCfg = DebugCrow|Any CPU
+ {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.DebugCrow|Any CPU.Build.0 = DebugCrow|Any CPU
+ {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.ReleaseSpirVTasks|Any CPU.ActiveCfg = Debug|Any CPU
+ {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.ReleaseSpirVTasks|Any CPU.Build.0 = Debug|Any CPU
+ {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.BuildPackages|Any CPU.ActiveCfg = Release|Any CPU
+ {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE}.BuildPackages|Any CPU.Build.0 = Release|Any CPU
+ {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.DebugCrow|Any CPU.ActiveCfg = Debug|Any CPU
+ {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU
+ {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.ReleaseSpirVTasks|Any CPU.ActiveCfg = Debug|Any CPU
+ {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.ReleaseSpirVTasks|Any CPU.Build.0 = Debug|Any CPU
+ {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.BuildPackages|Any CPU.ActiveCfg = Release|Any CPU
+ {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536}.BuildPackages|Any CPU.Build.0 = Release|Any CPU
+ {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.DebugCrow|Any CPU.ActiveCfg = Debug|Any CPU
+ {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU
+ {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.ReleaseSpirVTasks|Any CPU.ActiveCfg = Debug|Any CPU
+ {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.ReleaseSpirVTasks|Any CPU.Build.0 = Debug|Any CPU
+ {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.BuildPackages|Any CPU.ActiveCfg = Release|Any CPU
+ {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D}.BuildPackages|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{FEF3AF30-5B88-4D3C-8BD7-8734200E0D1E} = {4AA67AB0-C331-4CB2-9C00-B74F5DE31658}
{124152F8-FAE6-4D4B-87B9-6074DD365E9B} = {16439374-B8DB-4643-8116-EB3358B49A12}
{7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5} = {16439374-B8DB-4643-8116-EB3358B49A12}
{1D2A1968-8F04-4BE0-B03A-573F1F68AB66} = {16439374-B8DB-4643-8116-EB3358B49A12}
+ {82947B19-1EFA-4DF9-8BB8-56B0B48F3FBE} = {16439374-B8DB-4643-8116-EB3358B49A12}
+ {A05AAF6C-E925-4EF1-B051-A6DDA5BCB536} = {16439374-B8DB-4643-8116-EB3358B49A12}
+ {5AE929DA-4EA2-4BD9-BA38-7258AA9D2E4D} = {4AA67AB0-C331-4CB2-9C00-B74F5DE31658}
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0
#endregion
#region shaderc
+
+
public static ShaderInfo CreateShaderInfo (this shaderc.Compiler comp, Device dev, string shaderPath, shaderc.ShaderKind shaderKind,
SpecializationInfo specializationInfo = null, string entryPoint = "main") {
using (shaderc.Result res = comp.Compile (shaderPath, shaderKind)) {
- Console.WriteLine ($"SpirV generation: {shaderPath} {res.Status}");
if (res.Status != shaderc.Status.Success)
throw new Exception ($"Shaderc compilation failure: {res.ErrorMessage}");
- VkShaderStageFlags stageFlags;
- switch (shaderKind) {
- case shaderc.ShaderKind.VertexShader:
- stageFlags = VkShaderStageFlags.Vertex;
- break;
- case shaderc.ShaderKind.FragmentShader:
- stageFlags = VkShaderStageFlags.Fragment;
- break;
- case shaderc.ShaderKind.ComputeShader:
- stageFlags = VkShaderStageFlags.Compute;
- break;
- case shaderc.ShaderKind.GeometryShader:
- stageFlags = VkShaderStageFlags.Geometry;
- break;
- case shaderc.ShaderKind.TessControlShader:
- stageFlags = VkShaderStageFlags.TessellationControl;
- break;
- case shaderc.ShaderKind.TessEvaluationShader:
- stageFlags = VkShaderStageFlags.TessellationEvaluation;
- break;
- default:
- throw new NotSupportedException ($"shaderc compilation: shaderKind {shaderKind} not handled");
- }
+ VkShaderStageFlags stageFlags = Utils.ShaderKindToStageFlag (shaderKind);
return new ShaderInfo (dev, stageFlags, res.CodePointer, (UIntPtr)res.CodeLength, specializationInfo, entryPoint);
}
}
public class ShaderInfo : IDisposable {
readonly FixedUtf8String EntryPoint;
- internal VkPipelineShaderStageCreateInfo info = VkPipelineShaderStageCreateInfo.New ();
- Device dev;
+ protected VkPipelineShaderStageCreateInfo info = VkPipelineShaderStageCreateInfo.New ();
+ protected Device dev;
+
+ public VkShaderStageFlags Stage => info.stage;
+ public VkPipelineShaderStageCreateInfo Info => info;
+
+ public void RecreateModule(IntPtr code, UIntPtr codeSize) {
+ if (dev == null)
+ throw new Exception ("[ShaderInfo]Trying to recreate unowned shader module.");
+ dev.DestroyShaderModule (info.module);
+ info.module = dev.CreateShaderModule (code, codeSize);
+ }
+
/// <summary>
/// Create a new 'ShaderInfo' object by providing a handle to an native memory holding the compiled SpirV code
/// and its size in byte.
0, 0, zNear * zFar / (zNear - zFar), 0
);
}
+
+ public static VkShaderStageFlags ShaderKindToStageFlag (shaderc.ShaderKind shaderKind) {
+ switch (shaderKind) {
+ case shaderc.ShaderKind.VertexShader:
+ case shaderc.ShaderKind.GlslDefaultVertexShader:
+ return VkShaderStageFlags.Vertex;
+ case shaderc.ShaderKind.FragmentShader:
+ case shaderc.ShaderKind.GlslDefaultFragmentShader:
+ return VkShaderStageFlags.Fragment;
+ case shaderc.ShaderKind.ComputeShader:
+ case shaderc.ShaderKind.GlslDefaultComputeShader:
+ return VkShaderStageFlags.Compute;
+ case shaderc.ShaderKind.GeometryShader:
+ case shaderc.ShaderKind.GlslDefaultGeometryShader:
+ return VkShaderStageFlags.Geometry;
+ case shaderc.ShaderKind.TessControlShader:
+ case shaderc.ShaderKind.GlslDefaultTessControlShader:
+ return VkShaderStageFlags.TessellationControl;
+ case shaderc.ShaderKind.TessEvaluationShader:
+ case shaderc.ShaderKind.GlslDefaultTessEvaluationShader:
+ return VkShaderStageFlags.TessellationEvaluation;
+ case shaderc.ShaderKind.RaygenShader:
+ case shaderc.ShaderKind.GlslDefaultRaygenShader:
+ return VkShaderStageFlags.RaygenKHR;
+ case shaderc.ShaderKind.AnyhitShader:
+ case shaderc.ShaderKind.GlslDefaultAnyhitShader:
+ return VkShaderStageFlags.AnyHitKHR;
+ case shaderc.ShaderKind.ClosesthitShader:
+ case shaderc.ShaderKind.GlslDefaultClosesthitShader:
+ return VkShaderStageFlags.ClosestHitKHR;
+ case shaderc.ShaderKind.MissShader:
+ case shaderc.ShaderKind.GlslDefaultMissShader:
+ return VkShaderStageFlags.MissKHR;
+ case shaderc.ShaderKind.IntersectionShader:
+ case shaderc.ShaderKind.GlslDefaultIntersectionShader:
+ return VkShaderStageFlags.IntersectionKHR;
+ case shaderc.ShaderKind.CallableShader:
+ case shaderc.ShaderKind.GlslDefaultCallableShader:
+ return VkShaderStageFlags.CallableKHR;
+ case shaderc.ShaderKind.TaskShader:
+ case shaderc.ShaderKind.GlslDefaultTaskShader:
+ return VkShaderStageFlags.TaskNV;
+ case shaderc.ShaderKind.MeshShader:
+ case shaderc.ShaderKind.GlslDefaultMeshShader:
+ return VkShaderStageFlags.MeshNV;
+ default:
+ throw new NotSupportedException ($"shaderc shaderKind {shaderKind} conversion to VK StageFlag not handled");
+ }
+ }
+ public static shaderc.ShaderKind ShaderStageToShaderKind (VkShaderStageFlags stageFlag) {
+ switch (stageFlag) {
+ case VkShaderStageFlags.Vertex:
+ return shaderc.ShaderKind.VertexShader;
+ case VkShaderStageFlags.TessellationControl:
+ return shaderc.ShaderKind.TessControlShader;
+ case VkShaderStageFlags.TessellationEvaluation:
+ return shaderc.ShaderKind.TessEvaluationShader;
+ case VkShaderStageFlags.Geometry:
+ return shaderc.ShaderKind.GeometryShader;
+ case VkShaderStageFlags.Fragment:
+ return shaderc.ShaderKind.FragmentShader;
+ case VkShaderStageFlags.Compute:
+ return shaderc.ShaderKind.ComputeShader;
+ case VkShaderStageFlags.RaygenKHR:
+ return shaderc.ShaderKind.RaygenShader;
+ case VkShaderStageFlags.AnyHitKHR:
+ return shaderc.ShaderKind.AnyhitShader;
+ case VkShaderStageFlags.ClosestHitKHR:
+ return shaderc.ShaderKind.ClosesthitShader;
+ case VkShaderStageFlags.MissKHR:
+ return shaderc.ShaderKind.MissShader;
+ case VkShaderStageFlags.IntersectionKHR:
+ return shaderc.ShaderKind.IntersectionShader;
+ case VkShaderStageFlags.CallableKHR:
+ return shaderc.ShaderKind.CallableShader;
+ case VkShaderStageFlags.TaskNV:
+ return shaderc.ShaderKind.TaskShader;
+ case VkShaderStageFlags.MeshNV:
+ return shaderc.ShaderKind.MeshShader;
+ default:
+ throw new NotSupportedException ($"Error Shader Stage flag conversion to ShaderKind: {stageFlag}");
+ }
+ }
}
}
using (ShaderInfo shader = new ShaderInfo (Dev, VkShaderStageFlags.Compute, SpirVPath)) {
VkComputePipelineCreateInfo info = VkComputePipelineCreateInfo.New ();
info.layout = layout.Handle;
- info.stage = shader.info;
+ info.stage = shader.Info;
info.basePipelineHandle = 0;
info.basePipelineIndex = 0;
List<VkPipelineShaderStageCreateInfo> shaderStages = new List<VkPipelineShaderStageCreateInfo> ();
foreach (ShaderInfo shader in cfg.Shaders)
- shaderStages.Add (shader.info);
+ shaderStages.Add (shader.Info);
using (PinnedObjects pctx = new PinnedObjects ()) {
memory = memoryPool.vkMemory,
offset = poolOffset,
#else
- memory = vkMemory,
- offset = 0,
+ memory = vkMemory,
+ offset = 0,
#endif
size = AllocatedDeviceMemorySize
};
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
- <DefineConstants>MEMORY_POOLS;NETSTANDARD;NETSTANDARD2_0;DEBUG</DefineConstants>
+ <DefineConstants>_MEMORY_POOLS;NETSTANDARD;NETSTANDARD2_0;DEBUG</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
- <DefineConstants>MEMORY_POOLS;NETSTANDARD;NETSTANDARD2_0</DefineConstants>
+ <DefineConstants>_MEMORY_POOLS;NETSTANDARD;NETSTANDARD2_0</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('netstandard'))">
<ItemGroup>
<PackageReference Include="SpirVTasks" Version="$(SpirVTasksPackageVersion)" />
- <PackageReference Include="Vulkan" Version="0.2.20-beta" />
+ <PackageReference Include="Vulkan" Version="0.2.2.2-beta" />
<PackageReference Include="shaderc.net" Version="0.1.0" />
- <PackageReference Include="glfw-sharp" Version="0.2.3.4" />
+ <PackageReference Include="glfw-sharp" Version="0.2.5" />
</ItemGroup>
<ItemGroup>
<GLSLShader Include="shaders\**\*.frag;shaders\**\*.vert;shaders\**\*.comp;shaders\**\*.geom" />