private void CombineSegments(Mesh mesh, ManagedMesh[] resultSegments) { ManagedMesh result = ManagedMesh.Combine(resultSegments); mesh.Clear(); mesh.vertices = result.vertices; mesh.triangles = result.triangles; mesh.uv = result.uv; mesh.normals = result.normals; mesh.tangents = result.tangents; mesh.RecalculateBounds(); }
private void WeldAndSmooth(LoftingGroup group, ManagedMesh meshA, ManagedMesh meshB) { float weldDistanceSqr = group.WeldingDistance * group.WeldingDistance; var verticesA = meshA.vertices; var verticesB = meshB.vertices; var normalsA = meshA.normals; var normalsB = meshB.normals; int i, j, an, bn; an = verticesA.Length; bn = verticesB.Length; for (i = 0; i < an; i++) { for (j = 0; j < bn; j++) { // if any one inside limit distance... if (Vector3.SqrMagnitude(verticesA[i] - verticesB[j]) < weldDistanceSqr) { if (group.Weld) { verticesB[j] = verticesA[i]; } if (group.SmoothNormals && Vector3.Dot(normalsA[i], normalsB[j]) > 0) { normalsA[i] = Vector3.Slerp(normalsA[i], normalsB[j], 0.5f); normalsB[j] = normalsA[i]; } } } } meshA.vertices = verticesA; meshB.vertices = verticesB; meshA.normals = normalsA; meshB.normals = normalsB; }
public void Fix() { mSegmentMesh = (SegmentMesh != null) ? new ManagedMesh(SegmentMesh) : null; mStartPiece = (StartPiece != null) ? new ManagedMesh(StartPiece) : null; mEndPiece = (EndPiece != null) ? new ManagedMesh(EndPiece) : null; //Prevents mesh buffer overflow ActiveSegmentsNumber = Mathf.Clamp( ActiveSegmentsNumber, 1, ushort.MaxValue / mSegmentMesh.vertexCount); if (ResultSegments == null || ResultSegments.Length != ActiveSegmentsNumber) { var newResultSegments = new ManagedMesh[ActiveSegmentsNumber]; if (ResultSegments == null) { ResultSegments = new ManagedMesh[0]; } int minLenght = Math.Min(ResultSegments.Length, ActiveSegmentsNumber); for (int s = 0; s < minLenght; s++) { newResultSegments[s] = ResultSegments[s]; } for (int s = minLenght; s < ActiveSegmentsNumber; s++) { newResultSegments[s] = new ManagedMesh(); } for (int s = ActiveSegmentsNumber; s < ResultSegments.Length; s++) { ResultSegments[s].Clear(); } ResultSegments = newResultSegments; } }
/// <summary> /// Rebuilds the mesh for the specified lofting group /// </summary> /// <param name="group">lofting group</param> private void RebuildMesh(LoftingGroup group) { if (!group.IsValid) { throw new ArgumentException("SegmentMesh and MeshFilter can't be null"); } LoftDirection.Normalize(); var result = group.ResultMesh; float segmentStep = group.IntervalLength / group.ActiveSegmentsNumber; for (int s = 0; s < group.ActiveSegmentsNumber; s++) { ManagedMesh segment = group.ResultSegments[s]; segment.Clear(); ManagedMesh source = group.mSegmentMesh; if (s == 0 && group.mStartPiece != null) { source = group.mStartPiece; } if (s == group.ActiveSegmentsNumber - 1 && group.mEndPiece != null) { source = group.mEndPiece; } Vector3 pivotShift = Vector3.Project(source.bounds.center, LoftDirection); Vector3 startSPos = pivotShift - source.bounds.extents.Mul(LoftDirection); Vector3 endSPos = pivotShift + source.bounds.extents.Mul(LoftDirection); Vector3 sourceDir = (endSPos - startSPos); float sourceLenght = sourceDir.magnitude; bool flipSegment = RollerCoasterFix && _flipNext; Vector3 dirS = LoftDirection; Vector3[] sourceVertices = source.vertices; Vector3[] resultVertices = new Vector3[source.vertexCount]; Vector3[] sourceNormals = source.normals; Vector3[] resultNormals = new Vector3[source.vertexCount]; Vector4[] sourceTangents = source.tangents; Vector4[] resultTangents = new Vector4[source.vertexCount]; for (int i = 0; i < source.vertexCount; i++) { Vector3 curSPos = sourceVertices[i] - startSPos; Vector3 projected = Vector3.Project(curSPos, dirS); Vector3 perp = curSPos - projected; perp.Scale(SegmentScale); float sourceT = Mathf.InverseLerp(0f, sourceLenght, projected.magnitude); float resultT = group.StartPosition + segmentStep * s + segmentStep * sourceT; int nodeIndex; float nodeT = GetNodeT(resultT, out nodeIndex); if (nodeIndex < 0) { nodeIndex = 0; } else if (nodeIndex > Nodes.Count - 1) { nodeIndex = Nodes.Count - 1; } int nextIndex = nodeIndex + 1; if (nodeIndex >= Nodes.Count - 1) { if (Loop) { nextIndex = 0; } else { nodeIndex = Nodes.Count - 2; nextIndex = Nodes.Count - 1; } } SplineNode fromNode = Nodes[nodeIndex]; SplineNode toNode = Nodes[nextIndex]; Vector3 startRPos = fromNode.LocalPosition; Vector3 endRPos = toNode.LocalPosition; Vector3 nodesDir = (endRPos - startRPos); Vector3 upwardVector = Vector3.up; float additionalAngle = 0f; if (RollerCoasterFix && s > 0 && nodeIndex > 0) { SplineNode prevNode = Nodes[nodeIndex - 1]; Vector3 prevNodesDir = (startRPos - prevNode.LocalPosition); Vector3 prevNodesDirXZ = prevNodesDir; prevNodesDirXZ.y = 0; Vector3 nodesDirXZ = nodesDir; nodesDirXZ.y = 0; float dot = Vector3.Dot(prevNodesDirXZ, nodesDirXZ); if (Vector3.Dot(Vector3.up, nodesDir) > 0.5f) { upwardVector = Vector3.left; additionalAngle = -90f * Mathf.Abs(Vector3.Dot(LoftDirection, Vector3.left)); _flipNext = true; } else if (Vector3.Dot(Vector3.up, nodesDir) < -0.5f) { upwardVector = Vector3.right; additionalAngle = 90f * Mathf.Abs(Vector3.Dot(LoftDirection, Vector3.left)); _flipNext = false; } else { if (flipSegment) { additionalAngle = 180f; } } } Vector3 startR_RightP = fromNode.RightP; Vector3 endRPos_RightP = toNode.RightP; Vector3 endRPos_LeftP = toNode.LeftP; float loftAngle = LoftAngle + Mathf.Lerp(fromNode.AdditionalLoftAngle, toNode.AdditionalLoftAngle, nodeT); Vector3 dirR = nodesDir.normalized; if (Loop || (nodeIndex > 0 && nodeIndex + 2 < Nodes.Count)) { dirR = (startR_RightP - startRPos).normalized; Vector3 dirN = (endRPos_RightP - endRPos).normalized; float t = QuadraticSmooth ? (nodeT * nodeT) : nodeT; dirR = Vector3.Slerp(dirR, dirN, t); } Quaternion directionRot = Quaternion.LookRotation(dirR, upwardVector) * Quaternion.Inverse(Quaternion.LookRotation(dirS, upwardVector)); Quaternion loftRot = Quaternion.AngleAxis(additionalAngle + loftAngle, dirR); resultVertices[i] = startRPos + loftRot * (directionRot * perp) + SplinePowerVector3Extensions.Bezier( startRPos - startRPos, startR_RightP - startRPos, endRPos_LeftP - startRPos, endRPos - startRPos, nodeT); if (group.ProcessOriginNormals) { resultNormals[i] = loftRot * directionRot * sourceNormals[i]; } if (group.ProcessOriginTangents) { resultTangents[i] = loftRot * directionRot * sourceTangents[i]; } } segment.vertices = resultVertices; segment.triangles = source.triangles; segment.uv = source.uv; segment.normals = resultNormals; segment.tangents = resultTangents; } for (int s = 0; s < group.ResultSegments.Length; s++) { if (group.RecalculateNormals) { group.ResultSegments[s].RecalculateNormals(); } if (s > 0) { if (group.SmoothNormals || group.Weld) { WeldAndSmooth(group, group.ResultSegments[s - 1], group.ResultSegments[s]); } } if (Loop && s == 0) { if (group.SmoothNormals || group.Weld) { WeldAndSmooth(group, group.ResultSegments[group.ResultSegments.Length - 1], group.ResultSegments[s]); } } } CombineSegments(result, group.ResultSegments); #if UNITY_EDITOR UnityEditor.MeshUtility.SetMeshCompression(result, UnityEditor.ModelImporterMeshCompression.High); result.name = ExportOptions.GetName(this, group); #endif result.Optimize(); result.hideFlags = HideFlags.DontSave; group.ResultMesh = result; if (group.MeshFilter != null) { group.MeshFilter.sharedMesh = null; group.MeshFilter.sharedMesh = result; } if (group.MeshCollider != null) { group.MeshCollider.sharedMesh = null; group.MeshCollider.sharedMesh = result; } }
public static ManagedMesh Combine(ManagedMesh[] segments) { ManagedMesh result = new ManagedMesh(); Vector3[] vertices = new Vector3[segments.Sum(p => p.vertices.Length)]; int[] triangles = new int[segments.Sum(p => p.triangles.Length)]; Vector2[] uv = new Vector2[segments.Sum(p => p.uv.Length)]; Vector3[] normals = new Vector3[segments.Sum(p => p.normals.Length)]; Vector4[] tangents = new Vector4[segments.Sum(p => p.tangents.Length)]; int verticesShift = 0; int trianglesShift = 0; int uvShift = 0; int normalsShift = 0; int tangentsShift = 0; for (int k = 0; k < segments.Length; k++) { if (k > 0) { var previousSegment = segments[k - 1]; verticesShift += previousSegment.vertices.Length; trianglesShift += previousSegment.triangles.Length; uvShift += previousSegment.uv.Length; normalsShift += previousSegment.normals.Length; tangentsShift += previousSegment.tangents.Length; } var segment = segments[k]; for (int i = 0; i < segment.vertices.Length; i++) { vertices[verticesShift + i] = segment.vertices[i]; } for (int i = 0; i < segment.triangles.Length; i++) { triangles[trianglesShift + i] = verticesShift + segment.triangles[i]; } for (int i = 0; i < segment.uv.Length; i++) { uv[uvShift + i] = segment.uv[i]; } for (int i = 0; i < segment.normals.Length; i++) { normals[normalsShift + i] = segment.normals[i]; } for (int i = 0; i < segment.tangents.Length; i++) { tangents[tangentsShift + i] = segment.tangents[i]; } } result.vertices = vertices; result.triangles = triangles; result.uv = uv; result.normals = normals; result.tangents = tangents; return(result); }
private void WeldAndSmooth(LoftingGroup group, ManagedMesh meshA, ManagedMesh meshB) { float weldDistanceSqr = group.WeldingDistance * group.WeldingDistance; var verticesA = meshA.vertices; var verticesB = meshB.vertices; var normalsA = meshA.normals; var normalsB = meshB.normals; int i, j, an, bn; an = verticesA.Length; bn = verticesB.Length; for (i = 0; i < an; i++) for (j = 0; j < bn; j++) { // if any one inside limit distance... if (Vector3.SqrMagnitude(verticesA[i] - verticesB[j]) < weldDistanceSqr) { if (group.Weld) { verticesB[j] = verticesA[i]; } if (group.SmoothNormals && Vector3.Dot(normalsA[i], normalsB[j]) > 0) { normalsA[i] = Vector3.Slerp(normalsA[i], normalsB[j], 0.5f); normalsB[j] = normalsA[i]; } } } meshA.vertices = verticesA; meshB.vertices = verticesB; meshA.normals = normalsA; meshB.normals = normalsB; }
private void CombineSegments(Mesh mesh, ManagedMesh[] resultSegments) { ManagedMesh result = ManagedMesh.Combine(resultSegments); mesh.Clear(); mesh.vertices = result.vertices; mesh.triangles = result.triangles; mesh.uv = result.uv; mesh.normals = result.normals; mesh.tangents = result.tangents; mesh.RecalculateBounds(); }
public static ManagedMesh Combine(ManagedMesh[] segments) { ManagedMesh result = new ManagedMesh(); Vector3[] vertices = new Vector3[segments.Sum(p => p.vertices.Length)]; int[] triangles = new int[segments.Sum(p => p.triangles.Length)]; Vector2[] uv = new Vector2[segments.Sum(p => p.uv.Length)]; Vector3[] normals = new Vector3[segments.Sum(p => p.normals.Length)]; Vector4[] tangents = new Vector4[segments.Sum(p => p.tangents.Length)]; int verticesShift = 0; int trianglesShift = 0; int uvShift = 0; int normalsShift = 0; int tangentsShift = 0; for (int k = 0; k < segments.Length; k++) { if (k > 0) { var previousSegment = segments[k - 1]; verticesShift += previousSegment.vertices.Length; trianglesShift += previousSegment.triangles.Length; uvShift += previousSegment.uv.Length; normalsShift += previousSegment.normals.Length; tangentsShift += previousSegment.tangents.Length; } var segment = segments[k]; for (int i = 0; i < segment.vertices.Length; i++) { vertices[verticesShift + i] = segment.vertices[i]; } for (int i = 0; i < segment.triangles.Length; i++) { triangles[trianglesShift + i] = verticesShift + segment.triangles[i]; } for (int i = 0; i < segment.uv.Length; i++) { uv[uvShift + i] = segment.uv[i]; } for (int i = 0; i < segment.normals.Length; i++) { normals[normalsShift + i] = segment.normals[i]; } for (int i = 0; i < segment.tangents.Length; i++) { tangents[tangentsShift + i] = segment.tangents[i]; } } result.vertices = vertices; result.triangles = triangles; result.uv = uv; result.normals = normals; result.tangents = tangents; return result; }
public void Fix() { mSegmentMesh = (SegmentMesh != null) ? new ManagedMesh(SegmentMesh) : null; mStartPiece = (StartPiece != null) ? new ManagedMesh(StartPiece) : null; mEndPiece = (EndPiece != null) ? new ManagedMesh(EndPiece) : null; //Prevents mesh buffer overflow ActiveSegmentsNumber = Mathf.Clamp( ActiveSegmentsNumber, 1, ushort.MaxValue / mSegmentMesh.vertexCount); if (ResultSegments == null || ResultSegments.Length != ActiveSegmentsNumber) { var newResultSegments = new ManagedMesh[ActiveSegmentsNumber]; if (ResultSegments == null) { ResultSegments = new ManagedMesh[0]; } int minLenght = Math.Min(ResultSegments.Length, ActiveSegmentsNumber); for (int s = 0; s < minLenght; s++) { newResultSegments[s] = ResultSegments[s]; } for (int s = minLenght; s < ActiveSegmentsNumber; s++) { newResultSegments[s] = new ManagedMesh(); } for (int s = ActiveSegmentsNumber; s < ResultSegments.Length; s++) { ResultSegments[s].Clear(); } ResultSegments = newResultSegments; } }