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;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |