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 string GetName(SplineFormer splineFormer, LoftingGroup group) { if (!ExtendedNaming) { return(String.Format("{0} Lg#{1} result", splineFormer.gameObject.name, splineFormer.LoftingGroups.IndexOf(group))); } List <string> parts = new List <string>(10); if (AddObjectName) { parts.Add(splineFormer.gameObject.name); } if (AddLoftingGroupIndex) { parts.Add(String.Format("Lg#{0}", splineFormer.LoftingGroups.IndexOf(group))); } if (!String.IsNullOrEmpty(CustomName)) { parts.Add(CustomName); } if (AddDateTime) { parts.Add(DateTime.Now.ToString()); } if (AddAutoIncrementNumber) { _uk++; parts.Add(_uk.ToString()); } string name = String.Join(" ", parts.ToArray()); name = CleanFileName(name); return(name); }
/// <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 string GetName(SplineFormer splineFormer, LoftingGroup group) { if (!ExtendedNaming) { return String.Format("{0} Lg#{1} result", splineFormer.gameObject.name, splineFormer.LoftingGroups.IndexOf(group)); } List<string> parts = new List<string>(10); if (AddObjectName) parts.Add(splineFormer.gameObject.name); if (AddLoftingGroupIndex) parts.Add(String.Format("Lg#{0}", splineFormer.LoftingGroups.IndexOf(group))); if (!String.IsNullOrEmpty(CustomName)) parts.Add(CustomName); if (AddDateTime) parts.Add(DateTime.Now.ToString()); if (AddAutoIncrementNumber) { _uk++; parts.Add(_uk.ToString()); } string name = String.Join(" ", parts.ToArray()); name = CleanFileName(name); return name; }
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; }
/// <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; } }