From f076152956bae07e7e35ff5ca8a335a355cda2ca Mon Sep 17 00:00:00 2001 From: Cupiii Date: Sat, 12 Mar 2022 18:42:24 +0100 Subject: [PATCH 1/3] Rummer: New Rubber Mesh Generator selector old/new still inplace --- .../VPT/Rubber/RubberMeshGenerator.cs | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs b/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs index e96c28131..597ad8159 100644 --- a/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs @@ -76,7 +76,163 @@ private Matrix3D GetRotationMatrix() return fullMatrix; } + private Mesh GetMeshNew(float playfieldHeight, float meshHeight, int detailLevel, int acc = -1, bool createHitShape = false, float margin = 0f) + { + var mesh = new Mesh(); + // i dont understand the calculation of splineaccuracy here /cupiii + var accuracy = (int)(10.0f * 1.2f); + if (acc != -1) + { // hit shapes and UI display have the same, static, precision + accuracy = acc; + } + + var splineAccuracy = acc != -1 ? 4.0f * MathF.Pow(10.0f, (10.0f - PhysicsConstants.HitShapeDetailLevel) * (float)(1.0 / 1.5)) : -1.0f; + SplineVertex sv = new SplineVertex(_data.DragPoints, (int)(_data.Thickness + 0.5), detailLevel, splineAccuracy, margin: margin, loop: true); + + var height = playfieldHeight + meshHeight; + + + // one ring for each Splinevertex + + var numRings = sv.VertexCount; + var numSegments = accuracy; + + var up = new Vertex3D(0f, 0f, 1f); + var points = new Vertex3D[numRings]; // middlepoints of rings + var tangents = new Vertex3D[numRings]; // pointing into the direction of the spline, even first and last + var right = new Vertex3D[numRings]; // pointing right, looking into tangent direction + var down = new Vertex3D[numRings]; // pointing down from tangent view + var accLength = new float[numRings]; // accumulated length of the wire beginning at 0; + + // copy the data from the pline into the middle of the new variables + for (int i = 0; i < sv.VertexCount; i++) + { + points[i] = new Vertex3D(sv.MiddlePoints[i].X, sv.MiddlePoints[i].Y, height); + right[i] = new Vertex3D(sv.RgvLocal[i].X - sv.MiddlePoints[i].X, sv.RgvLocal[i].Y - sv.MiddlePoints[i].Y, 0f); + right[i].Normalize(); + tangents[i] = Vertex3D.CrossProduct(right[i], new Vertex3D(0f, 0f, 1f)); + tangents[i].Normalize(); + } + + // calculate downvectors + for (int i = 0; i < numRings; i++) + { + down[i] = Vertex3D.CrossProduct(right[i], tangents[i]); + down[i].Normalize(); + } + + // For UV calculation we need the whole length of the rubber + accLength[0] = 0.0f; + for (int i = 1; i < numRings; i++) + accLength[i] = accLength[i - 1] + (points[i] - points[i - 1]).Length(); + // add the lenth from the last ring to the first ring + var totalLength = accLength[numRings - 1] + (points[0] - points[numRings - 1]).Length(); ; + + var numVertices = (numRings + 1) * numSegments; + var numIndices = numRings * numSegments * 6; + mesh.Vertices = new Vertex3DNoTex2[numVertices]; + mesh.Indices = new int[numIndices]; + + // precalculate the rings (positive X is left, positive Y is up) Starting at the bottom clockwise (X=0, Y=1) + var ringsX = new float[numSegments]; + var ringsY = new float[numSegments]; + for (int i = 0; i < numSegments; i++) + { + ringsX[i] = -1.0f * (float)System.Math.Sin(System.Math.PI * 2 * i / numSegments) * _data.Thickness; + ringsY[i] = -1.0f * (float)System.Math.Cos(System.Math.PI + System.Math.PI * 2 * i / numSegments) * _data.Thickness; + } + + var verticesIndex = 0; + var indicesIndex = 0; + + // calculate Vertices first + for (int currentRing = 0; currentRing < numRings; currentRing++) + { + // calculate one ring + for (int currentSegment = 0; currentSegment < numSegments; currentSegment++) + { + mesh.Vertices[verticesIndex++] = new Vertex3DNoTex2 + { + X = points[currentRing].X + right[currentRing].X * ringsX[currentSegment] + down[currentRing].X * ringsY[currentSegment], + Y = points[currentRing].Y + right[currentRing].Y * ringsX[currentSegment] + down[currentRing].Y * ringsY[currentSegment], + Z = points[currentRing].Z + right[currentRing].Z * ringsX[currentSegment] + down[currentRing].Z * ringsY[currentSegment], + //normals seem to be somehow off, but are caculated again at the end of mesh creation. + Nx = right[currentRing].X * ringsX[currentSegment] + down[currentRing].X * ringsY[currentSegment], + Ny = right[currentRing].Y * ringsX[currentSegment] + down[currentRing].Y * ringsY[currentSegment], + Nz = right[currentRing].Z * ringsX[currentSegment] + down[currentRing].Z * ringsY[currentSegment], + Tu = accLength[currentRing] / totalLength, + Tv = (float)currentSegment / ((float)numSegments - 1) + + }; + } + + + // could be integrated in above for loop, but better to read and will be optimized anyway by compiler + if (currentRing > 0) + { + for (int currentSegment = 0; currentSegment < numSegments; currentSegment++) + { + var csp1 = currentSegment + 1; + if (csp1 >= numSegments) + csp1 = 0; + mesh.Indices[indicesIndex++] = (currentRing - 1) * numSegments + currentSegment; + mesh.Indices[indicesIndex++] = currentRing * numSegments + currentSegment; + mesh.Indices[indicesIndex++] = currentRing * numSegments + csp1; + mesh.Indices[indicesIndex++] = (currentRing - 1) * numSegments + currentSegment; + mesh.Indices[indicesIndex++] = currentRing * numSegments + csp1; + mesh.Indices[indicesIndex++] = (currentRing - 1) * numSegments + csp1; + } + } + } + + // copy first ring into last ring + for (int currentSegment = 0; currentSegment < numSegments; currentSegment++) + { + mesh.Vertices[verticesIndex++] = new Vertex3DNoTex2 + { + X = points[0].X + right[0].X * ringsX[currentSegment] + down[0].X * ringsY[currentSegment], + Y = points[0].Y + right[0].Y * ringsX[currentSegment] + down[0].Y * ringsY[currentSegment], + Z = points[0].Z + right[0].Z * ringsX[currentSegment] + down[0].Z * ringsY[currentSegment], + //normals seem to be somehow off, but are caculated again at the end of mesh creation. + Nx = right[0].X * ringsX[currentSegment] + down[0].X * ringsY[currentSegment], + Ny = right[0].Y * ringsX[currentSegment] + down[0].Y * ringsY[currentSegment], + Nz = right[0].Z * ringsX[currentSegment] + down[0].Z * ringsY[currentSegment], + Tu = 1f, + Tv = (float)currentSegment / ((float)numSegments - 1) + + }; + } + + for (int currentSegment = 0; currentSegment < numSegments; currentSegment++) + { + var csp1 = currentSegment + 1; + if (csp1 >= numSegments) + csp1 = 0; + mesh.Indices[indicesIndex++] = (numRings - 1) * numSegments + currentSegment; + mesh.Indices[indicesIndex++] = (numRings) * numSegments + currentSegment; + mesh.Indices[indicesIndex++] = (numRings) * numSegments + csp1; + mesh.Indices[indicesIndex++] = (numRings - 1) * numSegments + currentSegment; + mesh.Indices[indicesIndex++] = (numRings) * numSegments + csp1; + mesh.Indices[indicesIndex++] = (numRings - 1) * numSegments + csp1; + } + + Mesh.ComputeNormals(mesh.Vertices, numVertices, mesh.Indices, numIndices); + + return mesh; + + } + private Mesh GetMesh(float playfieldHeight, float meshHeight, int detailLevel, int acc = -1, bool createHitShape = false, float margin = 0f) + { + var newMesh = true; + if (newMesh) + return GetMeshNew(playfieldHeight, meshHeight, detailLevel, acc, createHitShape, margin); + else + return GetMeshOld(playfieldHeight, meshHeight, detailLevel, acc, createHitShape, margin); + } + + + private Mesh GetMeshOld(float playfieldHeight, float meshHeight, int detailLevel, int acc = -1, bool createHitShape = false, float margin = 0f) { var mesh = new Mesh(); var accuracy = (int)(10.0f * 1.2f); From 67893c6fa23fd18c4481377a4d7b1c1f6d1b0423 Mon Sep 17 00:00:00 2001 From: Cupiii Date: Sat, 12 Mar 2022 18:43:14 +0100 Subject: [PATCH 2/3] Rubber: deleted old mesh code --- .../VPT/Rubber/RubberMeshGenerator.cs | 161 +----------------- 1 file changed, 1 insertion(+), 160 deletions(-) diff --git a/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs b/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs index 597ad8159..5bfc3eebd 100644 --- a/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs @@ -76,7 +76,7 @@ private Matrix3D GetRotationMatrix() return fullMatrix; } - private Mesh GetMeshNew(float playfieldHeight, float meshHeight, int detailLevel, int acc = -1, bool createHitShape = false, float margin = 0f) + private Mesh GetMesh(float playfieldHeight, float meshHeight, int detailLevel, int acc = -1, bool createHitShape = false, float margin = 0f) { var mesh = new Mesh(); // i dont understand the calculation of splineaccuracy here /cupiii @@ -222,164 +222,5 @@ private Mesh GetMeshNew(float playfieldHeight, float meshHeight, int detailLevel } - private Mesh GetMesh(float playfieldHeight, float meshHeight, int detailLevel, int acc = -1, bool createHitShape = false, float margin = 0f) - { - var newMesh = true; - if (newMesh) - return GetMeshNew(playfieldHeight, meshHeight, detailLevel, acc, createHitShape, margin); - else - return GetMeshOld(playfieldHeight, meshHeight, detailLevel, acc, createHitShape, margin); - } - - - private Mesh GetMeshOld(float playfieldHeight, float meshHeight, int detailLevel, int acc = -1, bool createHitShape = false, float margin = 0f) - { - var mesh = new Mesh(); - var accuracy = (int)(10.0f * 1.2f); - if (acc != -1) { // hit shapes and UI display have the same, static, precision - accuracy = acc; - } - - var splineAccuracy = acc != -1 ? 4.0f * MathF.Pow(10.0f, (10.0f - PhysicsConstants.HitShapeDetailLevel) * (float) (1.0 / 1.5)) : -1.0f; - var sv = new SplineVertex(_data.DragPoints, _data.Thickness, detailLevel, splineAccuracy, margin: margin); - - var numRings = sv.VertexCount - 1; - var numSegments = accuracy; - - var numVertices = numRings * numSegments; - var numIndices = 6 * numVertices; //m_numVertices*2+2; - var height = playfieldHeight + meshHeight; - - mesh.Vertices = new Vertex3DNoTex2[numVertices]; - mesh.Indices = new int[numIndices]; - - var prevB = new Vertex3D(); - var invNr = 1.0f / numRings; - var invNs = 1.0f / numSegments; - var index = 0; - for (var i = 0; i < numRings; i++) { - var i2 = i == numRings - 1 ? 0 : i + 1; - var tangent = new Vertex3D(sv.MiddlePoints[i2].X - sv.MiddlePoints[i].X, - sv.MiddlePoints[i2].Y - sv.MiddlePoints[i].Y, 0.0f); - - Vertex3D biNormal; - Vertex3D normal; - if (i == 0) { - var up = new Vertex3D(sv.MiddlePoints[i2].X + sv.MiddlePoints[i].X, sv.MiddlePoints[i2].Y + sv.MiddlePoints[i].Y, height * 2.0f); - normal = new Vertex3D(tangent.Y * up.Z, -tangent.X * up.Z, tangent.X * up.Y - tangent.Y * up.X); // = CrossProduct(tangent, up) - biNormal = new Vertex3D(tangent.Y * normal.Z, -tangent.X * normal.Z, tangent.X * normal.Y - tangent.Y * normal.X); // = CrossProduct(tangent, normal) - - } else { - normal = Vertex3D.CrossProduct(prevB, tangent); - biNormal = Vertex3D.CrossProduct(tangent, normal); - } - - biNormal.Normalize(); - normal.Normalize(); - prevB = biNormal; - var u = i * invNr; - for (var j = 0; j < numSegments; j++) { - var v = ((float)j + u) * invNs; - var tmp = Vertex3D.GetRotatedAxis(j * (360.0f * invNs), tangent, normal) * ((_data.Thickness + margin) * 0.5f); - - mesh.Vertices[index] = new Vertex3DNoTex2 { - X = sv.MiddlePoints[i].X + tmp.X, - Y = sv.MiddlePoints[i].Y + tmp.Y - }; - if (createHitShape && (j == 0 || j == 3)) { - //!! hack, adapt if changing detail level for hitshape - // for a hit shape create a more rectangle mesh and not a smooth one - tmp.Z *= 0.6f; - } - mesh.Vertices[index].Z = height + tmp.Z; - - //texel - mesh.Vertices[index].Tu = u; - mesh.Vertices[index].Tv = v; - index++; - } - } - - // calculate faces - for (var i = 0; i < numRings; i++) { - for (var j = 0; j < numSegments; j++) { - var quad = new int[4]; - quad[0] = i * numSegments + j; - - if (j != numSegments - 1) { - quad[1] = i * numSegments + j + 1; - - } else { - quad[1] = i * numSegments; - } - - if (i != numRings - 1) { - quad[2] = (i + 1) * numSegments + j; - if (j != numSegments - 1) { - quad[3] = (i + 1) * numSegments + j + 1; - - } else { - quad[3] = (i + 1) * numSegments; - } - - } else { - quad[2] = j; - if (j != numSegments - 1) { - quad[3] = j + 1; - - } else { - quad[3] = 0; - } - } - - mesh.Indices[(i * numSegments + j) * 6] = quad[0]; - mesh.Indices[(i * numSegments + j) * 6 + 1] = quad[1]; - mesh.Indices[(i * numSegments + j) * 6 + 2] = quad[2]; - mesh.Indices[(i * numSegments + j) * 6 + 3] = quad[3]; - mesh.Indices[(i * numSegments + j) * 6 + 4] = quad[2]; - mesh.Indices[(i * numSegments + j) * 6 + 5] = quad[1]; - } - } - - Mesh.ComputeNormals(mesh.Vertices, numVertices, mesh.Indices, numIndices); - - var maxX = Constants.FloatMin; - var minX = Constants.FloatMax; - var maxY = Constants.FloatMin; - var minY = Constants.FloatMax; - var maxZ = Constants.FloatMin; - var minZ = Constants.FloatMax; - for (var i = 0; i < numVertices; i++) { - if (maxX < mesh.Vertices[i].X) { - maxX = mesh.Vertices[i].X; - } - - if (minX > mesh.Vertices[i].X) { - minX = mesh.Vertices[i].X; - } - - if (maxY < mesh.Vertices[i].Y) { - maxY = mesh.Vertices[i].Y; - } - - if (minY > mesh.Vertices[i].Y) { - minY = mesh.Vertices[i].Y; - } - - if (maxZ < mesh.Vertices[i].Z) { - maxZ = mesh.Vertices[i].Z; - } - - if (minZ > mesh.Vertices[i].Z) { - minZ = mesh.Vertices[i].Z; - } - } - - _middlePoint.X = (maxX + minX) * 0.5f; - _middlePoint.Y = (maxY + minY) * 0.5f; - _middlePoint.Z = (maxZ + minZ) * 0.5f; - - return mesh; - } } } From 87c6cc846930072a66885c6e575e928c1bfdf950 Mon Sep 17 00:00:00 2001 From: Cupiii Date: Sun, 13 Mar 2022 15:43:17 +0100 Subject: [PATCH 3/3] Rubber (and MWG) set _middlepoint so that gizmo is always in the middle --- .../MetalWireGuideMeshGenerator.cs | 20 +++++++++++++++++++ .../VPT/Rubber/RubberMeshGenerator.cs | 20 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideMeshGenerator.cs b/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideMeshGenerator.cs index eb63c3592..f7bca76bf 100644 --- a/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideMeshGenerator.cs @@ -238,6 +238,26 @@ private Mesh GetMesh(float playfieldHeight, float meshHeight, int detailLevel, f Mesh.ComputeNormals(mesh.Vertices, numVertices, mesh.Indices, numIndices); + var maxX = Constants.FloatMin; + var minX = Constants.FloatMax; + var maxY = Constants.FloatMin; + var minY = Constants.FloatMax; + var maxZ = Constants.FloatMin; + var minZ = Constants.FloatMax; + for (var i = 0; i < numVertices; i++) + { + MathF.Max(maxX, mesh.Vertices[i].X); + MathF.Max(maxY, mesh.Vertices[i].Y); + MathF.Max(maxZ, mesh.Vertices[i].Z); + MathF.Min(minX, mesh.Vertices[i].X); + MathF.Min(minY, mesh.Vertices[i].X); + MathF.Min(minZ, mesh.Vertices[i].X); + } + + _middlePoint.X = (maxX + minX) * 0.5f; + _middlePoint.Y = (maxY + minY) * 0.5f; + _middlePoint.Z = (maxZ + minZ) * 0.5f; + return mesh; } } diff --git a/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs b/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs index 5bfc3eebd..3571253f6 100644 --- a/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs @@ -218,6 +218,26 @@ private Mesh GetMesh(float playfieldHeight, float meshHeight, int detailLevel, i Mesh.ComputeNormals(mesh.Vertices, numVertices, mesh.Indices, numIndices); + var maxX = Constants.FloatMin; + var minX = Constants.FloatMax; + var maxY = Constants.FloatMin; + var minY = Constants.FloatMax; + var maxZ = Constants.FloatMin; + var minZ = Constants.FloatMax; + for (var i = 0; i < numVertices; i++) + { + MathF.Max(maxX, mesh.Vertices[i].X); + MathF.Max(maxY, mesh.Vertices[i].Y); + MathF.Max(maxZ, mesh.Vertices[i].Z); + MathF.Min(minX, mesh.Vertices[i].X); + MathF.Min(minY, mesh.Vertices[i].X); + MathF.Min(minZ, mesh.Vertices[i].X); + } + + _middlePoint.X = (maxX + minX) * 0.5f; + _middlePoint.Y = (maxY + minY) * 0.5f; + _middlePoint.Z = (maxZ + minZ) * 0.5f; + return mesh; }