From 50bb77cb2d0796bdf3edf6d50f5131dc6fb0befc Mon Sep 17 00:00:00 2001 From: MDietermann Date: Thu, 28 May 2026 12:08:58 +0200 Subject: [PATCH] feat: add shader pipeline and chunk GLSL shaders --- Assets/shaders/chunk.frag | 13 ++++++++ Assets/shaders/chunk.vert | 19 ++++++++++++ Rendering/Shader.cs | 64 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 Assets/shaders/chunk.frag create mode 100644 Assets/shaders/chunk.vert create mode 100644 Rendering/Shader.cs diff --git a/Assets/shaders/chunk.frag b/Assets/shaders/chunk.frag new file mode 100644 index 0000000..1dbd372 --- /dev/null +++ b/Assets/shaders/chunk.frag @@ -0,0 +1,13 @@ +#version 330 core +in vec2 vUv; +in float vShade; + +out vec4 FragColor; + +uniform sampler2D atlas; + +void main() +{ + vec4 texel = texture(atlas, vUv); + FragColor = vec4(texel.rgb * vShade, 1.0); +} diff --git a/Assets/shaders/chunk.vert b/Assets/shaders/chunk.vert new file mode 100644 index 0000000..61b38fb --- /dev/null +++ b/Assets/shaders/chunk.vert @@ -0,0 +1,19 @@ +#version 330 core +layout(location = 0) in vec3 aPos; +layout(location = 1) in vec2 aUv; +layout(location = 2) in float aShade; + +out vec2 vUv; +out float vShade; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +void main() +{ + vUv = aUv; + vShade = aShade; + // Vector-on-left convention; matrices are uploaded with transpose=true. + gl_Position = vec4(aPos, 1.0) * model * view * projection; +} diff --git a/Rendering/Shader.cs b/Rendering/Shader.cs new file mode 100644 index 0000000..6f6bc6f --- /dev/null +++ b/Rendering/Shader.cs @@ -0,0 +1,64 @@ +using OpenTK.Graphics.OpenGL4; +using OpenTK.Mathematics; + +namespace VoxelEngine.Rendering; + +public sealed class Shader : IDisposable +{ + private readonly int _handle; + private readonly Dictionary _uniforms = new(); + + public Shader(string vertexPath, string fragmentPath) + { + int vertex = CompileFromFile(ShaderType.VertexShader, vertexPath); + int fragment = CompileFromFile(ShaderType.FragmentShader, fragmentPath); + + _handle = GL.CreateProgram(); + GL.AttachShader(_handle, vertex); + GL.AttachShader(_handle, fragment); + GL.LinkProgram(_handle); + + GL.GetProgram(_handle, GetProgramParameterName.LinkStatus, out int linked); + if (linked == 0) + throw new InvalidOperationException($"Program link failed: {GL.GetProgramInfoLog(_handle)}"); + + GL.DetachShader(_handle, vertex); + GL.DetachShader(_handle, fragment); + GL.DeleteShader(vertex); + GL.DeleteShader(fragment); + } + + public void Use() => GL.UseProgram(_handle); + + public void SetMatrix4(string name, Matrix4 value) => + GL.UniformMatrix4(Location(name), true, ref value); + + public void SetInt(string name, int value) => + GL.Uniform1(Location(name), value); + + private int Location(string name) + { + if (!_uniforms.TryGetValue(name, out int location)) + { + location = GL.GetUniformLocation(_handle, name); + _uniforms[name] = location; + } + return location; + } + + private static int CompileFromFile(ShaderType type, string path) + { + string source = File.ReadAllText(path); + int shader = GL.CreateShader(type); + GL.ShaderSource(shader, source); + GL.CompileShader(shader); + + GL.GetShader(shader, ShaderParameter.CompileStatus, out int compiled); + if (compiled == 0) + throw new InvalidOperationException($"{type} compile failed ({path}): {GL.GetShaderInfoLog(shader)}"); + + return shader; + } + + public void Dispose() => GL.DeleteProgram(_handle); +}