using UnityEngine; using System.Collections.Generic; namespace Dreamteck.Splines { public partial class SplineMesh : MeshGenerator { [System.Serializable] public class Channel { public delegate float FloatHandler(double percent); public delegate Vector2 Vector2Handler(double percent); public delegate Vector3 Vector3Handler(double percent); public delegate Quaternion QuaternionHandler(double percent); public string name = "Channel"; public enum Type { Extrude, Place } public enum UVOverride { None, ClampU, ClampV, UniformU, UniformV } private System.Random iterationRandom; [SerializeField] [HideInInspector] private int _iterationSeed = 0; [SerializeField] [HideInInspector] private int _offsetSeed = 0; private System.Random _offsetRandom; private Vector2Handler _offsetHandler = null; [SerializeField] [HideInInspector] private int _rotationSeed = 0; private System.Random _rotationRandom; private QuaternionHandler _placeRotationHandler = null; private FloatHandler _extrudeRotationHandler = null; [SerializeField] [HideInInspector] private int _scaleSeed = 0; private System.Random _scaleRandom; private Vector3Handler _scaleHandler = null; [SerializeField] internal SplineMesh owner = null; [SerializeField] [HideInInspector] private List meshes = new List(); [SerializeField] [HideInInspector] private double _clipFrom = 0.0; [SerializeField] [HideInInspector] private double _clipTo = 1.0; [SerializeField] [HideInInspector] private bool _randomOrder = false; [SerializeField] [HideInInspector] private UVOverride _overrideUVs = UVOverride.None; [SerializeField] [HideInInspector] private Vector2 _uvScale = Vector2.one; [SerializeField] [HideInInspector] private Vector2 _uvOffset = Vector2.zero; [SerializeField] [HideInInspector] private bool _overrideNormal = false; [SerializeField] [HideInInspector] private Vector3 _customNormal = Vector3.up; [SerializeField] [HideInInspector] private Type _type = Type.Extrude; [SerializeField] [HideInInspector] private int _count = 1; [SerializeField] [HideInInspector] private bool _autoCount = false; [SerializeField] [HideInInspector] private double _spacing = 0.0; [SerializeField] [HideInInspector] private bool _randomRotation = false; [SerializeField] [HideInInspector] private Vector3 _minRotation = Vector3.zero; [SerializeField] [HideInInspector] private Vector3 _maxRotation = Vector3.zero; [SerializeField] [HideInInspector] private bool _randomOffset = false; [SerializeField] [HideInInspector] private Vector2 _minOffset = Vector2.one; [SerializeField] [HideInInspector] private Vector2 _maxOffset = Vector2.one; [SerializeField] [HideInInspector] private bool _randomScale = false; [SerializeField] [HideInInspector] private bool _uniformRandomScale = false; [SerializeField] [HideInInspector] private Vector3 _minScale = Vector3.one; [SerializeField] [HideInInspector] private Vector3 _maxScale = Vector3.one; private int iterator = 0; [SerializeField] [HideInInspector] private bool _overrideMaterialID = false; [SerializeField] [HideInInspector] private int _targetMaterialID = 0; [SerializeField] [HideInInspector] protected MeshScaleModifier _scaleModifier = new MeshScaleModifier(); public double clipFrom { get { return _clipFrom; } set { if (value != _clipFrom) { _clipFrom = value; Rebuild(); } } } public double clipTo { get { return _clipTo; } set { if (value != _clipTo) { _clipTo = value; Rebuild(); } } } public bool randomOffset { get { return _randomOffset; } set { if (value != _randomOffset) { _randomOffset = value; Rebuild(); } } } public Vector2Handler offsetHandler { get { return _offsetHandler; } set { if (value != _offsetHandler) { _offsetHandler = value; Rebuild(); } } } public bool overrideMaterialID { get { return _overrideMaterialID; } set { if (value != _overrideMaterialID) { _overrideMaterialID = value; Rebuild(); } } } public int targetMaterialID { get { return _targetMaterialID; } set { if (value != _targetMaterialID) { _targetMaterialID = value; Rebuild(); } } } public bool randomRotation { get { return _randomRotation; } set { if (value != _randomRotation) { _randomRotation = value; Rebuild(); } } } public QuaternionHandler placeRotationHandler { get { return _placeRotationHandler; } set { if (value != _placeRotationHandler) { _placeRotationHandler = value; Rebuild(); } } } public FloatHandler extrudeRotationHandler { get { return _extrudeRotationHandler; } set { if (value != _extrudeRotationHandler) { _extrudeRotationHandler = value; Rebuild(); } } } public bool randomScale { get { return _randomScale; } set { if (value != _randomScale) { _randomScale = value; Rebuild(); } } } public Vector3Handler scaleHandler { get { return _scaleHandler; } set { if (value != _scaleHandler) { _scaleHandler = value; Rebuild(); } } } public bool uniformRandomScale { get { return _uniformRandomScale; } set { if (value != _uniformRandomScale) { _uniformRandomScale = value; Rebuild(); } } } public int offsetSeed { get { return _offsetSeed; } set { if (value != _offsetSeed) { _offsetSeed = value; Rebuild(); } } } public int rotationSeed { get { return _rotationSeed; } set { if (value != _rotationSeed) { _rotationSeed = value; Rebuild(); } } } public int scaleSeed { get { return _scaleSeed; } set { if (value != _scaleSeed) { _scaleSeed = value; Rebuild(); } } } public double spacing { get { return _spacing; } set { if (value != _spacing) { _spacing = value; Rebuild(); } } } public Vector2 minOffset { get { return _minOffset; } set { if (value != _minOffset) { _minOffset = value; Rebuild(); } } } public Vector2 maxOffset { get { return _maxOffset; } set { if (value != _maxOffset) { _maxOffset = value; Rebuild(); } } } public Vector3 minRotation { get { return _minRotation; } set { if (value != _minRotation) { _minRotation = value; Rebuild(); } } } public Vector3 maxRotation { get { return _maxRotation; } set { if (value != _maxRotation) { _maxRotation = value; Rebuild(); } } } public Vector3 minScale { get { return _minScale; } set { if (value != _minScale) { _minScale = value; Rebuild(); } } } public Vector3 maxScale { get { return _maxScale; } set { if (value != _maxScale) { _maxScale = value; Rebuild(); } } } public Type type { get { return _type; } set { if (value != _type) { _type = value; Rebuild(); } } } public bool randomOrder { get { return _randomOrder; } set { if (value != _randomOrder) { _randomOrder = value; Rebuild(); } } } public int randomSeed { get { return _iterationSeed; } set { if (value != _iterationSeed) { _iterationSeed = value; if (_randomOrder) Rebuild(); } } } public int count { get { return _count; } set { if (value != _count) { _count = value; if (_count < 1) _count = 1; Rebuild(); } } } public bool autoCount { get { return _autoCount; } set { if (value != _autoCount) { _autoCount = value; Rebuild(); } } } public UVOverride overrideUVs { get { return _overrideUVs; } set { if (value != _overrideUVs) { _overrideUVs = value; Rebuild(); } } } public Vector2 uvOffset { get { return _uvOffset; } set { if (value != _uvOffset) { _uvOffset = value; Rebuild(); } } } public Vector2 uvScale { get { return _uvScale; } set { if (value != _uvScale) { _uvScale = value; Rebuild(); } } } public bool overrideNormal { get { return _overrideNormal; } set { if (value != _overrideNormal) { _overrideNormal = value; Rebuild(); } } } public Vector3 customNormal { get { return _customNormal; } set { if (value != _customNormal) { _customNormal = value; Rebuild(); } } } public MeshScaleModifier scaleModifier { get { return _scaleModifier; } } public Channel(string n, SplineMesh parent) { name = n; owner = parent; Init(); } public Channel(string n, Mesh inputMesh, SplineMesh parent) { name = n; owner = parent; meshes.Add(new MeshDefinition(inputMesh)); Init(); Rebuild(); } void Init() { _minScale = _maxScale = Vector3.one; _minOffset = _maxOffset = Vector3.zero; _minRotation = _maxRotation = Vector3.zero; } public void CopyTo(Channel target) { target.meshes.Clear(); for (int i = 0; i < meshes.Count; i++) target.meshes.Add(meshes[i].Copy()); target._clipFrom = _clipFrom; target._clipTo = _clipTo; target._customNormal = _customNormal; target._iterationSeed = _iterationSeed; target._minOffset = _minOffset; target._minRotation = _minRotation; target._minScale = _minScale; target._maxOffset = _maxOffset; target._maxRotation = _maxRotation; target._maxScale = _maxScale; target._randomOffset = _randomOffset; target._randomRotation = _randomRotation; target._randomScale = _randomScale; target._offsetSeed = _offsetSeed; target._offsetHandler = _offsetHandler; target._rotationSeed = _rotationSeed; target._placeRotationHandler = _placeRotationHandler; target._extrudeRotationHandler = _extrudeRotationHandler; target._scaleSeed = _scaleSeed; target._scaleHandler = _scaleHandler; target._iterationSeed = _iterationSeed; target._count = _count; target._spacing = _spacing; target._overrideUVs = _overrideUVs; target._type = _type; target._overrideMaterialID = _overrideMaterialID; target._targetMaterialID = _targetMaterialID; target._overrideNormal = _overrideNormal; } public int GetMeshCount() { return meshes.Count; } public void SwapMeshes(int a, int b) { if (a < 0 || a >= meshes.Count || b < 0 || b >= meshes.Count) return; MeshDefinition temp = meshes[b]; meshes[b] = meshes[a]; meshes[a] = temp; Rebuild(); } public void DuplicateMesh(int index) { if (index < 0 || index >= meshes.Count) return; meshes.Add(meshes[index].Copy()); Rebuild(); } public MeshDefinition GetMesh(int index) { return meshes[index]; } public void AddMesh(Mesh input) { meshes.Add(new MeshDefinition(input)); Rebuild(); } public void AddMesh(MeshDefinition meshDefinition) { if (!meshes.Contains(meshDefinition)) { meshes.Add(meshDefinition); Rebuild(); } } public void RemoveMesh(int index) { meshes.RemoveAt(index); Rebuild(); } public void ResetIteration() { if (_randomOrder) iterationRandom = new System.Random(_iterationSeed); if (_randomOffset) _offsetRandom = new System.Random(_offsetSeed); if (_randomRotation) _rotationRandom = new System.Random(_rotationSeed); if (_randomScale) _scaleRandom = new System.Random(_scaleSeed); iterator = 0; } public (Vector2, Quaternion, Vector3) GetCustomPlaceValues(double percent) { (Vector2, Quaternion, Vector3) values = (Vector2.zero, Quaternion.identity, Vector3.one); if (_offsetHandler != null) { values.Item1 = _offsetHandler(percent); } if (_placeRotationHandler != null) { values.Item2 = _placeRotationHandler(percent); } if (_scaleHandler != null) { values.Item3 = _scaleHandler(percent); } return values; } public (Vector2, float, Vector3) GetCustomExtrudeValues(double percent) { (Vector2, float, Vector3) values = (Vector2.zero, 0f, Vector3.one); if (_offsetHandler != null) { values.Item1 = _offsetHandler(percent); } if (_extrudeRotationHandler != null) { values.Item2 = _extrudeRotationHandler(percent); } if (_scaleHandler != null) { values.Item3 = _scaleHandler(percent); } return values; } public Vector2 NextRandomOffset() { if (_randomOffset) return new Vector2(Mathf.Lerp(_minOffset.x, _maxOffset.x, (float)_offsetRandom.NextDouble()), Mathf.Lerp(_minOffset.y, _maxOffset.y, (float)_offsetRandom.NextDouble())); return _minOffset; } public Quaternion NextRandomQuaternion() { if (_randomRotation) return Quaternion.Euler(new Vector3(Mathf.Lerp(_minRotation.x, _maxRotation.x, (float)_rotationRandom.NextDouble()), Mathf.Lerp(_minRotation.y, _maxRotation.y, (float)_rotationRandom.NextDouble()), Mathf.Lerp(_minRotation.z, _maxRotation.z, (float)_rotationRandom.NextDouble()))); return Quaternion.Euler(_minRotation); } public float NextRandomAngle() { if (_randomRotation) return Mathf.Lerp(_minRotation.z, _maxRotation.z, (float)_rotationRandom.NextDouble()); return _minRotation.z; } public Vector3 NextRandomScale() { if (_randomScale) { if (_uniformRandomScale) return Vector3.Lerp(new Vector3(_minScale.x, _minScale.y, 1f), new Vector3(_maxScale.x, _maxScale.y, 1f), (float)_scaleRandom.NextDouble()); return new Vector3(Mathf.Lerp(_minScale.x, _maxScale.x, (float)_scaleRandom.NextDouble()), Mathf.Lerp(_minScale.y, _maxScale.y, (float)_scaleRandom.NextDouble()), 1f); } return new Vector3(_minScale.x, _minScale.y, 1f); } public Vector3 NextPlaceScale() { if (_randomScale) { if (_uniformRandomScale) return Vector3.Lerp(_minScale, _maxScale, (float)_scaleRandom.NextDouble()); return new Vector3(Mathf.Lerp(_minScale.x, _maxScale.x, (float)_scaleRandom.NextDouble()), Mathf.Lerp(_minScale.y, _maxScale.y, (float)_scaleRandom.NextDouble()), Mathf.Lerp(_minScale.z, _maxScale.z, (float)_scaleRandom.NextDouble())); } return _minScale; } public MeshDefinition NextMesh() { if (_randomOrder) return meshes[iterationRandom.Next(meshes.Count)]; else { if (iterator >= meshes.Count) iterator = 0; return meshes[iterator++]; } } internal void Rebuild() { if (owner != null) owner.Rebuild(); } void Refresh() { for (int i = 0; i < meshes.Count; i++) meshes[i].Refresh(); Rebuild(); } [System.Serializable] public struct BoundsSpacing { public float front; public float back; } [System.Serializable] public class MeshDefinition { public enum MirrorMethod { None, X, Y, Z } [SerializeField] [HideInInspector] public Vector3[] vertices = new Vector3[0]; [SerializeField] [HideInInspector] public Vector3[] normals = new Vector3[0]; [SerializeField] [HideInInspector] public Vector4[] tangents = new Vector4[0]; [SerializeField] [HideInInspector] public Color[] colors = new Color[0]; [SerializeField] [HideInInspector] public Vector2[] uv = new Vector2[0]; [SerializeField] [HideInInspector] public Vector2[] uv2 = new Vector2[0]; [SerializeField] [HideInInspector] public Vector2[] uv3 = new Vector2[0]; [SerializeField] [HideInInspector] public Vector2[] uv4 = new Vector2[0]; [SerializeField] [HideInInspector] public int[] triangles = new int[0]; [SerializeField] [HideInInspector] public List subMeshes = new List(); [SerializeField] [HideInInspector] public TS_Bounds bounds = new TS_Bounds(Vector3.zero, Vector3.zero); [SerializeField] [HideInInspector] public List vertexGroups = new List(); [SerializeField] [HideInInspector] private Mesh _mesh = null; [SerializeField] [HideInInspector] private Vector3 _rotation = Vector3.zero; [SerializeField] [HideInInspector] private Vector3 _offset = Vector3.zero; [SerializeField] [HideInInspector] private Vector3 _scale = Vector3.one; [SerializeField] [HideInInspector] private Vector2 _uvScale = Vector2.one; [SerializeField] [HideInInspector] private Vector2 _uvOffset = Vector2.zero; [SerializeField] [HideInInspector] private float _uvRotation = 0f; [SerializeField] [HideInInspector] private MirrorMethod _mirror = MirrorMethod.None; [SerializeField] [HideInInspector] public BoundsSpacing _spacing = new BoundsSpacing(); [SerializeField] [HideInInspector] private float _vertexGroupingMargin = 0f; [SerializeField] [HideInInspector] private bool _removeInnerFaces = false; [SerializeField] [HideInInspector] private bool _flipFaces = false; [SerializeField] [HideInInspector] private bool _doubleSided = false; public Mesh mesh { get { return _mesh; } set { if (_mesh != value) { _mesh = value; Refresh(); } } } public Vector3 rotation { get { return _rotation; } set { if (rotation != value) { _rotation = value; Refresh(); } } } public Vector3 offset { get { return _offset; } set { if (_offset != value) { _offset = value; Refresh(); } } } public Vector3 scale { get { return _scale; } set { if (_scale != value) { _scale = value; Refresh(); } } } public BoundsSpacing spacing { get { return _spacing; } set { if (_spacing.back != value.back || _spacing.front != value.front) { _spacing = value; Refresh(); } } } public Vector2 uvScale { get { return _uvScale; } set { if (_uvScale != value) { _uvScale = value; Refresh(); } } } public Vector2 uvOffset { get { return _uvOffset; } set { if (_uvOffset != value) { _uvOffset = value; Refresh(); } } } public float uvRotation { get { return _uvRotation; } set { if (_uvRotation != value) { _uvRotation = value; Refresh(); } } } public float vertexGroupingMargin { get { return _vertexGroupingMargin; } set { if (_vertexGroupingMargin != value) { _vertexGroupingMargin = value; Refresh(); } } } public MirrorMethod mirror { get { return _mirror; } set { if (_mirror != value) { _mirror = value; Refresh(); } } } public bool removeInnerFaces { get { return _removeInnerFaces; } set { if (_removeInnerFaces != value) { _removeInnerFaces = value; Refresh(); } } } public bool flipFaces { get { return _flipFaces; } set { if (_flipFaces != value) { _flipFaces = value; Refresh(); } } } public bool doubleSided { get { return _doubleSided; } set { if (_doubleSided != value) { _doubleSided = value; Refresh(); } } } internal MeshDefinition Copy() { MeshDefinition target = new MeshDefinition(_mesh); target.vertices = new Vector3[vertices.Length]; target.normals = new Vector3[normals.Length]; target.colors = new Color[colors.Length]; target.tangents = new Vector4[tangents.Length]; target.uv = new Vector2[uv.Length]; target.uv2 = new Vector2[uv2.Length]; target.uv3 = new Vector2[uv3.Length]; target.uv4 = new Vector2[uv4.Length]; target.triangles = new int[triangles.Length]; vertices.CopyTo(target.vertices, 0); normals.CopyTo(target.normals, 0); colors.CopyTo(target.colors, 0); tangents.CopyTo(target.tangents, 0); uv.CopyTo(target.uv, 0); uv2.CopyTo(target.uv2, 0); uv3.CopyTo(target.uv3, 0); uv4.CopyTo(target.uv4, 0); triangles.CopyTo(target.triangles, 0); target.bounds = new TS_Bounds(bounds.min, bounds.max); target.subMeshes = new List(); for (int i = 0; i < subMeshes.Count; i++) { target.subMeshes.Add(new Submesh(new int[subMeshes[i].triangles.Length])); subMeshes[i].triangles.CopyTo(target.subMeshes[target.subMeshes.Count - 1].triangles, 0); } target._mirror = _mirror; target._offset = _offset; target._rotation = _rotation; target._scale = _scale; target._uvOffset = _uvOffset; target._uvScale = _uvScale; target._uvRotation = _uvRotation; target._flipFaces = _flipFaces; target._doubleSided = _doubleSided; return target; } public MeshDefinition(Mesh input) { _mesh = input; Refresh(); } public void Refresh() { if (_mesh == null) { vertices = new Vector3[0]; normals = new Vector3[0]; colors = new Color[0]; uv = new Vector2[0]; uv2 = new Vector2[0]; uv3 = new Vector2[0]; uv4 = new Vector2[0]; tangents = new Vector4[0]; triangles = new int[0]; subMeshes = new List(); vertexGroups = new List(); return; } if (vertices.Length != _mesh.vertexCount) vertices = new Vector3[_mesh.vertexCount]; if (normals.Length != _mesh.normals.Length) normals = new Vector3[_mesh.normals.Length]; if (colors.Length != _mesh.colors.Length) colors = new Color[_mesh.colors.Length]; if (uv.Length != _mesh.uv.Length) uv = new Vector2[_mesh.uv.Length]; if (uv2.Length != _mesh.uv2.Length) uv2 = new Vector2[_mesh.uv2.Length]; if (uv3.Length != _mesh.uv3.Length) uv3 = new Vector2[_mesh.uv3.Length]; if (uv4.Length != _mesh.uv4.Length) uv4 = new Vector2[_mesh.uv4.Length]; if (tangents.Length != _mesh.tangents.Length) tangents = new Vector4[_mesh.tangents.Length]; if (triangles.Length != _mesh.triangles.Length) triangles = new int[_mesh.triangles.Length]; vertices = _mesh.vertices; normals = _mesh.normals; colors = _mesh.colors; uv = _mesh.uv; uv2 = _mesh.uv2; uv3 = _mesh.uv3; uv4 = _mesh.uv4; tangents = _mesh.tangents; triangles = _mesh.triangles; colors = _mesh.colors; while (subMeshes.Count > _mesh.subMeshCount) subMeshes.RemoveAt(0); while (subMeshes.Count < _mesh.subMeshCount) subMeshes.Add(new Submesh(new int[0])); for (int i = 0; i < subMeshes.Count; i++) subMeshes[i].triangles = _mesh.GetTriangles(i); if (colors.Length != vertices.Length) { colors = new Color[vertices.Length]; for (int i = 0; i < colors.Length; i++) colors[i] = Color.white; } Mirror(); if (_doubleSided) DoubleSided(); else if (_flipFaces) FlipFaces(); TransformVertices(); CalculateBounds(); if (_removeInnerFaces) RemoveInnerFaces(); GroupVertices(); } void RemoveInnerFaces() { float min = float.MaxValue, max = 0f; for (int i = 0; i < vertices.Length; i++) { if (vertices[i].z < min) min = vertices[i].z; if (vertices[i].z > max) max = vertices[i].z; } for (int i = 0; i < subMeshes.Count; i++) { List newTris = new List(); for (int j = 0; j < subMeshes[i].triangles.Length; j += 3) { bool innerMax = true, innerMin = true; for (int k = j; k < j + 3; k++) { int index = subMeshes[i].triangles[k]; if (!Mathf.Approximately(vertices[index].z, max)) innerMax = false; if (!Mathf.Approximately(vertices[index].z, min)) innerMin = false; } if (!innerMax && !innerMin) { newTris.Add(subMeshes[i].triangles[j]); newTris.Add(subMeshes[i].triangles[j + 1]); newTris.Add(subMeshes[i].triangles[j + 2]); } } subMeshes[i].triangles = newTris.ToArray(); } } void FlipFaces() { TS_Mesh temp = new TS_Mesh(); temp.normals = normals; temp.tangents = tangents; temp.triangles = triangles; for (int i = 0; i < subMeshes.Count; i++) temp.subMeshes.Add(subMeshes[i].triangles); MeshUtility.FlipFaces(temp); } void DoubleSided() { TS_Mesh temp = new TS_Mesh(); temp.vertices = vertices; temp.normals = normals; temp.tangents = tangents; temp.colors = colors; temp.uv = uv; temp.uv2 = uv2; temp.uv3 = uv3; temp.uv4 = uv4; temp.triangles = triangles; for (int i = 0; i < subMeshes.Count; i++) temp.subMeshes.Add(subMeshes[i].triangles); MeshUtility.MakeDoublesided(temp); vertices = temp.vertices; normals = temp.normals; tangents = temp.tangents; colors = temp.colors; uv = temp.uv; uv2 = temp.uv2; uv3 = temp.uv3; uv4 = temp.uv4; triangles = temp.triangles; for (int i = 0; i < subMeshes.Count; i++) subMeshes[i].triangles = temp.subMeshes[i]; } public void Write(TS_Mesh target, int forceMaterialId = -1) { if (target.vertices.Length != vertices.Length) target.vertices = new Vector3[vertices.Length]; if (target.normals.Length != normals.Length) target.normals = new Vector3[normals.Length]; if (target.colors.Length != colors.Length) target.colors = new Color[colors.Length]; if (target.uv.Length != uv.Length) target.uv = new Vector2[uv.Length]; if (target.uv2.Length != uv2.Length) target.uv2 = new Vector2[uv2.Length]; if (target.uv3.Length != uv3.Length) target.uv3 = new Vector2[uv3.Length]; if (target.uv4.Length != uv4.Length) target.uv4 = new Vector2[uv4.Length]; if (target.tangents.Length != tangents.Length) target.tangents = new Vector4[tangents.Length]; if (target.triangles.Length != triangles.Length) target.triangles = new int[triangles.Length]; vertices.CopyTo(target.vertices, 0); normals.CopyTo(target.normals, 0); colors.CopyTo(target.colors, 0); uv.CopyTo(target.uv, 0); uv2.CopyTo(target.uv2, 0); uv3.CopyTo(target.uv3, 0); uv4.CopyTo(target.uv4, 0); tangents.CopyTo(target.tangents, 0); triangles.CopyTo(target.triangles, 0); if (target.subMeshes == null) target.subMeshes = new List(); if (forceMaterialId >= 0) { while (target.subMeshes.Count > forceMaterialId + 1) target.subMeshes.RemoveAt(0); while (target.subMeshes.Count < forceMaterialId + 1) target.subMeshes.Add(new int[0]); for (int i = 0; i < target.subMeshes.Count; i++) { if (i != forceMaterialId) { if (target.subMeshes[i].Length > 0) target.subMeshes[i] = new int[0]; } else { if (target.subMeshes[i].Length != triangles.Length) target.subMeshes[i] = new int[triangles.Length]; triangles.CopyTo(target.subMeshes[i], 0); } } } else { while (target.subMeshes.Count > subMeshes.Count) target.subMeshes.RemoveAt(0); while (target.subMeshes.Count < subMeshes.Count) target.subMeshes.Add(new int[0]); for (int i = 0; i < subMeshes.Count; i++) { if (subMeshes[i].triangles.Length != target.subMeshes[i].Length) target.subMeshes[i] = new int[subMeshes[i].triangles.Length]; subMeshes[i].triangles.CopyTo(target.subMeshes[i], 0); } } } void CalculateBounds() { Vector3 min = Vector3.zero; Vector3 max = Vector3.zero; for (int i = 0; i < vertices.Length; i++) { if (vertices[i].x < min.x) min.x = vertices[i].x; else if (vertices[i].x > max.x) max.x = vertices[i].x; if (vertices[i].y < min.y) min.y = vertices[i].y; else if (vertices[i].y > max.y) max.y = vertices[i].y; if (vertices[i].z < min.z) min.z = vertices[i].z; else if (vertices[i].z > max.z) max.z = vertices[i].z; } min.z -= spacing.back; max.z += spacing.front; bounds.CreateFromMinMax(min, max); } private void Mirror() { if (_mirror == MirrorMethod.None) return; switch (_mirror) { case MirrorMethod.X: for (int i = 0; i < vertices.Length; i++) { vertices[i].x *= -1f; normals[i].x = -normals[i].x; } break; case MirrorMethod.Y: for (int i = 0; i < vertices.Length; i++) { vertices[i].y *= -1f; normals[i].y = -normals[i].y; } break; case MirrorMethod.Z: for (int i = 0; i < vertices.Length; i++) { vertices[i].z *= -1f; normals[i].z = -normals[i].z; } break; } for (int i = 0; i < triangles.Length; i += 3) { int temp = triangles[i]; triangles[i] = triangles[i + 2]; triangles[i + 2] = temp; } for (int i = 0; i < subMeshes.Count; i++) { for (int j = 0; j < subMeshes[i].triangles.Length; j += 3) { int temp = subMeshes[i].triangles[j]; subMeshes[i].triangles[j] = subMeshes[i].triangles[j + 2]; subMeshes[i].triangles[j + 2] = temp; } } CalculateTangents(); } void TransformVertices() { Matrix4x4 vertexMatrix = new Matrix4x4(); vertexMatrix.SetTRS(_offset, Quaternion.Euler(_rotation), _scale); Matrix4x4 normalMatrix = vertexMatrix.inverse.transpose; for (int i = 0; i < vertices.Length; i++) { vertices[i] = vertexMatrix.MultiplyPoint3x4(vertices[i]); normals[i] = normalMatrix.MultiplyVector(normals[i]).normalized; } for (int i = 0; i < tangents.Length; i++) tangents[i] = normalMatrix.MultiplyVector(tangents[i]); for (int i = 0; i < uv.Length; i++) { uv[i].x *= _uvScale.x; uv[i].y *= _uvScale.y; uv[i] += _uvOffset; uv[i] = Quaternion.AngleAxis(uvRotation, Vector3.forward) * uv[i]; } } void GroupVertices() { vertexGroups = new List(); for (int i = 0; i < vertices.Length; i++) { float value = vertices[i].z; double percent = DMath.Clamp01(DMath.InverseLerp(bounds.min.z, bounds.max.z, value)); int index = FindInsertIndex(vertices[i], value); if (index >= vertexGroups.Count) vertexGroups.Add(new VertexGroup(value, percent, new int[] { i })); else { float valueDelta = Mathf.Abs(vertexGroups[index].value - value); if (valueDelta < vertexGroupingMargin || Mathf.Approximately(valueDelta, vertexGroupingMargin)) vertexGroups[index].AddId(i); else if (vertexGroups[index].value < value) vertexGroups.Insert(index, new VertexGroup(value, percent, new int[] { i })); else { if (index < vertexGroups.Count - 1) vertexGroups.Insert(index + 1, new VertexGroup(value, percent, new int[] { i })); else vertexGroups.Add(new VertexGroup(value, percent, new int[] { i })); } } } } int FindInsertIndex(Vector3 pos, float value) { int lower = 0; int upper = vertexGroups.Count - 1; while (lower <= upper) { int middle = lower + (upper - lower) / 2; if (vertexGroups[middle].value == value) return middle; else if (vertexGroups[middle].value < value) upper = middle - 1; else lower = middle + 1; } return lower; } void CalculateTangents() { if (vertices.Length == 0) { tangents = new Vector4[0]; return; } tangents = new Vector4[vertices.Length]; Vector3[] tan1 = new Vector3[vertices.Length]; Vector3[] tan2 = new Vector3[vertices.Length]; for (int i = 0; i < subMeshes.Count; i++) { for (int j = 0; j < subMeshes[i].triangles.Length; j += 3) { int i1 = subMeshes[i].triangles[j]; int i2 = subMeshes[i].triangles[j + 1]; int i3 = subMeshes[i].triangles[j + 2]; float x1 = vertices[i2].x - vertices[i1].x; float x2 = vertices[i3].x - vertices[i1].x; float y1 = vertices[i2].y - vertices[i1].y; float y2 = vertices[i3].y - vertices[i1].y; float z1 = vertices[i2].z - vertices[i1].z; float z2 = vertices[i3].z - vertices[i1].z; float s1 = uv[i2].x - uv[i1].x; float s2 = uv[i3].x - uv[i1].x; float t1 = uv[i2].y - uv[i1].y; float t2 = uv[i3].y - uv[i1].y; float div = s1 * t2 - s2 * t1; float r = div == 0f ? 0f : 1f / div; Vector3 sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); Vector3 tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); tan1[i1] += sdir; tan1[i2] += sdir; tan1[i3] += sdir; tan2[i1] += tdir; tan2[i2] += tdir; tan2[i3] += tdir; } } for (int i = 0; i < vertices.Length; i++) { Vector3 n = normals[i]; Vector3 t = tan1[i]; Vector3.OrthoNormalize(ref n, ref t); tangents[i].x = t.x; tangents[i].y = t.y; tangents[i].z = t.z; tangents[i].w = (Vector3.Dot(Vector3.Cross(n, t), tan2[i]) < 0.0f) ? -1.0f : 1.0f; } } [System.Serializable] public class Submesh { public int[] triangles = new int[0]; public Submesh() { } public Submesh(int[] input) { triangles = new int[input.Length]; input.CopyTo(triangles, 0); } } [System.Serializable] public class VertexGroup { public float value = 0f; public double percent = 0.0; public int[] ids; public VertexGroup(float val, double perc, int[] vertIds) { percent = perc; value = val; ids = vertIds; } public void AddId(int id) { int[] newIds = new int[ids.Length + 1]; ids.CopyTo(newIds, 0); newIds[newIds.Length - 1] = id; ids = newIds; } } } } } }