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