Created
June 15, 2024 23:56
-
-
Save DearthDev/c21d9b87ad44eecbdef935f68fe7b6ad to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Collections; | |
| using System.Collections.Generic; | |
| using UnityEngine; | |
| [ExecuteInEditMode, System.Serializable] | |
| public abstract class Rail : MonoBehaviour | |
| { | |
| [SerializeField] public RailMaterial material; | |
| [HideInInspector, SerializeField] protected List<Segment> segments = new(); | |
| public enum RailMaterial | |
| { | |
| Metal, | |
| Wood | |
| } | |
| public Vector3 GetClosestPosition(Vector3 position, out int end, out Quaternion rotation, out float distance) | |
| { | |
| float dist = Mathf.Infinity; | |
| Vector3 result = new(); | |
| end = 0; | |
| rotation = new(); | |
| distance = 0.0f; | |
| for (int i = 0; i < segments.Count - 1; i++) | |
| { | |
| Vector3 offset = segments[i + 1].position - segments[i].position; | |
| float l = offset.magnitude; | |
| Vector3 dir = offset.normalized; | |
| Vector3 relativePosition = position - segments[i].position; | |
| float t = Vector3.Dot(relativePosition, dir); | |
| int e = 0; | |
| if (i == 0 && t <= 0.0f) | |
| e = -1; | |
| else if (i == segments.Count - 2 && t >= l) | |
| e = 1; | |
| t = Mathf.Clamp(t, 0.0f, l); | |
| Vector3 p = segments[i].position + offset * t; | |
| float d = Vector3.Magnitude(p - position); | |
| if (d < dist) | |
| { | |
| dist = d; | |
| result = p; | |
| end = e; | |
| rotation = Quaternion.Lerp(segments[i].rotation, segments[i + 1].rotation, t / l); | |
| distance = Mathf.Lerp(segments[i].distance, segments[i + 1].distance, t / l); | |
| } | |
| } | |
| return result; | |
| } | |
| public float MoveOnRail(float distance, float amount, out int end, out Vector3 position, out Quaternion rotation) | |
| { | |
| end = 0; | |
| distance += amount; | |
| if (distance <= 0.0f) | |
| { | |
| end = -1; | |
| rotation = segments[0].rotation; | |
| position = segments[0].position; | |
| return 0.0f; | |
| } | |
| for (int i = 0; i < segments.Count - 1; i++) | |
| { | |
| if (distance >= segments[i + 1].distance) | |
| continue; | |
| float t = (distance - segments[i].distance) / (segments[i + 1].distance - segments[i].distance); | |
| position = Vector3.Lerp(segments[i].position, segments[i + 1].position, t); | |
| rotation = Quaternion.Lerp(segments[i].rotation, segments[i + 1].rotation, t); | |
| return distance; | |
| } | |
| end = 1; | |
| rotation = segments[^1].rotation; | |
| position = segments[^1].position; | |
| return segments[^1].distance; | |
| } | |
| #if UNITY_EDITOR | |
| private const float CurveSegmentSpacing = 1.0f; | |
| private Vector3 lastPosition = new(); | |
| private List<Vector3> childrenLastPositions = new(); | |
| protected List<Vector3> points = new(); | |
| private MeshCollider meshCollider = null; | |
| private Mesh collisionMesh = null; | |
| protected MeshFilter railMeshFilter = null; | |
| protected MeshCollider railMeshCollider = null; | |
| protected Mesh railMesh = null; | |
| protected MeshCollider invisWallCollider = null; | |
| protected Mesh invisWallMesh = null; | |
| private Transform pathContainer = null; | |
| private Transform railMeshObject = null; | |
| private Transform wallObject = null; | |
| protected int ignoreLayer = 0; | |
| protected float railMeshWidth = 1.0f; | |
| protected float railMeshHeight = 0.1f; | |
| protected bool snapPointsToGround = false; | |
| protected bool smoothCurve = true; | |
| protected abstract void PostPointsSet(); | |
| protected abstract void PostSegmentGeneration(); | |
| protected abstract void GenerateMeshes(); | |
| protected virtual void Awake() | |
| { | |
| ignoreLayer = (1 << LayerMask.NameToLayer("Rail")) | (1 << LayerMask.NameToLayer("Wall")) | (1 << LayerMask.NameToLayer("Ignore Raycast")); | |
| // Rail | |
| if (gameObject.layer != LayerMask.NameToLayer("Rail")) | |
| gameObject.layer = LayerMask.NameToLayer("Rail"); | |
| meshCollider = GetComponent<MeshCollider>(); | |
| if (!meshCollider) | |
| meshCollider = gameObject.AddComponent<MeshCollider>(); | |
| collisionMesh = meshCollider.sharedMesh; | |
| if (!collisionMesh) | |
| { | |
| meshCollider.sharedMesh = new Mesh(); | |
| collisionMesh = meshCollider.sharedMesh; | |
| } | |
| pathContainer = transform.Find("Path Container"); | |
| if (!pathContainer) | |
| { | |
| GameObject g = new("Path Container"); | |
| g.transform.position = transform.position; | |
| g.transform.rotation = transform.rotation; | |
| g.transform.parent = transform; | |
| pathContainer = g.transform; | |
| GameObject p = new("Point (1)"); | |
| p.transform.position = transform.position; | |
| p.transform.rotation = transform.rotation; | |
| p.transform.parent = pathContainer; | |
| p = new("Point (2)"); | |
| p.transform.position = transform.position - Vector3.forward * 10.0f; | |
| p.transform.rotation = transform.rotation; | |
| p.transform.parent = pathContainer; | |
| } | |
| } | |
| protected void AddRailMesh(bool collision) | |
| { | |
| // Rail mesh | |
| railMeshObject = transform.Find("Rail Mesh"); | |
| if (!railMeshObject) | |
| { | |
| GameObject g = new("Rail Mesh"); | |
| g.transform.position = transform.position; | |
| g.transform.rotation = transform.rotation; | |
| g.transform.parent = transform; | |
| railMeshObject = g.transform; | |
| } | |
| railMeshFilter = railMeshObject.GetComponent<MeshFilter>(); | |
| if (!railMeshFilter) | |
| railMeshFilter = railMeshObject.gameObject.AddComponent<MeshFilter>(); | |
| railMesh = railMeshFilter.sharedMesh; | |
| if (!railMesh) | |
| { | |
| railMeshFilter.sharedMesh = new Mesh(); | |
| railMesh = railMeshFilter.sharedMesh; | |
| } | |
| if (!railMeshObject.GetComponent<MeshRenderer>()) | |
| railMeshObject.gameObject.AddComponent<MeshRenderer>(); | |
| if (!collision) | |
| return; | |
| railMeshCollider = railMeshObject.GetComponent<MeshCollider>(); | |
| if (!railMeshCollider) | |
| railMeshCollider = railMeshObject.gameObject.AddComponent<MeshCollider>(); | |
| if (railMeshObject.gameObject.layer != LayerMask.NameToLayer("Wall")) | |
| railMeshObject.gameObject.layer = LayerMask.NameToLayer("Wall"); | |
| } | |
| protected void AddWallMesh() | |
| { | |
| // Wall mesh | |
| wallObject = transform.Find("Invis Wall"); | |
| if (!wallObject) | |
| { | |
| GameObject g = new("Invis Wall"); | |
| g.transform.position = transform.position; | |
| g.transform.rotation = transform.rotation; | |
| g.transform.parent = transform; | |
| wallObject = g.transform; | |
| } | |
| invisWallCollider = wallObject.GetComponent<MeshCollider>(); | |
| if (!invisWallCollider) | |
| invisWallCollider = wallObject.gameObject.AddComponent<MeshCollider>(); | |
| invisWallMesh = invisWallCollider.sharedMesh; | |
| if (!invisWallMesh) | |
| { | |
| invisWallCollider.sharedMesh = new Mesh(); | |
| invisWallMesh = invisWallCollider.sharedMesh; | |
| } | |
| if (wallObject.gameObject.layer != LayerMask.NameToLayer("Wall")) | |
| wallObject.gameObject.layer = LayerMask.NameToLayer("Wall"); | |
| } | |
| void LateUpdate() | |
| { | |
| if (pathContainer.childCount < 2) | |
| return; | |
| if (ShouldGenerate()) | |
| Generate(); | |
| } | |
| private bool ShouldGenerate() | |
| { | |
| if (transform.position != lastPosition) | |
| { | |
| lastPosition = transform.position; | |
| return true; | |
| } | |
| if (pathContainer.childCount != childrenLastPositions.Count) | |
| { | |
| childrenLastPositions.Clear(); | |
| for (int i = 0; i < pathContainer.childCount; i++) | |
| { | |
| childrenLastPositions.Add(pathContainer.GetChild(i).position); | |
| } | |
| return true; | |
| } | |
| else | |
| { | |
| for (int i = 0; i < pathContainer.childCount; i++) | |
| { | |
| if (childrenLastPositions[i] != pathContainer.GetChild(i).position) | |
| { | |
| childrenLastPositions[i] = pathContainer.GetChild(i).position; | |
| return true; | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| private void Generate() | |
| { | |
| SetPoints(); | |
| PostPointsSet(); | |
| if (smoothCurve) | |
| GenerateSmoothSegments(); | |
| else | |
| GenerateSharpSegments(); | |
| if (segments.Count < 2) | |
| return; | |
| PostSegmentGeneration(); | |
| CalculateSegmentLengths(); | |
| GenerateMeshes(); | |
| GenerateRailCollisionMesh(railMeshWidth, railMeshHeight); | |
| RemovePenetratingSegments(); | |
| } | |
| void SetPoints() | |
| { | |
| points.Clear(); | |
| for (int i = 0; i < pathContainer.childCount; i++) | |
| { | |
| if (snapPointsToGround) | |
| { | |
| Vector3 castPos = pathContainer.GetChild(i).position; | |
| if (Physics.Raycast(castPos, -Vector3.up, out RaycastHit hit, 1000.0f, ~ignoreLayer)) | |
| { | |
| points.Add(transform.InverseTransformPoint(hit.point + Vector3.up * 1.2f)); | |
| } | |
| else | |
| { | |
| points.Add(pathContainer.GetChild(i).localPosition); | |
| } | |
| } | |
| else | |
| { | |
| points.Add(pathContainer.GetChild(i).localPosition); | |
| } | |
| } | |
| } | |
| void GenerateSmoothSegments() | |
| { | |
| List<Vector3> handles = AutoSetHandles(); | |
| segments.Clear(); | |
| float dstSinceLastEvenPoint = 0; | |
| Vector3 previousPoint = points[0]; | |
| segments.Add(new Segment(previousPoint, Vector3.Normalize(points[1] - previousPoint))); | |
| for (int i = 0; i < points.Count - 1; i++) | |
| { | |
| Vector3 p1 = points[i]; | |
| Vector3 p2 = handles[i * 2]; | |
| Vector3 p3 = handles[i * 2 + 1]; | |
| Vector3 p4 = points[i + 1]; | |
| float controlNetLength = Vector3.Distance(p1, p2) + Vector3.Distance(p2, p3) + Vector3.Distance(p3, p4); | |
| float estimatedCurveLength = Vector3.Distance(p1, p4) + controlNetLength / 2f; | |
| int divisions = Mathf.CeilToInt(estimatedCurveLength * 10); | |
| float t = 0; | |
| while (t <= 1) | |
| { | |
| t += 1f / divisions; | |
| Vector3 pointOnCurve = EvaluateCubic(p1, p2, p3, p4, t); | |
| dstSinceLastEvenPoint += Vector3.Distance(previousPoint, pointOnCurve); | |
| while (dstSinceLastEvenPoint >= CurveSegmentSpacing) | |
| { | |
| float overshootDst = dstSinceLastEvenPoint - CurveSegmentSpacing; | |
| Vector3 dir = Vector3.Normalize(pointOnCurve - previousPoint); | |
| Vector3 newEvenlySpacedPoint = pointOnCurve + dir * overshootDst; | |
| segments.Add(new Segment(newEvenlySpacedPoint, dir)); | |
| dstSinceLastEvenPoint = overshootDst; | |
| previousPoint = newEvenlySpacedPoint; | |
| } | |
| previousPoint = pointOnCurve; | |
| } | |
| } | |
| } | |
| List<Vector3> AutoSetHandles() | |
| { | |
| List<Vector3> handles = new(); | |
| for (int i = 0; i < points.Count; i++) | |
| { | |
| Vector3 origin = points[i]; | |
| Vector3 dir = Vector3.zero; | |
| float dist1 = 0.0f; | |
| float dist2 = 0.0f; | |
| if (i > 0) | |
| { | |
| Vector3 offset = points[i - 1] - origin; | |
| dir += offset.normalized; | |
| dist1 = offset.magnitude; | |
| } | |
| if (i < points.Count - 1) | |
| { | |
| Vector3 offset = points[i + 1] - origin; | |
| dir -= offset.normalized; | |
| dist2 = -offset.magnitude; | |
| } | |
| dir = Vector3.Normalize(dir); | |
| if (i > 0) | |
| handles.Add(origin + dir * dist1 * 0.3f); | |
| if (i < points.Count - 1) | |
| handles.Add(origin + dir * dist2 * 0.3f); | |
| } | |
| return handles; | |
| } | |
| void GenerateSharpSegments() | |
| { | |
| segments.Clear(); | |
| for (int i = 1; i < points.Count; i++) | |
| { | |
| Vector3 a = points[i - 1]; | |
| Vector3 b = points[i]; | |
| Vector3 dir = Vector3.Normalize(b - a); | |
| int count = Mathf.RoundToInt((b - a).magnitude); | |
| for (int j = 0; j < count; j++) | |
| { | |
| segments.Add(new Segment(a + dir * j, dir)); | |
| } | |
| } | |
| segments.Add(new Segment(points[^1], Vector3.Normalize(points[^1] - points[^2]))); | |
| } | |
| void CalculateSegmentLengths() | |
| { | |
| for (int i = 1; i < segments.Count; i++) | |
| { | |
| float length = Vector3.Magnitude(segments[i].position - segments[i - 1].position); | |
| segments[i].distance = segments[i - 1].distance + length; | |
| } | |
| } | |
| void GenerateRailCollisionMesh(float width, float height) | |
| { | |
| collisionMesh.Clear(); | |
| List<Vector3> vertices = new(); | |
| List<Vector3> normals = new(); | |
| List<Vector2> uvs = new(); | |
| List<int> triangles = new(); | |
| AddSquareTube(width, height, -height * 0.5f, 0.0f, 1.0f, vertices, normals, uvs, triangles); | |
| collisionMesh.vertices = vertices.ToArray(); | |
| collisionMesh.normals = normals.ToArray(); | |
| collisionMesh.triangles = triangles.ToArray(); | |
| meshCollider.sharedMesh = collisionMesh; | |
| } | |
| void RemovePenetratingSegments() | |
| { | |
| int midIndex = segments.Count / 2; | |
| for (int i = 0; i < midIndex - 1; i++) | |
| { | |
| Vector3 castPos = transform.TransformPoint(segments[i + 1].position); | |
| Vector3 dir = transform.TransformPoint(segments[i].position) - castPos; | |
| if (Physics.Raycast(castPos, dir.normalized, dir.magnitude + 0.1f, ~ignoreLayer)) | |
| { | |
| segments.RemoveRange(0, i + 1); | |
| midIndex -= i + 1; | |
| break; | |
| } | |
| } | |
| for (int i = midIndex; i < segments.Count - 1; i++) | |
| { | |
| Vector3 castPos = transform.TransformPoint(segments[i].position); | |
| Vector3 dir = transform.TransformPoint(segments[i + 1].position) - castPos; | |
| if (Physics.Raycast(castPos, dir.normalized, dir.magnitude + 0.1f, ~ignoreLayer)) | |
| { | |
| segments.RemoveRange(i + 1, segments.Count - i - 1); | |
| break; | |
| } | |
| } | |
| } | |
| protected void AddSquareTube(float width, float height, float offset, float uvMin, float uvMax, List<Vector3> vertices, List<Vector3> normals, List<Vector2> uvs, List<int> triangles) | |
| { | |
| float halfWidth = width * 0.5f; | |
| float uvWidth = uvMax - uvMin; | |
| int idx = vertices.Count; | |
| for (int i = 0; i < segments.Count; i++) | |
| { | |
| Segment s = segments[i]; | |
| vertices.Add(s.rotation * new Vector3(-halfWidth, -0.04f, 0.0f) + s.position + new Vector3(0.0f, -offset, 0.0f)); | |
| vertices.Add(s.rotation * new Vector3(halfWidth, -0.04f, 0.0f) + s.position + new Vector3(0.0f, -offset, 0.0f)); | |
| vertices.Add(s.rotation * new Vector3(halfWidth, -0.04f, 0.0f) + s.position + new Vector3(0.0f, -offset, 0.0f)); | |
| vertices.Add(s.rotation * new Vector3(halfWidth, -0.04f - height, 0.0f) + s.position + new Vector3(0.0f, -offset, 0.0f)); | |
| vertices.Add(s.rotation * new Vector3(halfWidth, -0.04f - height, 0.0f) + s.position + new Vector3(0.0f, -offset, 0.0f)); | |
| vertices.Add(s.rotation * new Vector3(-halfWidth, -0.04f - height, 0.0f) + s.position + new Vector3(0.0f, -offset, 0.0f)); | |
| vertices.Add(s.rotation * new Vector3(-halfWidth, -0.04f - height, 0.0f) + s.position + new Vector3(0.0f, -offset, 0.0f)); | |
| vertices.Add(s.rotation * new Vector3(-halfWidth, -0.04f, 0.0f) + s.position + new Vector3(0.0f, -offset, 0.0f)); | |
| normals.Add(s.rotation * Vector3.up); | |
| normals.Add(s.rotation * Vector3.up); | |
| normals.Add(s.rotation * Vector3.right); | |
| normals.Add(s.rotation * Vector3.right); | |
| normals.Add(s.rotation * Vector3.down); | |
| normals.Add(s.rotation * Vector3.down); | |
| normals.Add(s.rotation * Vector3.left); | |
| normals.Add(s.rotation * Vector3.left); | |
| uvs.Add(new Vector3(uvMin + uvWidth, i / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 0.33f, i / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 0.33f, i / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 0.66f, i / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 0.66f, i / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 1.0f, i / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 1.0f, i / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth, i / 10.0f)); | |
| } | |
| for (int i = 0; i < segments.Count - 1; i++) | |
| { | |
| for (int j = 0; j < 4; j++) | |
| { | |
| int current = idx + i * 8 + j * 2; | |
| int next = current + 8; | |
| triangles.Add(current); | |
| triangles.Add(next); | |
| triangles.Add(current + 1); | |
| triangles.Add(current + 1); | |
| triangles.Add(next); | |
| triangles.Add(next + 1); | |
| } | |
| } | |
| // start cap | |
| triangles.Add(idx + 0); | |
| triangles.Add(idx + 2); | |
| triangles.Add(idx + 4); | |
| triangles.Add(idx + 0); | |
| triangles.Add(idx + 4); | |
| triangles.Add(idx + 6); | |
| // end cap | |
| idx = vertices.Count - 8; | |
| triangles.Add(idx + 0); | |
| triangles.Add(idx + 4); | |
| triangles.Add(idx + 2); | |
| triangles.Add(idx + 0); | |
| triangles.Add(idx + 6); | |
| triangles.Add(idx + 4); | |
| } | |
| protected void AddSupport(float radius, Vector3 top, Vector3 bottom, Quaternion rotation, float uvMin, float uvMax, int segmentIndex, List<Vector3> vertices, List<Vector3> normals, List<Vector2> uvs, List<int> triangles) | |
| { | |
| float uvWidth = uvMax - uvMin; | |
| int idx = vertices.Count; | |
| vertices.Add(rotation * new Vector3(-radius, 0.0f, radius) + top); | |
| vertices.Add(rotation * new Vector3(radius, 0.0f, radius) + top); | |
| vertices.Add(rotation * new Vector3(radius, 0.0f, radius) + top); | |
| vertices.Add(rotation * new Vector3(radius, 0.0f, -radius) + top); | |
| vertices.Add(rotation * new Vector3(radius, 0.0f, -radius) + top); | |
| vertices.Add(rotation * new Vector3(-radius, 0.0f, -radius) + top); | |
| vertices.Add(rotation * new Vector3(-radius, 0.0f, -radius) + top); | |
| vertices.Add(rotation * new Vector3(-radius, 0.0f, radius) + top); | |
| normals.Add(rotation * Vector3.forward); | |
| normals.Add(rotation * Vector3.forward); | |
| normals.Add(rotation * Vector3.right); | |
| normals.Add(rotation * Vector3.right); | |
| normals.Add(rotation * Vector3.back); | |
| normals.Add(rotation * Vector3.back); | |
| normals.Add(rotation * Vector3.left); | |
| normals.Add(rotation * Vector3.left); | |
| uvs.Add(new Vector3(uvMin + uvWidth, segmentIndex / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 0.33f, segmentIndex / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 0.33f, segmentIndex / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 0.66f, segmentIndex / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 0.66f, segmentIndex / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 1.0f, segmentIndex / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 1.0f, segmentIndex / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth, segmentIndex / 10.0f)); | |
| vertices.Add(rotation * new Vector3(-radius, 0.0f, radius) + bottom); | |
| vertices.Add(rotation * new Vector3(radius, 0.0f, radius) + bottom); | |
| vertices.Add(rotation * new Vector3(radius, 0.0f, radius) + bottom); | |
| vertices.Add(rotation * new Vector3(radius, 0.0f, -radius) + bottom); | |
| vertices.Add(rotation * new Vector3(radius, 0.0f, -radius) + bottom); | |
| vertices.Add(rotation * new Vector3(-radius, 0.0f, -radius) + bottom); | |
| vertices.Add(rotation * new Vector3(-radius, 0.0f, -radius) + bottom); | |
| vertices.Add(rotation * new Vector3(-radius, 0.0f, radius) + bottom); | |
| normals.Add(rotation * Vector3.forward); | |
| normals.Add(rotation * Vector3.forward); | |
| normals.Add(rotation * Vector3.right); | |
| normals.Add(rotation * Vector3.right); | |
| normals.Add(rotation * Vector3.back); | |
| normals.Add(rotation * Vector3.back); | |
| normals.Add(rotation * Vector3.left); | |
| normals.Add(rotation * Vector3.left); | |
| uvs.Add(new Vector3(uvMin + uvWidth, (segmentIndex + 1) / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 0.33f, (segmentIndex + 1) / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 0.33f, (segmentIndex + 1) / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 0.66f, (segmentIndex + 1) / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 0.66f, (segmentIndex + 1) / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 1.0f, (segmentIndex + 1) / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth * 1.0f, (segmentIndex + 1) / 10.0f)); | |
| uvs.Add(new Vector3(uvMin + uvWidth, (segmentIndex + 1) / 10.0f)); | |
| for (int j = 0; j < 4; j++) | |
| { | |
| int current = idx + j * 2; | |
| int next = current + 8; | |
| triangles.Add(current); | |
| triangles.Add(next); | |
| triangles.Add(current + 1); | |
| triangles.Add(current + 1); | |
| triangles.Add(next); | |
| triangles.Add(next + 1); | |
| } | |
| } | |
| public static Vector3 EvaluateQuadratic(Vector3 a, Vector3 b, Vector3 c, float t) | |
| { | |
| Vector3 p0 = Vector3.Lerp(a, b, t); | |
| Vector3 p1 = Vector3.Lerp(b, c, t); | |
| return Vector3.Lerp(p0, p1, t); | |
| } | |
| public static Vector3 EvaluateCubic(Vector3 a, Vector3 b, Vector3 c, Vector3 d, float t) | |
| { | |
| Vector3 p0 = EvaluateQuadratic(a, b, c, t); | |
| Vector3 p1 = EvaluateQuadratic(b, c, d, t); | |
| return Vector3.Lerp(p0, p1, t); | |
| } | |
| void OnDrawGizmosSelected() | |
| { | |
| Gizmos.color = Color.red; | |
| for (int i = 0; i < segments.Count - 1; i++) | |
| { | |
| Gizmos.DrawLine(transform.TransformPoint(segments[i].position), transform.TransformPoint(segments[i + 1].position)); | |
| } | |
| Gizmos.DrawLine(transform.TransformPoint(segments[^1].position), transform.TransformPoint(segments[^1].position + segments[^1].rotation * Vector3.forward * 300.0f)); | |
| } | |
| #endif | |
| [System.Serializable] | |
| public class Segment | |
| { | |
| public Vector3 position = Vector3.zero; | |
| public Quaternion rotation = Quaternion.identity; | |
| public float distance = 0.0f; | |
| public Segment(Vector3 pos, Vector3 dir) | |
| { | |
| position = pos; | |
| rotation = Quaternion.LookRotation(dir, Vector3.up); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Collections; | |
| using System.Collections.Generic; | |
| using UnityEngine; | |
| public class RailInvis : Rail | |
| { | |
| #if UNITY_EDITOR | |
| protected override void Awake() | |
| { | |
| base.Awake(); | |
| smoothCurve = false; | |
| } | |
| protected override void PostPointsSet() { } | |
| protected override void PostSegmentGeneration() { } | |
| protected override void GenerateMeshes() { } | |
| #endif | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Collections; | |
| using System.Collections.Generic; | |
| using UnityEngine; | |
| public class RailTube : Rail | |
| { | |
| #if UNITY_EDITOR | |
| protected override void Awake() | |
| { | |
| base.Awake(); | |
| AddRailMesh(true); | |
| } | |
| protected override void PostPointsSet() { } | |
| protected override void PostSegmentGeneration() { } | |
| protected override void GenerateMeshes() | |
| { | |
| railMesh.Clear(); | |
| List<Vector3> vertices = new(); | |
| List<Vector3> normals = new(); | |
| List<Vector2> uvs = new(); | |
| List<int> triangles = new(); | |
| AddSquareTube(0.16f, 0.16f, 0.0f, 0.0f, 1.0f, vertices, normals, uvs, triangles); | |
| // supports | |
| for (int i = segments.Count - 2; i > 20; i -= 20) | |
| { | |
| Segment s = segments[i]; | |
| Vector3 castPos = transform.TransformPoint(s.position); | |
| if (Physics.Raycast(castPos, -Vector3.up, out RaycastHit hit, 1000.0f, ~ignoreLayer)) | |
| { | |
| Vector3 top = s.position + Vector3.down * 0.1f; | |
| Vector3 bottom = transform.InverseTransformPoint(hit.point) - Vector3.up; | |
| AddSupport(0.06f, top, bottom, s.rotation, 0.0f, 1.0f, i, vertices, normals, uvs, triangles); | |
| } | |
| } | |
| railMesh.vertices = vertices.ToArray(); | |
| railMesh.normals = normals.ToArray(); | |
| railMesh.uv = uvs.ToArray(); | |
| railMesh.triangles = triangles.ToArray(); | |
| railMeshFilter.sharedMesh = railMesh; | |
| } | |
| #endif | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment