using System; using System.Numerics; using System.Runtime.InteropServices; using Glfw; using VKE; using Vulkan; using Buffer = VKE.Buffer; namespace ModelSample { class Program : VkWindow { static void Main (string[] args) { using (Program vke = new Program ()) { vke.Run (); } } 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; Pipeline pipeline; Framebuffer[] frameBuffers; Model model; Camera Camera = new Camera (Utils.DegreesToRadians (60f), 1f); Program () : base () { init (); model = new Model (dev, presentQueue, cmdPool, "../data/models/DamagedHelmet/glTF/DamagedHelmet.gltf"); model.WriteMaterialsDescriptorSets (descLayoutTextures, ShaderBinding.Color, ShaderBinding.Normal, ShaderBinding.AmbientOcclusion, ShaderBinding.MetalRoughness, ShaderBinding.Emissive); } void init (VkSampleCountFlags samples = VkSampleCountFlags.Count4) { descriptorPool = new DescriptorPool (dev, 2, new VkDescriptorPoolSize (VkDescriptorType.UniformBuffer) ); descLayoutMatrix = new DescriptorSetLayout (dev, new VkDescriptorSetLayoutBinding (0, VkShaderStageFlags.Vertex|VkShaderStageFlags.Fragment, VkDescriptorType.UniformBuffer)); 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); pipeline = new Pipeline (dev, swapChain.ColorFormat, dev.GetSuitableDepthFormat (), VkPrimitiveTopology.TriangleList, samples); pipeline.Layout = new PipelineLayout (dev, descLayoutMatrix, descLayoutTextures); pipeline.Layout.AddPushConstants ( new VkPushConstantRange (VkShaderStageFlags.Vertex, (uint)Marshal.SizeOf ()), new VkPushConstantRange (VkShaderStageFlags.Fragment, (uint)Marshal.SizeOf (), 64) ); pipeline.AddVertexBinding (0); pipeline.SetVertexAttributes (0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32b32Sfloat, VkFormat.R32g32Sfloat); pipeline.AddShader (VkShaderStageFlags.Vertex, "shaders/pbrtest.vert.spv"); pipeline.AddShader (VkShaderStageFlags.Fragment, "shaders/pbrtest.frag.spv"); pipeline.Activate (); uboMats = new HostBuffer (dev, VkBufferUsageFlags.UniformBuffer, (ulong)Marshal.SizeOf()); uboMats.Map ();//permanent map using (DescriptorSetWrites uboUpdate = new DescriptorSetWrites (dev)) { uboUpdate.AddWriteInfo (dsMats, descLayoutMatrix.Bindings[0], uboMats.Descriptor); uboUpdate.Update (); } } 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); cmd.BindDescriptorSet (pipeline.Layout, dsMats); pipeline.Bind (cmd); model.Bind (cmd); model.DrawAll (cmd, pipeline.Layout); pipeline.RenderPass.End (cmd); } void updateMatrices () { Camera.AspectRatio = (float)swapChain.Width / swapChain.Height; matrices.projection = Camera.Projection; matrices.view = Camera.View; matrices.model = Camera.Model; uboMats.Update (matrices, (uint)Marshal.SizeOf ()); } public override void Update () { updateMatrices (); updateRequested = false; } protected override void onMouseMove (double xPos, double yPos) { double diffX = lastMouseX - xPos; double diffY = lastMouseY - yPos; if (MouseButton[0]) { Camera.Rotate ((float)-diffX,(float)-diffY); } else if (MouseButton[1]) { Camera.Zoom ((float)diffY); } updateRequested = true; } protected override void onKeyDown (Key key, int scanCode, Modifier modifiers) { switch (key) { case Key.Up: Camera.Rotate (0, 0, 1); break; case Key.Down: Camera.Move (0, 0, -1); break; case Key.Left: Camera.Move (1, 0, 0); break; case Key.Right: Camera.Move (-1, 0, 0); break; case Key.PageUp: Camera.Move (0, 1, 0); break; case Key.PageDown: 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; break; default: base.onKeyDown (key, scanCode, modifiers); return; } updateRequested = true; } protected override void OnResize () { 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.Count1) ? new Image[] { swapChain.images[i], null } : new Image[] { null, null, swapChain.images[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 (); } } base.Dispose (disposing); } } }