using System.Collections.Generic; using UnityEngine; namespace RoadArchitect { public static class Intersections { public static GameObject CreateIntersection(SplineN _node1, SplineN _node2) { float RoadMod = 10f; GameObject SystemObj = _node1.transform.parent.parent.parent.gameObject; if (!SystemObj) { Debug.LogWarning("Could not find road system master object."); return null; } GameObject InterMaster = null; int cCount = SystemObj.transform.childCount; for (int i = 0; i < cCount; i++) { if (SystemObj.transform.GetChild(i).transform.name.ToLower() == "intersections") { InterMaster = SystemObj.transform.GetChild(i).gameObject; } } if (!InterMaster) { InterMaster = new GameObject("Intersections"); InterMaster.transform.parent = SystemObj.transform; } if (!InterMaster) { Debug.LogWarning("Could not find intersections master object for this road system."); return null; } cCount = InterMaster.transform.childCount; GameObject intersectionObject = new GameObject("Inter" + (cCount + 1).ToString()); intersectionObject.transform.parent = InterMaster.transform; RoadIntersection roadIntersection = intersectionObject.AddComponent(); roadIntersection.ignoreSide = -1; roadIntersection.isFirstSpecialFirst = false; roadIntersection.isFirstSpecialLast = false; roadIntersection.isSecondSpecialFirst = false; roadIntersection.isSecondSpecialLast = false; SplineN tNode1 = null; SplineN tNode2 = null; // same spline if (_node1.spline == _node2.spline) { if (_node1.idOnSpline < _node2.idOnSpline) { tNode1 = _node1; tNode2 = _node2; } else { tNode1 = _node2; tNode2 = _node1; } } else { // different spline tNode1 = _node1; tNode2 = _node2; } //If 3way, always add the single node as primary: if (_node1.isEndPoint) { tNode1 = _node1; tNode2 = _node2; } else if (_node2.isEndPoint) { tNode1 = _node2; tNode2 = _node1; } tNode1.intersectionOtherNode = tNode2; tNode2.intersectionOtherNode = tNode1; if (tNode1.isEndPoint || tNode2.isEndPoint) { roadIntersection.intersectionType = RoadIntersection.IntersectionTypeEnum.ThreeWay; } SplineN zNode = null; if (tNode1.isEndPoint) { bool isFirstNode = false; bool isAlreadyNode = false; if (tNode1.idOnSpline == 1 || tNode1.idOnSpline == 0) { isFirstNode = true; } if (isFirstNode && tNode1.idOnSpline == 1 && tNode1.spline.nodes[0].isSpecialEndNodeIsStart) { isAlreadyNode = true; } else if (!isFirstNode && tNode1.idOnSpline == tNode1.spline.GetNodeCount() - 2 && tNode1.spline.nodes[tNode1.spline.GetNodeCount() - 1].isSpecialEndNodeIsEnd) { isAlreadyNode = true; } Vector3 tPos = default(Vector3); if (isFirstNode) { tPos = ((tNode1.tangent * -1f).normalized * (tNode1.spline.road.RoadWidth() * RoadMod)) + tNode1.pos; } else { tPos = (tNode1.spline.GetSplineValue(0.999f, true).normalized * (tNode1.spline.road.RoadWidth() * RoadMod)) + tNode1.pos; } if (!isAlreadyNode) { if (isFirstNode) { zNode = Construction.InsertNode(tNode1.spline.road, true, tPos, false, 0, true, true); zNode.isSpecialEndNodeIsStart = true; zNode.isSpecialIntersection = true; zNode.tangent = tNode1.tangent; } else { zNode = Construction.CreateNode(tNode1.spline.road, true, tPos, true); zNode.isSpecialEndNodeIsEnd = true; zNode.isSpecialIntersection = true; zNode.tangent = tNode1.tangent; } } else { if (isFirstNode) { tNode1.spline.nodes[0].transform.position = tPos; } else { tNode1.spline.nodes[tNode1.spline.GetNodeCount() - 1].transform.position = tPos; } } if (isFirstNode) { tNode1.spline.isSpecialStartControlNode = true; roadIntersection.isFirstSpecialFirst = true; } else { tNode1.spline.isSpecialEndControlNode = true; roadIntersection.isFirstSpecialLast = true; } } else if (tNode2.isEndPoint) { bool isFirstNode = false; bool isAlreadyNode = false; if (tNode2.idOnSpline == 1 || tNode2.idOnSpline == 0) { isFirstNode = true; } if (isFirstNode && tNode2.idOnSpline == 1 && tNode2.spline.nodes[0].isSpecialEndNodeIsStart) { isAlreadyNode = true; } else if (!isFirstNode && tNode2.idOnSpline == tNode2.spline.GetNodeCount() - 2 && tNode2.spline.nodes[tNode2.spline.GetNodeCount() - 1].isSpecialEndNodeIsEnd) { isAlreadyNode = true; } Vector3 tPos = default(Vector3); if (isFirstNode) { tPos = ((tNode2.tangent * -1f).normalized * (tNode2.spline.road.RoadWidth() * RoadMod)) + tNode2.pos; } else { tPos = (tNode2.spline.GetSplineValue(0.999f, true).normalized * (tNode2.spline.road.RoadWidth() * RoadMod)) + tNode2.pos; } if (!isAlreadyNode) { if (isFirstNode) { zNode = Construction.InsertNode(tNode2.spline.road, true, tPos, false, 0, true, true); zNode.isSpecialEndNodeIsStart = true; zNode.isSpecialIntersection = true; zNode.tangent = tNode2.tangent; } else { zNode = Construction.CreateNode(tNode2.spline.road, true, tPos, true); zNode.isSpecialEndNodeIsEnd = true; zNode.isSpecialIntersection = true; zNode.tangent = tNode2.tangent; } } else { if (isFirstNode) { tNode2.spline.nodes[0].transform.position = tPos; } else { tNode2.spline.nodes[tNode2.spline.GetNodeCount() - 1].transform.position = tPos; } } if (isFirstNode) { tNode2.spline.isSpecialStartControlNode = true; roadIntersection.isSecondSpecialFirst = true; } else { tNode2.spline.isSpecialEndControlNode = true; roadIntersection.isSecondSpecialLast = true; } } EngineIntegration.RegisterUndo(intersectionObject, "Created intersection"); roadIntersection.Setup(tNode1, tNode2); intersectionObject.transform.position = _node1.transform.position; roadIntersection.ResetMaterialsAll(); //if(roadIntersection.isSameSpline) //{ // roadIntersection.node1.spline.road.UpdateRoad(); //} //else //{ // roadIntersection.node1.spline.road.UpdateRoad(); // roadIntersection.node2.spline.road.UpdateRoad(); //} tNode1.ToggleHideFlags(true); tNode2.ToggleHideFlags(true); if (roadIntersection != null && roadIntersection.node1 != null && roadIntersection.node2 != null) { if (!roadIntersection.isSameSpline) { roadIntersection.node1.spline.road.PiggyBacks = new SplineC[4]; roadIntersection.node1.spline.road.PiggyBacks[0] = roadIntersection.node2.spline; roadIntersection.node1.spline.road.PiggyBacks[1] = roadIntersection.node1.spline; roadIntersection.node1.spline.road.PiggyBacks[2] = roadIntersection.node2.spline; roadIntersection.node1.spline.road.PiggyBacks[3] = roadIntersection.node1.spline; //roadIntersection.node1.spline.road.PiggyBacks[4] = roadIntersection.node2.spline; } roadIntersection.node1.spline.road.isUpdateRequired = true; } return intersectionObject; } public static Vector3[] GetCornerVectorsTest(RoadIntersection _roadIntersection) { Vector3[] tVects = new Vector3[4]; SplineN tNode; tNode = _roadIntersection.node1; SplineC tSpline = tNode.spline; //RR = Node1 - 5, Node2 + 5 //RL = Node1 + 5, Node2 + 5 //LL = Node1 + 5, Node2 - 5 //LR = Node1 - 5, Node2 - 5 float tOffset = 5f; float tPos1 = tNode.time - (tOffset / tSpline.distance); float tPos2 = tNode.time + (tOffset / tSpline.distance); Vector3 tVect1 = tSpline.GetSplineValue(tPos1); Vector3 POS1 = tSpline.GetSplineValue(tPos1, true); Vector3 tVect2 = tSpline.GetSplineValue(tPos2); Vector3 POS2 = tSpline.GetSplineValue(tPos2, true); tVects[0] = (tVect1 + new Vector3(5f * POS1.normalized.z, 0, 5f * -POS1.normalized.x)); tVects[1] = (tVect1 + new Vector3(5f * -POS1.normalized.z, 0, 5f * POS1.normalized.x)); tVects[2] = (tVect2 + new Vector3(5f * POS2.normalized.z, 0, 5f * -POS2.normalized.x)); tVects[3] = (tVect2 + new Vector3(5f * -POS2.normalized.z, 0, 5f * POS2.normalized.x)); return tVects; } #region "Old intersection" public static void CreateIntersection(RoadIntersection _roadIntersection) { //1. Overlap sphere to find all road objects within intersection: float intersectionWidth = _roadIntersection.intersectionWidth * 1.25f; Collider[] colliders = Physics.OverlapSphere(_roadIntersection.transform.position, intersectionWidth); if (colliders == null || colliders.Length < 1) { return; } List roads = new List(); foreach (Collider collider in colliders) { if (collider.transform.parent) { Road tRoad = collider.transform.parent.GetComponent(); if (tRoad) { if (!roads.Contains(tRoad)) { roads.Add(tRoad); } } } } //Flatten intersection area: float height = -1f; FlattenIntersectionArea(ref roads, _roadIntersection, intersectionWidth, out height); //Create main intersection mesh: string name = _roadIntersection.transform.name; Vector3[] vects; CreateIntersectionMeshMain(_roadIntersection, height, out vects, ref name); //Now create the 4 text overlays: CreateIntersectionMeshOuter(_roadIntersection, vects, ref name); //Update connected nodes: Navigation.UpdateConnectedNodes(); //Now initialize intersection objects: InitializeIntersectionObjects(_roadIntersection); } private static void FlattenIntersectionArea(ref List _roads, RoadIntersection _roadIntersection, float _width, out float _height) { //Cycle through each road and get all mesh vertices that are within range: Vector3 tInterPos = _roadIntersection.transform.position; float tInterPosY = tInterPos.y; foreach (Road tRoad in _roads) { MeshFilter MF_Road = tRoad.MeshRoad.GetComponent(); MeshFilter MF_Road_SR = tRoad.MeshShoR.GetComponent(); MeshFilter MF_Road_SL = tRoad.MeshShoL.GetComponent(); Mesh Road = MF_Road.sharedMesh; Mesh Road_SR = MF_Road_SR.sharedMesh; Mesh Road_SL = MF_Road_SL.sharedMesh; Vector3[] tVects = Road.vertices; Vector3[] tVects_SR = Road_SR.vertices; Vector3[] tVects_SL = Road_SL.vertices; int VertCount = Road.vertices.Length; bool bLeftToggle = true; for (int i = 0; i < VertCount; i += 2) { if (Vector3.Distance(tVects[i], tInterPos) < _width) { tVects[i].y = tInterPosY; tVects[i + 1].y = tInterPosY; if (bLeftToggle) { //Left: tVects_SL[i + 2].y = tInterPosY; tVects_SL[i + 3].y = tInterPosY; } else { //Right: tVects_SR[i - 2].y = tInterPosY; tVects_SR[i - 1].y = tInterPosY; } } bLeftToggle = !bLeftToggle; } //Main road: Road.vertices = tVects; Road.RecalculateNormals(); MF_Road.sharedMesh = Road; //Right shoulder: Road_SR.vertices = tVects_SR; Road_SR.RecalculateNormals(); MF_Road_SR.sharedMesh = Road_SR; //Left shoulder: Road_SL.vertices = tVects_SL; Road_SL.RecalculateNormals(); MF_Road_SL.sharedMesh = Road_SL; } _height = tInterPosY; } private static bool V3Equal(Vector3 _a, Vector3 _b) { return Vector3.SqrMagnitude(_a - _b) < 0.0001f; } private static Vector3[] GetCornerVectors(RoadIntersection _roadIntersection, bool _isPrimary = true) { Vector3[] tVects = new Vector3[4]; SplineN tNode; if (_isPrimary) { tNode = _roadIntersection.node1; } else { tNode = _roadIntersection.node2; } SplineC tSpline = tNode.spline; float tOffset = 7f; float tPos1 = tNode.time - (tOffset / tSpline.distance); float tPos2 = tNode.time + (tOffset / tSpline.distance); Vector3 tVect1 = tSpline.GetSplineValue(tPos1); Vector3 POS1 = tSpline.GetSplineValue(tPos1, true); Vector3 tVect2 = tSpline.GetSplineValue(tPos2); Vector3 POS2 = tSpline.GetSplineValue(tPos2, true); tVects[0] = (tVect1 + new Vector3(5f * POS1.normalized.z, 0, 5f * -POS1.normalized.x)); tVects[1] = (tVect1 + new Vector3(5f * -POS1.normalized.z, 0, 5f * POS1.normalized.x)); tVects[2] = (tVect2 + new Vector3(5f * POS2.normalized.z, 0, 5f * -POS2.normalized.x)); tVects[3] = (tVect2 + new Vector3(5f * -POS2.normalized.z, 0, 5f * POS2.normalized.x)); return tVects; } private static Vector3[] GetExtendedVectors(RoadIntersection _roadIntersection, bool _isPrimary = true) { Vector3[] tVects = new Vector3[4]; SplineN tNode; if (_isPrimary) { tNode = _roadIntersection.node1; } else { tNode = _roadIntersection.node2; } SplineC tSpline = tNode.spline; Vector3 NodePos = tNode.transform.position; float tOffset = tNode.spline.road.RoadWidth(); float tOffset2 = tOffset * 0.5f; float tPos1 = tNode.time - (tOffset / tSpline.distance); float tPos2 = tNode.time + (tOffset / tSpline.distance); Vector3 tVect1 = tSpline.GetSplineValue(tPos1); Vector3 tVect2 = tSpline.GetSplineValue(tPos2); //Enforce distance: int SpamGuard = 0; int SGMax = 50; while (Vector3.Distance(tVect1, NodePos) < tOffset && SpamGuard < SGMax) { SpamGuard += 1; tPos1 -= (1f / tSpline.distance); tVect1 = tSpline.GetSplineValue(tPos1); } SpamGuard = 0; while (Vector3.Distance(tVect1, NodePos) > (tOffset * 1.2f) && SpamGuard < SGMax) { SpamGuard += 1; tPos1 += (0.25f / tSpline.distance); tVect1 = tSpline.GetSplineValue(tPos1); } SpamGuard = 0; while (Vector3.Distance(tVect2, NodePos) < tOffset && SpamGuard < SGMax) { SpamGuard += 1; tPos2 += (1f / tSpline.distance); tVect2 = tSpline.GetSplineValue(tPos2); } SpamGuard = 0; while (Vector3.Distance(tVect1, NodePos) > (tOffset * 1.2f) && SpamGuard < SGMax) { SpamGuard += 1; tPos2 -= (0.25f / tSpline.distance); tVect2 = tSpline.GetSplineValue(tPos2); } Vector3 POS1 = tSpline.GetSplineValue(tPos1, true); Vector3 POS2 = tSpline.GetSplineValue(tPos2, true); tVects[0] = (tVect1 + new Vector3(tOffset2 * POS1.normalized.z, 0, tOffset2 * -POS1.normalized.x)); tVects[1] = (tVect1 + new Vector3(tOffset2 * -POS1.normalized.z, 0, tOffset2 * POS1.normalized.x)); tVects[2] = (tVect2 + new Vector3(tOffset2 * POS2.normalized.z, 0, tOffset2 * -POS2.normalized.x)); tVects[3] = (tVect2 + new Vector3(tOffset2 * -POS2.normalized.z, 0, tOffset2 * POS2.normalized.x)); return tVects; } //Two non-parallel lines which may or may not touch each other have a point on each line which are closest //to each other. This function finds those two points. If the lines are not parallel, the function //outputs true, otherwise false. private static bool ClosestPointsOnTwoLines(out Vector3 _closestPointLine1, out Vector3 _closestPointLine2, Vector3 _linePoint1, Vector3 _lineVec1, Vector3 _linePoint2, Vector3 _lineVec2) { _closestPointLine1 = Vector3.zero; _closestPointLine2 = Vector3.zero; float a = Vector3.Dot(_lineVec1, _lineVec1); float b = Vector3.Dot(_lineVec1, _lineVec2); float e = Vector3.Dot(_lineVec2, _lineVec2); float d = a * e - b * b; //lines are not parallel if (d != 0.0f) { Vector3 r = _linePoint1 - _linePoint2; float c = Vector3.Dot(_lineVec1, r); float f = Vector3.Dot(_lineVec2, r); float s = (b * f - c * e) / d; float t = (a * f - c * b) / d; _closestPointLine1 = _linePoint1 + _lineVec1 * s; _closestPointLine2 = _linePoint2 + _lineVec2 * t; return true; } else { return false; } } private static void CreateIntersectionMeshMain(RoadIntersection _roadIntersection, float _height, out Vector3[] _vectors, ref string _name) { //Get four points: Vector3[] pVects = GetCornerVectors(_roadIntersection); Vector3[] sVects = GetCornerVectors(_roadIntersection, false); _vectors = new Vector3[4]; Vector3 oIntersection = new Vector3(0f, 0f, 0f); Vector3 oIntersection2 = new Vector3(0f, 0f, 0f);//Unused // bool bIntersection; ClosestPointsOnTwoLines(out oIntersection, out oIntersection2, pVects[0], (pVects[2] - pVects[0]), sVects[0], (sVects[2] - sVects[0])); _vectors[0] = oIntersection; _vectors[0].y = _height; ClosestPointsOnTwoLines(out oIntersection, out oIntersection2, pVects[0], (pVects[2] - pVects[0]), sVects[1], (sVects[3] - sVects[1])); _vectors[1] = oIntersection; _vectors[1].y = _height; ClosestPointsOnTwoLines(out oIntersection, out oIntersection2, pVects[1], (pVects[3] - pVects[1]), sVects[0], (sVects[2] - sVects[0])); _vectors[2] = oIntersection; _vectors[2].y = _height; ClosestPointsOnTwoLines(out oIntersection, out oIntersection2, pVects[1], (pVects[3] - pVects[1]), sVects[1], (sVects[3] - sVects[1])); _vectors[3] = oIntersection; _vectors[3].y = _height; CreateIntersectionMeshMainInternal(_vectors, _roadIntersection.transform.gameObject, ref _name); } private static void CreateIntersectionMeshMainInternal(Vector3[] _verts, GameObject _obj, ref string _name) { Mesh tMesh = new Mesh(); int MVL = 4; int triCount = (int)(4f * 1.5f); // GameObject tObj; // tObj = GameObject.Find("tInter1"); tObj.transform.position = tVerts[0]; // tObj = GameObject.Find("tInter2"); tObj.transform.position = tVerts[1]; // tObj = GameObject.Find("tInter3"); tObj.transform.position = tVerts[2]; // tObj = GameObject.Find("tInter4"); tObj.transform.position = tVerts[3]; for (int index = 0; index < MVL; index++) { _verts[index] -= _obj.transform.position; } tMesh.vertices = _verts; tMesh.RecalculateBounds(); int[] tri = new int[triCount]; tri[0] = 0; tri[1] = 2; tri[2] = 1; tri[3] = 2; tri[4] = 3; tri[5] = 1; tMesh.triangles = tri; Vector3[] normals = new Vector3[MVL]; for (int i = 0; i < MVL; i++) { normals[i] = -Vector3.forward; } tMesh.normals = normals; tMesh.RecalculateNormals(); Vector2[] uv = new Vector2[MVL]; uv[0] = new Vector2(0f, 0f); uv[1] = new Vector2(1f, 0f); uv[2] = new Vector2(0f, 1f); uv[3] = new Vector2(1f, 1f); tMesh.uv = uv; RootUtils.ProcessTangents(ref tMesh); //Final processing: MeshFilter MF = _obj.GetComponent(); if (!MF) { MF = _obj.AddComponent(); } MF.sharedMesh = tMesh; //MeshToFile(MF, RoadEditorUtility.GetBasePath() + "/Mesh/Intersections/" + name +".obj"); MeshCollider MC = _obj.GetComponent(); Object.DestroyImmediate(MC); //if(!MC){ MC = iObj.AddComponent(); } //MC.sharedMesh = MF.sharedMesh; MeshRenderer MR = _obj.GetComponent(); if (!MR) { MR = _obj.AddComponent(); } MR.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; MR.receiveShadows = true; RoadEditorUtility.SetRoadMaterial(RoadEditorUtility.GetBasePath() + "/Materials/RoadIntersection.mat", MR); } private static void CreateIntersectionMeshOuter(RoadIntersection _roadIntersection, Vector3[] _vects, ref string _name) { Vector3[] bVects1 = GetExtendedVectors(_roadIntersection); Vector3[] bVects2 = GetExtendedVectors(_roadIntersection, false); Vector3[] eVects = new Vector3[16]; eVects[0] = _vects[1]; eVects[1] = _vects[0]; eVects[2] = bVects2[3]; eVects[3] = bVects2[2]; eVects[4] = _vects[3]; eVects[5] = _vects[1]; eVects[6] = bVects1[3]; eVects[7] = bVects1[2]; eVects[8] = _vects[2]; eVects[9] = _vects[3]; eVects[10] = bVects2[0]; eVects[11] = bVects2[1]; eVects[12] = _vects[0]; eVects[13] = _vects[2]; eVects[14] = bVects1[0]; eVects[15] = bVects1[1]; int cCount = _roadIntersection.transform.childCount; //bool bOuter = false; GameObject tOuter = null; for (int index = 0; index < cCount; index++) { if (_roadIntersection.transform.GetChild(index).transform.name == "outer") { tOuter = _roadIntersection.transform.GetChild(index).transform.gameObject; } } if (!tOuter) { tOuter = new GameObject("outer"); tOuter.transform.parent = _roadIntersection.transform; } tOuter.transform.position = _roadIntersection.transform.position; // GameObject tObj; // tObj = GameObject.Find("tInter1"); tObj.transform.position = bVects2[0]; // tObj = GameObject.Find("tInter2"); tObj.transform.position = bVects2[1]; // tObj = GameObject.Find("tInter3"); tObj.transform.position = bVects2[2]; // tObj = GameObject.Find("tInter4"); tObj.transform.position = bVects2[3]; CreateIntersectionMeshOuterInternal(eVects, tOuter, _roadIntersection.transform.position, ref _name); } private static void CreateIntersectionMeshOuterInternal(Vector3[] _verts, GameObject _obj, Vector3 _vectorOffset, ref string _name) { Mesh tMesh = new Mesh(); int MVL = 16; int triCount = (int)(16f * 1.5f); for (int index = 0; index < MVL; index += 4) { // tVerts[index] += vOffset; // tVerts[index+1] += vOffset; _verts[index + 2] -= _vectorOffset; _verts[index + 3] -= _vectorOffset; } tMesh.vertices = _verts; tMesh.RecalculateBounds(); int[] tri = new int[triCount]; int cTri = 0; for (int i = 0; i < triCount; i += 4) { if (i + 3 >= MVL) { break; } tri[cTri] = i; cTri += 1; tri[cTri] = i + 2; cTri += 1; tri[cTri] = i + 1; cTri += 1; tri[cTri] = i + 2; cTri += 1; tri[cTri] = i + 3; cTri += 1; tri[cTri] = i + 1; cTri += 1; } tMesh.triangles = tri; Vector3[] normals = new Vector3[MVL]; for (int i = 0; i < 4; i++) { normals[i] = -Vector3.forward; } tMesh.normals = normals; tMesh.RecalculateNormals(); Vector2[] uv = new Vector2[MVL]; for (int i = 0; i < MVL; i += 4) { uv[i] = new Vector2(1f, 1f); uv[i + 1] = new Vector2(0f, 1f); uv[i + 2] = new Vector2(1f, 0f); uv[i + 3] = new Vector2(0f, 0f); } tMesh.uv = uv; RootUtils.ProcessTangents(ref tMesh); //Final processing: MeshFilter MF = _obj.GetComponent(); if (!MF) { MF = _obj.AddComponent(); } MF.sharedMesh = tMesh; //MeshToFile(MF, RoadEditorUtility.GetBasePath() + "/Mesh/Intersections/" + name +"-overlay.obj"); MeshCollider MC = _obj.GetComponent(); Object.DestroyImmediate(MC); //if(!MC){ MC = iObj.AddComponent(); } //MC.sharedMesh = MF.sharedMesh; MeshRenderer MR = _obj.GetComponent(); if (!MR) { MR = _obj.AddComponent(); } MR.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; MR.receiveShadows = true; RoadEditorUtility.SetRoadMaterial(RoadEditorUtility.GetBasePath() + "/Materials/InterText.mat", MR); } #region "Intersection creation" private static void InitializeIntersectionObjects(RoadIntersection _roadIntersection) { if (_roadIntersection != null) { InitializeIntersectionObjectsInternal(_roadIntersection); } else { Object[] allIntersections = GameObject.FindObjectsOfType(); //Add intersection components, if necessary: foreach (RoadIntersection roadIntersection in allIntersections) { InitializeIntersectionObjectsInternal(roadIntersection); } } } private static void InitializeIntersectionObjectsInternal(RoadIntersection _roadIntersection) { //1. Determine 3-way or 4-way. # of corners for 3-way: 2. 4-way = 4. if (_roadIntersection.intersectionType == RoadIntersection.IntersectionTypeEnum.ThreeWay) { _roadIntersection.cornerPoints = new RoadIntersection.CornerPositionMaker[2]; } else { _roadIntersection.cornerPoints = new RoadIntersection.CornerPositionMaker[4]; } //Contains int IDs of connected nodes: List tList = new List(); //Get all connected nodes on intersection node1: int cCount = _roadIntersection.node1.connectedID.Count; SplineN tNode; for (int index = 0; index < cCount; index++) { //tNode = GetNodeByID(_roadIntersection.node1.connectedID[index]); tNode = _roadIntersection.node1.connectedNode[index]; if (!tList.Contains(tNode)) { tList.Add(tNode); } } //Get all connected nodes on intersection node2: cCount = _roadIntersection.node2.connectedID.Count; for (int index = 0; index < cCount; index++) { //tNode = GetNodeByID(_roadIntersection.node2.connectedID[index]); tNode = _roadIntersection.node2.connectedNode[index]; if (!tList.Contains(tNode)) { tList.Add(tNode); } } //Declare connected nodes: SplineN n1, n2, n3, n4; n1 = tList[0]; n2 = tList[1]; n3 = tList[2]; n4 = null; if (tList.Count > 3) { n4 = tList[3]; } //Determine most relevant spline: SplineC n1Spline = n1.spline; SplineC n2Spline = n2.spline; SplineC n3Spline = n3.spline; SplineC n4Spline = null; if (n4 != null) { n4Spline = n4.spline; } //Get the point: Vector3 n1Point = GetFourCornerPoint(ref n1Spline, ref n1, _roadIntersection); Vector3 n2Point = GetFourCornerPoint(ref n2Spline, ref n2, _roadIntersection); Vector3 n3Point = GetFourCornerPoint(ref n3Spline, ref n3, _roadIntersection); Vector3 n4Point = new Vector3(0f, 0f, 0f); if (n4Spline != null) { n4Point = GetFourCornerPoint(ref n4Spline, ref n4, _roadIntersection); } //2. If 3 way, we know that 2 of the nodes have the same spline. if (1 == 1 && _roadIntersection.intersectionType == RoadIntersection.IntersectionTypeEnum.ThreeWay) { //Should be size 3: if (tList.Count != 3) { Debug.LogError("InitializeIntersections hashset != 3 connected on three way intersection, real size: " + tList.Count + " on intersection: " + _roadIntersection.transform.name); return; } ProcessFourCorners(ref n1Point, ref n2Point, _roadIntersection.transform.gameObject, GetLongestSplineDistance(n1Spline, n2Spline)); ProcessFourCorners(ref n1Point, ref n3Point, _roadIntersection.transform.gameObject, GetLongestSplineDistance(n1Spline, n3Spline)); ProcessFourCorners(ref n2Point, ref n3Point, _roadIntersection.transform.gameObject, GetLongestSplineDistance(n2Spline, n3Spline)); } else if (_roadIntersection.intersectionType == RoadIntersection.IntersectionTypeEnum.FourWay) { //Should be size 3: if (tList.Count != 4) { Debug.LogError("InitializeIntersections hashset != 4 connected on four way intersection, real size: " + tList.Count + " on intersection: " + _roadIntersection.transform.name); return; } ProcessFourCorners(ref n1Point, ref n2Point, _roadIntersection.transform.gameObject, GetLongestSplineDistance(n1Spline, n2Spline)); ProcessFourCorners(ref n1Point, ref n3Point, _roadIntersection.transform.gameObject, GetLongestSplineDistance(n1Spline, n3Spline)); ProcessFourCorners(ref n1Point, ref n4Point, _roadIntersection.transform.gameObject, GetLongestSplineDistance(n1Spline, n4Spline)); ProcessFourCorners(ref n2Point, ref n3Point, _roadIntersection.transform.gameObject, GetLongestSplineDistance(n2Spline, n3Spline)); ProcessFourCorners(ref n2Point, ref n4Point, _roadIntersection.transform.gameObject, GetLongestSplineDistance(n2Spline, n4Spline)); ProcessFourCorners(ref n3Point, ref n4Point, _roadIntersection.transform.gameObject, GetLongestSplineDistance(n3Spline, n4Spline)); } } #endregion #region "Intersection creation helpers" private static float GetLongestSplineDistance(SplineC _spline1, SplineC _spline2) { if (_spline1.distance > _spline2.distance) { return _spline1.distance; } else { return _spline2.distance; } } private static SplineN GetNodeByID(int _ID) { Object[] SplineNodeObjects = GameObject.FindObjectsOfType(); foreach (SplineN tNode in SplineNodeObjects) { if (tNode.id == _ID) { return tNode; } } return null; } private static Vector3 GetFourCornerPoint(ref SplineC _spline, ref SplineN _node, RoadIntersection _roadIntersection) { SplineN iNode; if (_node.connectedNode.Contains(_roadIntersection.node1)) { iNode = _roadIntersection.node1; } else { iNode = _roadIntersection.node2; } float Pos1 = _node.time; float iPos = iNode.time; float tFloat = 0; float NewSplinePos = 0; if (iPos >= Pos1) { tFloat = iPos - Pos1; tFloat = tFloat / 8; NewSplinePos = iPos - tFloat; } else { tFloat = Pos1 - iPos; tFloat = tFloat / 8; NewSplinePos = iPos + tFloat; } Vector3 tVect = new Vector3(0, 0, 0); bool bDone = false; int spamguard = 0; float tDist = 0f; while (!bDone && spamguard < 20000) { spamguard += 1; tVect = _spline.GetSplineValue(NewSplinePos); tDist = Vector3.Distance(tVect, iNode.transform.position); if (tDist > 22f) { //Get closer to intersection: if (iPos >= NewSplinePos) { NewSplinePos += 0.001f; } else { NewSplinePos -= 0.001f; } } else if (tDist < 20f) { //Move away from intersection: if (iPos >= NewSplinePos) { NewSplinePos -= 0.001f; } else { NewSplinePos += 0.001f; } } else { bDone = true; } } return tVect; } private static void ProcessFourCorners(ref Vector3 _n1, ref Vector3 _n2, GameObject _intersectionObject, float _splineDistance) { float Side1, Side2, Side3; Side1 = Vector3.Distance(_n1, _n2); Side2 = Vector3.Distance(_intersectionObject.transform.position, _n1); Side3 = Vector3.Distance(_intersectionObject.transform.position, _n2); float tAngle = AngleOfTriangle(Side2, Side3, Side1); if (tAngle > 20f && tAngle < 140f) { ProcessTwoCorners(ref _intersectionObject, ref _n1, ref _n2, _splineDistance); } } private static float AngleOfTriangle(float _a, float _b, float _c) { float cAng = (_a * _a + _b * _b - _c * _c) / (2 * _a * _b); float radAngle = Mathf.Acos(cAng); float degAngle = Mathf.Rad2Deg * radAngle; return degAngle; } private static void ProcessTwoCorners(ref GameObject _intersectionObject, ref Vector3 _n1, ref Vector3 _n2, float _splineDistance) { GameObject tCorner = GameObject.CreatePrimitive(PrimitiveType.Cube); tCorner.transform.localScale = new Vector3(0.5f, 20f, 0.5f); tCorner.name = "CornerPosition"; tCorner.transform.parent = _intersectionObject.transform; tCorner.layer = 0; //Calculate the angle: Vector3 v3BA = _n2 - _intersectionObject.transform.position; Vector3 v3BC = _n1 - _intersectionObject.transform.position; Vector3 axis = Vector3.Cross(v3BA, v3BC); float angle = Vector3.Angle(v3BA, v3BC); Vector3 v3 = Quaternion.AngleAxis(angle / 2.0f, axis) * v3BA; //Vector3 v3 = (((n2.transform.position + n1.transform.position)/2) - tIntersectionObject.transform.position); tCorner.transform.rotation = Quaternion.LookRotation(v3); float tStep = 1.25f / _splineDistance; bool bSuccess = MoveCorner(tStep, 3f, ref tCorner, ref _intersectionObject, v3); if (!bSuccess) { Debug.Log("not success"); Object.DestroyImmediate(tCorner); } } private static bool MoveCorner(float _step, float _dist, ref GameObject _corner, ref GameObject _intersectionObject, Vector3 _vector) { float tStart = 0.05f; bool isDone = false; int spamguard = 0; bool isRoadHit = false; Collider[] tCollider; while (!isDone) { spamguard += 1; _corner.transform.position = _intersectionObject.transform.position + (_vector * tStart); if (Vector3.Distance(_corner.transform.position, _intersectionObject.transform.position) > 25f) { Debug.Log("too long"); isDone = true; return false; } if (spamguard > 80000) { Debug.Log("spamguard"); isDone = true; return false; } //Cast sphere now isRoadHit = false; tCollider = Physics.OverlapSphere(_corner.transform.position, _dist); if (tCollider == null || tCollider.Length < 1) { tStart += _step; continue; } else { for (int k = 0; k < tCollider.Length; k++) { if (tCollider[k].transform.name.ToLower().Contains("road")) { isRoadHit = true; break; } } } if (isRoadHit) { tStart += _step; continue; } else { //Debug.Log ("Distance: " + Vector3.Distance(tCorner.transform.position,tIntersectionObject.transform.position)); isDone = true; break; } } return true; } #endregion #endregion } }