prepared pipeline for enable the rendering of meshes

This commit is contained in:
2025-12-06 19:48:52 +01:00
parent 70769336b5
commit 739d2e8daf
9 changed files with 93 additions and 22 deletions

View File

@@ -11,11 +11,11 @@ public struct Entity
public readonly long Id;
private Scene _scene;
public string Name { get; set; }
public required string Name { get; set; }
internal Entity(long id, Scene scene)
{
this.Id = id;
Id = id;
_scene = scene;
}

View File

@@ -14,7 +14,10 @@ public class Scene
public Entity CreateEntity(string name)
{
return new Entity(_nextSceneId++, this);
return new Entity(_nextSceneId++, this)
{
Name = name,
};
}
internal void StartComponents()

View File

@@ -82,10 +82,7 @@ internal class OpenGLEngine : IEngine
// TODO: Here render all meshes etc.
// MeshRenderer contains a mesh; Mesh contains a material; Material contains a shader and the values for all uniforms of the shader (apart from the matrices; I am not sure how to best handle the model matrix with this approach)
if (_currentScene is not null)
{
_currentScene.RenderComponents(_gl);
}
_currentScene?.RenderComponents(_gl);
}
private void OnResize(Vector2D<int> newDimensions)

View File

@@ -0,0 +1,52 @@
using Silk.NET.Maths;
namespace EngineSharp.Core.Rendering;
public class Material
{
public required Shader Shader { get; init; }
internal void UseShader() => Shader.Use();
#region Set uniforms
// All of this just relays to the shader. While it is a lot of "unnecessary" code it ensures that everything unsafe of OpenGL/Vulkan specific is abstracted away
public void SetInt(string name, int value)
{
UseShader();
Shader.SetInt(name, value);
}
public void SetFloat(string name, float value)
{
UseShader();
Shader.SetFloat(name, value);
}
public void SetVector(string name, Vector3D<double> value)
{
UseShader();
Shader.SetVector(name, value);
}
public void SetVector(string name, Vector3D<float> value)
{
UseShader();
Shader.SetVector(name, value);
}
public void SetMatrix(string name, Matrix4X4<double> matrix)
{
UseShader();
Shader.SetMatrix(name, matrix);
}
public void SetMatrix(string name, Matrix4X4<float> matrix)
{
UseShader();
Shader.SetMatrix(name, matrix);
}
#endregion
}

View File

@@ -4,6 +4,7 @@ namespace EngineSharp.Core.Rendering;
public class Mesh
{
public required Material Material { get; set; }
public Vector3D<float>[] Vertices { get; set; } = [];
public Vector3D<float>[] Normals { get; set; } = [];
public uint[] Indices { get; set; } = [];
@@ -30,8 +31,7 @@ public class Mesh
var v2 = Vertices[i2];
var normal = Vector3D.Cross(v1-v0, v2-v0);
// Commenting this out, will result in the normals being weighted based on the triangle area
normal = Vector3D.Normalize(normal);
normal = Vector3D.Normalize(normal); // Commenting this out, will result in the normals being weighted based on the triangle area
Normals[i0] += normal;
Normals[i1] += normal;
Normals[i2] += normal;
@@ -42,4 +42,7 @@ public class Mesh
Normals[i] = Vector3D.Normalize(Normals[i]); // smoothing for shared vertices
}
}
// This is probably the location where the model, view, projection matrices will be set!
internal void PrepareForRendering() => Material.UseShader();
}

View File

