diff --git a/src/Engine.Graphics.OpenGL/OpenGLInputState.cs b/src/Engine.Graphics.OpenGL/OpenGLInputState.cs index c75d12a..60c251b 100644 --- a/src/Engine.Graphics.OpenGL/OpenGLInputState.cs +++ b/src/Engine.Graphics.OpenGL/OpenGLInputState.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using Engine.Core; using Silk.NET.Input; +using System.Numerics; namespace Engine.Graphics.OpenGL; @@ -26,14 +27,14 @@ public sealed class OpenGLInputState : IInputState if (input.Keyboards.Count > 0) { _keyboard = input.Keyboards[0]; - _keyboard.KeyDown += (key, _) => + _keyboard.KeyDown += (kb, key, scancode) => { var k = SilkToKey(key); if (k == Engine.Core.Key.Unknown) return; if (!_keysDown.Contains(k)) _keysPressed.Add(k); _keysDown.Add(k); }; - _keyboard.KeyUp += (key, _) => + _keyboard.KeyUp += (kb, key, scancode) => { var k = SilkToKey(key); if (k == Engine.Core.Key.Unknown) return; @@ -44,18 +45,20 @@ public sealed class OpenGLInputState : IInputState if (input.Mice.Count > 0) { _mouse = input.Mice[0]; - _mouse.MouseMove += m => { MouseX = (int)m.Position.X; MouseY = (int)m.Position.Y; }; - _mouse.MouseDown += btn => { - if (btn == SilkMouseButton.Left) _mouseLeft = true; - if (btn == SilkMouseButton.Right) _mouseRight = true; - if (btn == SilkMouseButton.Middle) _mouseMiddle = true; + _mouse.MouseMove += (m, pos) => { MouseX = (int)pos.X; MouseY = (int)pos.Y; }; + _mouse.MouseDown += (m, btn) => + { + if (btn == MouseButton.Left) _mouseLeft = true; + if (btn == MouseButton.Right) _mouseRight = true; + if (btn == MouseButton.Middle) _mouseMiddle = true; }; - _mouse.MouseUp += btn => { - if (btn == SilkMouseButton.Left) _mouseLeft = false; - if (btn == SilkMouseButton.Right) _mouseRight = false; - if (btn == SilkMouseButton.Middle) _mouseMiddle = false; + _mouse.MouseUp += (m, btn) => + { + if (btn == MouseButton.Left) _mouseLeft = false; + if (btn == MouseButton.Right) _mouseRight = false; + if (btn == MouseButton.Middle) _mouseMiddle = false; }; - _mouse.Scroll += (_, y) => _mouseWheelDelta += (float)y; + _mouse.Scroll += (m, wheel) => _mouseWheelDelta += (float)wheel.Y; } } diff --git a/src/Engine.Graphics.OpenGL/OpenGLRenderContext.cs b/src/Engine.Graphics.OpenGL/OpenGLRenderContext.cs index 04cb815..6d4c539 100644 --- a/src/Engine.Graphics.OpenGL/OpenGLRenderContext.cs +++ b/src/Engine.Graphics.OpenGL/OpenGLRenderContext.cs @@ -5,9 +5,6 @@ using SilkWindow = Silk.NET.Windowing.IWindow; namespace Engine.Graphics.OpenGL; -/// -/// OpenGL render context using Silk.NET — owns the window and GL context. -/// public sealed class OpenGLRenderContext : IRenderContext { private readonly OpenGLWindow _window; @@ -22,9 +19,6 @@ public sealed class OpenGLRenderContext : IRenderContext _window = new OpenGLWindow("Cortex Engine (OpenGL)", width, height); } - /// - /// Called after the Silk.NET window has loaded its OpenGL context. - /// public void OnLoad() { _gl = _window.SilkView.CreateOpenGL(); @@ -39,7 +33,7 @@ public sealed class OpenGLRenderContext : IRenderContext public void Resize(int width, int height) { - // Silk.NET handles resize internally + _renderer?.SetScreenSize(width, height); } public void Dispose() diff --git a/src/Engine.Graphics.OpenGL/OpenGLRenderer.cs b/src/Engine.Graphics.OpenGL/OpenGLRenderer.cs index 69642b4..e51347c 100644 --- a/src/Engine.Graphics.OpenGL/OpenGLRenderer.cs +++ b/src/Engine.Graphics.OpenGL/OpenGLRenderer.cs @@ -13,30 +13,22 @@ using EngineTransform = Engine.Core.Components.Transform; namespace Engine.Graphics.OpenGL; -/// -/// OpenGL renderer using Silk.NET — full control over OpenGL state. -/// Supports shadow mapping, custom shaders, PBR lighting. -/// public sealed class OpenGLRenderer : IRenderer { private readonly GL _gl; private readonly uint _program; private readonly uint _shadowProgram; - private readonly uint _vao; private readonly uint _shadowFbo; private readonly uint _shadowTexture; private const int ShadowMapSize = 2048; private readonly Dictionary _meshCache = new(); - private readonly Dictionary _textureCache = new(); - // Uniform locations private readonly int _uMVP, _uModel, _uViewPos, _uMaterialColor, _uRoughness, _uMetallic; private readonly int _uAmbient, _uLightCount, _uLightDirs, _uLightIntensities, _uLightColors; private readonly int _uLightPositions, _uLightTypes, _uLightRanges; private readonly int _uLightViewProj, _uShadowMap, _uUseTexture; - // Light data private readonly float[] _lightDirs = new float[12]; private readonly float[] _lightPositions = new float[12]; private readonly float[] _lightIntensities = new float[4]; @@ -45,21 +37,19 @@ public sealed class OpenGLRenderer : IRenderer private readonly float[] _lightRanges = new float[4]; private int _lightCount; - private ScreenshotRequest? _pendingScreenshot; - private int _frameCount; + private int _screenWidth = 1280; + private int _screenHeight = 720; private bool _disposed; + private readonly float[] _matrixBuffer = new float[16]; public OpenGLRenderer(GL gl) { _gl = gl; _gl.Enable(GLEnum.DepthTest); - _gl.Enable(GLEnum.CullFace); - _gl.CullFace(GLEnum.Front); _program = CreateProgram(VertexShaderSource, FragmentShaderSource); _shadowProgram = CreateProgram(ShadowVertexSource, ShadowFragmentSource); - // Uniform locations _uMVP = _gl.GetUniformLocation(_program, "mvp"); _uModel = _gl.GetUniformLocation(_program, "model"); _uViewPos = _gl.GetUniformLocation(_program, "viewPos"); @@ -78,28 +68,30 @@ public sealed class OpenGLRenderer : IRenderer _uShadowMap = _gl.GetUniformLocation(_program, "shadowMap"); _uUseTexture = _gl.GetUniformLocation(_program, "useTexture"); - // Shadow FBO + // Shadow FBO with depth texture _shadowFbo = _gl.GenFramebuffer(); _gl.BindFramebuffer(GLEnum.Framebuffer, _shadowFbo); _shadowTexture = _gl.GenTexture(); _gl.BindTexture(GLEnum.Texture2D, _shadowTexture); - _gl.TexImage2D(GLEnum.Texture2D, 0, (int)GLEnum.DepthComponent, ShadowMapSize, ShadowMapSize, 0, GLEnum.DepthComponent, GLEnum.Float, null); + unsafe + { + _gl.TexImage2D(GLEnum.Texture2D, 0, (int)GLEnum.DepthComponent, (uint)ShadowMapSize, (uint)ShadowMapSize, 0, GLEnum.DepthComponent, GLEnum.Float, null); + } _gl.TexParameter(GLEnum.Texture2D, GLEnum.TextureMinFilter, (int)GLEnum.Nearest); _gl.TexParameter(GLEnum.Texture2D, GLEnum.TextureMagFilter, (int)GLEnum.Nearest); _gl.TexParameter(GLEnum.Texture2D, GLEnum.TextureWrapS, (int)GLEnum.ClampToEdge); _gl.TexParameter(GLEnum.Texture2D, GLEnum.TextureWrapT, (int)GLEnum.ClampToEdge); _gl.FramebufferTexture2D(GLEnum.Framebuffer, GLEnum.DepthAttachment, GLEnum.Texture2D, _shadowTexture, 0); - _gl.DrawBuffer(GLEnum.None); - _gl.ReadBuffer(GLEnum.None); + _gl.DrawBuffer(DrawBufferMode.None); + _gl.ReadBuffer(ReadBufferMode.None); _gl.BindFramebuffer(GLEnum.Framebuffer, 0); - - // Dummy VAO (required in core profile) - _vao = _gl.GenVertexArray(); } - public void RequestScreenshot(string outputPath) => _pendingScreenshot = new ScreenshotRequest(outputPath, null); - public bool IsScreenshotRequested => _pendingScreenshot != null; - public IScreenshotProvider ScreenshotProvider => new OpenGLScreenshotProvider(this); + public void RequestScreenshot(string outputPath) { } + public bool IsScreenshotRequested => false; + public IScreenshotProvider ScreenshotProvider => new OpenGLScreenshotProvider(); + + public void SetScreenSize(int w, int h) { _screenWidth = w; _screenHeight = h; } public void RenderWorld(World world) { @@ -120,9 +112,9 @@ public sealed class OpenGLRenderer : IRenderer lightViewProj = Matrix4x4.CreateOrthographicOffCenter(-15, 15, -15, 15, 1, 80) * Matrix4x4.CreateLookAt(lightPos, sceneCenter, up); - _gl.Viewport(0, 0, ShadowMapSize, ShadowMapSize); + _gl.Viewport(0, 0, (uint)ShadowMapSize, (uint)ShadowMapSize); _gl.BindFramebuffer(GLEnum.Framebuffer, _shadowFbo); - _gl.Clear(GLEnum.DepthBufferBit); + _gl.Clear((uint)GLEnum.DepthBufferBit); _gl.UseProgram(_shadowProgram); _gl.CullFace(GLEnum.Front); @@ -134,7 +126,12 @@ public sealed class OpenGLRenderer : IRenderer var glMesh = GetOrUploadMesh(e, mesh); var model = transform.GetMatrix(); var mvp = lightViewProj * model; - _gl.UniformMatrix4(shadowMvpLoc, 1, false, ref mvp); + CopyMatrixToBuffer(mvp); + unsafe + { + fixed (float* p = _matrixBuffer) + _gl.UniformMatrix4(shadowMvpLoc, 1, false, p); + } DrawMeshImmediate(glMesh); }); @@ -143,36 +140,42 @@ public sealed class OpenGLRenderer : IRenderer } // === PASS 2: Main render === - _gl.Viewport(0, 0, (uint)GetScreenWidth(), (uint)GetScreenHeight()); + _gl.Viewport(0, 0, (uint)_screenWidth, (uint)_screenHeight); _gl.ClearColor(0.098f, 0.118f, 0.157f, 1); - _gl.Clear(GLEnum.ColorBufferBit | GLEnum.DepthBufferBit); + _gl.Clear((uint)(GLEnum.ColorBufferBit | GLEnum.DepthBufferBit)); _gl.UseProgram(_program); var view = Matrix4x4.CreateLookAt(camera.Position, camera.Target, camera.Up); var proj = Matrix4x4.CreatePerspectiveFieldOfView(camera.FieldOfView, camera.AspectRatio, camera.NearPlane, camera.FarPlane); // Frame uniforms - _gl.Uniform3(_uViewPos, camera.Position); + _gl.Uniform3(_uViewPos, camera.Position.X, camera.Position.Y, camera.Position.Z); _gl.Uniform3(_uAmbient, 0.35f, 0.35f, 0.4f); _gl.Uniform1(_uLightCount, _lightCount); - _gl.Uniform3(_uLightDirs, 4, _lightDirs); - _gl.Uniform1(_uLightIntensities, 4, _lightIntensities); - _gl.Uniform3(_uLightColors, 4, _lightColors); - _gl.Uniform3(_uLightPositions, 4, _lightPositions); - _gl.Uniform1(_uLightTypes, 4, _lightTypes); - _gl.Uniform1(_uLightRanges, 4, _lightRanges); + unsafe + { + fixed (float* p = _lightDirs) _gl.Uniform3(_uLightDirs, 4, p); + fixed (float* p = _lightIntensities) _gl.Uniform1(_uLightIntensities, 4, p); + fixed (float* p = _lightColors) _gl.Uniform3(_uLightColors, 4, p); + fixed (float* p = _lightPositions) _gl.Uniform3(_uLightPositions, 4, p); + fixed (int* p = _lightTypes) _gl.Uniform1(_uLightTypes, 4, p); + fixed (float* p = _lightRanges) _gl.Uniform1(_uLightRanges, 4, p); + } - // Shadow uniforms if (hasDirLight) { - _gl.UniformMatrix4(_uLightViewProj, 1, false, ref lightViewProj); + CopyMatrixToBuffer(lightViewProj); + unsafe + { + fixed (float* p = _matrixBuffer) + _gl.UniformMatrix4(_uLightViewProj, 1, false, p); + } _gl.ActiveTexture(GLEnum.Texture1); _gl.BindTexture(GLEnum.Texture2D, _shadowTexture); _gl.Uniform1(_uShadowMap, 1); _gl.ActiveTexture(GLEnum.Texture0); } - // Draw all entities world.Each((Entity e, ref EngineMesh mesh, ref EngineTransform transform) => { if (e.Name() == "Grid") return; @@ -181,29 +184,23 @@ public sealed class OpenGLRenderer : IRenderer var model = transform.GetMatrix(); var mvp = proj * view * model; - _gl.UniformMatrix4(_uMVP, 1, false, ref mvp); - _gl.UniformMatrix4(_uModel, 1, false, ref model); - _gl.Uniform4(_uMaterialColor, new Vector4(material.Albedo, 1.0f)); + CopyMatrixToBuffer(mvp); + unsafe { fixed (float* pmvp = _matrixBuffer) _gl.UniformMatrix4(_uMVP, 1, false, pmvp); } + CopyMatrixToBuffer(model); + unsafe { fixed (float* pmodel = _matrixBuffer) _gl.UniformMatrix4(_uModel, 1, false, pmodel); } + _gl.Uniform4(_uMaterialColor, material.Albedo.X, material.Albedo.Y, material.Albedo.Z, 1.0f); _gl.Uniform1(_uRoughness, material.Roughness); _gl.Uniform1(_uMetallic, material.Metallic); _gl.Uniform1(_uUseTexture, 0); DrawMeshImmediate(glMesh); }); - - _frameCount++; - - if (_pendingScreenshot is { } req && _frameCount >= 3) - { - CaptureScreenshot(req); - _pendingScreenshot = null; - } } private void DrawMeshImmediate(GLMesh mesh) { _gl.BindVertexArray(mesh.Vao); - _gl.DrawElements(GLEnum.Triangles, (uint)mesh.IndexCount, GLEnum.UnsignedInt, 0); + unsafe { _gl.DrawElements(GLEnum.Triangles, (uint)mesh.IndexCount, GLEnum.UnsignedInt, null); } _gl.BindVertexArray(0); } @@ -215,9 +212,7 @@ public sealed class OpenGLRenderer : IRenderer var vao = _gl.GenVertexArray(); _gl.BindVertexArray(vao); - // Position - var posVbo = _gl.GenBuffer(); - _gl.BindBuffer(GLEnum.ArrayBuffer, posVbo); + // Position (location 0) var positions = new float[mesh.Vertices.Length * 3]; for (var i = 0; i < mesh.Vertices.Length; i++) { @@ -225,13 +220,13 @@ public sealed class OpenGLRenderer : IRenderer positions[i * 3 + 1] = mesh.Vertices[i].Position.Y; positions[i * 3 + 2] = mesh.Vertices[i].Position.Z; } - _gl.BufferData(GLEnum.ArrayBuffer, (nuint)(positions.Length * sizeof(float)), positions, GLEnum.StaticDraw); + var posVbo = _gl.GenBuffer(); + _gl.BindBuffer(GLEnum.ArrayBuffer, posVbo); + unsafe { fixed (float* p = positions) _gl.BufferData(GLEnum.ArrayBuffer, (nuint)(positions.Length * sizeof(float)), p, GLEnum.StaticDraw); } _gl.EnableVertexAttribArray(0); _gl.VertexAttribPointer(0, 3, GLEnum.Float, false, 3 * sizeof(float), 0); - // Normal - var nrmVbo = _gl.GenBuffer(); - _gl.BindBuffer(GLEnum.ArrayBuffer, nrmVbo); + // Normal (location 1) var normals = new float[mesh.Vertices.Length * 3]; for (var i = 0; i < mesh.Vertices.Length; i++) { @@ -239,13 +234,13 @@ public sealed class OpenGLRenderer : IRenderer normals[i * 3 + 1] = mesh.Vertices[i].Normal.Y; normals[i * 3 + 2] = mesh.Vertices[i].Normal.Z; } - _gl.BufferData(GLEnum.ArrayBuffer, (nuint)(normals.Length * sizeof(float)), normals, GLEnum.StaticDraw); + var nrmVbo = _gl.GenBuffer(); + _gl.BindBuffer(GLEnum.ArrayBuffer, nrmVbo); + unsafe { fixed (float* p = normals) _gl.BufferData(GLEnum.ArrayBuffer, (nuint)(normals.Length * sizeof(float)), p, GLEnum.StaticDraw); } _gl.EnableVertexAttribArray(1); _gl.VertexAttribPointer(1, 3, GLEnum.Float, false, 3 * sizeof(float), 0); - // Color - var colVbo = _gl.GenBuffer(); - _gl.BindBuffer(GLEnum.ArrayBuffer, colVbo); + // Color (location 2) var colors = new float[mesh.Vertices.Length * 4]; for (var i = 0; i < mesh.Vertices.Length; i++) { @@ -254,18 +249,20 @@ public sealed class OpenGLRenderer : IRenderer colors[i * 4 + 2] = mesh.Vertices[i].Color.Z; colors[i * 4 + 3] = 1.0f; } - _gl.BufferData(GLEnum.ArrayBuffer, (nuint)(colors.Length * sizeof(float)), colors, GLEnum.StaticDraw); + var colVbo = _gl.GenBuffer(); + _gl.BindBuffer(GLEnum.ArrayBuffer, colVbo); + unsafe { fixed (float* p = colors) _gl.BufferData(GLEnum.ArrayBuffer, (nuint)(colors.Length * sizeof(float)), p, GLEnum.StaticDraw); } _gl.EnableVertexAttribArray(2); _gl.VertexAttribPointer(2, 4, GLEnum.Float, false, 4 * sizeof(float), 0); // Indices var ebo = _gl.GenBuffer(); _gl.BindBuffer(GLEnum.ElementArrayBuffer, ebo); - _gl.BufferData(GLEnum.ElementArrayBuffer, (nuint)(mesh.Indices.Length * sizeof(uint)), mesh.Indices, GLEnum.StaticDraw); + unsafe { fixed (uint* p = mesh.Indices) _gl.BufferData(GLEnum.ElementArrayBuffer, (nuint)(mesh.Indices.Length * sizeof(uint)), p, GLEnum.StaticDraw); } _gl.BindVertexArray(0); - var glMesh = new GLMesh { Vao = vao, IndexCount = mesh.Indices.Length }; + var glMesh = new GLMesh(vao, mesh.Indices.Length); _meshCache[e] = glMesh; return glMesh; } @@ -298,11 +295,7 @@ public sealed class OpenGLRenderer : IRenderer _lightTypes[0] = (int)LightType.Directional; _lightRanges[0] = 20; count = 1; } - - for (var i = count; i < 4; i++) - { - _lightIntensities[i] = 0; _lightTypes[i] = 0; - } + for (var i = count; i < 4; i++) { _lightIntensities[i] = 0; _lightTypes[i] = 0; } _lightCount = count; } @@ -313,28 +306,25 @@ public sealed class OpenGLRenderer : IRenderer return cam; } - private int GetScreenWidth() => 1280; - private int GetScreenHeight() => 720; - private uint CreateProgram(string vs, string fs) { var vertex = _gl.CreateShader(GLEnum.VertexShader); _gl.ShaderSource(vertex, vs); _gl.CompileShader(vertex); _gl.GetShader(vertex, ShaderParameterName.CompileStatus, out int vStatus); - if (vStatus == 0) throw new Exception($"Vertex shader: {_gl.GetShaderInfoLog(vertex)}"); + if (vStatus == 0) throw new Exception($"VS: {_gl.GetShaderInfoLog(vertex)}"); var fragment = _gl.CreateShader(GLEnum.FragmentShader); _gl.ShaderSource(fragment, fs); _gl.CompileShader(fragment); _gl.GetShader(fragment, ShaderParameterName.CompileStatus, out int fStatus); - if (fStatus == 0) throw new Exception($"Fragment shader: {_gl.GetShaderInfoLog(fragment)}"); + if (fStatus == 0) throw new Exception($"FS: {_gl.GetShaderInfoLog(fragment)}"); var program = _gl.CreateProgram(); _gl.AttachShader(program, vertex); _gl.AttachShader(program, fragment); _gl.LinkProgram(program); - _gl.GetProgram(program, ProgramProperty.LinkStatus, out int lStatus); + _gl.GetProgram(program, ProgramPropertyARB.LinkStatus, out int lStatus); if (lStatus == 0) throw new Exception($"Link: {_gl.GetProgramInfoLog(program)}"); _gl.DeleteShader(vertex); @@ -342,18 +332,19 @@ public sealed class OpenGLRenderer : IRenderer return program; } - private void CaptureScreenshot(ScreenshotRequest req) + private void CopyMatrixToBuffer(Matrix4x4 m) { - // TODO: implement via glReadPixels + ImageSharp - Console.WriteLine($"[OpenGL] Screenshot saved: {req.Path}"); + _matrixBuffer[0] = m.M11; _matrixBuffer[1] = m.M12; _matrixBuffer[2] = m.M13; _matrixBuffer[3] = m.M14; + _matrixBuffer[4] = m.M21; _matrixBuffer[5] = m.M22; _matrixBuffer[6] = m.M23; _matrixBuffer[7] = m.M24; + _matrixBuffer[8] = m.M31; _matrixBuffer[9] = m.M32; _matrixBuffer[10] = m.M33; _matrixBuffer[11] = m.M34; + _matrixBuffer[12] = m.M41; _matrixBuffer[13] = m.M42; _matrixBuffer[14] = m.M43; _matrixBuffer[15] = m.M44; } public void Dispose() { if (_disposed) return; _disposed = true; - foreach (var mesh in _meshCache.Values) - _gl.DeleteVertexArray(mesh.Vao); + foreach (var m in _meshCache.Values) _gl.DeleteVertexArray(m.Vao); _meshCache.Clear(); _gl.DeleteProgram(_program); _gl.DeleteProgram(_shadowProgram); @@ -361,31 +352,28 @@ public sealed class OpenGLRenderer : IRenderer _gl.DeleteTexture(_shadowTexture); } - // Shaders private const string ShadowVertexSource = @"#version 330 core -layout(location = 0) in vec3 aPos; +layout(location=0) in vec3 aPos; uniform mat4 mvp; -void main() { gl_Position = mvp * vec4(aPos, 1.0); }"; - +void main(){gl_Position=mvp*vec4(aPos,1.0);}"; private const string ShadowFragmentSource = @"#version 330 core -void main() {}"; +void main(){}"; private const string VertexShaderSource = @"#version 330 core -layout(location = 0) in vec3 aPos; -layout(location = 1) in vec3 aNormal; -layout(location = 2) in vec4 aColor; +layout(location=0) in vec3 aPos; +layout(location=1) in vec3 aNormal; +layout(location=2) in vec4 aColor; uniform mat4 mvp; uniform mat4 model; out vec3 vNormal; out vec3 vWorldPos; out vec4 vColor; -void main() -{ - vec4 worldPos = model * vec4(aPos, 1.0); - vWorldPos = worldPos.xyz; - vNormal = mat3(transpose(inverse(model))) * aNormal; - vColor = aColor; - gl_Position = mvp * vec4(aPos, 1.0); +void main(){ + vec4 wp=model*vec4(aPos,1.0); + vWorldPos=wp.xyz; + vNormal=mat3(transpose(inverse(model)))*aNormal; + vColor=aColor; + gl_Position=mvp*vec4(aPos,1.0); }"; private const string FragmentShaderSource = @"#version 330 core @@ -407,97 +395,77 @@ uniform int lightTypes[4]; uniform float lightRanges[4]; uniform mat4 lightViewProj; uniform sampler2D shadowMap; +uniform int useTexture; -vec3 ACESFilm(vec3 x) -{ +vec3 ACESFilm(vec3 x){ const float a=2.51,b=0.03,c=2.43,d=0.59,e=0.14; return clamp((x*(a*x+b))/(x*(c*x+d)+e),0.0,1.0); } - -float Attenuation(float dist, float range) -{ +float Attenuation(float dist,float range){ float r=max(range,0.001),d=max(dist,0.001); - float x=d/r, x2=x*x, x4=x2*x2; + float x=d/r,x2=x*x,x4=x2*x2; return clamp(1.0/(1.0+25.0*x4),0.0,1.0)*smoothstep(1.0,0.0,x); } - -float CalculateShadow(vec3 worldPos) -{ - vec4 lp = lightViewProj * vec4(worldPos, 1.0); - vec3 ndc = lp.xyz / lp.w; - vec3 uvw = ndc * 0.5 + 0.5; - if (uvw.x < 0.0 || uvw.x > 1.0 || uvw.y < 0.0 || uvw.y > 1.0 || uvw.z > 1.0) - return 1.0; - float bias = 0.005; - vec2 ts = vec2(1.0 / 2048.0); - float s = 0.0; - for (int x = -1; x <= 1; x++) { - for (int y = -1; y <= 1; y++) { - float d = texture(shadowMap, uvw.xy + vec2(x, y) * ts).r; - s += (uvw.z - bias > d) ? 0.3 : 1.0; +float CalculateShadow(vec3 worldPos){ + vec4 lp=lightViewProj*vec4(worldPos,1.0); + vec3 ndc=lp.xyz/lp.w; + vec3 uvw=ndc*0.5+0.5; + if(uvw.x<0.0||uvw.x>1.0||uvw.y<0.0||uvw.y>1.0||uvw.z>1.0) return 1.0; + float bias=0.005; + vec2 ts=vec2(1.0/2048.0); + float s=0.0; + for(int x=-1;x<=1;x++){ + for(int y=-1;y<=1;y++){ + float d=texture(shadowMap,uvw.xy+vec2(x,y)*ts).r; + s+=(uvw.z-bias>d)?0.3:1.0; } } - return s / 9.0; + return s/9.0; } - -void main() -{ - vec3 normal = normalize(vNormal); - vec3 albedo = pow(vColor.rgb * materialColor.rgb, vec3(2.2)); - vec3 viewDir = normalize(viewPos - vWorldPos); - float rough = clamp(roughness, 0.05, 1.0); - float metal = clamp(metallic, 0.0, 1.0); - - vec3 skyColor = ambientColor; - vec3 groundColor = ambientColor * 0.2; - float hemisphere = 0.5 + 0.5 * normal.y; - vec3 result = albedo * mix(groundColor, skyColor, hemisphere) * 0.4; - - float shadow = 1.0; - if (lightCount > 0 && lightTypes[0] == 0) - shadow = CalculateShadow(vWorldPos); - - vec3 F0 = mix(vec3(0.04), albedo, metal); - float shininess = mix(8.0, 256.0, 1.0 - rough); - - for (int i = 0; i < lightCount; i++) - { - vec3 L; - float atten = 1.0; - if (lightTypes[i] == 1) { - vec3 toLight = lightPositions[i] - vWorldPos; - float dist = length(toLight); - L = toLight / max(dist, 0.001); - atten = Attenuation(dist, lightRanges[i]); - } else { - L = normalize(-lightDirs[i]); - } - float lightShadow = (i == 0 && lightTypes[0] == 0) ? shadow : 1.0; - vec3 H = normalize(L + viewDir); - float NdotL = max(dot(normal, L), 0.0); - float NdotH = max(dot(normal, H), 0.0); - float HdotV = max(dot(H, viewDir), 0.0); - float spec = pow(NdotH, shininess); - vec3 fresnel = F0 + (1.0 - F0) * pow(1.0 - HdotV, 5.0); - vec3 specularColor = mix(fresnel, albedo * fresnel, metal); - vec3 diffuse = albedo * lightColors[i] * NdotL * lightIntensities[i] * atten * 1.5 * lightShadow; - vec3 specular = specularColor * spec * lightIntensities[i] * atten * lightShadow; - diffuse *= (1.0 - fresnel * (1.0 - metal * 0.5)); - result += diffuse + specular; +void main(){ + vec3 normal=normalize(vNormal); + vec3 albedo=pow(vColor.rgb*materialColor.rgb,vec3(2.2)); + vec3 viewDir=normalize(viewPos-vWorldPos); + float rough=clamp(roughness,0.05,1.0); + float metal=clamp(metallic,0.0,1.0); + vec3 skyColor=ambientColor; + vec3 groundColor=ambientColor*0.2; + float hemisphere=0.5+0.5*normal.y; + vec3 result=albedo*mix(groundColor,skyColor,hemisphere)*0.4; + float shadow=1.0; + if(lightCount>0&&lightTypes[0]==0) shadow=CalculateShadow(vWorldPos); + vec3 F0=mix(vec3(0.04),albedo,metal); + float shininess=mix(8.0,256.0,1.0-rough); + for(int i=0;i? Tcs); private sealed class OpenGLScreenshotProvider : IScreenshotProvider { - private readonly OpenGLRenderer _r; - public OpenGLScreenshotProvider(OpenGLRenderer r) => _r = r; public Task CaptureAsync(string outputPath) => Task.FromResult(Array.Empty()); } } diff --git a/src/Engine.Graphics.OpenGL/OpenGLWindow.cs b/src/Engine.Graphics.OpenGL/OpenGLWindow.cs index f49f3d4..854e642 100644 --- a/src/Engine.Graphics.OpenGL/OpenGLWindow.cs +++ b/src/Engine.Graphics.OpenGL/OpenGLWindow.cs @@ -1,16 +1,12 @@ +using System; +using System.Collections.Generic; using Engine.Core; -using Engine.Core.Components; using Silk.NET.Input; +using Silk.NET.Windowing; using SilkWindow = Silk.NET.Windowing.IWindow; -using SilkKey = Silk.NET.Input.Key; -using SilkMouseButton = Silk.NET.Input.MouseButton; -using EngineKey = Engine.Core.Key; namespace Engine.Graphics.OpenGL; -/// -/// Silk.NET windowing-backed implementation of IWindow. -/// public sealed class OpenGLWindow : Engine.Core.IWindow, IDisposable { private readonly SilkWindow _silkWindow; @@ -23,7 +19,6 @@ public sealed class OpenGLWindow : Engine.Core.IWindow, IDisposable public bool ShouldClose => _shouldClose || _silkWindow.IsClosing; IInputState Engine.Core.IWindow.Input => _input; public nint Handle => 0; - public SilkWindow SilkView => _silkWindow; public OpenGLWindow(string title, int width, int height) @@ -34,7 +29,7 @@ public sealed class OpenGLWindow : Engine.Core.IWindow, IDisposable options.VSync = true; options.API = new GraphicsAPI(ContextAPI.OpenGL, ContextProfile.Core, ContextFlags.Default, new APIVersion(3, 3)); - _silkWindow = Silk.NET.Windowing.Window.Create(options); + _silkWindow = Window.Create(options); _silkWindow.Closing += () => _shouldClose = true; } @@ -44,13 +39,8 @@ public sealed class OpenGLWindow : Engine.Core.IWindow, IDisposable _input.Initialize(inputContext); } - public void PumpEvents() - { - _silkWindow.DoEvents(); - } - + public void PumpEvents() => _silkWindow.DoEvents(); public void Close() => _shouldClose = true; - public string[] GetRequiredVulkanExtensions() => Array.Empty(); public void Dispose() @@ -61,4 +51,3 @@ public sealed class OpenGLWindow : Engine.Core.IWindow, IDisposable _silkWindow.Dispose(); } } -