Skip to content

Instantly share code, notes, and snippets.

@sasame
Created January 8, 2024 15:51
Show Gist options
  • Select an option

  • Save sasame/7af41c1ae0d543a7cb5465df2bda7c5c to your computer and use it in GitHub Desktop.

Select an option

Save sasame/7af41c1ae0d543a7cb5465df2bda7c5c to your computer and use it in GitHub Desktop.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Mathematics;
using UnityEngine.Splines;
public class SplineRoad : MonoBehaviour
{
[SerializeField] SplineContainer _spline;
[SerializeField] Material _mtl;
[SerializeField] Material _mtlDuraBarrier;
[SerializeField] float _width = 5f;
[SerializeField] float _height = 5f;
[SerializeField] float _divideLength = 1f;
[SerializeField] float _barrierHeight = 1f;
[SerializeField] float _barrierWidth = 0.2f;
Mesh createMesh()
{
List<Vector3> points = new List<Vector3>();
List<Vector2> uvs = new List<Vector2>();
List<Vector3> normals = new List<Vector3>();
List<int> triangles = new List<int>();
int pointOfs = 0;
foreach(var s in _spline.Splines)
{
var length = s.CalculateLength(float4x4.identity);
int pointCount = 0;
for (float len = 0f; len < length; len += 1f)
{
var t = len / length;
var pos = (Vector3)s.EvaluatePosition(t);
var tangent = s.EvaluateTangent(t);
var up = s.EvaluateUpVector(t);
var right = Vector3.Cross(tangent, up).normalized;
points.Add(pos - right * _width * 0.5f); // left
points.Add(pos + right * _width * 0.5f); // right
uvs.Add(new Vector2(0f,len / _height)); // left
uvs.Add(new Vector2(1f, len / _height)); // right
normals.Add(up); // left
normals.Add(up); // right
++pointCount;
}
for(int i=0;i< pointCount-1;++i)
{
triangles.Add((i+ pointOfs) * 2 + 0); // 0
triangles.Add((i+ pointOfs) * 2 + 1); // 1
triangles.Add((i+ pointOfs) * 2 + 2); // 2
triangles.Add((i+ pointOfs) * 2 + 1); // 1
triangles.Add((i+ pointOfs) * 2 + 3); // 3
triangles.Add((i+ pointOfs) * 2 + 2); // 2
}
pointOfs += pointCount * 2;
}
var mesh = new Mesh();
mesh.SetVertices(points);
mesh.SetUVs(0, uvs);
mesh.SetNormals(normals);
mesh.SetTriangles(triangles,0);
mesh.RecalculateTangents();
return mesh;
}
Mesh createBarrierMesh()
{
List<Vector3> points = new List<Vector3>();
List<Vector2> uvs = new List<Vector2>();
List<Vector3> normals = new List<Vector3>();
List<int> triangles = new List<int>();
int pointOfs = 0;
foreach (var s in _spline.Splines)
{
var length = s.CalculateLength(float4x4.identity);
int pointCount = 0;
for (float len = 0f; len < length; len += 1f)
{
var t = len / length;
var pos = (Vector3)s.EvaluatePosition(t);
var tangent = s.EvaluateTangent(t);
var up = (Vector3)s.EvaluateUpVector(t);
var right = Vector3.Cross(tangent, up).normalized;
points.Add(pos - right * (_width * 0.5f + _barrierWidth)); // left 0
points.Add(pos - right * (_width * 0.5f + _barrierWidth) + up * _barrierHeight); // left 1
points.Add(pos - right * _width * 0.5f + up * _barrierHeight); // left 2
points.Add(pos - right * _width * 0.5f); // left 3
points.Add(pos + right * _width * 0.5f); // right0
points.Add(pos + right * _width * 0.5f + up * _barrierHeight); // right1
points.Add(pos + right * (_width * 0.5f + _barrierWidth) + up * _barrierHeight); // right2
points.Add(pos + right * (_width * 0.5f + _barrierWidth)); // right3
uvs.Add(new Vector2(0f, len / _height)); // left0
uvs.Add(new Vector2(1f, len / _height)); // left1
uvs.Add(new Vector2(1f, len / _height)); // left2
uvs.Add(new Vector2(0f, len / _height)); // left3
uvs.Add(new Vector2(0f, len / _height)); // right0
uvs.Add(new Vector2(1f, len / _height)); // right1
uvs.Add(new Vector2(1f, len / _height)); // right2
uvs.Add(new Vector2(0f, len / _height)); // right3
normals.Add(-right); // left0
normals.Add(-right); // left1
normals.Add(right); // left2
normals.Add(right); // left3
normals.Add(-right); // right0
normals.Add(-right); // right1
normals.Add(right); // right2
normals.Add(right); // right3
++pointCount;
}
const int linePoint = 8;
const int lineHalf = 4;
for (int i = 0; i < pointCount - 1; ++i)
{
for (int j = 0; j < 3; ++j)
{
triangles.Add((i + pointOfs) * linePoint + 0 + j); // 0
triangles.Add((i + pointOfs) * linePoint + 1 + j); // 1
triangles.Add((i + pointOfs + 1) * linePoint + 0 + j); // 2
triangles.Add((i + pointOfs) * linePoint + 1 + j); // 1
triangles.Add((i + pointOfs + 1) * linePoint + 1 + j); // 3
triangles.Add((i + pointOfs + 1) * linePoint + 0 + j); // 2
}
for (int j = 0; j < 3; ++j)
{
triangles.Add((i + pointOfs) * linePoint + 0+ lineHalf + j); // 0
triangles.Add((i + pointOfs) * linePoint + 1 + lineHalf + j); // 1
triangles.Add((i + pointOfs + 1) * linePoint + 0 + lineHalf + j); // 2
triangles.Add((i + pointOfs) * linePoint + 1 + lineHalf + j); // 1
triangles.Add((i + pointOfs + 1) * linePoint + 1 + lineHalf + j); // 3
triangles.Add((i + pointOfs + 1) * linePoint + 0 + lineHalf + j); // 2
}
}
pointOfs += pointCount * 2;
}
var mesh = new Mesh();
mesh.SetVertices(points);
mesh.SetUVs(0, uvs);
mesh.SetNormals(normals);
mesh.SetTriangles(triangles, 0);
mesh.RecalculateTangents();
return mesh;
}
private void OnDestroy()
{
var mf = gameObject.GetComponent<MeshFilter>();
if (mf)
{
DestroyImmediate(mf.sharedMesh);
}
}
// Start is called before the first frame update
void Start()
{
{
var o = new GameObject();
o.name = "Road";
o.transform.SetParent(transform, false);
var mesh = createMesh();
var mf = o.AddComponent<MeshFilter>();
mf.sharedMesh = mesh;
var mr = o.AddComponent<MeshRenderer>();
mr.sharedMaterial = _mtl;
var mc = o.AddComponent<MeshCollider>();
mc.sharedMesh = mesh;
}
{
var o = new GameObject();
o.name = "Barrier";
o.transform.SetParent(transform, false);
var mesh = createBarrierMesh();
var mf = o.AddComponent<MeshFilter>();
mf.sharedMesh = mesh;
var mr = o.AddComponent<MeshRenderer>();
mr.sharedMaterial = _mtlDuraBarrier;
var mc = o.AddComponent<MeshCollider>();
mc.sharedMesh = mesh;
}
}
// Update is called once per frame
void Update()
{
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment