Skip to content

Instantly share code, notes, and snippets.

@DearthDev
Created June 15, 2024 23:56
Show Gist options
  • Select an option

  • Save DearthDev/c21d9b87ad44eecbdef935f68fe7b6ad to your computer and use it in GitHub Desktop.

Select an option

Save DearthDev/c21d9b87ad44eecbdef935f68fe7b6ad to your computer and use it in GitHub Desktop.
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);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RailBanner : Rail
{
[SerializeField] private bool rideOn = false;
#if UNITY_EDITOR
protected override void Awake()
{
base.Awake();
snapPointsToGround = true;
AddRailMesh(false);
AddWallMesh();
}
protected override void PostPointsSet()
{
if (rideOn)
points[0] -= Vector3.up * 1.6f;
}
protected override void PostSegmentGeneration()
{
if (segments.Count <= 20 || !rideOn)
return;
int c = 1;
for (int i = segments.Count - 5; i < segments.Count; i++)
{
segments[i].position.y += 0.05f * c;
}
}
protected override void GenerateMeshes()
{
{
railMesh.Clear();
List<Vector3> vertices = new();
List<Vector3> normals = new();
List<Vector2> uvs = new();
List<int> triangles = new();
List<int> triangles2 = new();
int idx;
AddSquareTube(0.16f, 0.16f, 0.0f, 0.0f, 1.0f, vertices, normals, uvs, triangles);
// supports
int start = 15;
if (!rideOn)
start = 0;
for (int i = start; i < segments.Count; i += 5)
{
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);
}
}
// banners
int bannerCount = 0;
idx = vertices.Count;
for (int i = start; i < segments.Count; i += 5)
{
bannerCount++;
Segment s = segments[i];
vertices.Add(s.position - Vector3.up * 0.22f);
Vector3 castPos = transform.TransformPoint(s.position - Vector3.up * 0.22f);
if (Physics.Raycast(castPos, -Vector3.up, out RaycastHit hit, 1000.0f, ~ignoreLayer))
vertices.Add(transform.InverseTransformPoint(hit.point) + Vector3.up * 0.05f);
else
vertices.Add(s.rotation * new Vector3(0.0f, -0.24f, 0.1f) + s.position - Vector3.up * 0.8f);
normals.Add(s.rotation * Vector3.right);
normals.Add(s.rotation * Vector3.right);
uvs.Add(new Vector3(0.2f, i / 10.0f));
uvs.Add(new Vector3(0.3f, i / 10.0f));
}
for (int i = 0; i < bannerCount - 1; i++)
{
int first = idx + i * 2;
triangles2.Add(first + 0);
triangles2.Add(first + 2);
triangles2.Add(first + 1);
triangles2.Add(first + 1);
triangles2.Add(first + 2);
triangles2.Add(first + 3);
}
railMesh.vertices = vertices.ToArray();
railMesh.normals = normals.ToArray();
railMesh.uv = uvs.ToArray();
railMesh.subMeshCount = 2;
railMesh.SetTriangles(triangles.ToArray(), 0);
railMesh.SetTriangles(triangles2.ToArray(), 1);
railMeshFilter.mesh = railMesh;
}
{
invisWallMesh.Clear();
List<Vector3> vertices = new();
List<int> triangles = new();
for (int i = 0; i < segments.Count; i++)
{
Segment s = segments[i];
vertices.Add(s.rotation * new Vector3(-0.08f, -0.0f, 0.0f) + s.position + Vector3.down * 0.1f);
vertices.Add(s.rotation * new Vector3(0.08f, -0.0f, 0.0f) + s.position + Vector3.down * 0.1f);
vertices.Add(s.rotation * new Vector3(-0.08f, -0.0f, 0.0f) + s.position + Vector3.down * 3.0f);
vertices.Add(s.rotation * new Vector3(0.08f, -0.0f, 0.0f) + s.position + Vector3.down * 3.0f);
}
int c = 0;
for (int i = 0; i < segments.Count - 1; i++)
{
// top
triangles.Add(c + 0);
triangles.Add(c + 4);
triangles.Add(c + 1);
triangles.Add(c + 1);
triangles.Add(c + 4);
triangles.Add(c + 5);
// Right
triangles.Add(c + 1);
triangles.Add(c + 5);
triangles.Add(c + 7);
triangles.Add(c + 3);
triangles.Add(c + 1);
triangles.Add(c + 7);
// Left
triangles.Add(c + 2);
triangles.Add(c + 6);
triangles.Add(c + 0);
triangles.Add(c + 6);
triangles.Add(c + 4);
triangles.Add(c + 0);
c += 4;
}
invisWallMesh.vertices = vertices.ToArray();
invisWallMesh.triangles = triangles.ToArray();
invisWallMesh.RecalculateNormals();
invisWallCollider.sharedMesh = invisWallMesh;
}
}
#endif
}
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
}
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