Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
233 changes: 125 additions & 108 deletions VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,110 +79,141 @@ private Matrix3D GetRotationMatrix()
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
var accuracy = (int)(10.0f * 1.2f);
if (acc != -1) { // hit shapes and UI display have the same, static, precision
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 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 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);
}
// one ring for each Splinevertex

var numRings = sv.VertexCount;
var numSegments = accuracy;

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;
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();
}

//texel
mesh.Vertices[index].Tu = u;
mesh.Vertices[index].Tv = v;
index++;
}
// calculate downvectors
for (int i = 0; i < numRings; i++)
{
down[i] = Vertex3D.CrossProduct(right[i], tangents[i]);
down[i].Normalize();
}

// 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;
// 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(); ;

if (j != numSegments - 1) {
quad[1] = i * numSegments + j + 1;
var numVertices = (numRings + 1) * numSegments;
var numIndices = numRings * numSegments * 6;
mesh.Vertices = new Vertex3DNoTex2[numVertices];
mesh.Indices = new int[numIndices];

} else {
quad[1] = i * numSegments;
}
// 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;
}

if (i != numRings - 1) {
quad[2] = (i + 1) * numSegments + j;
if (j != numSegments - 1) {
quad[3] = (i + 1) * numSegments + j + 1;
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)

} else {
quad[3] = (i + 1) * numSegments;
}
};
}

} else {
quad[2] = j;
if (j != numSegments - 1) {
quad[3] = j + 1;

} else {
quad[3] = 0;
}
// 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;
}
}
}

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];
}
// 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);
Expand All @@ -193,37 +224,23 @@ private Mesh GetMesh(float playfieldHeight, float meshHeight, int detailLevel, i
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;
}
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;

}

}
}