diff --git a/Client/Content/shaders/blit.vert.glsl b/Client/Content/shaders/blit.vert.glsl index 6a0c1ce..87c9449 100644 --- a/Client/Content/shaders/blit.vert.glsl +++ b/Client/Content/shaders/blit.vert.glsl @@ -4,27 +4,16 @@ layout(location = 0) in vec3 Position; layout(location = 0) out vec2 fsin_texCoords; layout (set = 1, binding = 0) uniform TextureDrawParams { - vec2 SrcMin; - vec2 SrcMax; - vec2 DstMin; - vec2 DstMax; - vec2 SrcSize; - vec2 DstSize; + bool flip; }; void main() { - vec2 scaledDstMin = DstMin / DstSize; - vec2 scaledDstMax = DstMax / DstSize; - - //Move vertex to correct place on texture. - vec2 uv = (scaledDstMin + (scaledDstMax - scaledDstMin) * Position.xy); - uv.y = 1-uv.y; - - gl_Position = vec4((uv * 2) - 1, 0, 1); - - vec2 scaledSrcMin = SrcMin / SrcSize; - vec2 scaledSrcMax = SrcMax / SrcSize; + gl_Position = vec4((Position.xy * 2) - 1, 0, 1); //Sample from source texture. - fsin_texCoords = scaledSrcMin + (scaledSrcMax - scaledSrcMin) * Position.xy; + + vec2 uv = Position.xy; + if (flip) + uv = vec2(uv.x, 1 - uv.y); + fsin_texCoords = uv; } diff --git a/Client/Content/shaders/simple.frag.glsl b/Client/Content/shaders/simple.frag.glsl index fa8d55f..ca3c559 100644 --- a/Client/Content/shaders/simple.frag.glsl +++ b/Client/Content/shaders/simple.frag.glsl @@ -7,6 +7,7 @@ layout(location = 3) in vec2 fsin_UvMin; layout(location = 4) in vec2 fsin_UvMax; layout(location = 0) out vec4 fsout_Color; +layout(location = 1) out vec4 gbuffer_Color; layout (set = 1, binding = 0) uniform sampler TextureSampler; layout (set = 1, binding = 1) uniform texture2D Texture; @@ -40,6 +41,8 @@ void interpolatePixels() { texture(sampler2D(Texture, TextureSampler), vec2(newUvMax.x, newUvMin.y)) ) / 4; fsout_Color = sampledColor * fsin_Color; + + gbuffer_Color = vec4(1,1,0,1); } void main() { diff --git a/Client/Content/shaders/stitcher.frag.glsl b/Client/Content/shaders/stitcher.frag.glsl new file mode 100644 index 0000000..9df3212 --- /dev/null +++ b/Client/Content/shaders/stitcher.frag.glsl @@ -0,0 +1,11 @@ +#version 450 + +layout(location = 0) in vec2 fsin_texCoords; +layout(location = 0) out vec4 fsout_Color; + +layout (set = 0, binding = 0) uniform sampler TextureSampler; +layout (set = 0, binding = 1) uniform texture2D Texture; + +void main() { + fsout_Color = texture(sampler2D(Texture, TextureSampler), fsin_texCoords); +} diff --git a/Client/Content/shaders/stitcher.vert.glsl b/Client/Content/shaders/stitcher.vert.glsl new file mode 100644 index 0000000..6a0c1ce --- /dev/null +++ b/Client/Content/shaders/stitcher.vert.glsl @@ -0,0 +1,30 @@ +#version 450 + +layout(location = 0) in vec3 Position; +layout(location = 0) out vec2 fsin_texCoords; + +layout (set = 1, binding = 0) uniform TextureDrawParams { + vec2 SrcMin; + vec2 SrcMax; + vec2 DstMin; + vec2 DstMax; + vec2 SrcSize; + vec2 DstSize; +}; + +void main() { + vec2 scaledDstMin = DstMin / DstSize; + vec2 scaledDstMax = DstMax / DstSize; + + //Move vertex to correct place on texture. + vec2 uv = (scaledDstMin + (scaledDstMax - scaledDstMin) * Position.xy); + uv.y = 1-uv.y; + + gl_Position = vec4((uv * 2) - 1, 0, 1); + + vec2 scaledSrcMin = SrcMin / SrcSize; + vec2 scaledSrcMax = SrcMax / SrcSize; + + //Sample from source texture. + fsin_texCoords = scaledSrcMin + (scaledSrcMax - scaledSrcMin) * Position.xy; +} diff --git a/Client/Rendering/Debug/DebugRenderer.cs b/Client/Rendering/Debug/DebugRenderer.cs index d130245..c30da33 100644 --- a/Client/Rendering/Debug/DebugRenderer.cs +++ b/Client/Rendering/Debug/DebugRenderer.cs @@ -11,7 +11,7 @@ public class DebugRenderer : Renderer { private const int BatchSize = 8192 * 4; private static DebugRenderer Instance; - public readonly Pipeline DebugPipeline; + public Pipeline DebugPipeline; private readonly DeviceBuffer vertexBuffer; private readonly DebugVertex[] DebugVertices = new DebugVertex[BatchSize]; @@ -23,7 +23,13 @@ public class DebugRenderer : Renderer { public DebugRenderer(VoxelClient client) : base(client) { Instance = this; - if (!client.RenderSystem.ShaderManager.GetShaders("shaders/debug", out var shaders)) + + vertexBuffer = ResourceFactory.CreateBuffer(new BufferDescription { + Usage = BufferUsage.Dynamic | BufferUsage.VertexBuffer, SizeInBytes = (uint)Marshal.SizeOf() * BatchSize + }); + } + public override void CreatePipeline(MainFramebuffer framebuffer) { + if (!Client.RenderSystem.ShaderManager.GetShaders("shaders/debug", out var shaders)) throw new("Shaders not present."); DebugPipeline = ResourceFactory.CreateGraphicsPipeline(new() { @@ -31,7 +37,7 @@ public DebugRenderer(VoxelClient client) : base(client) { DepthStencilState = new() { DepthComparison = ComparisonKind.LessEqual, DepthTestEnabled = true, DepthWriteEnabled = true, }, - Outputs = RenderSystem.GraphicsDevice.SwapchainFramebuffer.OutputDescription, + Outputs = framebuffer.Framebuffer.OutputDescription, PrimitiveTopology = PrimitiveTopology.LineList, RasterizerState = new() { CullMode = FaceCullMode.None, DepthClipEnabled = false, FillMode = PolygonFillMode.Wireframe, ScissorTestEnabled = false, @@ -46,22 +52,18 @@ public DebugRenderer(VoxelClient client) : base(client) { Shaders = shaders } }); - - - vertexBuffer = ResourceFactory.CreateBuffer(new BufferDescription { - Usage = BufferUsage.Dynamic | BufferUsage.VertexBuffer, SizeInBytes = (uint)Marshal.SizeOf() * BatchSize - }); } + public override void Render(double delta) { - Flush(); + //Flush(); } private void Flush() { + return; if (vertexIndex == 0) return; CommandList.UpdateBuffer(vertexBuffer, 0, DebugVertices.AsSpan(0, vertexIndex)); - SetPipeline(DebugPipeline); CommandList.SetGraphicsResourceSet(0, Client.GameRenderer.CameraStateManager.CameraResourceSet); @@ -69,12 +71,10 @@ private void Flush() { CommandList.Draw((uint)vertexIndex); vertexIndex = 0; - - //RestoreLastPipeline(); } public override void Dispose() { - DebugPipeline.Dispose(); + } private void AddPoint(dvec3 pos) { @@ -129,12 +129,12 @@ public static void DrawCube(dvec3 min, dvec3 max, float expansion = 0) { DrawLine(new dvec3(realMax.x, realMin.y, realMax.z), new dvec3(realMax.x, realMin.y, realMin.z)); DrawLine(new dvec3(realMax.x, realMin.y, realMin.z), new dvec3(realMin.x, realMin.y, realMin.z)); - + DrawLine(new dvec3(realMin.x, realMax.y, realMin.z), new dvec3(realMin.x, realMax.y, realMax.z)); DrawLine(new dvec3(realMin.x, realMax.y, realMax.z), new dvec3(realMax.x, realMax.y, realMax.z)); DrawLine(new dvec3(realMax.x, realMax.y, realMax.z), new dvec3(realMax.x, realMax.y, realMin.z)); DrawLine(new dvec3(realMax.x, realMax.y, realMin.z), new dvec3(realMin.x, realMax.y, realMin.z)); - + DrawLine(new dvec3(realMin.x, realMin.y, realMin.z), new dvec3(realMin.x, realMax.y, realMin.z)); DrawLine(new dvec3(realMin.x, realMin.y, realMax.z), new dvec3(realMin.x, realMax.y, realMax.z)); diff --git a/Client/Rendering/GameRenderer.cs b/Client/Rendering/GameRenderer.cs index b63308b..164ac35 100644 --- a/Client/Rendering/GameRenderer.cs +++ b/Client/Rendering/GameRenderer.cs @@ -1,26 +1,32 @@ -using System; using GlmSharp; -using Voxel.Client.Keybinding; +using Veldrid; using Voxel.Client.Rendering.Debug; using Voxel.Client.Rendering.Gui; using Voxel.Client.Rendering.World; -using Voxel.Common.Collision; -using Voxel.Common.World; namespace Voxel.Client.Rendering; public class GameRenderer : Renderer { + public MainFramebuffer Framebuffer { get; private set; } + private uint msaaLevel = 1; + private bool needMainBufferRefresh = true; + /// /// Main camera, used to render main game window. /// Cannot be destroyed, it's essential for basic game rendering. /// public readonly Camera MainCamera; + public readonly CameraStateManager CameraStateManager; + + public readonly WorldRenderer WorldRenderer; public readonly GuiRenderer GuiRenderer; - public readonly CameraStateManager CameraStateManager; + + public readonly BlitRenderer BlitRenderer; public readonly DebugRenderer DebugRenderer; + public GameRenderer(VoxelClient client) : base(client) { //Jank but OK client.GameRenderer = this; @@ -31,12 +37,34 @@ public GameRenderer(VoxelClient client) : base(client) { WorldRenderer = new(client); GuiRenderer = new(client); - - DebugRenderer = new DebugRenderer(client); + BlitRenderer = new(client); + DebugRenderer = new(client); } + public override void CreatePipeline(MainFramebuffer framebuffer) { + WorldRenderer.CreatePipeline(framebuffer); + GuiRenderer.CreatePipeline(framebuffer); + + BlitRenderer.CreatePipeline(framebuffer); + DebugRenderer.CreatePipeline(framebuffer); + } public override void Render(double delta) { + if (needMainBufferRefresh) { + needMainBufferRefresh = false; + + if (Framebuffer != null) + Framebuffer.Dispose(); + Framebuffer = new MainFramebuffer(ResourceFactory, RenderSystem.GraphicsDevice.MainSwapchain.Framebuffer, (uint)Client.NativeWindow.Width, (uint)Client.NativeWindow.Height, msaaLevel); + + CreatePipeline(Framebuffer); + } + + CommandList.SetFramebuffer(Framebuffer.Framebuffer); + CommandList.ClearColorTarget(0, RgbaFloat.Grey); + CommandList.ClearColorTarget(1, RgbaFloat.Green); + CommandList.ClearDepthStencil(1); + MainCamera.position = Client.PlayerEntity?.SmoothPosition(Client.smoothFactor) + Client.PlayerEntity?.eyeOffset ?? dvec3.Zero; MainCamera.rotationVec = Client.PlayerEntity?.SmoothRotation(Client.smoothFactor) ?? dvec2.Zero; CameraStateManager.SetToCamera(MainCamera, Client.timeSinceLastTick); @@ -45,12 +73,29 @@ public override void Render(double delta) { GuiRenderer.Render(delta); DebugRenderer.Render(delta); + + Framebuffer.Resolve(RenderSystem); + + BlitRenderer.Blit(Framebuffer.ResolvedMainColor, RenderSystem.GraphicsDevice.MainSwapchain.Framebuffer, true); + } + + + public void RecreateMainFramebuffer() { + needMainBufferRefresh = true; + } + + public void SetMSAA(uint value) { + msaaLevel = value; + RecreateMainFramebuffer(); } public override void Dispose() { WorldRenderer.Dispose(); GuiRenderer.Dispose(); + BlitRenderer.Dispose(); DebugRenderer.Dispose(); + + Framebuffer.Dispose(); } } diff --git a/Client/Rendering/Gui/GuiRenderer.cs b/Client/Rendering/Gui/GuiRenderer.cs index cb8818a..4cf6a4d 100644 --- a/Client/Rendering/Gui/GuiRenderer.cs +++ b/Client/Rendering/Gui/GuiRenderer.cs @@ -2,21 +2,23 @@ using Veldrid; using Voxel.Client.Rendering.VertexTypes; -namespace Voxel.Client.Rendering.Gui; +namespace Voxel.Client.Rendering.Gui; public class GuiRenderer : Renderer, IDisposable { - public readonly Pipeline GuiPipeline; + public Pipeline GuiPipeline; public GuiRenderer(VoxelClient client) : base(client) { - if (!client.RenderSystem.ShaderManager.GetShaders("shaders/gui", out var shaders)) + + } + + public override void CreatePipeline(MainFramebuffer framebuffer) { + if (!Client.RenderSystem.ShaderManager.GetShaders("shaders/gui", out var shaders)) throw new("Shaders not present."); - - GuiPipeline = ResourceFactory.CreateGraphicsPipeline(new() { + + GuiPipeline = framebuffer.AddDependency(ResourceFactory.CreateGraphicsPipeline(new() { BlendState = BlendStateDescription.SingleAlphaBlend, DepthStencilState = new() { - DepthComparison = ComparisonKind.Never, - DepthTestEnabled = false, - DepthWriteEnabled = false, + DepthComparison = ComparisonKind.Never, DepthTestEnabled = false, DepthWriteEnabled = false, }, Outputs = RenderSystem.GraphicsDevice.SwapchainFramebuffer.OutputDescription, PrimitiveTopology = PrimitiveTopology.TriangleList, @@ -36,15 +38,14 @@ public GuiRenderer(VoxelClient client) : base(client) { }, Shaders = shaders } - }); + })); } - public override void Render(double delta) { - CommandList.SetPipeline(GuiPipeline); + //CommandList.SetPipeline(GuiPipeline); //CommandList.SetGraphicsResourceSet(0, TerrainAtlas.AtlasResourceSet); - CommandList.SetIndexBuffer(RenderSystem.CommonIndexBuffer, IndexFormat.UInt32); + //CommandList.SetIndexBuffer(RenderSystem.CommonIndexBuffer, IndexFormat.UInt32); } public override void Dispose() {} } diff --git a/Client/Rendering/MainFramebuffer.cs b/Client/Rendering/MainFramebuffer.cs new file mode 100644 index 0000000..d2369ca --- /dev/null +++ b/Client/Rendering/MainFramebuffer.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using Veldrid; +using Voxel.Core.Rendering; + +namespace Voxel.Client.Rendering; + +public class MainFramebuffer : IDisposable { + public readonly Framebuffer Framebuffer; + public readonly Framebuffer WindowFramebuffer; + + public readonly Veldrid.Texture MainColor; + public readonly Veldrid.Texture Normal; + public readonly Veldrid.Texture Depth; + + public readonly TextureSampleCount Samples; + + public readonly Veldrid.Texture ResolvedMainColor; + public readonly Veldrid.Texture ResolvedNormal; + public readonly Veldrid.Texture ResolvedDepth; + + + public readonly List Dependencies = new(); + + public MainFramebuffer(ResourceFactory factory, Framebuffer windowBuffer, uint width, uint height, uint sampleCount = 1) { + switch (sampleCount) { + default: + Samples = TextureSampleCount.Count1; + break; + case 2: + Samples = TextureSampleCount.Count2; + break; + case 4: + Samples = TextureSampleCount.Count4; + break; + case 8: + Samples = TextureSampleCount.Count8; + break; + } + + var baseDescription = new TextureDescription { + Width = width, + Height = height, + Depth = 1, + ArrayLayers = 1, + MipLevels = 1, + Type = TextureType.Texture2D, + SampleCount = Samples + }; + + baseDescription.Format = PixelFormat.R16_G16_B16_A16_Float; + baseDescription.Usage = TextureUsage.RenderTarget | TextureUsage.Sampled; + + MainColor = AddDependency(factory.CreateTexture(baseDescription)); + Normal = AddDependency(factory.CreateTexture(baseDescription)); + + baseDescription.Format = PixelFormat.R32_Float; + baseDescription.Usage = TextureUsage.DepthStencil | TextureUsage.Sampled; + + Depth = AddDependency(factory.CreateTexture(baseDescription)); + + if (Samples == TextureSampleCount.Count1) { + ResolvedMainColor = MainColor; + ResolvedNormal = Normal; + ResolvedDepth = Depth; + } else { + baseDescription.SampleCount = TextureSampleCount.Count1; + + baseDescription.Format = PixelFormat.R16_G16_B16_A16_Float; + baseDescription.Usage = TextureUsage.RenderTarget | TextureUsage.Sampled; + + ResolvedMainColor = AddDependency(factory.CreateTexture(baseDescription)); + ResolvedNormal = AddDependency(factory.CreateTexture(baseDescription)); + + baseDescription.Format = PixelFormat.R32_Float; + baseDescription.Usage = TextureUsage.DepthStencil | TextureUsage.Sampled; + + ResolvedDepth = AddDependency(factory.CreateTexture(baseDescription)); + } + + Framebuffer = AddDependency(factory.CreateFramebuffer(new FramebufferDescription { + ColorTargets = new[] { + new FramebufferAttachmentDescription(MainColor, 0), + new FramebufferAttachmentDescription(Normal, 0) + }, + DepthTarget = new FramebufferAttachmentDescription(Depth, 0) + })); + WindowFramebuffer = windowBuffer; + } + + public void Resolve(RenderSystem renderSystem) { + //If MSAA is 1, there's no need to resolve. + if (Samples == TextureSampleCount.Count1) return; + + renderSystem.MainCommandList.ResolveTexture(MainColor, ResolvedMainColor); + renderSystem.MainCommandList.ResolveTexture(Normal, ResolvedNormal); + //renderSystem.MainCommandList.ResolveTexture(Depth, ResolvedDepth); + } + + + public T AddDependency(T toAdd) where T : IDisposable { + Dependencies.Add(toAdd); + return toAdd; + } + + public void Dispose() { + foreach (var dependency in Dependencies) + dependency.Dispose(); + } +} diff --git a/Client/Rendering/Renderer.cs b/Client/Rendering/Renderer.cs index 170e5df..17fb16d 100644 --- a/Client/Rendering/Renderer.cs +++ b/Client/Rendering/Renderer.cs @@ -17,22 +17,9 @@ public Renderer(VoxelClient client) { ResourceFactory = RenderSystem.ResourceFactory; } - public abstract void Render(double delta); - - public void SetPipeline(Pipeline pipeline) { - RenderSystem.LastPipeline = RenderSystem.CurrentPipeline; - RenderSystem.CurrentPipeline = pipeline; - - CommandList.SetPipeline(pipeline); - } + public abstract void CreatePipeline(MainFramebuffer framebuffer); - public void RestoreLastPipeline() { - RenderSystem.CurrentPipeline = RenderSystem.LastPipeline; - RenderSystem.LastPipeline = null; - - if (RenderSystem.CurrentPipeline != null) - CommandList.SetPipeline(RenderSystem.CurrentPipeline); - } + public abstract void Render(double delta); public abstract void Dispose(); } diff --git a/Client/Rendering/Texture/Atlas.cs b/Client/Rendering/Texture/Atlas.cs index daedb3c..eaee129 100644 --- a/Client/Rendering/Texture/Atlas.cs +++ b/Client/Rendering/Texture/Atlas.cs @@ -51,7 +51,7 @@ public Atlas(string name, RenderSystem renderSystem, int cellsHorizontal = 4, in Name = name; RenderSystem = renderSystem; - if (!RenderSystem.ShaderManager.GetShaders("shaders/blit", out var shaders)) + if (!RenderSystem.ShaderManager.GetShaders("shaders/stitcher", out var shaders)) throw new("Blit shaders not found"); //Native atlas. diff --git a/Client/Rendering/Texture/BlitRenderer.cs b/Client/Rendering/Texture/BlitRenderer.cs new file mode 100644 index 0000000..574350d --- /dev/null +++ b/Client/Rendering/Texture/BlitRenderer.cs @@ -0,0 +1,110 @@ +using System.Runtime.InteropServices; +using GlmSharp; +using Veldrid; +using Voxel.Client.Rendering.Utils; +using Voxel.Client.Rendering.VertexTypes; + +namespace Voxel.Client.Rendering; + +/// +/// Solely responsible for blitting one texture into another. +/// +public class BlitRenderer : Renderer { + + private Pipeline DirectPipeline; + + private readonly DeviceBuffer VertexBuffer; + + private readonly TypedDeviceBuffer Params; + private readonly ResourceLayout ParamsLayout; + private readonly ResourceSet ParamsSet; + + public BlitRenderer(VoxelClient client) : base(client) { + + VertexBuffer = RenderSystem.ResourceFactory.CreateBuffer(new BufferDescription { + SizeInBytes = (uint)Marshal.SizeOf() * 4, Usage = BufferUsage.VertexBuffer + }); + RenderSystem.GraphicsDevice.UpdateBuffer(VertexBuffer, 0, new[] { + new BasicVertex(new vec3(0, 0, 0)), + new BasicVertex(new vec3(0, 1, 0)), + new BasicVertex(new vec3(1, 1, 0)), + new BasicVertex(new vec3(1, 0, 0)), + }); + + Params = new TypedDeviceBuffer(new BufferDescription { + Usage = BufferUsage.UniformBuffer | BufferUsage.Dynamic + }, RenderSystem); + + ParamsLayout = ResourceFactory.CreateResourceLayout(new ResourceLayoutDescription( + new ResourceLayoutElementDescription("Params", ResourceKind.UniformBuffer, ShaderStages.Vertex | ShaderStages.Fragment)) + ); + ParamsSet = ResourceFactory.CreateResourceSet(new ResourceSetDescription( + ParamsLayout, + Params.BackingBuffer + )); + } + + public override void CreatePipeline(MainFramebuffer framebuffer) { + + if (!RenderSystem.ShaderManager.GetShaders("shaders/blit", out var shaders)) + throw new("Blit shaders not found"); + + DirectPipeline = framebuffer.AddDependency(ResourceFactory.CreateGraphicsPipeline(new GraphicsPipelineDescription { + Outputs = framebuffer.WindowFramebuffer.OutputDescription, + BlendState = BlendStateDescription.SingleOverrideBlend, + DepthStencilState = new DepthStencilStateDescription { + DepthWriteEnabled = false, DepthTestEnabled = false, StencilTestEnabled = false, + }, + PrimitiveTopology = PrimitiveTopology.TriangleStrip, + RasterizerState = new RasterizerStateDescription { + CullMode = FaceCullMode.None, DepthClipEnabled = false, ScissorTestEnabled = false, FillMode = PolygonFillMode.Solid + }, + ShaderSet = new ShaderSetDescription { + VertexLayouts = new[] { + BasicVertex.Layout + }, + Shaders = shaders + }, + ResourceLayouts = new[] { + RenderSystem.TextureManager.TextureResourceLayout, + ParamsLayout, + } + })); + } + + public override void Render(double delta) { + + } + + public override void Dispose() { + VertexBuffer.Dispose(); + } + + public void Blit(Veldrid.Texture source, Framebuffer destination, bool flip = false) { + Params.SetValue(new BlitParams { + flipped = flip + }, CommandList); + + //Create resource set for this frame + var set = RenderSystem.TextureManager.CreateTextureResourceSet(source); + RenderSystem.GraphicsDevice.DisposeWhenIdle(set); + + CommandList.SetPipeline(DirectPipeline); + CommandList.SetFramebuffer(destination); + + //Set resource sets... + CommandList.SetGraphicsResourceSet(0, set); + CommandList.SetGraphicsResourceSet(1, ParamsSet); + + //Finally, draw a quad across the screen. + CommandList.SetVertexBuffer(0, VertexBuffer); + CommandList.SetIndexBuffer(RenderSystem.CommonIndexBuffer, IndexFormat.UInt32); + CommandList.DrawIndexed(6); + } + + + [StructLayout(LayoutKind.Sequential)] + private struct BlitParams { + public bool flipped; + } +} diff --git a/Client/Rendering/Utils/TypedDeviceBuffer.cs b/Client/Rendering/Utils/TypedDeviceBuffer.cs index 2d3652e..5589b96 100644 --- a/Client/Rendering/Utils/TypedDeviceBuffer.cs +++ b/Client/Rendering/Utils/TypedDeviceBuffer.cs @@ -19,7 +19,7 @@ public T value { public TypedDeviceBuffer(BufferDescription description, RenderSystem system) { RenderSystem = system; - description.SizeInBytes = (uint)Marshal.SizeOf(); + description.SizeInBytes = (uint)(Math.Ceiling(Marshal.SizeOf() / 16.0f) * 16.0f); BackingBuffer = system.ResourceFactory.CreateBuffer(description); } diff --git a/Client/Rendering/World/ChunkRenderSlot.cs b/Client/Rendering/World/ChunkRenderSlot.cs index c0f91e6..9840fc7 100644 --- a/Client/Rendering/World/ChunkRenderSlot.cs +++ b/Client/Rendering/World/ChunkRenderSlot.cs @@ -25,9 +25,13 @@ public class ChunkRenderSlot : Renderer { public ChunkRenderSlot(VoxelClient client) : base(client) {} + public override void CreatePipeline(MainFramebuffer framebuffer) { + + } + public override void Render(double delta) { //DebugDraw(new vec4(1, 1, 1, 1)); - + //Do nothing if this chunk render slot doesn't have a chunk yet, or if the chunk it does have is empty. if (targetChunk == null) { //DebugDraw(new vec4(0, 1, 1, 1)); @@ -55,9 +59,9 @@ public override void Render(double delta) { } } - public void Move(ivec3 absolutePos, VoxelWorld world) { - if (RealPosition == absolutePos) - return; + public void Move(ivec3 absolutePos, VoxelWorld world) { + if (RealPosition == absolutePos) + return; //DebugDraw(new vec4(0, 1, 0, 1)); diff --git a/Client/Rendering/World/ChunkRenderer.cs b/Client/Rendering/World/ChunkRenderer.cs index a1e8c91..95eb914 100644 --- a/Client/Rendering/World/ChunkRenderer.cs +++ b/Client/Rendering/World/ChunkRenderer.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using GlmSharp; using Veldrid; -using Voxel.Client.Rendering.Debug; using Voxel.Client.Rendering.Models; using Voxel.Client.Rendering.Texture; using Voxel.Client.Rendering.VertexTypes; @@ -13,7 +12,7 @@ namespace Voxel.Client.Rendering.World; public class ChunkRenderer : Renderer { - public readonly Pipeline ChunkPipeline; + public Pipeline ChunkPipeline; public readonly ResourceLayout ChunkResourceLayout; public readonly Atlas TerrainAtlas; @@ -56,16 +55,23 @@ public ChunkRenderer(VoxelClient client) : base(client) { ChunkResourceLayout = ResourceFactory.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("ModelMatrix", ResourceKind.UniformBuffer, ShaderStages.Vertex | ShaderStages.Fragment) )); + } - if (!client.RenderSystem.ShaderManager.GetShaders("shaders/simple", out var shaders)) + public override void CreatePipeline(MainFramebuffer framebuffer) { + if (!Client.RenderSystem.ShaderManager.GetShaders("shaders/simple", out var shaders)) throw new("Shaders not present."); - ChunkPipeline = ResourceFactory.CreateGraphicsPipeline(new() { - BlendState = BlendStateDescription.SingleOverrideBlend, + ChunkPipeline = framebuffer.AddDependency(ResourceFactory.CreateGraphicsPipeline(new() { + BlendState = new BlendStateDescription { + AttachmentStates = new[] { + BlendAttachmentDescription.OverrideBlend, + BlendAttachmentDescription.OverrideBlend + } + }, DepthStencilState = new() { DepthComparison = ComparisonKind.LessEqual, DepthTestEnabled = true, DepthWriteEnabled = true, }, - Outputs = RenderSystem.GraphicsDevice.SwapchainFramebuffer.OutputDescription, + Outputs = framebuffer.Framebuffer.OutputDescription, PrimitiveTopology = PrimitiveTopology.TriangleList, RasterizerState = new() { CullMode = FaceCullMode.Back, @@ -85,7 +91,7 @@ public ChunkRenderer(VoxelClient client) : base(client) { }, Shaders = shaders } - }); + })); } public void SetWorld(VoxelWorld world) { @@ -106,7 +112,7 @@ public override void Render(double delta) { SetRenderPosition(Client.GameRenderer.MainCamera.position); - SetPipeline(ChunkPipeline); + RenderSystem.MainCommandList.SetPipeline(ChunkPipeline); RenderSystem.MainCommandList.SetGraphicsResourceSet(0, Client.GameRenderer.CameraStateManager.CameraResourceSet); CommandList.SetGraphicsResourceSet(1, TerrainAtlas.AtlasResourceSet); diff --git a/Client/Rendering/World/WorldRenderer.cs b/Client/Rendering/World/WorldRenderer.cs index 7c11892..9eb44b9 100644 --- a/Client/Rendering/World/WorldRenderer.cs +++ b/Client/Rendering/World/WorldRenderer.cs @@ -13,6 +13,10 @@ public WorldRenderer(VoxelClient client) : base(client) { ChunkRenderer = new(client); } + public override void CreatePipeline(MainFramebuffer framebuffer) { + ChunkRenderer.CreatePipeline(framebuffer); + } + public override void Render(double delta) { if (Client.PlayerEntity?.world != targetWorld) { @@ -24,7 +28,7 @@ public override void Render(double delta) { if (targetWorld == null) return; - + ChunkRenderer.Render(delta); } diff --git a/Client/VoxelClient.cs b/Client/VoxelClient.cs index 8c0103a..62b101e 100644 --- a/Client/VoxelClient.cs +++ b/Client/VoxelClient.cs @@ -3,15 +3,12 @@ using Voxel.Client.Keybinding; using Voxel.Client.Network; using Voxel.Client.Rendering; -using Voxel.Client.Rendering.Debug; using Voxel.Client.Server; using Voxel.Client.World; using Voxel.Client.World.Entity; -using Voxel.Common.Collision; using Voxel.Common.Util; using Voxel.Common.World.Entity; using Voxel.Core; -using Voxel.Core.Util; namespace Voxel.Client; @@ -46,6 +43,8 @@ public class VoxelClient : Game { private dvec3 rayOrigin; private dvec3 rayDir; + private bool useMSAA = false; + public VoxelClient() { Instance = this; } @@ -84,8 +83,11 @@ public override void OnFrame(double delta, double tickAccumulator) { public override void OnTick() { Keybinds.Poll(); - if (Keybinds.Pause.justPressed) - GameRenderer.WorldRenderer.ChunkRenderer.Reload(); + if (Keybinds.Pause.justPressed) { + useMSAA = !useMSAA; + GameRenderer.SetMSAA(useMSAA ? 1u : 8u); + } + connection?.Tick(); world?.Tick(); } @@ -94,6 +96,7 @@ public override void OnWindowResize() { base.OnWindowResize(); GameRenderer.MainCamera.aspect = (float)NativeWindow.Width / NativeWindow.Height; + GameRenderer.RecreateMainFramebuffer(); } public override void Dispose() { diff --git a/Core/Game.cs b/Core/Game.cs index 60cb809..cea98b2 100644 --- a/Core/Game.cs +++ b/Core/Game.cs @@ -35,7 +35,9 @@ public void Run(int tps = 20, string windowTitle = "Game") { }; var gdo = new GraphicsDeviceOptions { - PreferDepthRangeZeroToOne = true, PreferStandardClipSpaceYDirection = true, SyncToVerticalBlank = true, SwapchainDepthFormat = PixelFormat.R32_Float, + PreferDepthRangeZeroToOne = true, + PreferStandardClipSpaceYDirection = true, + SyncToVerticalBlank = false, }; VeldridStartup.CreateWindowAndGraphicsDevice(wci, gdo, GraphicsBackend.Vulkan, out var nw, out var gd); @@ -80,15 +82,15 @@ public void Run(int tps = 20, string windowTitle = "Game") { } tickAccumulator = MathHelper.Repeat(tickAccumulator, tickFrequency); - + var inputState = NativeWindow.PumpEvents(); if (windowClosed) break; ImGuiRenderer.Update((float)difference, inputState); - RenderSystem.StartFrame(difference); OnFrame(difference, tickAccumulator); + RenderSystem.MainCommandList.SetFramebuffer(RenderSystem.GraphicsDevice.SwapchainFramebuffer); ImGuiRenderer.Render(GraphicsDevice, RenderSystem.MainCommandList); RenderSystem.EndFrame(); } diff --git a/Core/Rendering/RenderSystem.cs b/Core/Rendering/RenderSystem.cs index 932bce9..8dc2897 100644 --- a/Core/Rendering/RenderSystem.cs +++ b/Core/Rendering/RenderSystem.cs @@ -66,12 +66,6 @@ public RenderSystem(Game game, AssetReader assetReader) { GraphicsDevice.UpdateBuffer(CommonIndexBuffer, 0, commonBufferData); } - internal void StartFrame(double delta) { - MainCommandList.SetFramebuffer(GraphicsDevice.SwapchainFramebuffer); - MainCommandList.ClearColorTarget(0, RgbaFloat.Grey); - MainCommandList.ClearDepthStencil(1, 0); - } - internal void EndFrame() { RestartCommandBuffer(); GraphicsDevice.SwapBuffers();