From e2848da051ef7190700e2aebdeddb1264a30a377 Mon Sep 17 00:00:00 2001 From: Mathew O'Dwyer Date: Tue, 9 Jan 2024 18:53:03 +1100 Subject: [PATCH] Apply gamma correction using OpenGL and not shaders for now. --- FinalEngine.Examples.Sponza/Program.cs | 11 ++--- .../Buffers/OpenGLFrameBuffer.cs | 42 +++++++++---------- .../Invocation/IOpenGLInvoker.cs | 4 ++ .../Invocation/OpenGLInvoker.cs | 10 +++++ .../OpenGLGPUResourceFactory.cs | 6 +-- .../OpenGLRasterizer.cs | 15 +++++++ .../OpenGLRenderDevice.cs | 12 ++++++ FinalEngine.Rendering/Buffers/IFrameBuffer.cs | 8 +--- .../FinalEngine.Rendering.csproj | 6 +-- FinalEngine.Rendering/IGPUResourceFactory.cs | 2 +- FinalEngine.Rendering/IRasterizer.cs | 2 + FinalEngine.Rendering/IRenderDevice.cs | 2 + .../Textures/Texture2DResourceLoader.cs | 16 ++++--- .../RasterStateDescription.cs | 8 ++++ FinalEngine.Rendering/RenderingEngine.cs | 2 + .../{ => Batching}/sprite-geometry.fesp | 0 .../{ => Batching}/sprite-geometry.frag | 0 .../{ => Batching}/sprite-geometry.vert | 0 FinalEngine.Rendering/Textures/SizedFormat.cs | 2 + 19 files changed, 100 insertions(+), 48 deletions(-) rename FinalEngine.Rendering/Resources/Shaders/{ => Batching}/sprite-geometry.fesp (100%) rename FinalEngine.Rendering/Resources/Shaders/{ => Batching}/sprite-geometry.frag (100%) rename FinalEngine.Rendering/Resources/Shaders/{ => Batching}/sprite-geometry.vert (100%) diff --git a/FinalEngine.Examples.Sponza/Program.cs b/FinalEngine.Examples.Sponza/Program.cs index fc55d067..dadca3cf 100644 --- a/FinalEngine.Examples.Sponza/Program.cs +++ b/FinalEngine.Examples.Sponza/Program.cs @@ -18,7 +18,6 @@ using FinalEngine.Rendering.OpenGL.Invocation; using FinalEngine.Rendering.Primitives; using FinalEngine.Rendering.Renderers; -using FinalEngine.Rendering.Textures; using FinalEngine.Resources; using FinalEngine.Runtime; using FinalEngine.Runtime.Invocation; @@ -76,7 +75,7 @@ private static void Main() renderPipeline.Initialize(); ResourceManager.Instance.RegisterLoader(new ShaderResourceLoader(fileSystem, renderDevice)); - ResourceManager.Instance.RegisterLoader(new Texture2DResourceLoader(fileSystem, renderDevice.Factory)); + ResourceManager.Instance.RegisterLoader(new Texture2DResourceLoader(fileSystem, renderDevice)); ResourceManager.Instance.RegisterLoader(new ShaderProgramResourceLoader(ResourceManager.Instance, renderDevice, fileSystem)); renderDevice.Pipeline.AddShaderHeader("lighting", fileSystem.File.ReadAllText("Resources\\Shaders\\Includes\\lighting.glsl")); @@ -128,9 +127,7 @@ private static void Main() var material = new Material() { - DiffuseTexture = ResourceManager.Instance.LoadResource("Resources\\Textures\\Bricks\\bricks_diffuse.tga"), - NormalTexture = ResourceManager.Instance.LoadResource("Resources\\Textures\\Bricks\\bricks_normal.tga"), - SpecularTexture = ResourceManager.Instance.LoadResource("Resources\\Textures\\Bricks\\bricks_specular.tga"), + Shininess = 16.0f, }; bool isRunning = true; @@ -146,8 +143,8 @@ private static void Main() var light = new Light() { Type = LightType.Directional, - Intensity = 0.4f, - Color = new Vector3(0.6f, 0.4f, 0.2f), + Intensity = 0.5f, + Color = new Vector3(1f), Transform = new Transform() { Rotation = Quaternion.CreateFromAxisAngle(Vector3.UnitX, MathHelper.DegreesToRadians(45.0f)), diff --git a/FinalEngine.Rendering.OpenGL/Buffers/OpenGLFrameBuffer.cs b/FinalEngine.Rendering.OpenGL/Buffers/OpenGLFrameBuffer.cs index 837abf1f..37dc7952 100644 --- a/FinalEngine.Rendering.OpenGL/Buffers/OpenGLFrameBuffer.cs +++ b/FinalEngine.Rendering.OpenGL/Buffers/OpenGLFrameBuffer.cs @@ -6,53 +6,57 @@ namespace FinalEngine.Rendering.OpenGL.Buffers; using System; using System.Collections.Generic; -using System.Linq; using FinalEngine.Rendering.Buffers; using FinalEngine.Rendering.Exceptions; using FinalEngine.Rendering.OpenGL.Invocation; using FinalEngine.Rendering.OpenGL.Textures; -using FinalEngine.Rendering.Textures; using OpenTK.Graphics.OpenGL4; -public class OpenGLFrameBuffer : IFrameBuffer, IOpenGLFrameBuffer, IDisposable +public class OpenGLFrameBuffer : IFrameBuffer, IOpenGLFrameBuffer { private readonly IOpenGLInvoker invoker; private int rendererID; - public OpenGLFrameBuffer(IOpenGLInvoker invoker, IReadOnlyList colorTargets, IOpenGLTexture? depthTarget) + public OpenGLFrameBuffer(IOpenGLInvoker invoker, IReadOnlyList? colorTargets, IOpenGLTexture? depthTarget) { - ArgumentNullException.ThrowIfNull(colorTargets, nameof(colorTargets)); this.invoker = invoker ?? throw new ArgumentNullException(nameof(invoker)); int maximumColorAttachments = this.invoker.GetInteger(GetPName.MaxColorAttachments); + int colorAttachmentCount = colorTargets?.Count ?? 0; - if (colorTargets.Count > maximumColorAttachments) + if (colorAttachmentCount > maximumColorAttachments) { throw new FrameBufferTargetException($"The number of {nameof(colorTargets)} should not exceed the maximum number of color attachmemts: '{maximumColorAttachments}'."); } - this.DepthTarget = (ITexture2D?)depthTarget; - this.ColorTargets = colorTargets.Cast(); this.rendererID = invoker.CreateFramebuffer(); - int attachmentCount = colorTargets.Count; - - for (int i = 0; i < attachmentCount; i++) + for (int i = 0; i < colorAttachmentCount; i++) { - colorTargets[i].Attach(FramebufferAttachment.ColorAttachment0 + i, this.rendererID); + colorTargets![i].Attach(FramebufferAttachment.ColorAttachment0 + i, this.rendererID); } - Span bufs = stackalloc DrawBuffersEnum[attachmentCount]; - - for (int i = 0; i < attachmentCount; i++) + if (colorAttachmentCount > 0) { - bufs[i] = DrawBuffersEnum.ColorAttachment0 + i; + Span bufs = stackalloc DrawBuffersEnum[colorAttachmentCount]; + + for (int i = 0; i < colorAttachmentCount; i++) + { + bufs[i] = DrawBuffersEnum.ColorAttachment0 + i; + } + + this.invoker.NamedFramebufferDrawBuffers(this.rendererID, colorAttachmentCount, ref bufs[0]); } - this.invoker.NamedFramebufferDrawBuffers(this.rendererID, attachmentCount, ref bufs[0]); depthTarget?.Attach(FramebufferAttachment.DepthStencilAttachment, this.rendererID); + if (colorAttachmentCount <= 0) + { + this.invoker.NamedFramebufferDrawBuffer(this.rendererID, DrawBufferMode.None); + this.invoker.NamedFramebufferReadBuffer(this.rendererID, ReadBufferMode.None); + } + var status = invoker.CheckNamedFramebufferStatus(this.rendererID, FramebufferTarget.Framebuffer); if (status != FramebufferStatus.FramebufferComplete) @@ -66,10 +70,6 @@ public OpenGLFrameBuffer(IOpenGLInvoker invoker, IReadOnlyList c this.Dispose(false); } - public IEnumerable ColorTargets { get; } - - public ITexture2D? DepthTarget { get; } - protected bool IsDisposed { get; private set; } public void Bind() diff --git a/FinalEngine.Rendering.OpenGL/Invocation/IOpenGLInvoker.cs b/FinalEngine.Rendering.OpenGL/Invocation/IOpenGLInvoker.cs index c67d53de..e55b1969 100644 --- a/FinalEngine.Rendering.OpenGL/Invocation/IOpenGLInvoker.cs +++ b/FinalEngine.Rendering.OpenGL/Invocation/IOpenGLInvoker.cs @@ -119,8 +119,12 @@ void NamedBufferData(int buffer, int size, T2[] data, BufferUsageHint usage) void NamedBufferSubData(int buffer, IntPtr offset, int size, T3[] data) where T3 : struct; + void NamedFramebufferDrawBuffer(int framebuffer, DrawBufferMode buf); + void NamedFramebufferDrawBuffers(int fb, int n, ref DrawBuffersEnum bufs); + void NamedFramebufferReadBuffer(int framebuffer, ReadBufferMode buf); + void NamedFramebufferTexture(int framebuffer, FramebufferAttachment attachment, int texture, int level); void PolygonMode(MaterialFace face, PolygonMode mode); diff --git a/FinalEngine.Rendering.OpenGL/Invocation/OpenGLInvoker.cs b/FinalEngine.Rendering.OpenGL/Invocation/OpenGLInvoker.cs index d0878ac8..70944e88 100644 --- a/FinalEngine.Rendering.OpenGL/Invocation/OpenGLInvoker.cs +++ b/FinalEngine.Rendering.OpenGL/Invocation/OpenGLInvoker.cs @@ -427,6 +427,16 @@ public void NamedFramebufferDrawBuffers(int fb, int n, ref DrawBuffersEnum bufs) GL.NamedFramebufferDrawBuffers(fb, n, ref bufs); } + public void NamedFramebufferDrawBuffer(int framebuffer, DrawBufferMode buf) + { + GL.NamedFramebufferDrawBuffer(framebuffer, buf); + } + + public void NamedFramebufferReadBuffer(int framebuffer, ReadBufferMode buf) + { + GL.NamedFramebufferReadBuffer(framebuffer, buf); + } + private static void DebugCallback( DebugSource source, DebugType type, diff --git a/FinalEngine.Rendering.OpenGL/OpenGLGPUResourceFactory.cs b/FinalEngine.Rendering.OpenGL/OpenGLGPUResourceFactory.cs index 80af1908..d3163e33 100644 --- a/FinalEngine.Rendering.OpenGL/OpenGLGPUResourceFactory.cs +++ b/FinalEngine.Rendering.OpenGL/OpenGLGPUResourceFactory.cs @@ -31,16 +31,14 @@ public OpenGLGPUResourceFactory(IOpenGLInvoker invoker, IEnumMapper mapper) this.mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); } - public IFrameBuffer CreateFrameBuffer(IReadOnlyCollection colorTargets, ITexture2D? depthTarget = null) + public IFrameBuffer CreateFrameBuffer(IReadOnlyCollection? colorTargets, ITexture2D? depthTarget = null) { - ArgumentNullException.ThrowIfNull(colorTargets, nameof(colorTargets)); - if (depthTarget is not null and not IOpenGLTexture) { throw new ArgumentException($"The specified {nameof(depthTarget)} parameter is not of type {nameof(IOpenGLTexture)}.", nameof(depthTarget)); } - return new OpenGLFrameBuffer(this.invoker, colorTargets.Cast().ToList().AsReadOnly(), (IOpenGLTexture?)depthTarget); + return new OpenGLFrameBuffer(this.invoker, colorTargets?.Cast().ToList().AsReadOnly(), (IOpenGLTexture?)depthTarget); } public IIndexBuffer CreateIndexBuffer(BufferUsageType type, IReadOnlyCollection data, int sizeInBytes) diff --git a/FinalEngine.Rendering.OpenGL/OpenGLRasterizer.cs b/FinalEngine.Rendering.OpenGL/OpenGLRasterizer.cs index 8e54d7a6..da449eda 100644 --- a/FinalEngine.Rendering.OpenGL/OpenGLRasterizer.cs +++ b/FinalEngine.Rendering.OpenGL/OpenGLRasterizer.cs @@ -16,12 +16,19 @@ public class OpenGLRasterizer : IRasterizer private readonly IEnumMapper mapper; + private RasterStateDescription currentDescription; + public OpenGLRasterizer(IOpenGLInvoker invoker, IEnumMapper mapper) { this.invoker = invoker ?? throw new ArgumentNullException(nameof(invoker)); this.mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); } + public RasterStateDescription GetRasterState() + { + return this.currentDescription; + } + public Rectangle GetViewport() { int[] data = new int[4]; @@ -38,12 +45,20 @@ public Rectangle GetViewport() public void SetRasterState(RasterStateDescription description) { + if (this.currentDescription == description) + { + return; + } + this.invoker.Cap(EnableCap.CullFace, description.CullEnabled); this.invoker.Cap(EnableCap.ScissorTest, description.ScissorEnabled); this.invoker.Cap(EnableCap.Multisample, description.MultiSamplingEnabled); + this.invoker.Cap(EnableCap.FramebufferSrgb, description.GammaCorrectionEnabled); this.invoker.CullFace(this.mapper.Forward(description.CullMode)); this.invoker.FrontFace(this.mapper.Forward(description.WindingDirection)); this.invoker.PolygonMode(MaterialFace.FrontAndBack, this.mapper.Forward(description.FillMode)); + + this.currentDescription = description; } public void SetScissor(Rectangle rectangle) diff --git a/FinalEngine.Rendering.OpenGL/OpenGLRenderDevice.cs b/FinalEngine.Rendering.OpenGL/OpenGLRenderDevice.cs index 7a1a9834..10dd1ccd 100644 --- a/FinalEngine.Rendering.OpenGL/OpenGLRenderDevice.cs +++ b/FinalEngine.Rendering.OpenGL/OpenGLRenderDevice.cs @@ -104,6 +104,7 @@ public OpenGLRenderDevice(IOpenGLInvoker invoker) { SizedFormat.Rg8, SizedInternalFormat.Rg8 }, { SizedFormat.Rgb8, All.Rgb8 }, { SizedFormat.Rgba8, SizedInternalFormat.Rgba8 }, + { SizedFormat.Srgba, SizedInternalFormat.Srgb8Alpha8 }, { BufferUsageType.Static, BufferUsageHint.StaticDraw }, { BufferUsageType.Dynamic, BufferUsageHint.DynamicDraw }, }; @@ -139,4 +140,15 @@ public void DrawIndices(PrimitiveTopology topology, int first, int count) { this.invoker.DrawElements(this.mapper.Forward(topology), count, DrawElementsType.UnsignedInt, first); } + + public void Initialize() + { + this.Rasterizer.SetRasterState(default); + + this.OutputMerger.SetStencilState(default); + this.OutputMerger.SetDepthState(default); + this.OutputMerger.SetBlendState(default); + + this.Pipeline.SetFrameBuffer(null); + } } diff --git a/FinalEngine.Rendering/Buffers/IFrameBuffer.cs b/FinalEngine.Rendering/Buffers/IFrameBuffer.cs index 277aa520..eebf36fa 100644 --- a/FinalEngine.Rendering/Buffers/IFrameBuffer.cs +++ b/FinalEngine.Rendering/Buffers/IFrameBuffer.cs @@ -4,12 +4,8 @@ namespace FinalEngine.Rendering.Buffers; -using System.Collections.Generic; -using FinalEngine.Rendering.Textures; +using System; -public interface IFrameBuffer +public interface IFrameBuffer : IDisposable { - IEnumerable ColorTargets { get; } - - ITexture2D? DepthTarget { get; } } diff --git a/FinalEngine.Rendering/FinalEngine.Rendering.csproj b/FinalEngine.Rendering/FinalEngine.Rendering.csproj index b5450fb1..6b9abafa 100644 --- a/FinalEngine.Rendering/FinalEngine.Rendering.csproj +++ b/FinalEngine.Rendering/FinalEngine.Rendering.csproj @@ -73,13 +73,13 @@ PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest diff --git a/FinalEngine.Rendering/IGPUResourceFactory.cs b/FinalEngine.Rendering/IGPUResourceFactory.cs index 6749e5b7..2b87330e 100644 --- a/FinalEngine.Rendering/IGPUResourceFactory.cs +++ b/FinalEngine.Rendering/IGPUResourceFactory.cs @@ -11,7 +11,7 @@ namespace FinalEngine.Rendering; public interface IGPUResourceFactory { - IFrameBuffer CreateFrameBuffer(IReadOnlyCollection colorTargets, ITexture2D? depthTarget = null); + IFrameBuffer CreateFrameBuffer(IReadOnlyCollection? colorTargets, ITexture2D? depthTarget = null); IIndexBuffer CreateIndexBuffer(BufferUsageType type, IReadOnlyCollection data, int sizeInBytes) where T : struct; diff --git a/FinalEngine.Rendering/IRasterizer.cs b/FinalEngine.Rendering/IRasterizer.cs index 15cffc71..c9b91511 100644 --- a/FinalEngine.Rendering/IRasterizer.cs +++ b/FinalEngine.Rendering/IRasterizer.cs @@ -8,6 +8,8 @@ namespace FinalEngine.Rendering; public interface IRasterizer { + RasterStateDescription GetRasterState(); + Rectangle GetViewport(); void SetRasterState(RasterStateDescription description); diff --git a/FinalEngine.Rendering/IRenderDevice.cs b/FinalEngine.Rendering/IRenderDevice.cs index 1a4796e8..43453c5f 100644 --- a/FinalEngine.Rendering/IRenderDevice.cs +++ b/FinalEngine.Rendering/IRenderDevice.cs @@ -32,4 +32,6 @@ public interface IRenderDevice void Clear(Color color, float depth = 1.0f, int stencil = 0); void DrawIndices(PrimitiveTopology topology, int first, int count); + + void Initialize(); } diff --git a/FinalEngine.Rendering/Loaders/Textures/Texture2DResourceLoader.cs b/FinalEngine.Rendering/Loaders/Textures/Texture2DResourceLoader.cs index 19b8bb27..c840dfaa 100644 --- a/FinalEngine.Rendering/Loaders/Textures/Texture2DResourceLoader.cs +++ b/FinalEngine.Rendering/Loaders/Textures/Texture2DResourceLoader.cs @@ -17,16 +17,16 @@ namespace FinalEngine.Rendering.Loaders.Textures; public class Texture2DResourceLoader : ResourceLoaderBase { - private readonly IGPUResourceFactory factory; - private readonly IFileSystem fileSystem; private readonly IImageInvoker invoker; - public Texture2DResourceLoader(IFileSystem fileSystem, IGPUResourceFactory factory) + private readonly IRenderDevice renderDevice; + + public Texture2DResourceLoader(IFileSystem fileSystem, IRenderDevice renderDevice) { this.fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); - this.factory = factory ?? throw new ArgumentNullException(nameof(factory)); + this.renderDevice = renderDevice ?? throw new ArgumentNullException(nameof(renderDevice)); this.invoker = new ImageInvoker(); } @@ -63,7 +63,9 @@ public override ITexture2D LoadResource(string filePath) } } - return this.factory.CreateTexture2D( + var rasterState = this.renderDevice.Rasterizer.GetRasterState(); + + return this.renderDevice.Factory.CreateTexture2D( new Texture2DDescription() { Width = width, @@ -79,7 +81,9 @@ public override ITexture2D LoadResource(string filePath) GenerateMipmaps = true, }, - pixels.ToArray()); + pixels.ToArray(), + PixelFormat.Rgba, + rasterState.GammaCorrectionEnabled ? SizedFormat.Srgba : SizedFormat.Rgb8); } } } diff --git a/FinalEngine.Rendering/RasterStateDescription.cs b/FinalEngine.Rendering/RasterStateDescription.cs index 12081738..e3075d0d 100644 --- a/FinalEngine.Rendering/RasterStateDescription.cs +++ b/FinalEngine.Rendering/RasterStateDescription.cs @@ -33,6 +33,8 @@ public struct RasterStateDescription : IEquatable private RasterMode? fillMode; + private bool? gammaCorrectionEnabled; + private WindingDirection? windingDirection; public bool CullEnabled { get; set; } @@ -49,6 +51,12 @@ public RasterMode FillMode set { this.fillMode = value; } } + public bool GammaCorrectionEnabled + { + readonly get { return this.gammaCorrectionEnabled ?? true; } + set { this.gammaCorrectionEnabled = value; } + } + public bool MultiSamplingEnabled { get; set; } public bool ScissorEnabled { get; set; } diff --git a/FinalEngine.Rendering/RenderingEngine.cs b/FinalEngine.Rendering/RenderingEngine.cs index 290f96d6..abae9fe1 100644 --- a/FinalEngine.Rendering/RenderingEngine.cs +++ b/FinalEngine.Rendering/RenderingEngine.cs @@ -45,6 +45,8 @@ public RenderingEngine(IRenderDevice renderDevice, IGeometryRenderer geometryRen Type = LightType.Ambient, Intensity = 0.1f, }; + + this.renderDevice.Initialize(); } private IShaderProgram GeometryProgram diff --git a/FinalEngine.Rendering/Resources/Shaders/sprite-geometry.fesp b/FinalEngine.Rendering/Resources/Shaders/Batching/sprite-geometry.fesp similarity index 100% rename from FinalEngine.Rendering/Resources/Shaders/sprite-geometry.fesp rename to FinalEngine.Rendering/Resources/Shaders/Batching/sprite-geometry.fesp diff --git a/FinalEngine.Rendering/Resources/Shaders/sprite-geometry.frag b/FinalEngine.Rendering/Resources/Shaders/Batching/sprite-geometry.frag similarity index 100% rename from FinalEngine.Rendering/Resources/Shaders/sprite-geometry.frag rename to FinalEngine.Rendering/Resources/Shaders/Batching/sprite-geometry.frag diff --git a/FinalEngine.Rendering/Resources/Shaders/sprite-geometry.vert b/FinalEngine.Rendering/Resources/Shaders/Batching/sprite-geometry.vert similarity index 100% rename from FinalEngine.Rendering/Resources/Shaders/sprite-geometry.vert rename to FinalEngine.Rendering/Resources/Shaders/Batching/sprite-geometry.vert diff --git a/FinalEngine.Rendering/Textures/SizedFormat.cs b/FinalEngine.Rendering/Textures/SizedFormat.cs index 10b60bf4..51149994 100644 --- a/FinalEngine.Rendering/Textures/SizedFormat.cs +++ b/FinalEngine.Rendering/Textures/SizedFormat.cs @@ -13,4 +13,6 @@ public enum SizedFormat Rgb8, Rgba8, + + Srgba, }