2024-11-19 11:48:21 +01:00

1119 lines
42 KiB
C#

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>();
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<Road> roads = new List<Road>();
foreach (Collider collider in colliders)
{
if (collider.transform.parent)
{
Road tRoad = collider.transform.parent.GetComponent<Road>();
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<Road> _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>();
MeshFilter MF_Road_SR = tRoad.MeshShoR.GetComponent<MeshFilter>();
MeshFilter MF_Road_SL = tRoad.MeshShoL.GetComponent<MeshFilter>();
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<MeshFilter>();
if (!MF)
{
MF = _obj.AddComponent<MeshFilter>();
}
MF.sharedMesh = tMesh;
//MeshToFile(MF, RoadEditorUtility.GetBasePath() + "/Mesh/Intersections/" + name +".obj");
MeshCollider MC = _obj.GetComponent<MeshCollider>();
Object.DestroyImmediate(MC);
//if(!MC){ MC = iObj.AddComponent<MeshCollider>(); }
//MC.sharedMesh = MF.sharedMesh;
MeshRenderer MR = _obj.GetComponent<MeshRenderer>();
if (!MR)
{
MR = _obj.AddComponent<MeshRenderer>();
}
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<MeshFilter>();
if (!MF)
{
MF = _obj.AddComponent<MeshFilter>();
}
MF.sharedMesh = tMesh;
//MeshToFile(MF, RoadEditorUtility.GetBasePath() + "/Mesh/Intersections/" + name +"-overlay.obj");
MeshCollider MC = _obj.GetComponent<MeshCollider>();
Object.DestroyImmediate(MC);
//if(!MC){ MC = iObj.AddComponent<MeshCollider>(); }
//MC.sharedMesh = MF.sharedMesh;
MeshRenderer MR = _obj.GetComponent<MeshRenderer>();
if (!MR)
{
MR = _obj.AddComponent<MeshRenderer>();
}
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<RoadIntersection>();
//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<SplineN> tList = new List<SplineN>();
//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<SplineN>();
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
}
}