diff --git a/FinalEngine.Examples.Sponza/Program.cs b/FinalEngine.Examples.Sponza/Program.cs index 12ea804e..4ecc6db8 100644 --- a/FinalEngine.Examples.Sponza/Program.cs +++ b/FinalEngine.Examples.Sponza/Program.cs @@ -81,7 +81,7 @@ private static void Main() var watch = new Stopwatch(); var watchInvoker = new StopwatchInvoker(watch); - var gameTime = new GameTime(watchInvoker, 120.0f); + var gameTime = new GameTime(watchInvoker, 10000.0f); float fieldDepth = 10.0f; float fieldWidth = 10.0f; @@ -223,9 +223,9 @@ private static void Main() geometryRenderer.Enqueue(model); - for (var i = 0; i < 2; i++) + for (var i = 0; i < 5; i++) { - for (var j = 0; j < 2; j++) + for (var j = 0; j < 5; j++) { lightRenderer.Enqueue(new Light() { diff --git a/FinalEngine.Rendering.OpenGL/OpenGLPipeline.cs b/FinalEngine.Rendering.OpenGL/OpenGLPipeline.cs index 286bb83e..1b68bf0e 100644 --- a/FinalEngine.Rendering.OpenGL/OpenGLPipeline.cs +++ b/FinalEngine.Rendering.OpenGL/OpenGLPipeline.cs @@ -18,14 +18,10 @@ namespace FinalEngine.Rendering.OpenGL; public class OpenGLPipeline : IPipeline { - private const int InitialSizeCapacity = 50; - private readonly IOpenGLInvoker invoker; private readonly Dictionary nameToHeaderMap; - private readonly Dictionary uniformLocations; - private IOpenGLFrameBuffer? boundFrameBuffer; private IOpenGLShaderProgram? boundProgram; @@ -35,7 +31,6 @@ public class OpenGLPipeline : IPipeline public OpenGLPipeline(IOpenGLInvoker invoker) { this.invoker = invoker ?? throw new ArgumentNullException(nameof(invoker)); - this.uniformLocations = new Dictionary(InitialSizeCapacity); this.nameToHeaderMap = []; } @@ -106,8 +101,6 @@ public void SetShaderProgram(IShaderProgram program) throw new ArgumentException($"The specified {nameof(program)} parameter is not of type {nameof(IOpenGLShaderProgram)}.", nameof(program)); } - this.uniformLocations.Clear(); - this.boundProgram = glProgram; this.boundProgram.Bind(); } @@ -254,18 +247,6 @@ private bool TryGetUniformLocation(string name, out int location) return false; } - if (!this.uniformLocations.TryGetValue(name, out location)) - { - location = this.boundProgram.GetUniformLocation(name); - - if (location == -1) - { - return false; - } - - this.uniformLocations.Add(name, location); - } - - return true; + return this.boundProgram.TryGetUniformLocation(name, out location); } } diff --git a/FinalEngine.Rendering.OpenGL/Pipeline/IOpenGLShaderProgram.cs b/FinalEngine.Rendering.OpenGL/Pipeline/IOpenGLShaderProgram.cs index f10991a5..7635c674 100644 --- a/FinalEngine.Rendering.OpenGL/Pipeline/IOpenGLShaderProgram.cs +++ b/FinalEngine.Rendering.OpenGL/Pipeline/IOpenGLShaderProgram.cs @@ -10,5 +10,5 @@ public interface IOpenGLShaderProgram : IShaderProgram { void Bind(); - int GetUniformLocation(string name); + bool TryGetUniformLocation(string name, out int location); } diff --git a/FinalEngine.Rendering.OpenGL/Pipeline/OpenGLShaderProgram.cs b/FinalEngine.Rendering.OpenGL/Pipeline/OpenGLShaderProgram.cs index f227ccec..1a5ef6b2 100644 --- a/FinalEngine.Rendering.OpenGL/Pipeline/OpenGLShaderProgram.cs +++ b/FinalEngine.Rendering.OpenGL/Pipeline/OpenGLShaderProgram.cs @@ -13,6 +13,8 @@ public class OpenGLShaderProgram : IOpenGLShaderProgram, IDisposable { private readonly IOpenGLInvoker invoker; + private readonly Dictionary uniformNameToLocationMap; + private int rendererID; public OpenGLShaderProgram(IOpenGLInvoker invoker, IReadOnlyCollection shaders) @@ -20,6 +22,7 @@ public OpenGLShaderProgram(IOpenGLInvoker invoker, IReadOnlyCollection, IRenderQueue, IGeometryRenderer { - private readonly Dictionary> modelToTransformMap; + private readonly Dictionary> materialToRenderModelMap; private readonly IRenderDevice renderDevice; public GeometryRenderer(IRenderDevice renderDevice) { this.renderDevice = renderDevice ?? throw new ArgumentNullException(nameof(renderDevice)); - this.modelToTransformMap = []; + this.materialToRenderModelMap = []; } public bool CanRender { - get { return this.modelToTransformMap.Count != 0; } + get { return this.materialToRenderModelMap.Count != 0; } } public void Clear() { - this.modelToTransformMap.Clear(); + this.materialToRenderModelMap.Clear(); } public void Enqueue(RenderModel renderable) { ArgumentNullException.ThrowIfNull(renderable, nameof(renderable)); - if (!this.modelToTransformMap.TryGetValue(renderable, out var batch)) + if (!this.materialToRenderModelMap.TryGetValue(renderable.Material, out var batch)) { - batch = new List(); - this.modelToTransformMap.Add(renderable, batch); + batch = new List(); + this.materialToRenderModelMap.Add(renderable.Material, batch); } - ((IList)batch).Add(renderable.Transform); + batch.Add(renderable); } public void Enqueue(Model renderable) @@ -61,20 +61,17 @@ public void Enqueue(Model renderable) public void Render() { - foreach (var kvp in this.modelToTransformMap) + foreach (var kvp in this.materialToRenderModelMap) { - var model = kvp.Key; + var material = kvp.Key; var batch = kvp.Value; - if (!this.TryPrepareModel(model)) - { - continue; - } + material.Bind(this.renderDevice.Pipeline); - foreach (var transform in batch) + foreach (var renderModel in batch) { - this.UpdateUniforms(transform); - this.RenderBatchInstance(model.Mesh); + this.UpdateUniforms(renderModel.Transform); + this.RenderBatchInstance(renderModel.Mesh); } } } @@ -86,25 +83,8 @@ private void RenderBatchInstance(IMesh? mesh) return; } - mesh.Draw(this.renderDevice); - } - - private bool TryPrepareModel(RenderModel model) - { - ArgumentNullException.ThrowIfNull(model, nameof(model)); - - var mesh = model.Mesh; - var material = model.Material; - - if (mesh == null) - { - return false; - } - - material.Bind(this.renderDevice.Pipeline); mesh.Bind(this.renderDevice.InputAssembler); - - return true; + mesh.Draw(this.renderDevice); } private void UpdateUniforms(Transform transform) diff --git a/FinalEngine.Rendering/Resources/Shaders/Includes/lighting.glsl b/FinalEngine.Rendering/Resources/Shaders/Includes/lighting.glsl index cd362352..a0bc0db5 100644 --- a/FinalEngine.Rendering/Resources/Shaders/Includes/lighting.glsl +++ b/FinalEngine.Rendering/Resources/Shaders/Includes/lighting.glsl @@ -44,25 +44,34 @@ struct SpotLight float outerRadius; }; -uniform bool u_test; - vec3 CalculateLight(LightBase light, Material material, vec3 direction, vec3 normal, vec3 viewPosition, vec3 fragPosition, vec2 texCoord) { normal = normalize(normal); direction = normalize(direction); + vec3 diffuseColor = vec3(0, 0, 0); + vec3 specularColor = vec3(0, 0, 0); + // As the angle widens, diffuse shading decreases. float diffuseShading = max(dot(direction, normal), 0.0); - vec3 diffuseColor = diffuseShading * light.color * light.intensity * texture(material.diffuseTexture, texCoord).rgb; - // Now let's measure the angle between the normal and halfway point of the light and view direction. - vec3 viewDirection = normalize(viewPosition - fragPosition); - vec3 halfWayDirection = normalize(direction + viewDirection); + if (diffuseShading > 0) + { + diffuseColor = diffuseShading * light.color * light.intensity * texture(material.diffuseTexture, texCoord).rgb; + + // Now let's measure the angle between the normal and halfway point of the light and view direction. + vec3 viewDirection = normalize(viewPosition - fragPosition); + vec3 halfWayDirection = normalize(direction + viewDirection); - // As the angle widens, specular shading decreases. - // This is why we raise to the power of shininess. - float specularShading = pow(max(dot(normal, halfWayDirection), 0.0), material.shininess); - vec3 specularColor = specularShading * light.color * light.intensity * texture(material.specularTexture, texCoord).rgb; + // As the angle widens, specular shading decreases. + // This is why we raise to the power of shininess. + float specularShading = pow(max(dot(normal, halfWayDirection), 0.0), material.shininess); + + if (specularShading > 0) + { + specularColor = specularShading * light.color * light.intensity * texture(material.specularTexture, texCoord).rgb; + } + } // Calculate emission map here as it's a lighting effect. vec3 emissionColor = texture(material.emissionTexture, texCoord).rgb; @@ -70,8 +79,6 @@ vec3 CalculateLight(LightBase light, Material material, vec3 direction, vec3 nor return diffuseColor + specularColor + emissionColor; } - - vec3 CalculateDirectionalLight(DirectionalLight light, Material material, vec3 normal, vec3 viewPosition, vec3 fragPosition, vec2 texCoord) { return CalculateLight(light.base, material, -light.direction, normal, viewPosition, fragPosition, texCoord);