From be9a0c072ef0069ebd852f354bdb943a6457b043 Mon Sep 17 00:00:00 2001 From: notgiven688 Date: Sat, 3 Feb 2024 13:12:00 +0100 Subject: [PATCH 1/3] Use setAsInverse feature of RigidBody.SetMassInertia in SoftBody demos --- src/JitterDemo/Demos/SoftBody/PressurizedSphere.cs | 4 ++-- src/JitterDemo/Demos/SoftBody/SoftBodyCloth.cs | 4 +--- src/JitterDemo/Demos/SoftBody/SoftBodyCube.cs | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/JitterDemo/Demos/SoftBody/PressurizedSphere.cs b/src/JitterDemo/Demos/SoftBody/PressurizedSphere.cs index fab6ed74..18a702cf 100644 --- a/src/JitterDemo/Demos/SoftBody/PressurizedSphere.cs +++ b/src/JitterDemo/Demos/SoftBody/PressurizedSphere.cs @@ -28,7 +28,7 @@ public void SupportMap(in JVector direction, out JVector result) private static IEnumerable GenSphereTriangles(JVector offset) { - return ShapeHelper.MakeHull(new UnitSphere()) + return ShapeHelper.MakeHull(new UnitSphere(), subdivisions: 4) .Select(t => new JTriangle(t.V0 + offset, t.V1 + offset, t.V2 + offset)); } @@ -48,7 +48,7 @@ public SoftBodySphere(World world, JVector offset) : base(world, GenSphereTriang { foreach (var rb in Vertices) { - rb.SetMassInertia(JMatrix.Identity * 1000, 0.01f); + rb.SetMassInertia(JMatrix.Zero, 100.0f, true); rb.Damping = (0.001f, 0); } diff --git a/src/JitterDemo/Demos/SoftBody/SoftBodyCloth.cs b/src/JitterDemo/Demos/SoftBody/SoftBodyCloth.cs index 9d799286..ebd3de99 100644 --- a/src/JitterDemo/Demos/SoftBody/SoftBodyCloth.cs +++ b/src/JitterDemo/Demos/SoftBody/SoftBodyCloth.cs @@ -35,8 +35,6 @@ public Edge(ushort u0, ushort u1) public List Triangles => triangles; - private List MatchConstraints = new(); - public SoftBodyCloth(World world, IEnumerable triangles) : base(world) { this.world = world; @@ -85,7 +83,7 @@ private void Build() foreach (var vertex in vertices) { RigidBody body = world.CreateRigidBody(); - body.SetMassInertia(JMatrix.Identity * 1000, 0.01f); + body.SetMassInertia(JMatrix.Zero, 100.0f, true); body.Position = vertex; Vertices.Add(body); } diff --git a/src/JitterDemo/Demos/SoftBody/SoftBodyCube.cs b/src/JitterDemo/Demos/SoftBody/SoftBodyCube.cs index 2946961a..e039f6d1 100644 --- a/src/JitterDemo/Demos/SoftBody/SoftBodyCube.cs +++ b/src/JitterDemo/Demos/SoftBody/SoftBodyCube.cs @@ -33,7 +33,7 @@ public SoftBodyCube(World world, JVector offset) : base(world) for (int i = 0; i < 8; i++) { var rb = world.CreateRigidBody(); - rb.SetMassInertia(JMatrix.Identity * 100000, 0.2f); + rb.SetMassInertia(JMatrix.Zero, 5.0f, true); rb.Position = vertices[i] + offset; Vertices.Add(rb); } From a885869921bc8067a3acd82ebb6beed4f48691d5 Mon Sep 17 00:00:00 2001 From: notgiven688 Date: Sat, 3 Feb 2024 14:24:20 +0100 Subject: [PATCH 2/3] Use Euler-characteristic for better upper bounds of vertices and triangles in ConvexPolytope.cs --- .../Collision/NarrowPhase/ConvexPolytope.cs | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/Jitter2/Collision/NarrowPhase/ConvexPolytope.cs b/src/Jitter2/Collision/NarrowPhase/ConvexPolytope.cs index 2f0cc5d9..24181204 100644 --- a/src/Jitter2/Collision/NarrowPhase/ConvexPolytope.cs +++ b/src/Jitter2/Collision/NarrowPhase/ConvexPolytope.cs @@ -89,25 +89,28 @@ public static bool Equals(in Edge a, in Edge b) private const float NumericEpsilon = 1e-16f; - private const int MaxVertices = 100; - private const int MaxTriangles = 3 * MaxVertices; + // (*) Euler-characteristic: V (vertices) - E (edges) + F (faces) = 2 + // We have triangles T instead of faces: F = T + // and every edge shares two triangles -> T = 2*V - 4 + private const int MaxVertices = 128; + private const int MaxTriangles = 2 * MaxVertices; private Triangle* triangles; private Vertex* vertices; - private short tCount; + private short tPointer; private short vPointer; private bool originEnclosed; private JVector center; - public Span HullTriangles => new Span(triangles, tCount); + public Span HullTriangles => new Span(triangles, tPointer); [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref ConvexPolytope.Vertex GetVertex(int index) { - System.Diagnostics.Debug.Assert(index < MaxTriangles, "Out of bounds."); + System.Diagnostics.Debug.Assert(index < MaxVertices, "Out of bounds."); return ref vertices[index]; } @@ -237,7 +240,7 @@ private readonly bool IsLit(int candidate, int w) private bool CreateTriangle(short a, short b, short c) { - ref Triangle triangle = ref triangles[tCount]; + ref Triangle triangle = ref triangles[tPointer]; triangle.A = a; triangle.B = b; triangle.C = c; @@ -277,7 +280,7 @@ private bool CreateTriangle(short a, short b, short c) triangle.ClosestToOriginSq = triangle.ClosestToOrigin.LengthSquared(); } - tCount++; + tPointer++; return true; } @@ -292,7 +295,7 @@ public ref Triangle GetClosestTriangle() originEnclosed = true; - for (int i = 0; i < tCount; i++) + for (int i = 0; i < tPointer; i++) { if (triangles[i].ClosestToOriginSq < currentMin) { @@ -313,7 +316,7 @@ public void InitTetrahedron() { originEnclosed = false; vPointer = 4; - tCount = 0; + tPointer = 0; center = 0.25f * (vertices[0].V + vertices[1].V + vertices[2].V + vertices[3].V); @@ -330,7 +333,7 @@ public void InitTetrahedron(in JVector point) { originEnclosed = false; vPointer = 4; - tCount = 0; + tPointer = 0; center = point; const float scale = 1e-2f; // minkowski sums not allowed to be thinner @@ -379,21 +382,22 @@ public bool AddPoint(in JVector point) /// Indicates whether the polyhedron successfully incorporated the new vertex. public bool AddVertex(in Vertex vertex) { - Edge* edges = stackalloc Edge[256]; + System.Diagnostics.Debug.Assert(vPointer < MaxVertices, "Maximum number of vertices exceeded."); + + // see (*) above + Edge* edges = stackalloc Edge[MaxVertices * 3 / 2]; vertices[vPointer] = vertex; int ePointer = 0; - for (int index = tCount; index-- > 0;) + for (int index = tPointer; index-- > 0;) { if (!IsLit(index, vPointer)) continue; - Edge edge; - bool added; for (int k = 0; k < 3; k++) { - edge = new Edge(triangles[index][(k + 0) % 3], triangles[index][(k + 1) % 3]); - added = true; + Edge edge = new Edge(triangles[index][(k + 0) % 3], triangles[index][(k + 1) % 3]); + bool added = true; for (int e = ePointer; e-- > 0;) { if (Edge.Equals(edges[e], edge)) @@ -406,7 +410,7 @@ public bool AddVertex(in Vertex vertex) if (added) edges[ePointer++] = edge; } - triangles[index] = triangles[--tCount]; + triangles[index] = triangles[--tPointer]; } if (ePointer == 0) return false; @@ -418,7 +422,6 @@ public bool AddVertex(in Vertex vertex) } vPointer++; - return true; } } \ No newline at end of file From 78788818b4dd72e802406675df2f452fc9445478 Mon Sep 17 00:00:00 2001 From: notgiven688 Date: Sat, 3 Feb 2024 17:01:38 +0100 Subject: [PATCH 3/3] Beautify Image.cs and Mesh.cs in JitterDemo --- src/JitterDemo/ConvexDecomposition.cs | 2 +- src/JitterDemo/Demos/Demo06.cs | 4 +- src/JitterDemo/Renderer/Assets/Image.cs | 12 +-- src/JitterDemo/Renderer/Assets/Mesh.cs | 94 ++++++++++--------- .../Renderer/CSM/Instances/MultiMesh.cs | 2 +- 5 files changed, 60 insertions(+), 54 deletions(-) diff --git a/src/JitterDemo/ConvexDecomposition.cs b/src/JitterDemo/ConvexDecomposition.cs index 305ee715..b6c4bc04 100644 --- a/src/JitterDemo/ConvexDecomposition.cs +++ b/src/JitterDemo/ConvexDecomposition.cs @@ -48,7 +48,7 @@ public void Load() { List hullTriangles = new(); - for (int i = group.FromInclusive; i < group.ToExlusive; i++) + for (int i = group.FromInclusive; i < group.ToExclusive; i++) { ref TriangleVertexIndex tvi = ref mesh.Indices[i]; diff --git a/src/JitterDemo/Demos/Demo06.cs b/src/JitterDemo/Demos/Demo06.cs index e5ee3c91..01e5c73e 100644 --- a/src/JitterDemo/Demos/Demo06.cs +++ b/src/JitterDemo/Demos/Demo06.cs @@ -79,7 +79,7 @@ public override void LightPass(PhongShader shader) shader.MaterialProperties.ColorMixing.Set(0.1f, 0, 1.2f); shader.MaterialProperties.Shininess.Set(1000); shader.MaterialProperties.Specular.Set(1, 1, 1); - GLDevice.DrawElementsInstanced(DrawMode.Triangles, 3 * (mg.ToExlusive - mg.FromInclusive), + GLDevice.DrawElementsInstanced(DrawMode.Triangles, 3 * (mg.ToExclusive - mg.FromInclusive), IndexType.UnsignedInt, mg.FromInclusive * sof * 3, Count); // glass @@ -88,7 +88,7 @@ public override void LightPass(PhongShader shader) shader.MaterialProperties.Color.Set(0.6f, 0.6f, 0.6f); shader.MaterialProperties.Alpha.Set(0.6f); shader.MaterialProperties.Shininess.Set(1000.0f); - GLDevice.DrawElementsInstanced(DrawMode.Triangles, 3 * (mg.ToExlusive - mg.FromInclusive), + GLDevice.DrawElementsInstanced(DrawMode.Triangles, 3 * (mg.ToExclusive - mg.FromInclusive), IndexType.UnsignedInt, mg.FromInclusive * sof * 3, Count); shader.MaterialProperties.Alpha.Set(1.0f); } diff --git a/src/JitterDemo/Renderer/Assets/Image.cs b/src/JitterDemo/Renderer/Assets/Image.cs index 9fdfff3b..828e3bb6 100644 --- a/src/JitterDemo/Renderer/Assets/Image.cs +++ b/src/JitterDemo/Renderer/Assets/Image.cs @@ -32,7 +32,7 @@ public class Image private readonly byte[] argbData; - public Image(byte[] argbData, int width, int height) + private Image(byte[] argbData, int width, int height) { this.argbData = argbData; Width = width; @@ -40,12 +40,12 @@ public Image(byte[] argbData, int width, int height) } /// - /// Minimimal *.tga (Truevision TGA) loader for true color images with runtime + /// Minimal *.tga (Truevision TGA) loader for true color images with runtime /// length encoding support. /// public static Image LoadImage(string filename) { - const int DataOffset = 18; + const int dataOffset = 18; var data = File.ReadAllBytes(filename).AsSpan(); @@ -56,18 +56,18 @@ public static Image LoadImage(string filename) int descriptor = data[17]; // Image type 2 and 10: The image data is a direct representation of the pixel color. - // For a Pixel Depth of 15 and 16 bit, each pixel is stored with 5 bits per color. + // For a Pixel Depth of 15 and 16 bit, each pixel is stored with 5 bits per color. // If the pixel depth is 16 bits, the topmost bit is reserved for transparency. For // a pixel depth of 24 bits, each pixel is stored with 8 bits per color. A 32-bit pixel // depth defines an additional 8-bit alpha channel. // [https://en.wikipedia.org/wiki/Truevision_TGA] - if (!((imageType == 2 || imageType == 10) && (bitPerPixel == 24 || bitPerPixel == 32))) + if (!(imageType is 2 or 10 && bitPerPixel is 24 or 32)) { throw new Exception("Only 24bit and 32bit encoded *.tga-files supported!"); } - var colorData = data[DataOffset..data.Length]; + var colorData = data[dataOffset..data.Length]; int bytesPerPixel = bitPerPixel / 8; diff --git a/src/JitterDemo/Renderer/Assets/Mesh.cs b/src/JitterDemo/Renderer/Assets/Mesh.cs index a2c71cce..a6ac1b66 100644 --- a/src/JitterDemo/Renderer/Assets/Mesh.cs +++ b/src/JitterDemo/Renderer/Assets/Mesh.cs @@ -14,7 +14,7 @@ public struct Group { public string Name; public int FromInclusive; - public int ToExlusive; + public int ToExclusive; } public readonly Vertex[] Vertices; @@ -55,44 +55,45 @@ public static Mesh LoadMesh(string filename, bool revertWinding = false) { var format = new NumberFormatInfo { NumberDecimalSeparator = "." }; - float PF(string str) - { - return float.Parse(str, format); - } // Parse float - - int PIm1(string str) - { - return int.Parse(str) - 1; - } // Parse int minus 1 + float ParseFloat(string str) => float.Parse(str, format); + int ParseIndex(string str) => int.Parse(str) - 1; string[] content = filename.EndsWith(".zip") ? ReadFromZip(filename).ToArray() : File.ReadAllLines(filename); var lines = content.Select(s => s.Trim()).Where(s => s != string.Empty); - List v = new(); - List vn = new(); - List vt = new(); + List v = [], vn = []; + List vt = []; foreach (string line in lines) { var s = line.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); - if (s[0] == "v") v.Add(new Vector3(PF(s[1]), PF(s[2]), PF(s[3]))); - if (s[0] == "vn") vn.Add(new Vector3(PF(s[1]), PF(s[2]), PF(s[3]))); - if (s[0] == "vt") vt.Add(new Vector2(PF(s[1]), PF(s[2]))); + switch (s[0]) + { + case "v": + v.Add(new Vector3(ParseFloat(s[1]), ParseFloat(s[2]), ParseFloat(s[3]))); + break; + case "vn": + vn.Add(new Vector3(ParseFloat(s[1]), ParseFloat(s[2]), ParseFloat(s[3]))); + break; + case "vt": + vt.Add(new Vector2(ParseFloat(s[1]), ParseFloat(s[2]))); + break; + } } bool hasTexture = vt.Count > 0; bool hasNormals = vn.Count > 0; Dictionary dict = new(); - List vertices = new(); - List indices = new(); + List vertices = []; + List indices = []; int AddVertex(string s) { var a = s.Split("/"); - if (hasTexture && hasNormals) vertices.Add(new Vertex(v[PIm1(a[0])], vn[PIm1(a[2])], vt[PIm1(a[1])])); - else if (hasNormals) vertices.Add(new Vertex(v[PIm1(a[0])], vn[PIm1(a[2])])); - else vertices.Add(new Vertex(v[PIm1(a[0])])); + if (hasTexture && hasNormals) vertices.Add(new Vertex(v[ParseIndex(a[0])], vn[ParseIndex(a[2])], vt[ParseIndex(a[1])])); + else if (hasNormals) vertices.Add(new Vertex(v[ParseIndex(a[0])], vn[ParseIndex(a[2])])); + else vertices.Add(new Vertex(v[ParseIndex(a[0])])); return vertices.Count - 1; } @@ -112,41 +113,46 @@ int AddVertex(string s) } } - List groups = new(); - Group glast = new(); - bool firstg = true; + List groups = []; + Group groupLast = new(); + bool firstGroup = true; foreach (string line in lines) { - var s = line.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); + var s = line.Split(' ', StringSplitOptions.TrimEntries | + StringSplitOptions.RemoveEmptyEntries); - if (s[0] == "o") + switch (s[0]) { - if (!firstg) + case "o": { - glast.ToExlusive = indices.Count; - groups.Add(glast); + if (!firstGroup) + { + groupLast.ToExclusive = indices.Count; + groups.Add(groupLast); + } + + firstGroup = false; + groupLast.FromInclusive = indices.Count; + groupLast.Name = s.Length > 1 ? s[1] : string.Empty; + break; } + case "f": + { + int i0 = dict[s[1]]; + int i1 = dict[s[2]]; + int i2 = dict[s[3]]; - firstg = false; - glast.FromInclusive = indices.Count; - glast.Name = s.Length > 1 ? s[1] : string.Empty; - } - else if (s[0] == "f") - { - int i0 = dict[s[1]]; - int i1 = dict[s[2]]; - int i2 = dict[s[3]]; - - if (revertWinding) indices.Add(new TriangleVertexIndex(i1, i0, i2)); - else indices.Add(new TriangleVertexIndex(i0, i1, i2)); + indices.Add(revertWinding ? new TriangleVertexIndex(i1, i0, i2) : new TriangleVertexIndex(i0, i1, i2)); + break; + } } } - if (!firstg) + if (!firstGroup) { - glast.ToExlusive = indices.Count; - groups.Add(glast); + groupLast.ToExclusive = indices.Count; + groups.Add(groupLast); } return new Mesh(vertices.ToArray(), indices.ToArray(), groups.ToArray()); diff --git a/src/JitterDemo/Renderer/CSM/Instances/MultiMesh.cs b/src/JitterDemo/Renderer/CSM/Instances/MultiMesh.cs index 42fefcde..7cf0c70d 100644 --- a/src/JitterDemo/Renderer/CSM/Instances/MultiMesh.cs +++ b/src/JitterDemo/Renderer/CSM/Instances/MultiMesh.cs @@ -31,7 +31,7 @@ public override void LightPass(PhongShader shader) GLDevice.DrawElementsInstanced(DrawMode.Triangles, - 3 * (mesh.Groups[i].ToExlusive - mesh.Groups[i].FromInclusive), IndexType.UnsignedInt, + 3 * (mesh.Groups[i].ToExclusive - mesh.Groups[i].FromInclusive), IndexType.UnsignedInt, mesh.Groups[i].FromInclusive * sof * 3, Count); }