From 22f69204ca84af2ec8be40bef862dd39865dcd87 Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Wed, 7 Feb 2024 12:06:23 +0100 Subject: [PATCH] Separated ShaderObjects to its own class --- PCK-Studio/PckStudio.csproj | 5 +- PCK-Studio/Rendering/Renderer.cs | 3 +- PCK-Studio/Rendering/Shader/ShaderObject.cs | 62 +++++++++++++ .../{Shader.cs => Shader/ShaderProgram.cs} | 49 +++++----- .../Rendering/{ => Shader}/ShaderSource.cs | 4 +- PCK-Studio/Rendering/SkinRenderer.cs | 89 +++++++++++++------ .../shader/skyboxFragmentShader.glsl | 3 +- 7 files changed, 161 insertions(+), 54 deletions(-) create mode 100644 PCK-Studio/Rendering/Shader/ShaderObject.cs rename PCK-Studio/Rendering/{Shader.cs => Shader/ShaderProgram.cs} (79%) rename PCK-Studio/Rendering/{ => Shader}/ShaderSource.cs (83%) diff --git a/PCK-Studio/PckStudio.csproj b/PCK-Studio/PckStudio.csproj index 61ec8eee..5f2ab09c 100644 --- a/PCK-Studio/PckStudio.csproj +++ b/PCK-Studio/PckStudio.csproj @@ -159,8 +159,9 @@ - - + + + UserControl diff --git a/PCK-Studio/Rendering/Renderer.cs b/PCK-Studio/Rendering/Renderer.cs index 85dd789a..84cad74d 100644 --- a/PCK-Studio/Rendering/Renderer.cs +++ b/PCK-Studio/Rendering/Renderer.cs @@ -16,12 +16,13 @@ * 3. This notice may not be removed or altered from any source distribution. **/ using OpenTK.Graphics.OpenGL; +using PckStudio.Rendering.Shader; namespace PckStudio.Rendering { internal static class Renderer { - public static void Draw(Shader shader, RenderBuffer renderBuffer) + public static void Draw(ShaderProgram shader, RenderBuffer renderBuffer) { shader.Bind(); renderBuffer.VertexArray.Bind(); diff --git a/PCK-Studio/Rendering/Shader/ShaderObject.cs b/PCK-Studio/Rendering/Shader/ShaderObject.cs new file mode 100644 index 00000000..1d594f3f --- /dev/null +++ b/PCK-Studio/Rendering/Shader/ShaderObject.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTK.Graphics.OpenGL; + +namespace PckStudio.Rendering.Shader +{ + internal class ShaderObject + { + private int _shaderId; + private ShaderSource _source; + private int _compileStatus; + + internal bool CompileStatusOK => _compileStatus != 0; + + private ShaderObject(ShaderSource source) + { + _shaderId = GL.CreateShader(source.Type); + _source = source; + _compileStatus = 0; + } + + internal static ShaderObject CreateNew(ShaderSource shaderSource) + { + var shaderObject = new ShaderObject(shaderSource); + shaderObject.Compile(); + if (!shaderObject.CompileStatusOK) + { + shaderObject.Delete(); + return null; + } + return shaderObject; + } + + internal void Delete() + { + GL.DeleteShader(_shaderId); + } + + private void Compile() + { + GL.ShaderSource(_shaderId, _source.Source); + GL.CompileShader(_shaderId); + + GL.GetShader(_shaderId, ShaderParameter.CompileStatus, out _compileStatus); + + if (!CompileStatusOK) + { + string infoLog = GL.GetShaderInfoLog(_shaderId); + Debug.Fail(infoLog); + } + } + + internal void AttachToProgram(int programId) + { + GL.AttachShader(programId, _shaderId); + } + } +} diff --git a/PCK-Studio/Rendering/Shader.cs b/PCK-Studio/Rendering/Shader/ShaderProgram.cs similarity index 79% rename from PCK-Studio/Rendering/Shader.cs rename to PCK-Studio/Rendering/Shader/ShaderProgram.cs index 67f2f613..df029499 100644 --- a/PCK-Studio/Rendering/Shader.cs +++ b/PCK-Studio/Rendering/Shader/ShaderProgram.cs @@ -8,14 +8,14 @@ using System.Threading.Tasks; using OpenTK; using OpenTK.Graphics.OpenGL; -namespace PckStudio.Rendering +namespace PckStudio.Rendering.Shader { - internal class Shader : IDisposable + internal class ShaderProgram : IDisposable { private int _programId; private Dictionary locationCache = new Dictionary(); - private Shader(int programId) + private ShaderProgram(int programId) { _programId = programId; } @@ -25,7 +25,6 @@ namespace PckStudio.Rendering GL.UseProgram(_programId); } - [Conditional("DEBUG")] public void Unbind() { GL.UseProgram(0); @@ -43,6 +42,12 @@ namespace PckStudio.Rendering GL.Uniform1(location, value); } + public void SetUniform1(string name, float value) + { + int location = GetUniformLocation(name); + GL.Uniform1(location, value); + } + public void SetUniform2(string name, Vector2 value) { int location = GetUniformLocation(name); @@ -94,21 +99,13 @@ namespace PckStudio.Rendering return shaderId; } - public static Shader Create(string vertexSource, string fragmentSource) - { - return Create( - new ShaderSource(ShaderType.VertexShader, vertexSource), - new ShaderSource(ShaderType.FragmentShader, fragmentSource) - ); - } - private bool Link() { GL.LinkProgram(_programId); GL.GetProgram(_programId, GetProgramParameterName.LinkStatus, out int status); bool success = status != 0; if (!success) - Debug.WriteLine(GL.GetProgramInfoLog(_programId), category: nameof(Shader)); + Debug.WriteLine(GL.GetProgramInfoLog(_programId), category: nameof(ShaderProgram)); return success; } @@ -119,33 +116,41 @@ namespace PckStudio.Rendering GL.GetProgram(_programId, GetProgramParameterName.ValidateStatus, out int status); bool success = status != 0; if (!success) - Debug.WriteLine(GL.GetProgramInfoLog(_programId), category: nameof(Shader)); + Debug.WriteLine(GL.GetProgramInfoLog(_programId), category: nameof(ShaderProgram)); return success; #else return true; #endif } - public static Shader Create(params ShaderSource[] shaderSources) + public static ShaderProgram Create(string vertexSource, string fragmentSource) + { + return Create( + new ShaderSource(ShaderType.VertexShader, vertexSource), + new ShaderSource(ShaderType.FragmentShader, fragmentSource) + ); + } + + public static ShaderProgram Create(params ShaderSource[] shaderSources) { int programId = GL.CreateProgram(); - var shaderIds = new List(shaderSources.Length); + var shaderObjects = new List(shaderSources.Length); foreach (var shaderSource in shaderSources) { - int shaderId = CompileShader(shaderSource.Type, shaderSource.Source); - GL.AttachShader(programId, shaderId); - shaderIds.Add(shaderId); + ShaderObject shaderObject = ShaderObject.CreateNew(shaderSource); + shaderObject.AttachToProgram(programId); + shaderObjects.Add(shaderObject); } - var shader = new Shader(programId); + var shader = new ShaderProgram(programId); bool success = shader.Link(); Debug.Assert(success, "Shader Program linking failed."); - foreach (var shaderId in shaderIds) + foreach (var shaderObject in shaderObjects) { - GL.DeleteShader(shaderId); + shaderObject.Delete(); } return shader; } diff --git a/PCK-Studio/Rendering/ShaderSource.cs b/PCK-Studio/Rendering/Shader/ShaderSource.cs similarity index 83% rename from PCK-Studio/Rendering/ShaderSource.cs rename to PCK-Studio/Rendering/Shader/ShaderSource.cs index d7b9007a..f923949a 100644 --- a/PCK-Studio/Rendering/ShaderSource.cs +++ b/PCK-Studio/Rendering/Shader/ShaderSource.cs @@ -5,9 +5,9 @@ using System.Text; using System.Threading.Tasks; using OpenTK.Graphics.OpenGL; -namespace PckStudio.Rendering +namespace PckStudio.Rendering.Shader { - internal readonly struct ShaderSource + public readonly struct ShaderSource { public readonly ShaderType Type; public readonly string Source; diff --git a/PCK-Studio/Rendering/SkinRenderer.cs b/PCK-Studio/Rendering/SkinRenderer.cs index 7ee43723..990f2792 100644 --- a/PCK-Studio/Rendering/SkinRenderer.cs +++ b/PCK-Studio/Rendering/SkinRenderer.cs @@ -33,6 +33,7 @@ using System.Drawing.Imaging; using System.IO; using PckStudio.Rendering.Camera; using PckStudio.Rendering.Texture; +using PckStudio.Rendering.Shader; namespace PckStudio.Rendering { @@ -158,11 +159,12 @@ namespace PckStudio.Rendering private Point PreviousMouseLocation; private Point CurrentMouseLocation; - private Shader _skinShader; + private ShaderProgram _skinShader; private SkinANIM _anim; private Image _texture; private Shader _skyboxShader; + private ShaderProgram _skyboxShader; private RenderBuffer _skyboxRenderBuffer; private CubeTexture _skyboxTexture; private float skyboxRotation = 0f; @@ -198,12 +200,27 @@ namespace PckStudio.Rendering private Matrix4 RightLegMatrix { get; set; } = Matrix4.Identity; private Matrix4 LeftLegMatrix { get; set; } = Matrix4.Identity; + private static Vector3[] cubeVertices = new Vector3[] + { + // front + new Vector3(-1.0f, -1.0f, 1.0f), + new Vector3( 1.0f, -1.0f, 1.0f), + new Vector3( 1.0f, 1.0f, 1.0f), + new Vector3(-1.0f, 1.0f, 1.0f), + // back + new Vector3(-1.0f, -1.0f, -1.0f), + new Vector3( 1.0f, -1.0f, -1.0f), + new Vector3( 1.0f, 1.0f, -1.0f), + new Vector3(-1.0f, 1.0f, -1.0f) + }; public SkinRenderer() : base() { - InitializeComponent(); InitializeCamera(); InitializeSkinData(); - ANIM ??= SkinANIM.Empty; + InitializeShaders(); + InitializeComponent(); + + ANIM ??= new SkinANIM(SkinAnimMask.RESOLUTION_64x64); OnTimerTick = AnimationTick; ModelData = new ObservableCollection(); ModelData.CollectionChanged += ModelData_CollectionChanged; @@ -321,9 +338,8 @@ namespace PckStudio.Rendering leftLegOverlay.Submit(); } - protected override void OnLoad(EventArgs e) + private void InitializeShaders() { - base.OnLoad(e); if (DesignMode) return; @@ -331,22 +347,34 @@ namespace PckStudio.Rendering Trace.TraceInformation(GL.GetString(StringName.Version)); - // Initialize skybox shader + // Skin shader { - Vector3[] cubeVertices = new Vector3[] - { - // front - new Vector3(-1.0f, -1.0f, 1.0f), - new Vector3( 1.0f, -1.0f, 1.0f), - new Vector3( 1.0f, 1.0f, 1.0f), - new Vector3(-1.0f, 1.0f, 1.0f), - // back - new Vector3(-1.0f, -1.0f, -1.0f), - new Vector3( 1.0f, -1.0f, -1.0f), - new Vector3( 1.0f, 1.0f, -1.0f), - new Vector3(-1.0f, 1.0f, -1.0f) - }; + _skinShader = ShaderProgram.Create( + new ShaderSource(ShaderType.VertexShader, Resources.skinVertexShader), + new ShaderSource(ShaderType.FragmentShader, Resources.skinFragmentShader), + new ShaderSource(ShaderType.GeometryShader, Resources.skinGeometryShader) + ); + _skinShader.Bind(); + _skinShader.SetUniform1("u_Texture", 0); + _skinShader.Validate(); + GLErrorCheck(); + skinTexture = new Texture2D(0); + skinTexture.PixelFormat = OpenTK.Graphics.OpenGL.PixelFormat.Bgra; + skinTexture.InternalPixelFormat = PixelInternalFormat.Rgba8; + skinTexture.MinFilter = TextureMinFilter.Nearest; + skinTexture.MagFilter = TextureMagFilter.Nearest; + skinTexture.WrapS = TextureWrapMode.Repeat; + skinTexture.WrapT = TextureWrapMode.Repeat; + + Texture ??= Resources.classic_template; + + _skinShader.Unbind(); + GLErrorCheck(); + } + + // Skybox shader + { var skyboxVAO = new VertexArray(); var skyboxVBO = new VertexBuffer(cubeVertices, cubeVertices.Length * Vector3.SizeInBytes); var vboLayout = new VertexBufferLayout(); @@ -377,6 +405,12 @@ namespace PckStudio.Rendering skyboxVAO.Unbind(); skybocIBO.Unbind(); + _skyboxShader = ShaderProgram.Create(Resources.skyboxVertexShader, Resources.skyboxFragmentShader); + _skyboxShader.Bind(); + _skyboxShader.SetUniform1("skybox", 1); + _skyboxShader.SetUniform1("brightness", 1f); + _skyboxShader.Validate(); + string customSkyboxFilepath = Path.Combine(Program.AppData, "cubemap.png"); Image skyboxImage = File.Exists(customSkyboxFilepath) ? Image.FromFile(customSkyboxFilepath) @@ -553,21 +587,23 @@ namespace PckStudio.Rendering MakeCurrent(); - Camera.Update(AspectRatio); + GL.Viewport(Size); + GL.ClearColor(BackColor); + GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); + GL.Enable(EnableCap.DepthTest); // Enable correct Z Drawings + + // Render (custom) skin + { var viewProjection = Camera.GetViewProjection(); _skinShader.Bind(); _skinShader.SetUniformMat4("u_ViewProjection", ref viewProjection); _skinShader.SetUniform2("u_TexSize", new Vector2(TextureSize.Width, TextureSize.Height)); - GL.Viewport(Size); - - GL.ClearColor(BackColor); - GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); + skinTexture.Bind(); GL.Enable(EnableCap.Texture2D); // Enable textures - GL.Enable(EnableCap.DepthTest); // Enable correct Z Drawings GL.DepthFunc(DepthFunction.Lequal); // Enable correct Z Drawings GL.DepthMask(true); @@ -620,7 +656,8 @@ namespace PckStudio.Rendering RenderBodyPart(new Vector3( 4f, 2f, 0f), new Vector3(slimModel ? -4f : -5f, -2f, 0f), RightArmMatrix * armRightMatrix, modelMatrix, "ARM0", "SLEEVE0"); RenderBodyPart(new Vector3(-4f, 2f, 0f), new Vector3( 5f, -2f, 0f), LeftArmMatrix * armLeftMatrix , modelMatrix, "ARM1", "SLEEVE1"); RenderBodyPart(new Vector3(0f, 12f, 0f), new Vector3(-2f, -12f, 0f), RightLegMatrix * legRightMatrix, modelMatrix, "LEG0", "PANTS0"); - RenderBodyPart(new Vector3(0f, 12f, 0f), new Vector3( 2f, -12f, 0f), LeftLegMatrix * legLeftMatrix , modelMatrix, "LEG1", "PANTS1"); + RenderBodyPart(new Vector3(0f, 12f, 0f), new Vector3(2f, -12f, 0f), LeftLegMatrix * legLeftMatrix, modelMatrix, "LEG1", "PANTS1"); + } // Render Skybox { diff --git a/PCK-Studio/Resources/shader/skyboxFragmentShader.glsl b/PCK-Studio/Resources/shader/skyboxFragmentShader.glsl index b242f456..f356fd63 100644 --- a/PCK-Studio/Resources/shader/skyboxFragmentShader.glsl +++ b/PCK-Studio/Resources/shader/skyboxFragmentShader.glsl @@ -3,10 +3,11 @@ layout(location = 0) out vec4 color; uniform samplerCube skybox; +uniform float brightness; in vec3 texCoords; void main() { - color = texture(skybox, texCoords); + color = texture(skybox, texCoords) * vec4(vec3(clamp(brightness, 0.0, 1.0)), 1.0); } \ No newline at end of file