204 lines
6.0 KiB
C#

using System;
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
//data structure describing a section of skidmarks
[Serializable]
public class markSection
{
public Vector3 pos;
public Vector3 normal;
public Vector3 posl;
public Vector3 posr;
public float intensity = 0.0f;
public int lastIndex = -1;
}
[Serializable]
public class Skidmarks : MonoBehaviour
{
//maximal number of skidmarks
private int maxMarks = 256;
//width of skid marks
public float markWidth = 0.225f;
//time interval new mesh segments are generated in
//the lower this value, the smoother the generated tracks
private float updateRate = 0.2f;
// /*UNUSED*/ private int indexShift = 0;
private int numMarks = 0;
private float updateTime = 0.0f;
private bool newTrackFlag = true;
private bool updateMeshFlag = true;
private MeshFilter meshFilter;
private Mesh mesh;
public markSection[] skidmarks;
// Use this for initialization
public void Start()
{
//create structures
skidmarks = new markSection[maxMarks];
for (int i = 0; i < maxMarks; i++)
{
skidmarks[i] = new markSection();
}
meshFilter = (MeshFilter)gameObject.GetComponent(typeof(MeshFilter));
mesh = meshFilter.mesh;
if (mesh == null)
{
mesh = new Mesh();
}
}
//called by the car script to add a skid mark at position pos with the supplied normal.
//transparency can be specified in the intensity parameter. Connects to the track segment
//indexed by lastIndex (or it won't display if lastIndex is -1). returns an index value
//which can be passed as lastIndex to the next AddSkidMark call
public int AddSkidMark(Vector3 pos, Vector3 normal, float intensity, int lastIndex)
{
intensity = Mathf.Clamp01(intensity);
//get index for new segment
int currIndex = numMarks;
//reuse lastIndex if we don't need to create a new one this frame
if (lastIndex != -1 && !newTrackFlag)
{
currIndex = lastIndex;
}
//setup skidmark structure
markSection curr = skidmarks[currIndex % maxMarks];
curr.pos = pos + normal * 0.05f - transform.position;
curr.normal = normal;
curr.intensity = intensity;
if (lastIndex == -1 || newTrackFlag)
{
curr.lastIndex = lastIndex;
}
//if we have a valid lastIndex, get positions for marks
if (curr.lastIndex != -1)
{
markSection last = skidmarks[curr.lastIndex % maxMarks];
Vector3 dir = curr.pos - last.pos;
Vector3 normalized = Vector3.Cross(dir, normal).normalized;
curr.posl = curr.pos + normalized * markWidth * 0.5f;
curr.posr = curr.pos - normalized * markWidth * 0.5f;
if (last.lastIndex == -1)
{
last.posl = curr.pos + normalized * markWidth * 0.5f;
last.posr = curr.pos - normalized * markWidth * 0.5f;
}
}
if (lastIndex == -1 || newTrackFlag)
{
numMarks++;
}
updateMeshFlag = true;
return currIndex;
}
//regenerate the skidmarks mesh
public void UpdateMesh()
{
//count visible segments
int segmentCount = 0;
for (int i = 0; i < numMarks && i < maxMarks; i++)
{
if (
skidmarks[i].lastIndex != -1 &&
skidmarks[i].lastIndex > numMarks - maxMarks)
{
segmentCount++;
}
}
//create skidmark mesh coordinates
Vector3[] vertices = new Vector3[segmentCount * 4];
Vector3[] normals = new Vector3[segmentCount * 4];
Color[] colors = new Color[segmentCount * 4];
Vector2[] uvs = new Vector2[segmentCount * 4];
int[] triangles = new int[segmentCount * 6];
segmentCount = 0;
for (int i = 0; i < numMarks && i < maxMarks; i++)
{
if (
skidmarks[i].lastIndex != -1 &&
skidmarks[i].lastIndex > numMarks - maxMarks)
{
markSection curr = skidmarks[i];
markSection last = skidmarks[curr.lastIndex % maxMarks];
vertices[segmentCount * 4 + 0] = last.posl;
vertices[segmentCount * 4 + 1] = last.posr;
vertices[segmentCount * 4 + 2] = curr.posl;
vertices[segmentCount * 4 + 3] = curr.posr;
normals[segmentCount * 4 + 0] = last.normal;
normals[segmentCount * 4 + 1] = last.normal;
normals[segmentCount * 4 + 2] = curr.normal;
normals[segmentCount * 4 + 3] = curr.normal;
colors[segmentCount * 4 + 0] = new Color(1f, 1f, 1f, last.intensity);
colors[segmentCount * 4 + 1] = new Color(1f, 1f, 1f, last.intensity);
colors[segmentCount * 4 + 2] = new Color(1f, 1f, 1f, curr.intensity);
colors[segmentCount * 4 + 3] = new Color(1f, 1f, 1f, curr.intensity);
uvs[segmentCount * 4 + 0] = new Vector2(0f, 0f);
uvs[segmentCount * 4 + 1] = new Vector2(1f, 0f);
uvs[segmentCount * 4 + 2] = new Vector2(0f, 0f);
uvs[segmentCount * 4 + 3] = new Vector2(1f, 0f);
triangles[segmentCount * 6 + 0] = segmentCount * 4 + 0;
triangles[segmentCount * 6 + 1] = segmentCount * 4 + 1;
triangles[segmentCount * 6 + 2] = segmentCount * 4 + 2;
triangles[segmentCount * 6 + 3] = segmentCount * 4 + 2;
triangles[segmentCount * 6 + 4] = segmentCount * 4 + 1;
triangles[segmentCount * 6 + 5] = segmentCount * 4 + 3;
segmentCount++;
}
}
//update mesh
mesh.Clear();
mesh.vertices = vertices;
mesh.normals = normals;
mesh.triangles = triangles;
mesh.colors = colors;
mesh.uv = uvs;
updateMeshFlag = false;
}
public void Update()
{
//update mesh if skidmarks have changed since last frame
if (updateMeshFlag)
{
UpdateMesh();
}
}
public void FixedUpdate()
{
//set flag for creating new segments this frame if an update is pending
newTrackFlag = false;
updateTime += Time.deltaTime;
if (updateTime > updateRate)
{
newTrackFlag = true;
updateTime -= updateRate;
}
}
}