Separated ShaderObjects to its own class

This commit is contained in:
miku-666
2024-02-07 12:06:23 +01:00
parent 2e13d410a7
commit 22f69204ca
7 changed files with 161 additions and 54 deletions

View File

@@ -159,8 +159,9 @@
<Compile Include="Rendering\RenderBuffer.cs" />
<Compile Include="Rendering\Renderer.cs" />
<Compile Include="Rendering\RenderGroup.cs" />
<Compile Include="Rendering\Shader.cs" />
<Compile Include="Rendering\ShaderSource.cs" />
<Compile Include="Rendering\Shader\ShaderProgram.cs" />
<Compile Include="Rendering\Shader\ShaderObject.cs" />
<Compile Include="Rendering\Shader\ShaderSource.cs" />
<Compile Include="Rendering\SkinRenderer.cs">
<SubType>UserControl</SubType>
</Compile>

View File

@@ -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();

View File

@@ -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);
}
}
}

View File

@@ -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<string, int> locationCache = new Dictionary<string, int>();
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<int>(shaderSources.Length);
var shaderObjects = new List<ShaderObject>(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;
}

View File

@@ -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;

View File

@@ -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<SkinBOX>();
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<Vector3>(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
{

View File

@@ -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);
}