Updated Sphere generation
Some checks failed
Gitea Actions Demo / Scan the project (push) Failing after 7s
Some checks failed
Gitea Actions Demo / Scan the project (push) Failing after 7s
This commit is contained in:
parent
cf6fb35eb2
commit
8470304859
|
@ -1 +0,0 @@
|
||||||
global using Xunit;
|
|
|
@ -1,29 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
|
||||||
<IsTestProject>true</IsTestProject>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
|
||||||
<PackageReference Include="xunit" Version="2.4.2" />
|
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
</PackageReference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Nebulix\Nebulix.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
|
@ -1,12 +0,0 @@
|
||||||
using Nebulix.InputSystem;
|
|
||||||
|
|
||||||
namespace Nebulix.Test
|
|
||||||
{
|
|
||||||
public class TestInputSystem
|
|
||||||
{
|
|
||||||
[Fact]
|
|
||||||
public void IfSingleKeyIsPressed_InputIsKeyPressedShouldReturnTrue()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
36
Nebulix/ArrayExtensions.cs
Normal file
36
Nebulix/ArrayExtensions.cs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
using System.Numerics;
|
||||||
|
using Silk.NET.Maths;
|
||||||
|
|
||||||
|
namespace Nebulix
|
||||||
|
{
|
||||||
|
public static class ArrayExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the given arrays to the start of this array. The order of <paramref name="arrays"/> is preserved
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="arrays">The arrays copied into this array</param>
|
||||||
|
public static void CopyFrom(this Array array, params Array[] arrays)
|
||||||
|
{
|
||||||
|
int lastIndex = 0;
|
||||||
|
for (int i = 0; i < arrays.Length; i++)
|
||||||
|
{
|
||||||
|
arrays[i].CopyTo(array, lastIndex);
|
||||||
|
lastIndex += arrays[i].Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T[] ExtractComponents<T>(this Vector3D<T>[] array) where T : unmanaged, IFormattable, IEquatable<T>, IComparable<T>
|
||||||
|
{
|
||||||
|
T[] result = new T[array.Length * 3]; // * 3 cause a Vector3D has 3 components
|
||||||
|
int resultIdx = 0;
|
||||||
|
for (int i = 0; i < array.Length; i++)
|
||||||
|
{
|
||||||
|
result[resultIdx] = array[i].X;
|
||||||
|
result[resultIdx + 1] = array[i].Y;
|
||||||
|
result[resultIdx + 2] = array[i].Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,19 +5,29 @@ namespace Nebulix.Rendering
|
||||||
public sealed class Mesh
|
public sealed class Mesh
|
||||||
{
|
{
|
||||||
public float[] Vertices { get => vertices; set { vertices = value; regenerate = true; } }
|
public float[] Vertices { get => vertices; set { vertices = value; regenerate = true; } }
|
||||||
public float[] Indices { get => indices; set { indices = value; regenerate = true; } }
|
public nuint[] Indices { get => indices; set { indices = value; regenerate = true; } }
|
||||||
public float[] Normals { get => normals; }
|
|
||||||
|
|
||||||
private uint vao = 0, vbo = 0, ebo = 0;
|
private uint vao = 0, vbo = 0, ebo = 0;
|
||||||
private bool regenerate = true;
|
private bool regenerate = true;
|
||||||
|
|
||||||
private float[] vertices = [];
|
private float[] vertices = [];
|
||||||
private float[] indices = [];
|
private nuint[] indices = [];
|
||||||
private float[] normals = [];
|
private float[] normals = [];
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
vertices = [];
|
||||||
|
indices = [];
|
||||||
|
}
|
||||||
|
|
||||||
// getting called by "Engine" which currently is in other assembly, meaning I probably need to make this public
|
public void CalculateNormals()
|
||||||
internal void Use(GL gl)
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
{
|
{
|
||||||
if (regenerate) Generate(gl);
|
if (regenerate) Generate(gl);
|
||||||
|
|
||||||
|
@ -44,7 +54,7 @@ namespace Nebulix.Rendering
|
||||||
gl.BindBuffer(BufferTargetARB.ArrayBuffer, vbo);
|
gl.BindBuffer(BufferTargetARB.ArrayBuffer, vbo);
|
||||||
gl.BufferData(BufferTargetARB.ArrayBuffer, (nuint)(data.Length * sizeof(float)), data, BufferUsageARB.StaticDraw);
|
gl.BufferData(BufferTargetARB.ArrayBuffer, (nuint)(data.Length * sizeof(float)), data, BufferUsageARB.StaticDraw);
|
||||||
|
|
||||||
ReadOnlySpan<float> indicesData = new(indices);
|
ReadOnlySpan<nuint> indicesData = new(indices);
|
||||||
gl.BindBuffer(BufferTargetARB.ElementArrayBuffer, ebo);
|
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(uint)), indicesData, BufferUsageARB.StaticDraw);
|
||||||
|
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
namespace Engine_silk.NET
|
|
||||||
{
|
|
||||||
public static class ArrayExtensions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Copies the given arrays to the start of this array. The order of <paramref name="arrays"/> is preserved
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="arrays">The arrays copied into this array</param>
|
|
||||||
public static void CopyFrom(this Array array, params Array[] arrays)
|
|
||||||
{
|
|
||||||
int lastIndex = 0;
|
|
||||||
for (int i = 0; i < arrays.Length; i++)
|
|
||||||
{
|
|
||||||
arrays[i].CopyTo(array, lastIndex);
|
|
||||||
lastIndex += arrays[i].Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,11 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Engine_silk.NET", "Engine_s
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nebulix", "..\Nebulix\Nebulix.csproj", "{0DEED1E3-932E-47C3-AF2D-FCA74000908E}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nebulix", "..\Nebulix\Nebulix.csproj", "{0DEED1E3-932E-47C3-AF2D-FCA74000908E}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nebulix.Test", "..\Nebulix.Test\Nebulix.Test.csproj", "{60B8C905-7AC4-45EE-BAB1-26D3F826124B}"
|
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
|
||||||
{0DEED1E3-932E-47C3-AF2D-FCA74000908E} = {0DEED1E3-932E-47C3-AF2D-FCA74000908E}
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -26,10 +21,6 @@ Global
|
||||||
{0DEED1E3-932E-47C3-AF2D-FCA74000908E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{0DEED1E3-932E-47C3-AF2D-FCA74000908E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{0DEED1E3-932E-47C3-AF2D-FCA74000908E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{0DEED1E3-932E-47C3-AF2D-FCA74000908E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{0DEED1E3-932E-47C3-AF2D-FCA74000908E}.Release|Any CPU.Build.0 = Release|Any CPU
|
{0DEED1E3-932E-47C3-AF2D-FCA74000908E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{60B8C905-7AC4-45EE-BAB1-26D3F826124B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{60B8C905-7AC4-45EE-BAB1-26D3F826124B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{60B8C905-7AC4-45EE-BAB1-26D3F826124B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{60B8C905-7AC4-45EE-BAB1-26D3F826124B}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
@ -31,7 +31,6 @@ public static class Program
|
||||||
private static uint _vao, _vbo, _ebo;
|
private static uint _vao, _vbo, _ebo;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
WindowOptions options = WindowOptions.Default with
|
WindowOptions options = WindowOptions.Default with
|
||||||
|
@ -158,9 +157,6 @@ public static class Program
|
||||||
_gl.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, 8 * sizeof(float), (void*)(6 * sizeof(float)));
|
_gl.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, 8 * sizeof(float), (void*)(6 * sizeof(float)));
|
||||||
|
|
||||||
_texture = new Texture2D(_gl, "images/container.png", ImageFormat.RGBA);
|
_texture = new Texture2D(_gl, "images/container.png", ImageFormat.RGBA);
|
||||||
|
|
||||||
Sphere s = new(_gl, 1, 10);
|
|
||||||
s.GetVertices();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnUpdate(double deltaTime)
|
private static void OnUpdate(double deltaTime)
|
||||||
|
|
165
src/Sphere.cs
165
src/Sphere.cs
|
@ -1,123 +1,96 @@
|
||||||
using Nebulix.Rendering;
|
using Nebulix;
|
||||||
|
using Nebulix.Rendering;
|
||||||
using Silk.NET.Maths;
|
using Silk.NET.Maths;
|
||||||
using Silk.NET.OpenGL;
|
using Silk.NET.OpenGL;
|
||||||
|
|
||||||
namespace Engine_silk.NET
|
namespace Engine_silk.NET
|
||||||
{
|
{
|
||||||
// TODO: Think about just creating a cube with a certain resolution and then use this cube to generate the Sphere.
|
|
||||||
// also maybe make an ISphere and call this class "CubeSphere"?
|
// also maybe make an ISphere and call this class "CubeSphere"?
|
||||||
public class Sphere(GL gl, float radius, uint resolution)
|
public class Sphere(uint resolution)
|
||||||
{
|
{
|
||||||
|
private readonly Face[] sphereFaces = new Face[6];
|
||||||
public void CreateSphere()
|
public void CreateSphere()
|
||||||
{
|
{
|
||||||
uint _vao, _vbo, _ebo;
|
Vector3D<float>[] directions =
|
||||||
|
|
||||||
_vao = gl.CreateVertexArray();
|
|
||||||
gl.BindVertexArray(_vao);
|
|
||||||
|
|
||||||
ReadOnlySpan<float> verticesData = GetVertices();
|
|
||||||
|
|
||||||
_vbo = gl.GenBuffer();
|
|
||||||
gl.BindBuffer(BufferTargetARB.ArrayBuffer, _vbo);
|
|
||||||
gl.BufferData(BufferTargetARB.ArrayBuffer, (nuint)(verticesData.Length * sizeof(float)), verticesData, BufferUsageARB.StaticDraw);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RenderSphere()
|
|
||||||
{
|
{
|
||||||
|
Vector3D<float>.UnitZ, -Vector3D<float>.UnitZ,
|
||||||
|
Vector3D<float>.UnitY, -Vector3D<float>.UnitY,
|
||||||
|
Vector3D<float>.UnitX, -Vector3D<float>.UnitX
|
||||||
|
};
|
||||||
|
|
||||||
}
|
for (int i = 0; i < sphereFaces.Length; i++)
|
||||||
|
|
||||||
// TODO: make this private after testing
|
|
||||||
public ReadOnlySpan<float> GetVertices()
|
|
||||||
{
|
{
|
||||||
var front = GetSide(Vector3D<float>.UnitZ).Item1;
|
// TODO: Refactor so that a face gets a mesh it can only change the contents of (should improve performance)
|
||||||
var back = GetSide(-Vector3D<float>.UnitZ).Item1;
|
sphereFaces[i] = new Face(directions[i], resolution);
|
||||||
var up = GetSide(Vector3D<float>.UnitY).Item1;
|
|
||||||
var down = GetSide(-Vector3D<float>.UnitY).Item1;
|
|
||||||
var left = GetSide(Vector3D<float>.UnitX).Item1;
|
|
||||||
var right = GetSide(-Vector3D<float>.UnitX).Item1;
|
|
||||||
|
|
||||||
var finalArray = new float[front.Length + back.Length + up.Length + down.Length + left.Length + right.Length];
|
|
||||||
finalArray.CopyFrom(front, back, up, down, left, right);
|
|
||||||
|
|
||||||
return new ReadOnlySpan<float>(finalArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[Obsolete("Use Sphere.GetFace(Vector3D<float>) instead")]
|
|
||||||
private (float[], float[]) GetSide(Vector3D<float> localUp)
|
|
||||||
{
|
|
||||||
|
|
||||||
float stepSize = 2f / resolution;
|
|
||||||
|
|
||||||
List<float> vertices = new((int)(3 * resolution * resolution * 2)); // resolution * resolution == number of rows/columns; 3 * ... == each vertex has 3 positions; 2 * ... == vertex also needs normal
|
|
||||||
|
|
||||||
Vector3D<float> position = localUp;
|
|
||||||
for (uint y = 0; y <= resolution; y++)
|
|
||||||
{
|
|
||||||
for (uint x = 0; x <= resolution; x++)
|
|
||||||
{
|
|
||||||
uint i = x + y * resolution;
|
|
||||||
Vector2D<float> percent = new Vector2D<float>(x, y) / (resolution - 1);
|
|
||||||
//Vector3D<float> pointOnUnitCube = localUp + (percent.X - 0.5f) * stepSize *
|
|
||||||
|
|
||||||
if (localUp.X != 0)
|
|
||||||
{
|
|
||||||
position.Y = x * stepSize - 1;
|
|
||||||
position.Z = y * stepSize - 1;
|
|
||||||
}
|
|
||||||
else if (localUp.Y != 0)
|
|
||||||
{
|
|
||||||
position.X = x * stepSize - 1;
|
|
||||||
position.Z = y * stepSize - 1;
|
|
||||||
}
|
|
||||||
else if (localUp.Z != 0)
|
|
||||||
{
|
|
||||||
position.X = x * stepSize - 1;
|
|
||||||
position.Y = y * stepSize - 1;
|
|
||||||
}
|
|
||||||
vertices.AddRange([position.X, position.Y, position.Z, localUp.X, localUp.Y, localUp.Z]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<uint> indices = new((int)(resolution * resolution * 6)); // ... * 6 == one quad has 6 indices and we have resolution * resolution quads
|
public void RenderSphere(GL gl) // Will not be needed
|
||||||
Console.WriteLine($"Indices size before Loop: {indices.Capacity}");
|
|
||||||
|
|
||||||
uint vi = 0; // vertexIndex
|
|
||||||
for (uint i = 0; i < vertices.Count; i += 6)
|
|
||||||
{
|
{
|
||||||
if ((vi + 1) % resolution == 0)
|
// Use default shader etc. to render the sphere
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
vi++;
|
Mesh m = sphereFaces[i].GetMesh();
|
||||||
continue;
|
m.Use(gl);
|
||||||
}
|
}
|
||||||
|
|
||||||
indices.AddRange([vi, vi+1, vi+1+resolution,
|
|
||||||
vi, vi+1+resolution, vi+resolution]);
|
|
||||||
vi++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine($"Indices size after Loop: {indices.Count}");
|
|
||||||
|
|
||||||
return (vertices.ToArray(), []);
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://youtu.be/QN39W020LqU?si=a66D1Lnic1vNaC6l&t=89
|
|
||||||
// https://github.com/SebLague/Procedural-Planets/blob/master/Procedural%20Planet%20E01/Assets/TerrainFace.cs
|
|
||||||
/// <param name="localUp">The unit vector in which the side should point. E.g. Vector.UnitX</param>
|
|
||||||
public Mesh GetFace(Vector3D<float> localUp)
|
|
||||||
{
|
|
||||||
// this all probably needs to be rewritten to use the "Face" record below and split the stuff better
|
|
||||||
return new Mesh();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal record struct Face
|
internal record struct Face
|
||||||
{
|
{
|
||||||
public Face()
|
private readonly Vector3D<float> _localX;
|
||||||
{
|
private readonly Vector3D<float> _localY;
|
||||||
|
|
||||||
|
private readonly Vector3D<float> _localUp;
|
||||||
|
private readonly uint _resolution;
|
||||||
|
|
||||||
|
public Face(Vector3D<float> localUp, uint resolution)
|
||||||
|
{
|
||||||
|
_localX = new(localUp.Y, localUp.Z, localUp.X);
|
||||||
|
_localY = Vector3D.Cross(localUp, _localX);
|
||||||
|
_localUp = localUp;
|
||||||
|
_resolution = resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Mesh GetMesh()
|
||||||
|
{
|
||||||
|
var vertices = new Vector3D<float>[_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];
|
||||||
|
int triangleIndex = 0;
|
||||||
|
|
||||||
|
uint i;
|
||||||
|
for (uint y = 0; y < _resolution; y++)
|
||||||
|
{
|
||||||
|
for (uint x = 0; x < _resolution; x++)
|
||||||
|
{
|
||||||
|
i = x + y * _resolution;
|
||||||
|
Vector2D<float> percent = new Vector2D<float>(x, y) / (_resolution - 1);
|
||||||
|
// place vertex on correct position of the plane to easily calculate indices
|
||||||
|
Vector3D<float> vertexPosition = _localUp + (percent.X - 0.5f) * 2 * _localX + (percent.Y - 0.5f) * 2 * _localY;
|
||||||
|
vertices[i] = Vector3D.Normalize(vertexPosition); // normalise vertex position to get it to be "on the sphere" and not "on the plane"
|
||||||
|
|
||||||
|
if (x != _resolution - 1 && y != _resolution - 1) // we didn't reach the bottom right point yet
|
||||||
|
{
|
||||||
|
indices[triangleIndex] = i;
|
||||||
|
indices[triangleIndex + 1] = i + _resolution + 1;
|
||||||
|
indices[triangleIndex + 2] = i + _resolution;
|
||||||
|
|
||||||
|
indices[triangleIndex + 3] = i;
|
||||||
|
indices[triangleIndex + 4] = i + 1;
|
||||||
|
indices[triangleIndex + 5] = i + _resolution + 1;
|
||||||
|
|
||||||
|
triangleIndex += 6; // doing it this way is faster than doing indices[triangleIndex++] (takes about double the time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Mesh m = new Mesh();
|
||||||
|
m.Vertices = vertices.ExtractComponents();
|
||||||
|
m.Indices = indices;
|
||||||
|
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user