Upload project files

This commit is contained in:
Misaki
2024-09-16 00:08:10 +09:00
commit 0a4745662a
218 changed files with 13387 additions and 0 deletions

445
Runtime/Cloner/Cloner.cs Normal file
View File

@@ -0,0 +1,445 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Unity.Mathematics;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using Random = Unity.Mathematics.Random;
namespace Misaki.ArtTool
{
[ExecuteInEditMode]
public class Cloner : MonoBehaviour
{
public List<InputObjectData> inputObjects = new();
public DistributionMode distributionMode = DistributionMode.Grid;
public bool isRandomDistribution = false;
public uint seed = 123456;
public bool autoGenerate;
public bool isRenderInstancing;
public SplineDistributionSetting splineDistributionSetting = new();
public LinearDistributionSetting linearDistributionSetting = new();
public GridDistributionSetting gridDistributionSetting = new();
public List<EffectorData> effectors;
public DebugMode debugMode;
private static readonly ArrayPool<PointData> _pointPool = ArrayPool<PointData>.Shared;
private int _pointSize;
private PointData[] _points;
private List<GameObject> _instantiateObjects = new();
private readonly Dictionary<int, List<Matrix4x4>> _objectGroup = new();
private bool _isPointsDirty = false;
private const float GIZMOS_LINE_BASE_LENGTH = 0.5f;
private void OnEnable()
{
foreach (var item in effectors)
{
if (item.effector == null)
{
return;
}
item.effector.propertyChanged += OnPropertyChanged;
}
if (transform.childCount > 0 && _instantiateObjects.Count == 0)
{
for (var i = 0; i < transform.childCount; i++)
{
_instantiateObjects.Add(transform.GetChild(i).gameObject);
}
}
}
private void OnDisable()
{
foreach (var item in effectors)
{
if (item.effector == null)
{
return;
}
item.effector.propertyChanged -= OnPropertyChanged;
}
}
//private void OnDestroy()
//{
// Clear();
//}
public void OnPropertyChanged(object sender, EventArgs e)
{
if (sender is not EffectorBase && sender is not FieldBase)
{
return;
}
_isPointsDirty = true;
}
private void Update()
{
if (_isPointsDirty && autoGenerate)
{
GeneratePoints();
InstantiateGameObjectOnPoints();
}
if (_objectGroup == null || _objectGroup.Count <= 0 || !isRenderInstancing)
{
return;
}
foreach (var item in _objectGroup)
{
if (inputObjects.Count <= item.Key || inputObjects[item.Key] == null)
{
continue;
}
var objectData = inputObjects[item.Key];
var mat = objectData.Material;
var renderParams = new RenderParams(mat)
{
shadowCastingMode = ShadowCastingMode.On
};
Graphics.RenderMeshInstanced(renderParams, objectData.Mesh, 0, item.Value, _pointSize);
}
}
public void GeneratePoints()
{
Clear();
switch (distributionMode)
{
case DistributionMode.Object:
break;
case DistributionMode.Spline:
_pointSize = splineDistributionSetting.DistributionCount;
break;
case DistributionMode.Linear:
_pointSize = (int)linearDistributionSetting.count;
break;
case DistributionMode.Grid:
_pointSize = gridDistributionSetting.DistributionCount;
break;
case DistributionMode.Radial:
break;
case DistributionMode.Honeycomb:
break;
default:
break;
}
if (_pointSize == 0)
{
return;
}
if (_points == null || _pointSize > _points.Length)
{
_points = _pointPool.Rent(_pointSize);
}
foreach (var effectorData in effectors)
{
effectorData.effector.Initialize();
}
var splineLength = 0.0f;
var splineMatrix = float4x4.identity;
if (distributionMode == DistributionMode.Spline && splineDistributionSetting.spline != null)
{
splineLength = splineDistributionSetting.spline.CalculateLength();
splineMatrix = splineDistributionSetting.spline.transform.localToWorldMatrix;
}
var worldMatrix = transform.localToWorldMatrix;
Parallel.For(0, _pointSize, i =>
{
var pointMatrix = float4x4.identity;
var isValid = true;
switch (distributionMode)
{
case DistributionMode.Object:
break;
case DistributionMode.Spline:
Distribution.SplineDistribution(i, _pointSize, splineLength, splineMatrix, splineDistributionSetting, out pointMatrix, out isValid);
break;
case DistributionMode.Linear:
Distribution.LinearDistribution(i, linearDistributionSetting, out pointMatrix, out isValid);
break;
case DistributionMode.Grid:
Distribution.GridDistribution(i, gridDistributionSetting, out pointMatrix, out isValid);
break;
case DistributionMode.Radial:
break;
case DistributionMode.Honeycomb:
break;
default:
break;
}
pointMatrix = math.mul(worldMatrix, pointMatrix);
_points[i].matrix = pointMatrix;
_points[i].isValid = isValid;
});
Parallel.For(0, _pointSize, i =>
{
for (var e = 0; e < effectors.Count; e++)
{
if (!effectors[e].enable)
{
continue;
}
if (effectors[e].effector == null)
{
continue;
}
effectors[e].effector.Operate(i, worldMatrix, _points, ref _points[i].matrix, ref _points[i].isValid);
}
if (math.all(_points[i].matrix.GetScale() == float3.zero))
{
_points[i].isValid = false;
}
});
_isPointsDirty = false;
}
public void InstantiateGameObjectOnPoints()
{
if (_points == null && _pointSize <= 0)
{
return;
}
if (_instantiateObjects.Count > 0)
{
for (var i = 0; i < _instantiateObjects.Count; i++)
{
if (_instantiateObjects[i] == null)
{
continue;
}
#if UNITY_EDITOR
DestroyImmediate(_instantiateObjects[i]);
#else
Destroy(child.gameObject);
#endif
}
}
if (isRandomDistribution)
{
// Use Fisher-Yates Shuffle algorithm to swap value
var random = new Random(seed);
for (var i = _pointSize - 1; i > 0; i--)
{
var k = random.NextInt(0, i + 1);
(_points[i], _points[k]) = (_points[k], _points[i]);
}
}
foreach (var item in _objectGroup)
{
item.Value.Clear();
}
var currentIndex = 0;
var objectIndex = 0;
while (currentIndex < _pointSize)
{
if (!_points[currentIndex].isValid)
{
currentIndex++;
continue;
}
objectIndex %= inputObjects.Count;
if (inputObjects[objectIndex].gameObject == null)
{
currentIndex++;
continue;
}
if (!_objectGroup.ContainsKey(objectIndex))
{
_objectGroup[objectIndex] = new();
}
for (var f = 0; f < inputObjects[objectIndex].frequency; f++)
{
_objectGroup[objectIndex].Add(_points[currentIndex].matrix);
currentIndex++;
if (currentIndex >= _pointSize)
{
break;
}
}
objectIndex++;
}
for (var i = 0; i < _objectGroup.Count; i++)
{
var group = _objectGroup.ElementAt(i);
if (group.Value.Count <= 0)
{
_objectGroup.Remove(group.Key);
}
}
if (!isRenderInstancing)
{
foreach (var item in _objectGroup)
{
Span<Vector3> positionsSpan = stackalloc Vector3[item.Value.Count];
Span<Quaternion> rotationsSpan = stackalloc Quaternion[item.Value.Count];
var scaleArray = new Vector3[item.Value.Count];
MatrixHelper.DecomposeMatrixListAsSpan(item.Value,
positionsSpan, rotationsSpan, scaleArray);
var iop = InstantiateAsync(
inputObjects[item.Key].gameObject, item.Value.Count,
transform, positionsSpan, rotationsSpan);
iop.completed += (op) =>
{
var instantiatedObjects = iop.GetAwaiter().GetResult();
for (var i = 0; i < instantiatedObjects.Length; i++)
{
var instantiatedObject = instantiatedObjects[i];
instantiatedObject.transform.localScale = scaleArray[i];
_instantiateObjects.Add(instantiatedObject);
}
};
}
}
}
public void Clear(bool isClearPoints = true, bool isClearObjects = true)
{
if (isClearPoints)
{
_pointPool.Return(_points, true);
}
if (isClearObjects)
{
_objectGroup.Clear();
if (_instantiateObjects.Count <= 0)
{
return;
}
for (var i = 0; i < _instantiateObjects.Count; i++)
{
if (_instantiateObjects[i] == null)
{
continue;
}
#if UNITY_EDITOR
DestroyImmediate(_instantiateObjects[i]);
#else
Destroy(child.gameObject);
#endif
}
}
}
private void OnDrawGizmosSelected()
{
if (_pointSize <= 0 || _points.Length < _pointSize)
{
return;
}
for (var i = 0; i < _pointSize; i++)
{
var point = _points[i];
switch (debugMode)
{
case DebugMode.None:
break;
case DebugMode.Transform:
if (!point.isValid)
{
continue;
}
var scale = point.matrix.GetScale();
Gizmos.matrix = point.matrix;
// Draw the x-axis in red
Gizmos.color = Color.red;
Gizmos.DrawLine(Vector3.zero, Vector3.right * scale * GIZMOS_LINE_BASE_LENGTH);
// Draw the y-axis in green
Gizmos.color = Color.green;
Gizmos.DrawLine(Vector3.zero, Vector3.up * scale * GIZMOS_LINE_BASE_LENGTH);
// Draw the z-axis in blue
Gizmos.color = Color.blue;
Gizmos.DrawLine(Vector3.zero, Vector3.forward * scale * GIZMOS_LINE_BASE_LENGTH);
break;
case DebugMode.Index:
if (!point.isValid)
{
continue;
}
Handles.matrix = point.matrix;
Handles.Label(Vector3.zero, i.ToString());
break;
case DebugMode.Validity:
if (point.isValid)
{
Gizmos.color = Color.green;
}
else
{
Gizmos.color = Color.red;
}
Gizmos.DrawSphere(point.matrix.c3.xyz, GIZMOS_LINE_BASE_LENGTH / 2.0f);
break;
default:
break;
}
}
}
}
}