public SpeedAnalyzer(ClosedSpline <Vector3> idealLine, ClosedSpline <float> bankSpline, CurvatureAnalyzer curvature, int sampleRate) { this.idealLine = idealLine; vs = new float[sampleRate]; force = new Vector3[sampleRate]; for (int i = 0; i < sampleRate; i++) { vs[i] = 0f; force[i] = Vector3.zero; } for (int twice = 0; twice < 2; twice++) { for (int i = 0; i < sampleRate; i++) { int iPrev = i - 1; if (iPrev < 0) { iPrev = sampleRate - 1; } float sPrev = ((float)iPrev) / sampleRate; float s = ((float)i) / sampleRate; float angleHere = Vector3.Angle(idealLine.TangentAt(sPrev)[1] - idealLine.TangentAt(sPrev)[0], new Vector3((idealLine.TangentAt(sPrev)[1] - idealLine.TangentAt(sPrev)[0]).x, 0f, (idealLine.TangentAt(sPrev)[1] - idealLine.TangentAt(sPrev)[0]).z)); if ((idealLine.TangentAt(sPrev)[1] - idealLine.TangentAt(sPrev)[0]).y < 0f) { angleHere = -angleHere; } float estimatedT = -1f + Mathf.Sqrt(1f + (Vector3.Distance(idealLine.SplineAt(s), idealLine.SplineAt(sPrev)) * 2f) / carAcceleration(vs[iPrev], angleHere)); float v = vs[iPrev] + estimatedT * carAcceleration(vs[iPrev], angleHere); float aZ = carAcceleration(vs[iPrev], angleHere); float radius = Mathf.Abs(1f / curvature.Curvature[(int)(s * curvature.Curvature.Length)]); float bankToRightAngle = bankSpline.SplineAt(s); float vMax = lateralAcceleration(bankToRightAngle, radius, curvature.Curvature[(int)(s * curvature.Curvature.Length)] >= 0f); //float vMax = Mathf.Sqrt(lateralAcceleration(v) * radius); if (vMax < v) { v = vMax; float vBack = v; for (int j = 1; j < sampleRate; j++) { int index = i - j; if (index < 0) { index = sampleRate + index; } int indexPrev = index + 1; if (indexPrev >= sampleRate) { indexPrev = 0; } float sTempPrev = ((float)indexPrev) / sampleRate; float sTemp = ((float)index) / sampleRate; float estimatedTTemp = -1f + Mathf.Sqrt(1f + (Vector3.Distance(idealLine.SplineAt(s), idealLine.SplineAt(sPrev)) * 2f) / carAcceleration(vs[iPrev], angleHere)); float vMaxBack = vBack + estimatedTTemp * braking(vBack, angleHere); if (vMaxBack < vs[index]) { vs[index] = vMaxBack; force[index] = new Vector3((vMaxBack * vMaxBack) / radius, force[index].y, -braking(vBack, angleHere)); vBack = vMaxBack; } else { break; } } } vs[i] = v; force[i] = new Vector3((v * v * Mathf.Sign(curvature.Curvature[(int)(s * curvature.Curvature.Length)])) / radius, 0f, aZ); } } }
public DiscreteTrack(GeneratedTrack track, TerrainModifier terrainModifier) { List <Vector3> lefts = new List <Vector3>(); List <Vector3> rights = new List <Vector3>(); List <Vector3> leftsCurv = new List <Vector3>(); List <Vector3> rightsCurv = new List <Vector3>(); List <int> indcs = new List <int>(); int indcsCounter = 0; List <float> idealLineMeshList = new List <float>(); int idLineMeshCounter = 0; for (int i = 0; i < track.Elements.Length; i++) { if (track.Elements[i].GetType() == typeof(GeneratedStraight)) { Vector3 middle = track.Elements[i].Position; Vector3 toRight = (new Vector3(Mathf.Cos(track.Elements[i].Direction), 0f, -Mathf.Sin(track.Elements[i].Direction))).normalized; Vector3 toFront = (new Vector3(Mathf.Sin(track.Elements[i].Direction), 0f, Mathf.Cos(track.Elements[i].Direction))).normalized; lefts.Add(middle - toRight * track.Elements[i].WidthStart); rights.Add(middle + toRight * track.Elements[i].WidthStart); indcsCounter = -1; GeneratedStraight straight = (GeneratedStraight)track.Elements[i]; int segsAmount = (int)(straight.Length / straightSegmentingFactorIdealline); int segmentsAmountMesh = (int)(straight.Length / straightSegmentingFactorMesh); for (int j = 0; j < segmentsAmountMesh; j++) { //idealLineMesh[idLineMeshCounter] = 1f; idealLineMeshList.Add(1f); idLineMeshCounter++; } for (int j = 0; j < segsAmount; j++) { leftsCurv.Add(middle - toRight * track.Elements[i].WidthStart + toFront * straight.Length * (((float)j) / ((float)segsAmount))); rightsCurv.Add(middle + toRight * track.Elements[i].WidthStart + toFront * straight.Length * (((float)j) / segsAmount)); indcsCounter++; } indcs.Add(indcsCounter); } else if (track.Elements[i].GetType() == typeof(GeneratedTurn)) { GeneratedTurn turn = (GeneratedTurn)track.Elements[i]; bool rightTurn = turn.Degree >= 0f; Vector3 toRight = (Quaternion.Euler(0f, (turn.Direction * 180f) / Mathf.PI, 0f)) * (new Vector3(1f, 0f, 0f)); Vector3 toFront = (Quaternion.Euler(0f, (turn.Direction * 180f) / Mathf.PI, 0f)) * (new Vector3(0f, 0f, 1f)); Vector3 middlePoint = toRight * turn.Radius * (rightTurn ? 1f : -1f); int segmentsAmount = ((int)(Mathf.Abs(turn.Degree) / 30f)) + 1; for (int j = 0; j < segmentsAmount; j++) { Vector3 toRightTurned = (Quaternion.Euler(0f, (turn.Degree / ((float)segmentsAmount)) * j, 0f)) * toRight; Vector3 segmentPos = middlePoint + (toRightTurned * (rightTurn ? -1f : 1f) * turn.Radius); float currentWidth = (turn.WidthEnd - turn.WidthStart) * (float)((float)j / (float)segmentsAmount) + turn.WidthStart; lefts.Add(segmentPos + toRightTurned * currentWidth * -1f + turn.Position); rights.Add(segmentPos + toRightTurned * currentWidth + turn.Position); leftsCurv.Add(segmentPos + toRightTurned * currentWidth * -1f + turn.Position); rightsCurv.Add(segmentPos + toRightTurned * currentWidth + turn.Position); indcs.Add(0); } } else if (track.Elements[i].GetType() == typeof(GeneratedBezSpline)) { GeneratedBezSpline bezierSpline = (GeneratedBezSpline)track.Elements[i]; for (int j = 0; j < bezierSpline.RenderVertsLeft.Length - 1; j++) { if (j == 0) { //idealLineMesh[idLineMeshCounter] = 2f; idealLineMeshList.Add(2f); } else { //idealLineMesh[idLineMeshCounter] = 0f; idealLineMeshList.Add(0f); } idLineMeshCounter++; if (j % 3 == 0) { lefts.Add(bezierSpline.RenderVertsLeft[j]); rights.Add(bezierSpline.RenderVertsRight[j]); leftsCurv.Add(bezierSpline.RenderVertsLeft[j]); rightsCurv.Add(bezierSpline.RenderVertsRight[j]); indcs.Add(0); } } } } idealLineMesh = idealLineMeshList.ToArray(); leftPoints = lefts.ToArray(); rightPoints = rights.ToArray(); leftPointsCurv = leftsCurv.ToArray(); rightPointsCurv = rightsCurv.ToArray(); indcsFromPathIntoCurvature = indcs.ToArray(); shortestPathTrajectory = minimizePathTrajectory(); if (false) { for (int i = 0; i < leftPoints.Length; i++) { int i2 = (i + 1) % leftPoints.Length; Debug.DrawLine(leftPoints[i], leftPoints[i2], Color.white, 10000f); Debug.DrawLine(rightPoints[i], rightPoints[i2], Color.white, 10000f); Debug.DrawLine(leftPoints[i], rightPoints[i], Color.white, 10000f); Debug.DrawLine(shortestPathTrajectory[i] * (leftPoints[i] - rightPoints[i]) + rightPoints[i], shortestPathTrajectory[i2] * (leftPoints[i2] - rightPoints[i2]) + rightPoints[i2], Color.green, 10000f); } } minimumCurvatureTrajectory = minimizeCurvatureTrajectory(); if (false) { for (int i = 0; i < leftPointsCurv.Length; i++) { int i2 = (i + 1) % leftPointsCurv.Length; Debug.DrawLine(leftPointsCurv[i], leftPointsCurv[i2], Color.white, 10000f); Debug.DrawLine(rightPointsCurv[i], rightPointsCurv[i2], Color.white, 10000f); Debug.DrawLine(leftPointsCurv[i], rightPointsCurv[i], Color.white, 10000f); Debug.DrawLine(minimumCurvatureTrajectory[i] * (leftPointsCurv[i] - rightPointsCurv[i]) + rightPointsCurv[i], minimumCurvatureTrajectory[i2] * (leftPointsCurv[i2] - rightPointsCurv[i2]) + rightPointsCurv[i2], Color.green, 10000f); } } float epsilon = 0.1f; idealLine = applyEpsilon(shortestPathTrajectory, minimumCurvatureTrajectory, epsilon, indcsFromPathIntoCurvature); /*for (int i = 0; i < idealLine.Length; i++) * { * Debug.Log("IL [" + i + "]: " + idealLine[i]); * }*/ Debug.Log("cnter: " + idLineMeshCounter); transferToMeshIdealLine(track, idealLine, idealLineMesh); List <float> cpsBankAngles = new List <float>(); List <Vector3> cpsMinDistance = new List <Vector3>(); float minDistance = 15f; Vector3[] cps = new Vector3[idealLine.Length]; float[] cpsBank = new float[idealLine.Length]; cpsMinDistance.Add(idealLine[0] * (leftPointsCurv[0] - rightPointsCurv[0]) + rightPointsCurv[0]); for (int i = 1; i < idealLine.Length; i++) { Vector3 point = idealLine[i] * (leftPointsCurv[i] - rightPointsCurv[i]) + rightPointsCurv[i]; //cps[i] = point; if (Vector3.Distance(cpsMinDistance[cpsMinDistance.Count - 1], point) > minDistance) { cpsBankAngles.Add(Vector3.Angle(new Vector3(rightPointsCurv[i].x - leftPointsCurv[i].x, terrainModifier.GetTensorHeight(rightPointsCurv[i].x, rightPointsCurv[i].z) - terrainModifier.GetTensorHeight(leftPointsCurv[i].x, leftPointsCurv[i].z), rightPointsCurv[i].z - leftPointsCurv[i].z), new Vector3((rightPointsCurv[i] - leftPointsCurv[i]).x, 0f, (rightPointsCurv[i] - leftPointsCurv[i]).z)) * Mathf.Sign((rightPointsCurv[i] - leftPointsCurv[i]).y)); cpsMinDistance.Add(point); } } cps = cpsMinDistance.ToArray(); cpsBank = cpsBankAngles.ToArray(); for (int i = 0; i < cps.Length; i++) { cps[i] = new Vector3(cps[i].x, terrainModifier.GetTensorHeight(cps[i].x, cps[i].z), cps[i].z); } idealLineSpline = new ClosedSpline <Vector3>(cps); ClosedSpline <float> bankSpline = new ClosedSpline <float>(cpsBank); curvatureAnalyzer = new CurvatureAnalyzer(idealLineSpline, 300); speedAnalyzer = new SpeedAnalyzer(idealLineSpline, bankSpline, curvatureAnalyzer, 300); curvatureAnalyzerTrack = new CurvatureAnalyzer(track, 300); curvatureIdealLineAnalyzer = new CurvatureIdeallineAnalyzer(idealLineSpline); float startFinishLength = 500f; float partStartFinish = startFinishLength / track.TrackLength; int elementsStartFinishAmount = (int)(idealLineSpline.ControlPointsAmount * partStartFinish); elementsStartFinishAmount = (int)(partStartFinish * 300f); int startFinishIndex = minCurvatureForAmount(curvatureAnalyzerTrack.Curvature, elementsStartFinishAmount); float partpart = curvatureAnalyzerTrack.trackPartIndices[startFinishIndex]; //Vector3 beginStartFinishPoint = idealLineSpline.controlPoints[startFinishIndex]; Debug.Log("Start Finish point: " + partpart); int elementStartFinishBeginIndex = (int)partpart; Vector3 elementStartPos = track.Elements[elementStartFinishBeginIndex].Position; startFinishLineIndex = partpart; //Debug.Log("Start Finish point: " + elementStartPos); }