@@ -5,7 +5,7 @@ namespace EngineSharp.Core.Rendering;
public class MeshRenderer : RenderComponent
{
public required Mesh Mesh { get; set; }
public required Mesh Mesh { get; set; } // in the future this might be an array, or alternatively, a mesh can have submeshes. we will see
private uint vao, vbo, ebo;
@@ -24,6 +24,7 @@ public class MeshRenderer : RenderComponent
if(vbo == 0) { vbo = gl.GenBuffer(); }
if(ebo == 0) { ebo = gl.GenBuffer(); }
Mesh.PrepareForRendering();
var meshData = new float[Mesh.Vertices.Length * 3 + Mesh.Indices.Length * 3];
for (int i = 0, insert = 0; i < Mesh.Vertices.Length; i++, insert += 6)
{

View File

@@ -4,9 +4,12 @@ using Silk.NET.OpenGL;
namespace EngineSharp.Core.Rendering;
// Do the following to not JIT compile the shader:
// use the file paths as an index to a dictionary; the dictionary stores the programID to the already compiled shader
// I don't know if Vulkan also uses an ID as a uint but I think so. If so, this change would decouple the shader from OpenGL (but the question is, do I want to decouple the shader? Maybe not, as this could then couple the material to OpenGL)
public class Shader
{
private readonly GL _gl;
private readonly GL _gl; // not as a variable. Add it as a parameter to the methods probably (in the future it should be possible to compile the shaders beforehand. if context is passed as parameter, all shaders are JIT compiled which isn't great
private readonly uint _shaderProgramId;
public Shader(GL openGLContext, string pathToVertexShader, string pathToFragmentShader)
@@ -21,36 +24,36 @@ public class Shader
_shaderProgramId = CreateProgram(vertexShader, fragmentShader);
}
public void Use() => _gl.UseProgram(_shaderProgramId);
internal void Use() => _gl.UseProgram(_shaderProgramId);
#region Set uniforms
public void SetInt(string name, int value)
internal void SetInt(string name, int value)
{
_gl.Uniform1(_gl.GetUniformLocation(_shaderProgramId, name), value);
}
public void SetFloat(string name, float value)
internal void SetFloat(string name, float value)
{
_gl.Uniform1(_gl.GetUniformLocation(_shaderProgramId, name), value);
}
public void SetVector(string name, Vector3D<double> value)
internal void SetVector(string name, Vector3D<double> value)
{
_gl.Uniform3(_gl.GetUniformLocation(_shaderProgramId, name), value.X, value.Y, value.Z);
}
public void SetVector(string name, Vector3D<float> value)
internal void SetVector(string name, Vector3D<float> value)
{
_gl.Uniform3(_gl.GetUniformLocation(_shaderProgramId, name), value.X, value.Y, value.Z);
}
public void SetMatrix(string name, Matrix4X4<double> matrix)
internal void SetMatrix(string name, Matrix4X4<double> matrix)
{
unsafe
{
_gl.UniformMatrix4(_gl.GetUniformLocation(_shaderProgramId, name), 1, false, (double*) &matrix);
}
}
public void SetMatrix(string name, Matrix4X4<float> matrix)
internal void SetMatrix(string name, Matrix4X4<float> matrix)
{
unsafe
{
@@ -61,9 +64,9 @@ public class Shader
/// <summary>
/// Compiles the given shadercode.
/// Compiles the given shader code.
/// </summary>
/// <param name="shaderCode">The shadercode</param>
/// <param name="shaderCode">The shader code</param>
/// <param name="shaderType">The type of shader to compile</param>
/// <returns>Returns the id of the compiled shader.</returns>
/// <exception cref="ShaderCompileException"></exception>

View File

@@ -6,6 +6,8 @@ namespace Engine_silk.NET;
public class IcoSphere
{
public required Material Material { get; set; }
private readonly IcoSphereGenerator _generator = new();
public required int Resolution
@@ -25,7 +27,10 @@ public class IcoSphere
public Mesh CreateSphere()
{
var mesh = new Mesh();
var mesh = new Mesh
{
Material = Material,
};
_generator.Generate(Resolution);
mesh.Vertices = _generator.Vertices;

View File

@@ -20,9 +20,16 @@ static class Program
var engine = EngineFactory.Create(GraphicsAPI.OpenGL, options);
var mainScene = engine.CreateScene();
var cube = mainScene.CreateEntity("cube");
var shader = new Shader(null, "", ""); // make a factory in IEngine so I don't have to pass graphics library specific values
var material = new Material
{
Shader = shader,
};
var sphereGenerator = new IcoSphere
{
Resolution = 10
Resolution = 10,
Material = material,
};
var cubeMeshRenderer = new MeshRenderer
{