204 lines
6.0 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|