diff --git a/Nebulix/Rendering/Mesh.cs b/Nebulix/Rendering/Mesh.cs index 04df87b..ef50e45 100644 --- a/Nebulix/Rendering/Mesh.cs +++ b/Nebulix/Rendering/Mesh.cs @@ -1,18 +1,19 @@ -using Silk.NET.OpenGL; +using Silk.NET.Maths; +using Silk.NET.OpenGL; namespace Nebulix.Rendering { public sealed class Mesh { - public float[] Vertices { get => vertices; set { vertices = value; regenerate = true; } } + public Vector3D[] Vertices { get => vertices; set { vertices = value; regenerate = true; } } public nuint[] Indices { get => indices; set { indices = value; regenerate = true; } } private uint vao = 0, vbo = 0, ebo = 0; private bool regenerate = true; - private float[] vertices = []; + private Vector3D[] vertices = []; private nuint[] indices = []; - private float[] normals = []; + private Vector3D[] normals = []; public void Clear() { @@ -22,21 +23,41 @@ namespace Nebulix.Rendering public void CalculateNormals() { - throw new NotImplementedException(); + normals = new Vector3D[vertices.Length]; + for (int j = 0; j < vertices.Length; j++) + { + normals[j] = Vector3D.Zero; + } + + return; + for (int i = 0; i < indices.Length; i += 3) + { + Vector3D a = vertices[indices[i] - 1]; + Vector3D b = vertices[indices[i + 1] - 1]; + Vector3D c = vertices[indices[i + 2] - 1]; + + Vector3D normal = Vector3D.Cross(b-a, c-a); + normal = Vector3D.Normalize(normal); + normals[indices[i] - 1] = normal; + normals[indices[i + 1] - 1] = normal; + normals[indices[i + 2] - 1] = normal; + } } // getting called by "Engine" which currently is in another assembly, meaning I probably need to make this public // needs to be change for the real engine - public void Use(GL gl) + public void Render(GL gl) { if (regenerate) Generate(gl); gl.BindVertexArray(vao); - + gl.DrawElements(PrimitiveType.Triangles, (uint)vertices.Length * 3, DrawElementsType.UnsignedInt, 0); } private unsafe void Generate(GL gl) { + regenerate = false; + if(vao == 0) vao = gl.CreateVertexArray(); if(vbo == 0) @@ -46,23 +67,23 @@ namespace Nebulix.Rendering gl.BindVertexArray(vao); - // TODO: meshData needs to also contain uv coords if I decide to add some - List meshData = new(vertices.Length + normals.Length); - meshData.AddRange(vertices); - meshData.AddRange(normals); + List meshData = new(vertices.Length * 3 + normals.Length * 3); + meshData.AddRange(vertices.ExtractComponents()); + //meshData.AddRange(normals.ExtractComponents()); ReadOnlySpan data = new(meshData.ToArray()); gl.BindBuffer(BufferTargetARB.ArrayBuffer, vbo); gl.BufferData(BufferTargetARB.ArrayBuffer, (nuint)(data.Length * sizeof(float)), data, BufferUsageARB.StaticDraw); ReadOnlySpan indicesData = new(indices); gl.BindBuffer(BufferTargetARB.ElementArrayBuffer, ebo); - gl.BufferData(BufferTargetARB.ElementArrayBuffer, (nuint)(indicesData.Length * sizeof(uint)), indicesData, BufferUsageARB.StaticDraw); + gl.BufferData(BufferTargetARB.ElementArrayBuffer, (nuint)(indicesData.Length * sizeof(nuint)), indicesData, BufferUsageARB.StaticDraw); // vertices gl.EnableVertexAttribArray(0); - gl.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 6 * sizeof(float), (void*)0); - gl.EnableVertexAttribArray(1); - gl.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, false, 6 * sizeof(float), (void*)(3 * sizeof(float))); + gl.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 3 * sizeof(float), null); + // normals + //gl.EnableVertexAttribArray(1); + //gl.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, false, 6 * sizeof(float), (void*)(3 * sizeof(float))); } } } diff --git a/Nebulix/Rendering/Shaders/Shader.cs b/Nebulix/Rendering/Shaders/Shader.cs index 571c17c..77b417e 100644 --- a/Nebulix/Rendering/Shaders/Shader.cs +++ b/Nebulix/Rendering/Shaders/Shader.cs @@ -4,6 +4,7 @@ using System.Numerics; namespace Nebulix.Rendering; +// TODO: make IDisposable public class Shader { private readonly GL _glContext; @@ -21,7 +22,7 @@ public class Shader _shaderProgramId = CreateProgram(vertexShader, fragmentShader); } - public void Use() { _glContext.UseProgram(_shaderProgramId); } + public void Use() => _glContext.UseProgram(_shaderProgramId); #region Set uniforms public void SetInt(string name, int value) diff --git a/Nebulix/Rendering/Shaders/ShaderCompileException.cs b/Nebulix/Rendering/Shaders/ShaderCompileException.cs index 65d4244..028014c 100644 --- a/Nebulix/Rendering/Shaders/ShaderCompileException.cs +++ b/Nebulix/Rendering/Shaders/ShaderCompileException.cs @@ -11,17 +11,14 @@ namespace Nebulix.Rendering; [Serializable] public class ShaderCompileException : Exception { - protected ShaderType _shaderType; + protected ShaderType ShaderType; - public ShaderCompileException(ShaderType shaderType) : base("Unable to compile shader.") { _shaderType = shaderType; } - public ShaderCompileException(ShaderType shaderType, string message) : base(message) { _shaderType = shaderType; } - public ShaderCompileException(ShaderType shaderType, string message, Exception inner) : base(message, inner) { _shaderType = shaderType; } - protected ShaderCompileException( - System.Runtime.Serialization.SerializationInfo info, - System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + public ShaderCompileException(ShaderType shaderType) : base("Unable to compile shader.") { ShaderType = shaderType; } + public ShaderCompileException(ShaderType shaderType, string message) : base(message) { ShaderType = shaderType; } + public ShaderCompileException(ShaderType shaderType, string message, Exception inner) : base(message, inner) { ShaderType = shaderType; } public override string ToString() { - return $"Type of Shader: '{_shaderType}'" + "\n" + Message; + return $"Type of Shader: '{ShaderType}'" + "\n" + Message; } } diff --git a/Nebulix/Rendering/Shaders/ShaderLinkException.cs b/Nebulix/Rendering/Shaders/ShaderLinkException.cs index 27a3f8b..a919ddb 100644 --- a/Nebulix/Rendering/Shaders/ShaderLinkException.cs +++ b/Nebulix/Rendering/Shaders/ShaderLinkException.cs @@ -13,7 +13,4 @@ public class ShaderLinkException : Exception public ShaderLinkException() : base("Error occured while trying to link a shader.") { } public ShaderLinkException(string message) : base(message) { } public ShaderLinkException(string message, Exception inner) : base(message, inner) { } - protected ShaderLinkException( - System.Runtime.Serialization.SerializationInfo info, - System.Runtime.Serialization.StreamingContext context) : base(info, context) { } } \ No newline at end of file diff --git a/src/Engine_silk.NET.csproj b/src/Engine_silk.NET.csproj index 6e39abd..3239511 100644 --- a/src/Engine_silk.NET.csproj +++ b/src/Engine_silk.NET.csproj @@ -28,6 +28,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + diff --git a/src/Program.cs b/src/Program.cs index c55cf83..850b55c 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -24,12 +24,13 @@ public static class Program private static IWindow _window; private static GL _gl; - private static Nebulix.Rendering.Shader _shader; + private static Nebulix.Rendering.Shader _shader, _sphereShader; private static Texture2D _texture; private static Camera _cam; private static Vector2 _lastMousePosition; private static uint _vao, _vbo, _ebo; - + private static Sphere sphere; + public static void Main(string[] args) { @@ -46,6 +47,7 @@ public static class Program _window.Run(); } + private static unsafe void OnLoad() { @@ -157,6 +159,13 @@ public static class Program _gl.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, 8 * sizeof(float), (void*)(6 * sizeof(float))); _texture = new Texture2D(_gl, "images/container.png", ImageFormat.RGBA); + + + // Sphere + sphere = new Sphere(10); + sphere.CreateSphere(); + _sphereShader = + new Nebulix.Rendering.Shader(_gl, "./Shaders/Sphere/sphere.vert", "./Shaders/Sphere/sphere.frag"); } private static void OnUpdate(double deltaTime) @@ -193,18 +202,28 @@ public static class Program var modelMatrix = Matrix4x4.CreateRotationY(Maths.Convert.ToRadians(difference)) * Matrix4x4.CreateRotationX(Maths.Convert.ToRadians(difference)); var viewMatrix = _cam.ViewMatrix; var projectionMatrix = Matrix4X4.CreatePerspectiveFieldOfView(Maths.Convert.ToRadians(_cam.Fov), Width / (float)Height, 0.1f, 100.0f); + + // _shader.Use(); + // _shader.SetMatrix("modelMatrix", modelMatrix); + // _shader.SetMatrix("projectionMatrix", projectionMatrix); + // _shader.SetMatrix("viewMatrix", viewMatrix); + // + // _shader.SetInt("tex", 0); + // _texture.Bind(); + // + // _gl.BindVertexArray(_vao); + // _gl.DrawArrays(PrimitiveType.Triangles, 0, 36); - _gl.BindVertexArray(_vao); + // Sphere + // modelMatrix = Matrix4x4.CreateTranslation(1, 0, 1); + _sphereShader.Use(); + _sphereShader.SetMatrix("modelMatrix", modelMatrix); + _sphereShader.SetMatrix("projectionMatrix", projectionMatrix); + _sphereShader.SetMatrix("viewMatrix", viewMatrix); + sphere.RenderSphere(_gl); - _shader.Use(); - _shader.SetMatrix("modelMatrix", modelMatrix); - _shader.SetMatrix("projectionMatrix", projectionMatrix); - _shader.SetMatrix("viewMatrix", viewMatrix); - - _shader.SetInt("tex", 0); - _texture.Bind(); - - _gl.DrawArrays(PrimitiveType.Triangles, 0, 36); + // var f = new Face(-Vector3D.UnitX, 10); + // f.GetMesh().Render(_gl); } private static void OnKeyDown(IKeyboard keyboard, Key key, int keyCode) diff --git a/src/Shaders/Sphere/sphere.frag b/src/Shaders/Sphere/sphere.frag new file mode 100644 index 0000000..4f2b70b --- /dev/null +++ b/src/Shaders/Sphere/sphere.frag @@ -0,0 +1,15 @@ +#version 330 core + +out vec4 colour; + +in vec3 FragPos; +//in vec3 Normal; + +void main() +{ + vec3 col = vec3(1.0, 0.5, 0.2) * FragPos; + //vec3 col = texture(tex, TexCoords); + //colour = vec4(texture(tex, TexCoords).rgb, 1.0); +// colour = vec4(col, 1); + colour = vec4(1); +} \ No newline at end of file diff --git a/src/Shaders/Sphere/sphere.vert b/src/Shaders/Sphere/sphere.vert new file mode 100644 index 0000000..e600edc --- /dev/null +++ b/src/Shaders/Sphere/sphere.vert @@ -0,0 +1,21 @@ +#version 330 core + +layout (location = 0) in vec3 aPosition; +layout (location = 1) in vec3 normalVector; + +uniform mat4 modelMatrix; +uniform mat4 viewMatrix; +uniform mat4 projectionMatrix; + +out vec3 FragPos; +//out vec3 Normal; + +void main() +{ + vec4 pos = vec4(aPosition, 1.0); + + // TODO: calculate the inverse of the model matrix beforehand since "inverse()" is very costly to calculate for every vertex +// Normal = mat3(transpose(inverse(modelMatrix))) * normalVector; + FragPos = vec3(modelMatrix * pos); + gl_Position = projectionMatrix * viewMatrix * modelMatrix * pos; +} \ No newline at end of file diff --git a/src/Sphere.cs b/src/Sphere.cs index f001aae..f7e7538 100644 --- a/src/Sphere.cs +++ b/src/Sphere.cs @@ -12,52 +12,58 @@ namespace Engine_silk.NET public void CreateSphere() { Vector3D[] directions = - { + [ Vector3D.UnitZ, -Vector3D.UnitZ, Vector3D.UnitY, -Vector3D.UnitY, Vector3D.UnitX, -Vector3D.UnitX - }; + ]; for (int i = 0; i < sphereFaces.Length; i++) { - // TODO: Refactor so that a face gets a mesh it can only change the contents of (should improve performance) - sphereFaces[i] = new Face(directions[i], resolution); + sphereFaces[i] = new Face(directions[i], new Mesh(), resolution); + sphereFaces[i].GenerateMesh(); } } + /// + /// Renders the mesh. No Shader is specified and needs to be called beforehand + /// public void RenderSphere(GL gl) // Will not be needed { // Use default shader etc. to render the sphere for (int i = 0; i < 6; i++) { - Mesh m = sphereFaces[i].GetMesh(); - m.Use(gl); + sphereFaces[i].Mesh.Render(gl); } } } internal record struct Face { + public Mesh Mesh => _mesh; + + private readonly Mesh _mesh; private readonly Vector3D _localX; private readonly Vector3D _localY; private readonly Vector3D _localUp; private readonly uint _resolution; - public Face(Vector3D localUp, uint resolution) + public Face(Vector3D localUp, Mesh mesh, uint resolution) { + _mesh = mesh; _localX = new(localUp.Y, localUp.Z, localUp.X); _localY = Vector3D.Cross(localUp, _localX); _localUp = localUp; _resolution = resolution; } - internal Mesh GetMesh() + internal void GenerateMesh() { var vertices = new Vector3D[_resolution * _resolution]; // _resolution - 1 because the vertices index starts at 0 // * 6 because each triangle needs 3 points and each small quad has 2 triangles 3*2 = 6 - nuint[] indices = new nuint[(_resolution - 1) * (_resolution - 1) * 6]; + var indices = new nuint[(_resolution - 1) * (_resolution - 1) * 6]; int triangleIndex = 0; uint i; @@ -86,11 +92,10 @@ namespace Engine_silk.NET } } - Mesh m = new Mesh(); - m.Vertices = vertices.ExtractComponents(); - m.Indices = indices; - - return m; + _mesh.Clear(); + _mesh.Vertices = vertices; + _mesh.Indices = indices; + _mesh.CalculateNormals(); } } }