rabidus-test/Assets/Dreamteck/Splines/Components/MeshGenerator.cs

618 lines
16 KiB
C#
Raw Normal View History

2023-07-24 16:38:13 +03:00
using UnityEngine;
using System.Collections;
using System.Threading;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Dreamteck.Splines
{
public class MeshGenerator : SplineUser
{
protected const int UNITY_16_VERTEX_LIMIT = 65535;
public float size
{
get { return _size; }
set
{
if (value != _size)
{
_size = value;
Rebuild();
} else _size = value;
}
}
public Color color
{
get { return _color; }
set
{
if (value != _color)
{
_color = value;
Rebuild();
}
}
}
public Vector3 offset
{
get { return _offset; }
set
{
if (value != _offset)
{
_offset = value;
Rebuild();
}
}
}
public NormalMethod normalMethod
{
get { return _normalMethod; }
set
{
if (value != _normalMethod)
{
_normalMethod = value;
Rebuild();
}
}
}
public bool useSplineSize
{
get { return _useSplineSize; }
set
{
if (value != _useSplineSize)
{
_useSplineSize = value;
Rebuild();
}
}
}
public bool useSplineColor
{
get { return _useSplineColor; }
set
{
if (value != _useSplineColor)
{
_useSplineColor = value;
Rebuild();
}
}
}
public bool calculateTangents
{
get { return _calculateTangents; }
set
{
if (value != _calculateTangents)
{
_calculateTangents = value;
Rebuild();
}
}
}
public float rotation
{
get { return _rotation; }
set
{
if (value != _rotation)
{
_rotation = value;
Rebuild();
}
}
}
public bool flipFaces
{
get { return _flipFaces; }
set
{
if (value != _flipFaces)
{
_flipFaces = value;
Rebuild();
}
}
}
public bool doubleSided
{
get { return _doubleSided; }
set
{
if (value != _doubleSided)
{
_doubleSided = value;
Rebuild();
}
}
}
public UVMode uvMode
{
get { return _uvMode; }
set
{
if (value != _uvMode)
{
_uvMode = value;
Rebuild();
}
}
}
public Vector2 uvScale
{
get { return _uvScale; }
set
{
if (value != _uvScale)
{
_uvScale = value;
Rebuild();
}
}
}
public Vector2 uvOffset
{
get { return _uvOffset; }
set
{
if (value != _uvOffset)
{
_uvOffset = value;
Rebuild();
}
}
}
public float uvRotation
{
get { return _uvRotation; }
set
{
if (value != _uvRotation)
{
_uvRotation = value;
Rebuild();
}
}
}
public UnityEngine.Rendering.IndexFormat meshIndexFormat
{
get { return _meshIndexFormat; }
set
{
if (value != _meshIndexFormat)
{
_meshIndexFormat = value;
RefreshMesh();
Rebuild();
}
}
}
public bool baked
{
get
{
return _baked;
}
}
public bool markDynamic
{
get { return _markDynamic; }
set
{
if (value != _markDynamic)
{
_markDynamic = value;
RefreshMesh();
Rebuild();
}
}
}
public enum UVMode { Clip, UniformClip, Clamp, UniformClamp }
public enum NormalMethod { Recalculate, SplineNormals }
[SerializeField]
[HideInInspector]
private bool _baked = false;
[SerializeField]
[HideInInspector]
private bool _markDynamic = true;
[SerializeField]
[HideInInspector]
private float _size = 1f;
[SerializeField]
[HideInInspector]
private Color _color = Color.white;
[SerializeField]
[HideInInspector]
private Vector3 _offset = Vector3.zero;
[SerializeField]
[HideInInspector]
private NormalMethod _normalMethod = NormalMethod.SplineNormals;
[SerializeField]
[HideInInspector]
private bool _calculateTangents = true;
[SerializeField]
[HideInInspector]
private bool _useSplineSize = true;
[SerializeField]
[HideInInspector]
private bool _useSplineColor = true;
[SerializeField]
[HideInInspector]
[Range(-360f, 360f)]
private float _rotation = 0f;
[SerializeField]
[HideInInspector]
private bool _flipFaces = false;
[SerializeField]
[HideInInspector]
private bool _doubleSided = false;
[SerializeField]
[HideInInspector]
private UVMode _uvMode = UVMode.Clip;
[SerializeField]
[HideInInspector]
private Vector2 _uvScale = Vector2.one;
[SerializeField]
[HideInInspector]
private Vector2 _uvOffset = Vector2.zero;
[SerializeField]
[HideInInspector]
private float _uvRotation = 0f;
[SerializeField]
[HideInInspector]
private UnityEngine.Rendering.IndexFormat _meshIndexFormat = UnityEngine.Rendering.IndexFormat.UInt16;
[SerializeField]
[HideInInspector]
private Mesh _bakedMesh;
[HideInInspector]
public float colliderUpdateRate = 0.2f;
protected bool _updateCollider = false;
protected float _lastUpdateTime = 0f;
private float _vDist = 0f;
protected static Vector2 __uvs = Vector2.zero;
protected virtual string meshName => "Mesh";
protected TS_Mesh _tsMesh { get; private set; }
protected Mesh _mesh;
protected MeshFilter filter;
protected MeshRenderer meshRenderer;
protected MeshCollider meshCollider;
#if UNITY_EDITOR
public void Bake(bool makeStatic, bool lightmapUV)
{
if (_mesh == null) return;
gameObject.isStatic = false;
UnityEditor.MeshUtility.Optimize(_mesh);
if (spline != null)
{
spline.Unsubscribe(this);
}
filter = GetComponent<MeshFilter>();
meshRenderer = GetComponent<MeshRenderer>();
filter.hideFlags = meshRenderer.hideFlags = HideFlags.None;
_bakedMesh = Instantiate(_mesh);
_bakedMesh.name = meshName + " - Baked";
if (lightmapUV)
{
Unwrapping.GenerateSecondaryUVSet(_bakedMesh);
}
filter.sharedMesh = _bakedMesh;
_mesh = null;
gameObject.isStatic = makeStatic;
_baked = true;
}
public void Unbake()
{
gameObject.isStatic = false;
_baked = false;
DestroyImmediate(_bakedMesh);
_bakedMesh = null;
CreateMesh();
spline.Subscribe(this);
Rebuild();
}
public override void EditorAwake()
{
GetComponents();
base.EditorAwake();
}
#endif
protected override void Awake()
{
GetComponents();
base.Awake();
}
protected override void Reset()
{
base.Reset();
GetComponents();
#if UNITY_EDITOR
bool materialFound = false;
for (int i = 0; i < meshRenderer.sharedMaterials.Length; i++)
{
if (meshRenderer.sharedMaterials[i] != null)
{
materialFound = true;
break;
}
}
if (!materialFound) meshRenderer.sharedMaterial = AssetDatabase.GetBuiltinExtraResource<Material>("Default-Diffuse.mat");
#endif
}
private void GetComponents()
{
filter = GetComponent<MeshFilter>();
meshRenderer = GetComponent<MeshRenderer>();
meshCollider = GetComponent<MeshCollider>();
}
public override void Rebuild()
{
if (_baked) return;
base.Rebuild();
}
public override void RebuildImmediate()
{
if (_baked) return;
base.RebuildImmediate();
}
protected override void OnEnable()
{
base.OnEnable();
}
protected override void OnDisable()
{
base.OnDisable();
}
protected override void OnDestroy()
{
base.OnDestroy();
MeshFilter filter = GetComponent<MeshFilter>();
MeshRenderer rend = GetComponent<MeshRenderer>();
if (filter != null) filter.hideFlags = HideFlags.None;
if (rend != null) rend.hideFlags = HideFlags.None;
}
public void UpdateCollider()
{
meshCollider = GetComponent<MeshCollider>();
if (meshCollider == null) meshCollider = gameObject.AddComponent<MeshCollider>();
meshCollider.sharedMesh = filter.sharedMesh;
}
protected override void LateRun()
{
if (_baked) return;
base.LateRun();
if (_updateCollider)
{
if (meshCollider != null)
{
if (Time.time - _lastUpdateTime >= colliderUpdateRate)
{
_lastUpdateTime = Time.time;
_updateCollider = false;
meshCollider.sharedMesh = filter.sharedMesh;
}
}
}
}
protected override void Build()
{
base.Build();
if (_tsMesh == null || _mesh == null)
{
CreateMesh();
}
if (sampleCount > 1)
{
BuildMesh();
} else
{
ClearMesh();
}
}
protected override void PostBuild()
{
base.PostBuild();
WriteMesh();
}
protected virtual void ClearMesh()
{
_tsMesh.Clear();
_mesh.Clear();
}
protected virtual void BuildMesh()
{
//Logic for mesh generation, automatically called in the Build method
}
protected virtual void WriteMesh()
{
MeshUtility.TransformMesh(_tsMesh, trs.worldToLocalMatrix);
if (_doubleSided)
{
MeshUtility.MakeDoublesidedHalf(_tsMesh);
}
else if (_flipFaces)
{
MeshUtility.FlipFaces(_tsMesh);
}
if (_calculateTangents)
{
MeshUtility.CalculateTangents(_tsMesh);
}
if (_meshIndexFormat == UnityEngine.Rendering.IndexFormat.UInt16 && _tsMesh.vertexCount > UNITY_16_VERTEX_LIMIT)
{
Debug.LogError("WARNING: The generated mesh for " + name + " exceeds the maximum vertex count for standard meshes in Unity (" + UNITY_16_VERTEX_LIMIT + "). To create bigger meshes, set the Index Format inside the Vertices foldout to 32.");
}
_tsMesh.indexFormat = _meshIndexFormat;
_tsMesh.WriteMesh(ref _mesh);
if (_markDynamic)
{
_mesh.MarkDynamic();
}
if (_normalMethod == 0)
{
_mesh.RecalculateNormals();
}
if (filter != null)
{
filter.sharedMesh = _mesh;
}
_updateCollider = true;
}
protected virtual void AllocateMesh(int vertexCount, int trisCount)
{
if(trisCount < 0)
{
trisCount = 0;
}
if(vertexCount < 0)
{
vertexCount = 0;
}
if (_doubleSided)
{
vertexCount *= 2;
trisCount *= 2;
}
if (_tsMesh.vertexCount != vertexCount)
{
_tsMesh.vertices = new Vector3[vertexCount];
_tsMesh.normals = new Vector3[vertexCount];
_tsMesh.tangents = new Vector4[vertexCount];
_tsMesh.colors = new Color[vertexCount];
_tsMesh.uv = new Vector2[vertexCount];
}
if (_tsMesh.triangles.Length != trisCount)
{
_tsMesh.triangles = new int[trisCount];
}
}
protected void ResetUVDistance()
{
_vDist = 0f;
if (uvMode == UVMode.UniformClip)
{
_vDist = spline.CalculateLength(0.0, GetSamplePercent(0));
}
}
protected void AddUVDistance(int sampleIndex)
{
if (sampleIndex == 0) return;
SplineSample current = new SplineSample();
SplineSample last = new SplineSample();
GetSampleRaw(sampleIndex, ref current);
GetSampleRaw(sampleIndex - 1, ref last);
_vDist += Vector3.Distance(current.position, last.position);
}
protected void CalculateUVs(double percent, float u)
{
__uvs.x = u * _uvScale.x - _uvOffset.x;
switch (uvMode)
{
case UVMode.Clip: __uvs.y = (float)percent * _uvScale.y - _uvOffset.y; break;
case UVMode.Clamp: __uvs.y = (float)DMath.InverseLerp(clipFrom, clipTo, percent) * _uvScale.y - _uvOffset.y; break;
case UVMode.UniformClamp: __uvs.y = _vDist * _uvScale.y / (float)span - _uvOffset.y; break;
default: __uvs.y = _vDist * _uvScale.y - _uvOffset.y; break;
}
}
protected float GetBaseSize(SplineSample sample)
{
return _useSplineSize? sample.size: 1f;
}
protected Color GetBaseColor(SplineSample sample)
{
return _useSplineColor ? sample.color : Color.white;
}
protected virtual void CreateMesh()
{
_tsMesh = new TS_Mesh();
_mesh = new Mesh();
_mesh.name = meshName;
_mesh.indexFormat = _meshIndexFormat;
_tsMesh.indexFormat = _meshIndexFormat;
if (_markDynamic)
{
_mesh.MarkDynamic();
}
}
private void RefreshMesh()
{
if (!Application.isPlaying)
{
DestroyImmediate(_mesh);
}
else
{
Destroy(_mesh);
}
_mesh = null;
_tsMesh.Clear();
_tsMesh = null;
CreateMesh();
}
}
}