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

324 lines
13 KiB
C#

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
namespace Dreamteck.Splines
{
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
[AddComponentMenu("Dreamteck/Splines/Users/Spline Mesh")]
public partial class SplineMesh : MeshGenerator
{
//Mesh data
[SerializeField]
[HideInInspector, UnityEngine.Serialization.FormerlySerializedAs("channels")]
private List<Channel> _channels = new List<Channel>();
private bool _useLastResult = false;
private List<TS_Mesh> _combineMeshes = new List<TS_Mesh>();
protected override string meshName => "Custom Mesh";
private Matrix4x4 _vertexMatrix = new Matrix4x4();
private Matrix4x4 _normalMatrix = new Matrix4x4();
private SplineSample _lastResult = new SplineSample(), _modifiedResult = new SplineSample();
protected override void Awake()
{
base.Awake();
#if UNITY_EDITOR
for (int i = 0; i < _channels.Count; i++)
{
for (int j = 0; j < _channels[i].GetMeshCount(); j++)
{
_channels[i].GetMesh(j).Refresh();
}
}
#endif
}
protected override void Reset()
{
base.Reset();
AddChannel("Channel 1");
}
public void RemoveChannel(int index)
{
_channels.RemoveAt(index);
Rebuild();
}
public void SwapChannels(int a, int b)
{
if (a < 0 || a >= _channels.Count || b < 0 || b >= _channels.Count) return;
Channel temp = _channels[b];
_channels[b] = _channels[a];
_channels[a] = temp;
Rebuild();
}
public Channel AddChannel(Mesh inputMesh, string name)
{
Channel channel = new Channel(name, inputMesh, this);
_channels.Add(channel);
return channel;
}
public Channel AddChannel(string name)
{
Channel channel = new Channel(name, this);
_channels.Add(channel);
return channel;
}
public int GetChannelCount()
{
return _channels.Count;
}
public Channel GetChannel(int index)
{
return _channels[index];
}
protected override void BuildMesh()
{
base.BuildMesh();
Generate();
}
private void Generate()
{
int meshCount = 0;
for (int i = 0; i < _channels.Count; i++)
{
if (_channels[i].GetMeshCount() == 0) continue;
if (_channels[i].autoCount)
{
float avgBounds = 0f;
for (int j = 0; j < _channels[i].GetMeshCount(); j++)
{
avgBounds += _channels[i].GetMesh(j).bounds.size.z;
}
if (_channels[i].GetMeshCount() > 1)
{
avgBounds /= _channels[i].GetMeshCount();
}
if (avgBounds > 0f)
{
float length = CalculateLength(_channels[i].clipFrom, _channels[i].clipTo);
int newCount = Mathf.RoundToInt(length / avgBounds);
if (newCount < 1)
{
newCount = 1;
}
_channels[i].count = newCount;
}
}
meshCount += _channels[i].count;
}
if(meshCount == 0)
{
_tsMesh.Clear();
return;
}
if (_combineMeshes.Count < meshCount)
{
_combineMeshes.AddRange(new TS_Mesh[meshCount - _combineMeshes.Count]);
}
else if (_combineMeshes.Count > meshCount)
{
_combineMeshes.RemoveRange((_combineMeshes.Count - 1) - (_combineMeshes.Count - meshCount), _combineMeshes.Count - meshCount);
}
int combineMeshIndex = 0;
for (int i = 0; i < _channels.Count; i++)
{
if (_channels[i].GetMeshCount() == 0) continue;
_channels[i].ResetIteration();
_useLastResult = false;
double step = 1.0 / _channels[i].count;
double space = step * _channels[i].spacing * 0.5;
switch (_channels[i].type)
{
case Channel.Type.Extrude:
for (int j = 0; j < _channels[i].count; j++)
{
double from = DMath.Lerp(_channels[i].clipFrom, _channels[i].clipTo, j * step + space);
double to = DMath.Lerp(_channels[i].clipFrom, _channels[i].clipTo, j * step + step - space);
if (_combineMeshes[combineMeshIndex] == null)
{
_combineMeshes[combineMeshIndex] = new TS_Mesh();
}
Extrude(_channels[i], _combineMeshes[combineMeshIndex], from, to);
combineMeshIndex++;
}
if (space == 0f) _useLastResult = true;
break;
case Channel.Type.Place:
for (int j = 0; j < _channels[i].count; j++)
{
if (_combineMeshes[combineMeshIndex] == null)
{
_combineMeshes[combineMeshIndex] = new TS_Mesh();
}
Place(_channels[i], _combineMeshes[combineMeshIndex], DMath.Lerp(_channels[i].clipFrom, _channels[i].clipTo, (double)j / Mathf.Max(_channels[i].count - 1, 1)));
combineMeshIndex++;
}
break;
}
}
_tsMesh.Combine(_combineMeshes);
}
private void Place(Channel channel, TS_Mesh target, double percent)
{
Channel.MeshDefinition definition = channel.NextMesh();
if (target == null) target = new TS_Mesh();
definition.Write(target, channel.overrideMaterialID ? channel.targetMaterialID : -1);
Vector2 channelOffset = channel.NextRandomOffset();
Quaternion channelRotation = channel.NextRandomQuaternion();
var customValues = channel.GetCustomPlaceValues(percent);
Vector2 finalOffset = channelOffset + customValues.Item1 + new Vector2(offset.x, offset.y);
Quaternion finalRotation = channelRotation * Quaternion.AngleAxis(rotation, Vector3.forward) * customValues.Item2;
Vector3 finalScale = channel.NextPlaceScale();
Evaluate(percent, ref evalResult);
ModifySample(ref evalResult);
Vector3 originalNormal = evalResult.up;
Vector3 originalRight = evalResult.right;
Vector3 originalDirection = evalResult.forward;
if (channel.overrideNormal)
{
evalResult.forward = Vector3.Cross(evalResult.right, channel.customNormal);
evalResult.up = channel.customNormal;
}
if (!channel.scaleModifier.useClippedPercent)
{
UnclipPercent(ref evalResult.percent);
}
Vector3 scaleMod = channel.scaleModifier.GetScale(evalResult);
finalScale.x *= customValues.Item3.x * scaleMod.x;
finalScale.y *= customValues.Item3.y * scaleMod.y;
finalScale.z *= customValues.Item3.z * scaleMod.z;
if (!channel.scaleModifier.useClippedPercent)
{
ClipPercent(ref evalResult.percent);
}
float resultSize = GetBaseSize(evalResult);
_vertexMatrix.SetTRS(evalResult.position + originalRight * (finalOffset.x * resultSize) + originalNormal * (finalOffset.y * resultSize) + originalDirection * offset.z, //Position
evalResult.rotation * finalRotation, //Rotation
finalScale * resultSize ); //Scale
_normalMatrix = _vertexMatrix.inverse.transpose;
for (int i = 0; i < target.vertexCount; i++)
{
target.vertices[i] = _vertexMatrix.MultiplyPoint3x4(definition.vertices[i]);
target.normals[i] = _normalMatrix.MultiplyVector(definition.normals[i]);
}
for (int i = 0; i < Mathf.Min(target.colors.Length, definition.colors.Length); i++)
{
target.colors[i] = definition.colors[i] * evalResult.color * color;
}
}
private void Extrude(Channel channel, TS_Mesh target, double from, double to)
{
Channel.MeshDefinition definition = channel.NextMesh();
if (target == null) target = new TS_Mesh();
definition.Write(target, channel.overrideMaterialID ? channel.targetMaterialID : -1);
Vector2 uv = Vector2.zero;
Vector3 trsVector = Vector3.zero;
Vector3 channelOffset = channel.NextRandomOffset();
Vector3 channelScale = channel.NextRandomScale();
float channelRotation = channel.NextRandomAngle();
for (int i = 0; i < definition.vertexGroups.Count; i++)
{
if (_useLastResult && i == definition.vertexGroups.Count)
{
evalResult = _lastResult;
}
else
{
Evaluate(DMath.Lerp(from, to, definition.vertexGroups[i].percent), ref evalResult);
}
ModifySample(ref evalResult, ref _modifiedResult);
Vector3 originalNormal = _modifiedResult.up;
Vector3 originalRight = _modifiedResult.right;
Vector3 originalDirection = _modifiedResult.forward;
if (channel.overrideNormal)
{
_modifiedResult.forward = Vector3.Cross(_modifiedResult.right, channel.customNormal);
_modifiedResult.up = channel.customNormal;
}
var customValues = channel.GetCustomExtrudeValues(_modifiedResult.percent);
Vector3 finalOffset = offset + channelOffset + (Vector3)customValues.Item1;
float finalRotation = rotation + channelRotation + customValues.Item2;
Vector3 finalScale = channelScale;
if (!channel.scaleModifier.useClippedPercent)
{
UnclipPercent(ref _modifiedResult.percent);
}
Vector2 scaleMod = channel.scaleModifier.GetScale(_modifiedResult);
if (!channel.scaleModifier.useClippedPercent)
{
ClipPercent(ref _modifiedResult.percent);
}
finalScale.x *= customValues.Item3.x * scaleMod.x;
finalScale.y *= customValues.Item3.y * scaleMod.y;
finalScale.z = 1f;
float resultSize = _modifiedResult.size;
_vertexMatrix.SetTRS(_modifiedResult.position + originalRight * (finalOffset.x * resultSize) + originalNormal * (finalOffset.y * resultSize) + originalDirection * offset.z, //Position
_modifiedResult.rotation * Quaternion.AngleAxis(finalRotation, Vector3.forward), //Rotation
finalScale * resultSize); //Scale
_normalMatrix = _vertexMatrix.inverse.transpose;
if (i == 0)
{
_lastResult = evalResult;
}
for (int n = 0; n < definition.vertexGroups[i].ids.Length; n++)
{
int index = definition.vertexGroups[i].ids[n];
trsVector = definition.vertices[index];
trsVector.z = 0f;
target.vertices[index] = _vertexMatrix.MultiplyPoint3x4(trsVector);
trsVector = definition.normals[index];
target.normals[index] = _normalMatrix.MultiplyVector(trsVector);
target.colors[index] = target.colors[index] * _modifiedResult.color * color;
if (target.uv.Length > index)
{
uv = target.uv[index];
switch (channel.overrideUVs)
{
case Channel.UVOverride.ClampU: uv.x = (float)_modifiedResult.percent; break;
case Channel.UVOverride.ClampV: uv.y = (float)_modifiedResult.percent; break;
case Channel.UVOverride.UniformU: uv.x = CalculateLength(0.0, ClipPercent(_modifiedResult.percent)); break;
case Channel.UVOverride.UniformV: uv.y = CalculateLength(0.0, ClipPercent(_modifiedResult.percent)); break;
}
target.uv[index] = new Vector2(uv.x * uvScale.x * channel.uvScale.x, uv.y * uvScale.y * channel.uvScale.y);
target.uv[index] += uvOffset + channel.uvOffset;
}
}
}
}
}
}