private HitObject[] GenerateCurvedHitObjects(Table.Table table, IItem item) { var hitObjects = new List <HitObject>(); var height = table.GetSurfaceHeight(_data.Surface, _data.Center.X, _data.Center.Y); var vVertex = DragPoint.GetRgVertex <RenderVertex2D, CatmullCurve2DCatmullCurveFactory>(_data.DragPoints); var count = vVertex.Length; var rgv = new RenderVertex2D[count]; var rgv3D = new Vertex3D[count]; for (var i = 0; i < count; i++) { rgv[i] = vVertex[i]; rgv3D[i] = new Vertex3D(rgv[i].X, rgv[i].Y, height + (float)(PhysicsConstants.PhysSkin * 2.0)); } for (var i = 0; i < count; i++) { var pv2 = rgv[i < count - 1 ? i + 1 : 0]; var pv3 = rgv[i < count - 2 ? i + 2 : i + 2 - count]; hitObjects.Add(GetLineSeg(pv2, pv3, height, item)); } hitObjects.AddRange(new Hit3DPoly(rgv3D, ItemType.Trigger, item).ConvertToTriangles()); return(hitObjects.ToArray()); }
public RenderVertex3D[] GetCentralCurve(Table.Table table, float acc = -1.0f) { float accuracy; // as solid ramps are rendered into the static buffer, always use maximum precision if (acc != -1.0) { accuracy = acc; // used for hit shape calculation, always! } else { var mat = table.GetMaterial(_data.Material); if (mat == null || !mat.IsOpacityActive) { accuracy = 10.0f; } else { accuracy = table.GetDetailLevel(); } } // min = 4 (highest accuracy/detail level), max = 4 * 10^(10/1.5) = ~18.000.000 (lowest accuracy/detail level) accuracy = 4.0f * MathF.Pow(10.0f, (10.0f - accuracy) * (1.0f / 1.5f)); return(DragPoint.GetRgVertex <RenderVertex3D, CatmullCurve3DCatmullCurveFactory>(_data.DragPoints, false, accuracy)); }
internal void GenerateColliders(float playfieldHeight, List <ICollider> colliders, float margin = 0f) { var vVertex = DragPoint.GetRgVertex <RenderVertex2D, CatmullCurve2DCatmullCurveFactory>(_component.DragPoints); var count = vVertex.Length; var rgv3Dt = new float3[count]; var rgv3Db = _colliderComponent.IsBottomSolid ? new float3[count] : null; var bottom = _component.HeightBottom + playfieldHeight - margin; var top = _component.HeightTop + playfieldHeight + margin; for (var i = 0; i < count; ++i) { var pv1 = vVertex[i]; rgv3Dt[i] = new float3(pv1.X, pv1.Y, top); if (rgv3Db != null) { rgv3Db[count - 1 - i] = new float3(pv1.X, pv1.Y, bottom); } var pv2 = vVertex[(i + 1) % count]; var pv3 = vVertex[(i + 2) % count]; GenerateLinePolys(pv2, pv3, playfieldHeight, colliders); } ColliderUtils.Generate3DPolyColliders(in rgv3Dt, _api.GetColliderInfo(), colliders); if (rgv3Db != null) { ColliderUtils.Generate3DPolyColliders(in rgv3Db, _api.GetColliderInfo(), colliders); } }
private static RenderVertex2D[] GetCentralCurve(DragPointData[] dragPoints, int tableDetailLevel, float acc, bool staticRendering = true, bool loop = true) { float accuracy; // as solid rubbers are rendered into the static buffer, always use maximum precision if (acc != -1.0f) { accuracy = acc; // used for hit shape calculation, always! } else { accuracy = staticRendering ? 10.0f : tableDetailLevel; // min = 4 (highest accuracy/detail level), max = 4 * 10^(10/1.5) = ~18.000.000 (lowest accuracy/detail level) accuracy = 4.0f * MathF.Pow(10.0f, (10.0f - accuracy) * (float)(1.0 / 1.5)); } return(DragPoint.GetRgVertex <RenderVertex2D, CatmullCurve2DCatmullCurveFactory>(dragPoints, loop, accuracy)); }
private void GenerateCurvedHitObjects(ICollection <ICollider> colliders) { var height = _component.PositionZ; var vVertex = DragPoint.GetRgVertex <RenderVertex2D, CatmullCurve2DCatmullCurveFactory>(_component.DragPoints); var count = vVertex.Length; var rgv = new RenderVertex2D[count]; var rgv3D = new float3[count]; for (var i = 0; i < count; i++) { rgv[i] = vVertex[i]; rgv3D[i] = new float3(rgv[i].X, rgv[i].Y, height + (float)(PhysicsConstants.PhysSkin * 2.0)); } ColliderUtils.Generate3DPolyColliders(rgv3D, _api.GetColliderInfo(), colliders); for (var i = 0; i < count; i++) { var pv2 = rgv[i < count - 1 ? i + 1 : 0]; var pv3 = rgv[i < count - 2 ? i + 2 : i + 2 - count]; AddLineSeg(pv2.ToUnityFloat2(), pv3.ToUnityFloat2(), height, colliders); } }
/// <summary> /// Returns all hit objects for the surface. /// </summary> private HitObject[] Generate3DPolys(Table.Table table, IItem item) { var hitObjects = new List <HitObject>(); var vVertex = DragPoint.GetRgVertex <RenderVertex2D, CatmullCurve2DCatmullCurveFactory>(_data.DragPoints); var count = vVertex.Length; var rgv3Dt = new Vertex3D[count]; var rgv3Db = _data.IsBottomSolid ? new Vertex3D[count] : null; var bottom = _data.HeightBottom + table.TableHeight; var top = _data.HeightTop + table.TableHeight; for (var i = 0; i < count; ++i) { var pv1 = vVertex[i]; rgv3Dt[i] = new Vertex3D(pv1.X, pv1.Y, top); if (rgv3Db != null) { rgv3Db[count - 1 - i] = new Vertex3D(pv1.X, pv1.Y, bottom); } var pv2 = vVertex[(i + 1) % count]; var pv3 = vVertex[(i + 2) % count]; hitObjects.AddRange(GenerateLinePolys(pv2, pv3, table, item)); } hitObjects.AddRange(new Hit3DPoly(rgv3Dt, ItemType.Surface, item).ConvertToTriangles()); if (rgv3Db != null) { hitObjects.AddRange(new Hit3DPoly(rgv3Db, ItemType.Surface, item).ConvertToTriangles()); } return(hitObjects.ToArray()); }
private Mesh GenerateTopMesh(Table.Table table) { var topMesh = new Mesh("Top"); var vVertex = DragPoint.GetRgVertex <RenderVertex2D, CatmullCurve2DCatmullCurveFactory>(_data.DragPoints); var numVertices = vVertex.Length; var rgNormal = new Vertex2D[numVertices]; for (var i = 0; i < numVertices; i++) { var pv1 = vVertex[i]; var pv2 = vVertex[i < numVertices - 1 ? i + 1 : 0]; var dx = pv1.X - pv2.X; var dy = pv1.Y - pv2.Y; if (dx != 0.0f || dy != 0.0f) { var invLen = 1.0f / MathF.Sqrt(dx * dx + dy * dy); rgNormal[i] = new Vertex2D { X = dy * invLen, Y = dx * invLen }; } else { rgNormal[i] = new Vertex2D { X = 0.0f, Y = 0.0f }; } } // draw top var vPoly = new List <int>(new int[numVertices]); for (var i = 0; i < numVertices; i++) { vPoly[i] = i; } topMesh.Indices = Mesh.PolygonToTriangles(vVertex, vPoly); var numPolys = topMesh.Indices.Length / 3; if (numPolys == 0) { // no polys to render leave vertex buffer undefined return(null); } var heightNotDropped = _data.HeightTop * table.GetScaleZ(); var heightDropped = _data.HeightBottom * table.GetScaleZ() + 0.1; var invTableWidth = 1.0f / table.Width; var invTableHeight = 1.0f / table.Height; Vertex3DNoTex2[][] vertsTop = { new Vertex3DNoTex2[numVertices], new Vertex3DNoTex2[numVertices], new Vertex3DNoTex2[numVertices] }; for (var i = 0; i < numVertices; i++) { var pv0 = vVertex[i]; vertsTop[0][i] = new Vertex3DNoTex2 { X = pv0.X, Y = pv0.Y, Z = heightNotDropped + table.TableHeight, Tu = pv0.X * invTableWidth, Tv = pv0.Y * invTableHeight, Nx = 0, Ny = 0, Nz = 1.0f }; vertsTop[1][i] = new Vertex3DNoTex2 { X = pv0.X, Y = pv0.Y, Z = (float)heightDropped, Tu = pv0.X * invTableWidth, Tv = pv0.Y * invTableHeight, Nx = 0, Ny = 0, Nz = 1.0f }; vertsTop[2][i] = new Vertex3DNoTex2 { X = pv0.X, Y = pv0.Y, Z = _data.HeightBottom, Tu = pv0.X * invTableWidth, Tv = pv0.Y * invTableHeight, Nx = 0, Ny = 0, Nz = -1.0f }; } topMesh.Vertices = vertsTop[0]; return(topMesh); }
private Mesh GenerateSideMesh(Table.Table table) { var sideMesh = new Mesh("Side"); var vVertex = DragPoint.GetRgVertex <RenderVertex2D, CatmullCurve2DCatmullCurveFactory>(_data.DragPoints); var rgTexCoord = DragPoint.GetTextureCoords(_data.DragPoints, vVertex); var numVertices = vVertex.Length; var rgNormal = new Vertex2D[numVertices]; for (var i = 0; i < numVertices; i++) { var pv1 = vVertex[i]; var pv2 = vVertex[i < numVertices - 1 ? i + 1 : 0]; var dx = pv1.X - pv2.X; var dy = pv1.Y - pv2.Y; if (dx != 0.0f || dy != 0.0f) { var invLen = 1.0f / MathF.Sqrt(dx * dx + dy * dy); rgNormal[i] = new Vertex2D { X = dy * invLen, Y = dx * invLen }; } else { rgNormal[i] = new Vertex2D { X = 0.0f, Y = 0.0f }; } } var bottom = _data.HeightBottom * table.GetScaleZ() + table.TableHeight; var top = _data.HeightTop * table.GetScaleZ() + table.TableHeight; var offset = 0; // Render side sideMesh.Vertices = new Vertex3DNoTex2[numVertices * 4]; for (var i = 0; i < numVertices; i++) { var pv1 = vVertex[i]; var pv2 = vVertex[i < numVertices - 1 ? i + 1 : 0]; var a = i == 0 ? numVertices - 1 : i - 1; var c = i < numVertices - 1 ? i + 1 : 0; var vNormal = new [] { new Vertex2D(), new Vertex2D() }; if (pv1.Smooth) { vNormal[0].X = (rgNormal[a].X + rgNormal[i].X) * 0.5f; vNormal[0].Y = (rgNormal[a].Y + rgNormal[i].Y) * 0.5f; } else { vNormal[0].X = rgNormal[i].X; vNormal[0].Y = rgNormal[i].Y; } if (pv2.Smooth) { vNormal[1].X = (rgNormal[i].X + rgNormal[c].X) * 0.5f; vNormal[1].Y = (rgNormal[i].Y + rgNormal[c].Y) * 0.5f; } else { vNormal[1].X = rgNormal[i].X; vNormal[1].Y = rgNormal[i].Y; } vNormal[0].Normalize(); vNormal[1].Normalize(); sideMesh.Vertices[offset] = new Vertex3DNoTex2(); sideMesh.Vertices[offset + 1] = new Vertex3DNoTex2(); sideMesh.Vertices[offset + 2] = new Vertex3DNoTex2(); sideMesh.Vertices[offset + 3] = new Vertex3DNoTex2(); sideMesh.Vertices[offset].X = pv1.X; sideMesh.Vertices[offset].Y = pv1.Y; sideMesh.Vertices[offset].Z = bottom; sideMesh.Vertices[offset + 1].X = pv1.X; sideMesh.Vertices[offset + 1].Y = pv1.Y; sideMesh.Vertices[offset + 1].Z = top; sideMesh.Vertices[offset + 2].X = pv2.X; sideMesh.Vertices[offset + 2].Y = pv2.Y; sideMesh.Vertices[offset + 2].Z = top; sideMesh.Vertices[offset + 3].X = pv2.X; sideMesh.Vertices[offset + 3].Y = pv2.Y; sideMesh.Vertices[offset + 3].Z = bottom; if (_data.SideImage != null) { sideMesh.Vertices[offset].Tu = rgTexCoord[i]; sideMesh.Vertices[offset].Tv = 1.0f; sideMesh.Vertices[offset + 1].Tu = rgTexCoord[i]; sideMesh.Vertices[offset + 1].Tv = 0f; sideMesh.Vertices[offset + 2].Tu = rgTexCoord[c]; sideMesh.Vertices[offset + 2].Tv = 0f; sideMesh.Vertices[offset + 3].Tu = rgTexCoord[c]; sideMesh.Vertices[offset + 3].Tv = 1.0f; } sideMesh.Vertices[offset].Nx = vNormal[0].X; sideMesh.Vertices[offset].Ny = -vNormal[0].Y; sideMesh.Vertices[offset].Nz = 0f; sideMesh.Vertices[offset + 1].Nx = vNormal[0].X; sideMesh.Vertices[offset + 1].Ny = -vNormal[0].Y; sideMesh.Vertices[offset + 1].Nz = 0f; sideMesh.Vertices[offset + 2].Nx = vNormal[1].X; sideMesh.Vertices[offset + 2].Ny = -vNormal[1].Y; sideMesh.Vertices[offset + 2].Nz = 0f; sideMesh.Vertices[offset + 3].Nx = vNormal[1].X; sideMesh.Vertices[offset + 3].Ny = -vNormal[1].Y; sideMesh.Vertices[offset + 3].Nz = 0f; offset += 4; } // prepare index buffer for sides var offset2 = 0; sideMesh.Indices = new int[numVertices * 6]; for (var i = 0; i < numVertices; i++) { sideMesh.Indices[i * 6] = offset2; sideMesh.Indices[i * 6 + 1] = offset2 + 1; sideMesh.Indices[i * 6 + 2] = offset2 + 2; sideMesh.Indices[i * 6 + 3] = offset2; sideMesh.Indices[i * 6 + 4] = offset2 + 2; sideMesh.Indices[i * 6 + 5] = offset2 + 3; offset2 += 4; } return(sideMesh); }
/// <summary> /// Construct & display the curve from DragPointsHandler control points /// Find the curve traveller position along the curve /// </summary> /// /// <remarks> /// Will use the DragPointExposure from the handler's item to display slingshot segments accordingly /// Will update handler's curve traveller position and control point base index for point insertion /// </remarks> private void DisplayCurve() { List <Vector3>[] controlPointsSegments = new List <Vector3> [_handler.ControlPoints.Count].Select(item => new List <Vector3>()).ToArray(); // Display Curve & handle curve traveller if (_handler.ControlPoints.Count > 1) { var transformedDPoints = new List <DragPointData>(); foreach (var controlPoint in _handler.ControlPoints) { var newDp = new DragPointData(controlPoint.DragPoint) { Center = controlPoint.WorldPos.ToVertex3D() }; transformedDPoints.Add(newDp); } var vAccuracy = Vector3.one; vAccuracy = _handler.Transform.localToWorldMatrix.MultiplyVector(vAccuracy); var accuracy = Mathf.Abs(vAccuracy.x * vAccuracy.y * vAccuracy.z); accuracy *= HandleUtility.GetHandleSize(_handler.CurveTravellerPosition) * ControlPoint.ScreenRadius; var vVertex = DragPoint.GetRgVertex <RenderVertex3D, CatmullCurve3DCatmullCurveFactory>( transformedDPoints.ToArray(), _handler.DragPointInspector.PointsAreLooping, accuracy ); if (vVertex.Length > 0) { // Fill Control points paths ControlPoint currentControlPoint = null; foreach (var v in vVertex) { if (v.IsControlPoint) { if (currentControlPoint != null) { controlPointsSegments[currentControlPoint.Index].Add(v.ToUnityVector3()); } currentControlPoint = _handler.ControlPoints.Find(cp => cp.WorldPos == v.ToUnityVector3()); } if (currentControlPoint != null) { controlPointsSegments[currentControlPoint.Index].Add(v.ToUnityVector3()); } } // close loop if needed if (_handler.DragPointInspector.PointsAreLooping) { controlPointsSegments[_handler.ControlPoints.Count - 1].Add(controlPointsSegments[0][0]); } // construct full path _pathPoints.Clear(); const float splitRatio = 0.1f; foreach (var controlPoint in _handler.ControlPoints) { // Split straight segments to avoid HandleUtility.ClosestPointToPolyLine issues ref var segments = ref controlPointsSegments[controlPoint.Index]; if (segments.Count == 2) { var dir = segments[1] - segments[0]; var dist = dir.magnitude; dir = Vector3.Normalize(dir); var newPath = new List <Vector3> { segments[0] }; for (var splitDist = dist * splitRatio; splitDist < dist; splitDist += dist * splitRatio) { newPath.Add(newPath[0] + dir * splitDist); } newPath.Add(segments[1]); segments = newPath; } _pathPoints.AddRange(segments); } _curveTravellerMoved = false; if (_pathPoints.Count > 1) { var newPos = HandleUtility.ClosestPointToPolyLine(_pathPoints.ToArray()); if ((newPos - _handler.CurveTravellerPosition).magnitude >= HandleUtility.GetHandleSize(_handler.CurveTravellerPosition) * ControlPoint.ScreenRadius * CurveTravellerSizeRatio * 0.1f) { _handler.CurveTravellerPosition = newPos; _curveTravellerMoved = true; } } // Render Curve with correct color regarding drag point properties & find curve section where the curve traveller is _handler.CurveTravellerControlPointIdx = -1; var minDist = float.MaxValue; foreach (var controlPoint in _handler.ControlPoints) { var segments = controlPointsSegments[controlPoint.Index].ToArray(); if (segments.Length > 1) { Handles.color = _handler.DragPointInspector.DragPointExposition.Contains(DragPointExposure.SlingShot) && controlPoint.DragPoint.IsSlingshot ? CurveSlingShotColor : CurveColor; Handles.DrawAAPolyLine(CurveWidth, segments); var closestToPath = HandleUtility.ClosestPointToPolyLine(segments); var dist = (closestToPath - _handler.CurveTravellerPosition).magnitude; if (dist < minDist) { minDist = dist; _handler.CurveTravellerControlPointIdx = controlPoint.Index; } } } } }
private Dictionary <string, Mesh> GenerateMeshes(Table.Table table) { var meshes = new Dictionary <string, Mesh>(); var topMesh = new Mesh("Top"); var sideMesh = new Mesh("Side"); var vVertex = DragPoint.GetRgVertex <RenderVertex2D, CatmullCurve2DCatmullCurveFactory>(_data.DragPoints); var rgTexCoord = DragPoint.GetTextureCoords(_data.DragPoints, vVertex); var numVertices = vVertex.Length; var rgNormal = new Vertex2D[numVertices]; for (var i = 0; i < numVertices; i++) { var pv1 = vVertex[i]; var pv2 = vVertex[i < numVertices - 1 ? i + 1 : 0]; var dx = pv1.X - pv2.X; var dy = pv1.Y - pv2.Y; var invLen = 1.0f / MathF.Sqrt(dx * dx + dy * dy); rgNormal[i] = new Vertex2D { X = dy * invLen, Y = dx * invLen }; } var bottom = _data.HeightBottom * table.GetScaleZ() + table.TableHeight; var top = _data.HeightTop * table.GetScaleZ() + table.TableHeight; var offset = 0; // Render side sideMesh.Vertices = new Vertex3DNoTex2[numVertices * 4]; for (var i = 0; i < numVertices; i++) { var pv1 = vVertex[i]; var pv2 = vVertex[i < numVertices - 1 ? i + 1 : 0]; var a = i == 0 ? numVertices - 1 : i - 1; var c = i < numVertices - 1 ? i + 1 : 0; var vNormal = new [] { new Vertex2D(), new Vertex2D() }; if (pv1.Smooth) { vNormal[0].X = (rgNormal[a].X + rgNormal[i].X) * 0.5f; vNormal[0].Y = (rgNormal[a].Y + rgNormal[i].Y) * 0.5f; } else { vNormal[0].X = rgNormal[i].X; vNormal[0].Y = rgNormal[i].Y; } if (pv2.Smooth) { vNormal[1].X = (rgNormal[i].X + rgNormal[c].X) * 0.5f; vNormal[1].Y = (rgNormal[i].Y + rgNormal[c].Y) * 0.5f; } else { vNormal[1].X = rgNormal[i].X; vNormal[1].Y = rgNormal[i].Y; } vNormal[0].Normalize(); vNormal[1].Normalize(); sideMesh.Vertices[offset] = new Vertex3DNoTex2(); sideMesh.Vertices[offset + 1] = new Vertex3DNoTex2(); sideMesh.Vertices[offset + 2] = new Vertex3DNoTex2(); sideMesh.Vertices[offset + 3] = new Vertex3DNoTex2(); sideMesh.Vertices[offset].X = pv1.X; sideMesh.Vertices[offset].Y = pv1.Y; sideMesh.Vertices[offset].Z = bottom; sideMesh.Vertices[offset + 1].X = pv1.X; sideMesh.Vertices[offset + 1].Y = pv1.Y; sideMesh.Vertices[offset + 1].Z = top; sideMesh.Vertices[offset + 2].X = pv2.X; sideMesh.Vertices[offset + 2].Y = pv2.Y; sideMesh.Vertices[offset + 2].Z = top; sideMesh.Vertices[offset + 3].X = pv2.X; sideMesh.Vertices[offset + 3].Y = pv2.Y; sideMesh.Vertices[offset + 3].Z = bottom; if (_data.SideImage != null) { sideMesh.Vertices[offset].Tu = rgTexCoord[i]; sideMesh.Vertices[offset].Tv = 1.0f; sideMesh.Vertices[offset + 1].Tu = rgTexCoord[i]; sideMesh.Vertices[offset + 1].Tv = 0f; sideMesh.Vertices[offset + 2].Tu = rgTexCoord[c]; sideMesh.Vertices[offset + 2].Tv = 0f; sideMesh.Vertices[offset + 3].Tu = rgTexCoord[c]; sideMesh.Vertices[offset + 3].Tv = 1.0f; } sideMesh.Vertices[offset].Nx = vNormal[0].X; sideMesh.Vertices[offset].Ny = -vNormal[0].Y; sideMesh.Vertices[offset].Nz = 0f; sideMesh.Vertices[offset + 1].Nx = vNormal[0].X; sideMesh.Vertices[offset + 1].Ny = -vNormal[0].Y; sideMesh.Vertices[offset + 1].Nz = 0f; sideMesh.Vertices[offset + 2].Nx = vNormal[1].X; sideMesh.Vertices[offset + 2].Ny = -vNormal[1].Y; sideMesh.Vertices[offset + 2].Nz = 0f; sideMesh.Vertices[offset + 3].Nx = vNormal[1].X; sideMesh.Vertices[offset + 3].Ny = -vNormal[1].Y; sideMesh.Vertices[offset + 3].Nz = 0f; offset += 4; } // prepare index buffer for sides var offset2 = 0; sideMesh.Indices = new int[numVertices * 6]; for (var i = 0; i < numVertices; i++) { sideMesh.Indices[i * 6] = offset2; sideMesh.Indices[i * 6 + 1] = offset2 + 1; sideMesh.Indices[i * 6 + 2] = offset2 + 2; sideMesh.Indices[i * 6 + 3] = offset2; sideMesh.Indices[i * 6 + 4] = offset2 + 2; sideMesh.Indices[i * 6 + 5] = offset2 + 3; offset2 += 4; } // draw top var vPoly = new List <int>(new int[numVertices]); for (var i = 0; i < numVertices; i++) { vPoly[i] = i; } topMesh.Indices = Mesh.PolygonToTriangles(vVertex, vPoly); var numPolys = topMesh.Indices.Length / 3; if (numPolys == 0) { // no polys to render leave vertex buffer undefined return(meshes); } var heightNotDropped = _data.HeightTop * table.GetScaleZ(); var heightDropped = _data.HeightBottom * table.GetScaleZ() + 0.1; var invTableWidth = 1.0f / table.Width; var invTableHeight = 1.0f / table.Height; Vertex3DNoTex2[][] vertsTop = { new Vertex3DNoTex2[numVertices], new Vertex3DNoTex2[numVertices], new Vertex3DNoTex2[numVertices] }; for (var i = 0; i < numVertices; i++) { var pv0 = vVertex[i]; vertsTop[0][i] = new Vertex3DNoTex2 { X = pv0.X, Y = pv0.Y, Z = heightNotDropped + table.TableHeight, Tu = pv0.X * invTableWidth, Tv = pv0.Y * invTableHeight, Nx = 0, Ny = 0, Nz = 1.0f }; vertsTop[1][i] = new Vertex3DNoTex2 { X = pv0.X, Y = pv0.Y, Z = (float)heightDropped, Tu = pv0.X * invTableWidth, Tv = pv0.Y * invTableHeight, Nx = 0, Ny = 0, Nz = 1.0f }; vertsTop[2][i] = new Vertex3DNoTex2 { X = pv0.X, Y = pv0.Y, Z = _data.HeightBottom, Tu = pv0.X * invTableWidth, Tv = pv0.Y * invTableHeight, Nx = 0, Ny = 0, Nz = -1.0f }; } topMesh.Vertices = vertsTop[0]; if (topMesh.Vertices.Length > 0) { meshes["Top"] = topMesh; } if (System.Math.Abs(top - bottom) > 0.00001f) { meshes["Side"] = sideMesh; } return(meshes); }