Upload project files
This commit is contained in:
445
Runtime/Cloner/Cloner.cs
Normal file
445
Runtime/Cloner/Cloner.cs
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Cloner/Cloner.cs.meta
Normal file
11
Runtime/Cloner/Cloner.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35466656a0ebc42449023a440cfad411
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 858ef2b4b0d5f7e4fb055cc7102b5292, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Runtime/Cloner/Contracts.meta
Normal file
8
Runtime/Cloner/Contracts.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de1401f6b38da8643abf01231a6395fb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Runtime/Cloner/Contracts/Effector.meta
Normal file
8
Runtime/Cloner/Contracts/Effector.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 107650ad99360724989708b1799990a5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
84
Runtime/Cloner/Contracts/Effector/EffectorBase.cs
Normal file
84
Runtime/Cloner/Contracts/Effector/EffectorBase.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public abstract class EffectorBase : MonoBehaviour
|
||||
{
|
||||
public float strength = 1.0f;
|
||||
|
||||
public List<FieldData> fieldDataList = new();
|
||||
|
||||
public EventHandler propertyChanged;
|
||||
|
||||
protected float4x4 effectorMatrix;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
foreach (var item in fieldDataList)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
item.field.propertyChanged += OnPropertyChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
foreach (var item in fieldDataList)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
item.field.propertyChanged -= OnPropertyChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPropertyChanged(object sender, EventArgs e)
|
||||
{
|
||||
propertyChanged?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
public virtual void Initialize()
|
||||
{
|
||||
for (var i = 0; i < fieldDataList.Count; i++)
|
||||
{
|
||||
fieldDataList[i].field.Initialize();
|
||||
}
|
||||
|
||||
effectorMatrix = transform.localToWorldMatrix;
|
||||
}
|
||||
|
||||
public virtual void Operate(int index, float4x4 nodeWorldMatrix, ReadOnlySpan<PointData> points, ref float4x4 pointWorldMatrix, ref bool isValid)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected float CalculateFieldsWeight(float3 worldPosition)
|
||||
{
|
||||
var weight = 1.0f;
|
||||
var fieldCount = fieldDataList.Count;
|
||||
for (var i = 0; i < fieldCount; i++)
|
||||
{
|
||||
var fieldData = fieldDataList[i];
|
||||
if (!fieldData.enable || fieldData.opacity <= 0.0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
weight = math.lerp(weight, fieldData.field.Operate(worldPosition), fieldData.opacity);
|
||||
}
|
||||
|
||||
weight *= strength;
|
||||
|
||||
return weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Contracts/Effector/EffectorBase.cs.meta
Normal file
2
Runtime/Cloner/Contracts/Effector/EffectorBase.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7ccd97731dd96b4fa2c848321321710
|
||||
6
Runtime/Cloner/Contracts/Effector/IterateEffectorBase.cs
Normal file
6
Runtime/Cloner/Contracts/Effector/IterateEffectorBase.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public class IterateEffectorBase : EffectorBase
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5144695703dc3434c93bc038017a3ac3
|
||||
8
Runtime/Cloner/Contracts/Field.meta
Normal file
8
Runtime/Cloner/Contracts/Field.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8ea1a2aeb0489a4babf1d34f2ff07c2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
42
Runtime/Cloner/Contracts/Field/FieldBase.cs
Normal file
42
Runtime/Cloner/Contracts/Field/FieldBase.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public abstract class FieldBase : MonoBehaviour
|
||||
{
|
||||
public RemappingSetting remappingSetting = new();
|
||||
|
||||
public EventHandler propertyChanged;
|
||||
|
||||
public virtual void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
public abstract float Operate(float3 position);
|
||||
|
||||
protected float Remapping(float weight)
|
||||
{
|
||||
if (!remappingSetting.enable)
|
||||
{
|
||||
return weight;
|
||||
}
|
||||
|
||||
weight = math.saturate(weight / (1.0f - remappingSetting.innerOffset));
|
||||
weight = math.lerp(remappingSetting.min, remappingSetting.max, weight);
|
||||
weight = remappingSetting.invert ? 1.0f - weight : weight;
|
||||
weight *= remappingSetting.strength;
|
||||
return weight;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (transform.hasChanged)
|
||||
{
|
||||
propertyChanged.Invoke(this, null);
|
||||
transform.hasChanged = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Contracts/Field/FieldBase.cs.meta
Normal file
2
Runtime/Cloner/Contracts/Field/FieldBase.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c07d37f0b7524644aab721afc849c508
|
||||
8
Runtime/Cloner/Distribution.meta
Normal file
8
Runtime/Cloner/Distribution.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 65fe35f62bdb64d4f8b4a2e4e8ec0a39
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
55
Runtime/Cloner/Distribution/GridDistribution.cs
Normal file
55
Runtime/Cloner/Distribution/GridDistribution.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public static partial class Distribution
|
||||
{
|
||||
public static void GridDistribution(int index, GridDistributionSetting setting, out float4x4 localMatrix, out bool isValid)
|
||||
{
|
||||
var random = Random.CreateFromIndex((uint)index);
|
||||
|
||||
var localPosition = GetCubePosition(index, setting.count) * setting.spacing;
|
||||
|
||||
switch (setting.shape)
|
||||
{
|
||||
case GridShape.Cube:
|
||||
isValid = true;
|
||||
break;
|
||||
|
||||
case GridShape.Sphere:
|
||||
var isInsideSphere = ShapeHelper.IsInsideSphere(localPosition, 0.0f, setting.count * setting.spacing);
|
||||
|
||||
isValid = isInsideSphere;
|
||||
break;
|
||||
|
||||
case GridShape.Cylinder:
|
||||
var isInsideCylinder = ShapeHelper.IsInsideCylinder(localPosition, 0.0f, setting.count * setting.spacing);
|
||||
isValid = isInsideCylinder;
|
||||
break;
|
||||
default:
|
||||
isValid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (random.NextFloat() > setting.fill && isValid == true)
|
||||
{
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
localMatrix = float4x4.TRS(localPosition, quaternion.identity, new float3(1.0f));
|
||||
}
|
||||
|
||||
private static float3 GetCubePosition(int index, int3 size)
|
||||
{
|
||||
float3 localPosition;
|
||||
var yIndex = index / (size.x * size.z);
|
||||
var remain = index % (size.x * size.z);
|
||||
var zIndex = remain / size.x;
|
||||
var xIndex = remain % size.x;
|
||||
|
||||
localPosition = new float3(xIndex, yIndex, zIndex);
|
||||
localPosition -= (float3)(size - 1) * 0.5f;
|
||||
return localPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Distribution/GridDistribution.cs.meta
Normal file
2
Runtime/Cloner/Distribution/GridDistribution.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 776811becd42a27408b353bb0cc8e54e
|
||||
21
Runtime/Cloner/Distribution/LinearDistribution.cs
Normal file
21
Runtime/Cloner/Distribution/LinearDistribution.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public static partial class Distribution
|
||||
{
|
||||
public static void LinearDistribution(int index, LinearDistributionSetting setting, out float4x4 localMatrix, out bool isValid)
|
||||
{
|
||||
var pointIndex = (uint)index + setting.indexOffset;
|
||||
var localPosition = pointIndex * setting.positionSpacing;
|
||||
var localEulerRotation = pointIndex * setting.rotationSpacing;
|
||||
var localScale = 1.0f - (pointIndex * (1.0f - setting.scaleSpacing));
|
||||
|
||||
localPosition = math.mul(float3x3.EulerXYZ(math.radians(setting.stepRotation * pointIndex)), localPosition);
|
||||
var localRotation = math.mul(quaternion.EulerXYZ(math.radians(localEulerRotation)), quaternion.EulerXYZ(math.radians(setting.stepRotation * pointIndex)));
|
||||
|
||||
localMatrix = float4x4.TRS(localPosition, localRotation, localScale);
|
||||
isValid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Distribution/LinearDistribution.cs.meta
Normal file
2
Runtime/Cloner/Distribution/LinearDistribution.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6bf561350efd524a9a65100521eb388
|
||||
47
Runtime/Cloner/Distribution/SplineDistribution.cs
Normal file
47
Runtime/Cloner/Distribution/SplineDistribution.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine.Splines;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public static partial class Distribution
|
||||
{
|
||||
public static void SplineDistribution(int index, int pointSize, float splineLength, float4x4 splineWorldMatrix, SplineDistributionSetting setting, out float4x4 localMatrix, out bool isValid)
|
||||
{
|
||||
var pointIndex = index + setting.indexOffset;
|
||||
|
||||
|
||||
if (pointIndex > pointSize)
|
||||
{
|
||||
localMatrix = float4x4.zero;
|
||||
isValid = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var spline = setting.spline;
|
||||
float t;
|
||||
|
||||
if (setting.isSpacingMode)
|
||||
{
|
||||
t = (pointIndex * setting.spacing) / splineLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = pointIndex / (float)(pointSize - 1);
|
||||
}
|
||||
|
||||
if (SplineUtility.Evaluate(spline.Spline, t, out var position, out var normal, out var upVector))
|
||||
{
|
||||
var localRotation = quaternion.LookRotationSafe(normal, upVector);
|
||||
|
||||
localMatrix = math.mul(splineWorldMatrix, float4x4.TRS(position, localRotation, new float3(1.0f)));
|
||||
isValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
localMatrix = float4x4.zero;
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Distribution/SplineDistribution.cs.meta
Normal file
2
Runtime/Cloner/Distribution/SplineDistribution.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 843f013f896d37543a4d48166e71b6b6
|
||||
8
Runtime/Cloner/Effector.meta
Normal file
8
Runtime/Cloner/Effector.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2781ff4287895d40835ad3a238647d8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
98
Runtime/Cloner/Effector/PlainEffector.cs
Normal file
98
Runtime/Cloner/Effector/PlainEffector.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
public class PlainEffector : EffectorBase
|
||||
{
|
||||
public TransformSpace transformSpace;
|
||||
|
||||
public bool isEnablePosition;
|
||||
public float3 position;
|
||||
|
||||
public bool isEnableRotation;
|
||||
public float3 rotation;
|
||||
|
||||
public bool isEnableScale;
|
||||
public bool isAbsoluteScale;
|
||||
public bool isUniformScale;
|
||||
public float3 scale;
|
||||
public float uniformScale;
|
||||
|
||||
public override void Operate(int index, float4x4 nodeWorldMatrix, ReadOnlySpan<PointData> points, ref float4x4 pointWorldMatrix, ref bool isValid)
|
||||
{
|
||||
if (!isEnablePosition && !isEnableRotation && !isEnableScale)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MatrixHelper.DecomposeMatrix(pointWorldMatrix, out var position, out var rotation, out var scale);
|
||||
|
||||
var weight = CalculateFieldsWeight(pointWorldMatrix.c3.xyz);
|
||||
if (weight == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEnablePosition)
|
||||
{
|
||||
var newPosition = position;
|
||||
switch (transformSpace)
|
||||
{
|
||||
case TransformSpace.Node:
|
||||
newPosition += this.position;
|
||||
break;
|
||||
case TransformSpace.Effector:
|
||||
newPosition += math.mul(effectorMatrix, new float4(this.position, 0)).xyz;
|
||||
break;
|
||||
case TransformSpace.Object:
|
||||
newPosition += math.mul(pointWorldMatrix, new float4(this.position, 0)).xyz;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
position = math.lerp(position, newPosition, weight);
|
||||
}
|
||||
|
||||
if (isEnableRotation)
|
||||
{
|
||||
var newRotation = rotation;
|
||||
switch (transformSpace)
|
||||
{
|
||||
case TransformSpace.Node:
|
||||
newRotation = math.mul(rotation, quaternion.EulerXYZ(math.radians(this.rotation)));
|
||||
break;
|
||||
case TransformSpace.Effector:
|
||||
newRotation = math.mul(rotation,
|
||||
quaternion.EulerXYZ(math.mul(effectorMatrix, new float4(math.radians(this.rotation), 0)).xyz));
|
||||
break;
|
||||
case TransformSpace.Object:
|
||||
newRotation = math.mul(rotation,
|
||||
quaternion.EulerXYZ(math.mul(pointWorldMatrix, new float4(math.radians(this.rotation), 0)).xyz));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
rotation = Quaternion.Lerp(rotation, newRotation, weight);
|
||||
}
|
||||
|
||||
if (isEnableScale)
|
||||
{
|
||||
var newScale = scale;
|
||||
if (isUniformScale)
|
||||
{
|
||||
newScale = isAbsoluteScale ? uniformScale : scale - uniformScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
newScale = isAbsoluteScale ? this.scale : scale - this.scale;
|
||||
}
|
||||
scale = math.lerp(scale, newScale, weight);
|
||||
}
|
||||
|
||||
pointWorldMatrix = float4x4.TRS(position, rotation, scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Effector/PlainEffector.cs.meta
Normal file
2
Runtime/Cloner/Effector/PlainEffector.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6601a6a85943a3444a503fdeb1cba30e
|
||||
43
Runtime/Cloner/Effector/PushApartEffector.cs
Normal file
43
Runtime/Cloner/Effector/PushApartEffector.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public class PushApartEffector : EffectorBase
|
||||
{
|
||||
public float radius = 1.0f;
|
||||
public uint iteration = 10;
|
||||
|
||||
// TODO: Average the push direction and distance of each point for more consistence result
|
||||
public override void Operate(int index, float4x4 nodeWorldMatrix, ReadOnlySpan<PointData> points, ref float4x4 pointWorldMatrix, ref bool isValid)
|
||||
{
|
||||
var currentPoint = points[index];
|
||||
|
||||
var weight = CalculateFieldsWeight(pointWorldMatrix.c3.xyz);
|
||||
if (weight == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < iteration; i++)
|
||||
{
|
||||
for (var p = 0; p < points.Length; p++)
|
||||
{
|
||||
var targetPoint = points[p];
|
||||
|
||||
if (ReferenceEquals(currentPoint, targetPoint))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var distance = math.distance(currentPoint.matrix.c3.xyz, targetPoint.matrix.c3.xyz);
|
||||
if (distance < radius)
|
||||
{
|
||||
var direction = math.normalizesafe(currentPoint.matrix.c3.xyz - targetPoint.matrix.c3.xyz);
|
||||
pointWorldMatrix.c3.xyz += distance * weight * direction;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Effector/PushApartEffector.cs.meta
Normal file
2
Runtime/Cloner/Effector/PushApartEffector.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c74fdb9922181d940a34522dd3878624
|
||||
123
Runtime/Cloner/Effector/RandomEffector.cs
Normal file
123
Runtime/Cloner/Effector/RandomEffector.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using Random = Unity.Mathematics.Random;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public class RandomEffector : EffectorBase
|
||||
{
|
||||
public float2 minMax = new(-1.0f, 1.0f);
|
||||
|
||||
public bool synchronized;
|
||||
public uint seed = 123456;
|
||||
|
||||
public TransformSpace transformSpace;
|
||||
|
||||
public bool isEnablePosition;
|
||||
public float3 positionMinMax;
|
||||
|
||||
public bool isEnableRotation;
|
||||
public float3 rotationMinMax;
|
||||
|
||||
public bool isEnableScale;
|
||||
public bool isAbsoluteScale;
|
||||
public bool isUniformScale;
|
||||
public float3 scaleMinMax;
|
||||
public float uniformScaleMinMax;
|
||||
|
||||
public override void Operate(int index, float4x4 nodeWorldMatrix, ReadOnlySpan<PointData> points, ref float4x4 pointWorldMatrix, ref bool isValid)
|
||||
{
|
||||
if (!isEnablePosition && !isEnableRotation && !isEnableScale)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Random random;
|
||||
if (synchronized)
|
||||
{
|
||||
random = Random.CreateFromIndex(seed);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index > uint.MaxValue - seed)
|
||||
{
|
||||
random = Random.CreateFromIndex(seed - (uint)index);
|
||||
}
|
||||
else
|
||||
{
|
||||
random = Random.CreateFromIndex(seed + (uint)index);
|
||||
}
|
||||
}
|
||||
|
||||
MatrixHelper.DecomposeMatrix(pointWorldMatrix, out var position, out var rotation, out var scale);
|
||||
|
||||
var weight = CalculateFieldsWeight(pointWorldMatrix.c3.xyz);
|
||||
if (weight == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEnablePosition)
|
||||
{
|
||||
var newPosition = random.NextFloat3(positionMinMax * minMax.x, positionMinMax * minMax.y);
|
||||
|
||||
switch (transformSpace)
|
||||
{
|
||||
case TransformSpace.Effector:
|
||||
newPosition = math.mul(effectorMatrix, new float4(newPosition, 0.0f)).xyz;
|
||||
break;
|
||||
case TransformSpace.Object:
|
||||
newPosition = math.mul(pointWorldMatrix, new float4(newPosition, 0.0f)).xyz;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
position = math.lerp(position, position + newPosition, weight);
|
||||
}
|
||||
|
||||
if (isEnableRotation)
|
||||
{
|
||||
var angle = random.NextFloat3(rotationMinMax * minMax.x, rotationMinMax * minMax.y);
|
||||
|
||||
switch (transformSpace)
|
||||
{
|
||||
case TransformSpace.Effector:
|
||||
angle = math.mul(effectorMatrix, new float4(angle, 0.0f)).xyz;
|
||||
break;
|
||||
case TransformSpace.Object:
|
||||
angle = math.mul(pointWorldMatrix, new float4(angle, 0.0f)).xyz;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
var newRotation = quaternion.Euler(math.radians(angle));
|
||||
rotation = Quaternion.Lerp(rotation, math.mul(rotation, newRotation), weight);
|
||||
}
|
||||
|
||||
if (isEnableScale)
|
||||
{
|
||||
float3 newScale;
|
||||
if (isUniformScale)
|
||||
{
|
||||
var minScale = isAbsoluteScale ? uniformScaleMinMax : 1.0f + (uniformScaleMinMax - 1.0f) * minMax.x;
|
||||
var maxScale = isAbsoluteScale ? 0.0f : 1.0f + (uniformScaleMinMax - 1.0f) * minMax.y;
|
||||
|
||||
newScale = random.NextFloat(minScale, maxScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
var minScale = isAbsoluteScale ? scaleMinMax : 1.0f + ((scaleMinMax - 1.0f) * minMax.x);
|
||||
var maxScale = isAbsoluteScale ? 0.0f : 1.0f + ((scaleMinMax - 1.0f) * minMax.y);
|
||||
|
||||
newScale = random.NextFloat3(minScale, maxScale);
|
||||
}
|
||||
|
||||
scale = math.lerp(scale, scale + newScale, weight);
|
||||
}
|
||||
|
||||
pointWorldMatrix = float4x4.TRS(position, rotation, scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Effector/RandomEffector.cs.meta
Normal file
2
Runtime/Cloner/Effector/RandomEffector.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd224efbdb8a5bb41bdc7a5db7a08533
|
||||
8
Runtime/Cloner/Enums.meta
Normal file
8
Runtime/Cloner/Enums.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce4ee28bfe031d2438248933fcffc908
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
14
Runtime/Cloner/Enums/BlendingMode.cs
Normal file
14
Runtime/Cloner/Enums/BlendingMode.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public enum BlendingMode
|
||||
{
|
||||
Normal,
|
||||
Min,
|
||||
Subtract,
|
||||
Multiply,
|
||||
Overlay,
|
||||
Max,
|
||||
Add,
|
||||
Screen
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Enums/BlendingMode.cs.meta
Normal file
2
Runtime/Cloner/Enums/BlendingMode.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6337269e529baa4a9554b85d8eb01b9
|
||||
8
Runtime/Cloner/Enums/CloneMode.cs
Normal file
8
Runtime/Cloner/Enums/CloneMode.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public enum CloneMode
|
||||
{
|
||||
Iterate,
|
||||
Random
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Enums/CloneMode.cs.meta
Normal file
2
Runtime/Cloner/Enums/CloneMode.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12f9d13e6e10c8442abb4950e246e64c
|
||||
10
Runtime/Cloner/Enums/DebugMode.cs
Normal file
10
Runtime/Cloner/Enums/DebugMode.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public enum DebugMode
|
||||
{
|
||||
None,
|
||||
Transform,
|
||||
Index,
|
||||
Validity
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Enums/DebugMode.cs.meta
Normal file
2
Runtime/Cloner/Enums/DebugMode.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1cac92d7e0ef2b4ba204b72fd657c78
|
||||
12
Runtime/Cloner/Enums/DistributionMode.cs
Normal file
12
Runtime/Cloner/Enums/DistributionMode.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public enum DistributionMode
|
||||
{
|
||||
Object,
|
||||
Spline,
|
||||
Linear,
|
||||
Grid,
|
||||
Radial,
|
||||
Honeycomb
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Enums/DistributionMode.cs.meta
Normal file
2
Runtime/Cloner/Enums/DistributionMode.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a17ee44970fcc3479a0cdd04da3a8ad
|
||||
9
Runtime/Cloner/Enums/GridShape.cs
Normal file
9
Runtime/Cloner/Enums/GridShape.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public enum GridShape
|
||||
{
|
||||
Cube,
|
||||
Sphere,
|
||||
Cylinder
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Enums/GridShape.cs.meta
Normal file
2
Runtime/Cloner/Enums/GridShape.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 860e24fd1e850654cac3e4bbe5bbde1d
|
||||
8
Runtime/Cloner/Enums/TransformMode.cs
Normal file
8
Runtime/Cloner/Enums/TransformMode.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public enum TransformMode
|
||||
{
|
||||
Relative,
|
||||
Absolute
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Enums/TransformMode.cs.meta
Normal file
2
Runtime/Cloner/Enums/TransformMode.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ed88eac104f9fb45b885db70217db5c
|
||||
9
Runtime/Cloner/Enums/TransformSpace.cs
Normal file
9
Runtime/Cloner/Enums/TransformSpace.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public enum TransformSpace
|
||||
{
|
||||
Node,
|
||||
Effector,
|
||||
Object
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Enums/TransformSpace.cs.meta
Normal file
2
Runtime/Cloner/Enums/TransformSpace.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fec82e7e110164249abb0f36870043a1
|
||||
8
Runtime/Cloner/Fields.meta
Normal file
8
Runtime/Cloner/Fields.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31693103866ca2745810c1cc323eb764
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
49
Runtime/Cloner/Fields/LinearField.cs
Normal file
49
Runtime/Cloner/Fields/LinearField.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
public class LinearField : FieldBase
|
||||
{
|
||||
public float length = 1.0f;
|
||||
|
||||
private float3 fieldForward;
|
||||
private float3 fieldPosition;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
fieldForward = transform.forward;
|
||||
fieldPosition = transform.position;
|
||||
}
|
||||
|
||||
public override float Operate(float3 position)
|
||||
{
|
||||
var plane = new Unity.Mathematics.Geometry.Plane(fieldForward, fieldPosition);
|
||||
var distance = plane.SignedDistanceToPoint(position) / length;
|
||||
var weight = math.saturate(distance / 2.0f + 0.5f);
|
||||
|
||||
weight = Remapping(weight);
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
Gizmos.matrix = transform.localToWorldMatrix;
|
||||
|
||||
var end = Vector3.forward * length;
|
||||
var start = Vector3.forward * -length;
|
||||
|
||||
Gizmos.DrawLine(start, end);
|
||||
var right = Quaternion.LookRotation(Vector3.forward) * Quaternion.Euler(0.0f, 180.0f + 30.0f, 0.0f) * Vector3.forward;
|
||||
var left = Quaternion.LookRotation(Vector3.forward) * Quaternion.Euler(0.0f, 180.0f - 30.0f, 0.0f) * Vector3.forward;
|
||||
|
||||
Gizmos.DrawLine(end, end + right * 0.5f);
|
||||
Gizmos.DrawLine(end, end + left * 0.5f);
|
||||
|
||||
Gizmos.DrawWireCube(end, Vector3.one);
|
||||
Gizmos.DrawWireCube(start, Vector3.one);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Fields/LinearField.cs.meta
Normal file
2
Runtime/Cloner/Fields/LinearField.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73f4542d4baa2f94c87fea0390d5c524
|
||||
31
Runtime/Cloner/Fields/SphereField.cs
Normal file
31
Runtime/Cloner/Fields/SphereField.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public class SphereField : FieldBase
|
||||
{
|
||||
public float radius = 1.0f;
|
||||
|
||||
private float3 fieldPosition;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
fieldPosition = transform.position;
|
||||
}
|
||||
|
||||
public override float Operate(float3 position)
|
||||
{
|
||||
var weight = ShapeHelper.Linear01DistanceToSphereCenter(position, fieldPosition, radius);
|
||||
weight = Remapping(weight);
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
Gizmos.color = Color.cyan;
|
||||
Gizmos.DrawWireSphere(fieldPosition, radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Fields/SphereField.cs.meta
Normal file
2
Runtime/Cloner/Fields/SphereField.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bca26ff5ff452044c873ff07452adb51
|
||||
8
Runtime/Cloner/Helper.meta
Normal file
8
Runtime/Cloner/Helper.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0edc45ee28a6b240b4a458ef29e5b8b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Runtime/Cloner/Helper/Converter.meta
Normal file
8
Runtime/Cloner/Helper/Converter.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0fb3963eff3a815418c93ea649c97569
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
30
Runtime/Cloner/Helper/Converter/BoolToDisplayConvertor.cs
Normal file
30
Runtime/Cloner/Helper/Converter/BoolToDisplayConvertor.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public struct BoolToDisplayConverter
|
||||
{
|
||||
public static StyleEnum<DisplayStyle> ConvertTo(bool value)
|
||||
{
|
||||
return value ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
}
|
||||
|
||||
public static bool ConvertBack(StyleEnum<DisplayStyle> value)
|
||||
{
|
||||
return value == DisplayStyle.Flex;
|
||||
}
|
||||
}
|
||||
|
||||
public struct InverseBoolToDisplayConverter
|
||||
{
|
||||
public static StyleEnum<DisplayStyle> ConvertTo(bool value)
|
||||
{
|
||||
return value ? DisplayStyle.None : DisplayStyle.Flex;
|
||||
}
|
||||
|
||||
public static bool ConvertBack(StyleEnum<DisplayStyle> value)
|
||||
{
|
||||
return value == DisplayStyle.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b81c44f05fc751c48826ea9ce03b7c01
|
||||
45
Runtime/Cloner/Helper/Converter/ConverterInitializer.cs
Normal file
45
Runtime/Cloner/Helper/Converter/ConverterInitializer.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using Unity.Mathematics;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
internal class ConverterInitializer
|
||||
{
|
||||
[InitializeOnLoadMethod]
|
||||
public static void Initialize()
|
||||
{
|
||||
var boolToDisplayGroup = new ConverterGroup("BoolToDisplayConvertor");
|
||||
|
||||
boolToDisplayGroup.AddConverter((ref bool v) => BoolToDisplayConverter.ConvertTo(v));
|
||||
boolToDisplayGroup.AddConverter((ref StyleEnum<DisplayStyle> v) => BoolToDisplayConverter.ConvertBack(v));
|
||||
|
||||
ConverterGroups.RegisterConverterGroup(boolToDisplayGroup);
|
||||
|
||||
|
||||
var inverseBoolToDisplayGroup = new ConverterGroup("InverseBoolToDisplayConverter");
|
||||
|
||||
inverseBoolToDisplayGroup.AddConverter((ref bool v) => InverseBoolToDisplayConverter.ConvertTo(v));
|
||||
inverseBoolToDisplayGroup.AddConverter((ref StyleEnum<DisplayStyle> v) => InverseBoolToDisplayConverter.ConvertBack(v));
|
||||
|
||||
ConverterGroups.RegisterConverterGroup(inverseBoolToDisplayGroup);
|
||||
|
||||
|
||||
var float2ToVector2Group = new ConverterGroup("Float2ToVector2Converter");
|
||||
|
||||
float2ToVector2Group.AddConverter((ref float2 v) => Float2ToVector2Converter.ConvertTo(v));
|
||||
float2ToVector2Group.AddConverter((ref Vector2 v) => Float2ToVector2Converter.ConvertBack(v));
|
||||
|
||||
ConverterGroups.RegisterConverterGroup(float2ToVector2Group);
|
||||
|
||||
|
||||
var float3ToVector3Group = new ConverterGroup("Float3ToVector3Converter");
|
||||
|
||||
float3ToVector3Group.AddConverter((ref float3 v) => Float3ToVector3Converter.ConvertTo(v));
|
||||
float3ToVector3Group.AddConverter((ref Vector3 v) => Float3ToVector3Converter.ConvertBack(v));
|
||||
|
||||
ConverterGroups.RegisterConverterGroup(float3ToVector3Group);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c562049c7c1eae74cabb57e558e84cd6
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public struct DistributionModeToDisplayStyleConverter
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc563d199e512194591ea87c5554c7fd
|
||||
31
Runtime/Cloner/Helper/Converter/FloatToVectorConverter.cs
Normal file
31
Runtime/Cloner/Helper/Converter/FloatToVectorConverter.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public struct Float2ToVector2Converter
|
||||
{
|
||||
public static Vector2 ConvertTo(float2 value)
|
||||
{
|
||||
return (Vector2)value;
|
||||
}
|
||||
|
||||
public static float2 ConvertBack(Vector2 value)
|
||||
{
|
||||
return (float2)value;
|
||||
}
|
||||
}
|
||||
|
||||
public struct Float3ToVector3Converter
|
||||
{
|
||||
public static Vector3 ConvertTo(float3 value)
|
||||
{
|
||||
return (Vector3)value;
|
||||
}
|
||||
|
||||
public static float3 ConvertBack(Vector3 value)
|
||||
{
|
||||
return (float3)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e4440b512db4634782a08acd72568a3
|
||||
78
Runtime/Cloner/Helper/MatrixHelper.cs
Normal file
78
Runtime/Cloner/Helper/MatrixHelper.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
internal static class MatrixHelper
|
||||
{
|
||||
internal static void DecomposeMatrix(float4x4 matrix, out float3 position, out quaternion rotation, out float3 scale)
|
||||
{
|
||||
position = matrix.c3.xyz;
|
||||
scale = new float3(
|
||||
math.length(matrix.c0.xyz),
|
||||
math.length(matrix.c1.xyz),
|
||||
math.length(matrix.c2.xyz)
|
||||
);
|
||||
|
||||
rotation = quaternion.LookRotation(matrix.c2.xyz / scale.z, matrix.c1.xyz / scale.y);
|
||||
}
|
||||
|
||||
internal static void DecomposeMatrixToVector(float4x4 matrix, out Vector3 position, out Quaternion rotation, out Vector3 scale)
|
||||
{
|
||||
position = matrix.c3.xyz;
|
||||
scale = new Vector3(
|
||||
math.length(matrix.c0.xyz),
|
||||
math.length(matrix.c1.xyz),
|
||||
math.length(matrix.c2.xyz)
|
||||
);
|
||||
|
||||
rotation = Quaternion.LookRotation(matrix.c2.xyz / scale.z, matrix.c1.xyz / scale.y);
|
||||
}
|
||||
|
||||
internal static void DecomposeMatrixListAsSpan(in IList<Matrix4x4> matrixList, Span<Vector3> positions, Span<Quaternion> rotations, Span<Vector3> scales)
|
||||
{
|
||||
if (matrixList.Count != positions.Length || matrixList.Count != rotations.Length || matrixList.Count != scales.Length)
|
||||
{
|
||||
throw new ArgumentException("The length of the spans must match the number of matrices in the list.");
|
||||
}
|
||||
|
||||
for (var i = 0; i < matrixList.Count; i++)
|
||||
{
|
||||
DecomposeMatrixToVector(matrixList[i], out positions[i], out rotations[i], out scales[i]);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DecomposeMatrixListAsSpan(ReadOnlySpan<float4x4> matrixList, Span<Vector3> positions, Span<Quaternion> rotations, Span<Vector3> scales)
|
||||
{
|
||||
if (matrixList.Length != positions.Length || matrixList.Length != rotations.Length || matrixList.Length != scales.Length)
|
||||
{
|
||||
throw new ArgumentException("The length of the spans must match the number of matrices in the list.");
|
||||
}
|
||||
|
||||
for (var i = 0; i < matrixList.Length; i++)
|
||||
{
|
||||
DecomposeMatrixToVector(matrixList[i], out positions[i], out rotations[i], out scales[i]);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DecomposeMatrixListAsSpan(ReadOnlySpan<PointData> matrixList, Span<Vector3> positions, Span<Quaternion> rotations, Span<Vector3> scales)
|
||||
{
|
||||
if (matrixList.Length != positions.Length || matrixList.Length != rotations.Length || matrixList.Length != scales.Length)
|
||||
{
|
||||
throw new ArgumentException("The length of the spans must match the number of matrices in the list.");
|
||||
}
|
||||
|
||||
for (var i = 0; i < matrixList.Length; i++)
|
||||
{
|
||||
DecomposeMatrixToVector(matrixList[i].matrix, out positions[i], out rotations[i], out scales[i]);
|
||||
}
|
||||
}
|
||||
|
||||
internal static float3 GetScale(this float4x4 matrix)
|
||||
{
|
||||
return new float3(math.length(matrix.c0.xyz), math.length(matrix.c1.xyz), math.length(matrix.c2.xyz));
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Helper/MatrixHelper.cs.meta
Normal file
2
Runtime/Cloner/Helper/MatrixHelper.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d449f80c59d696f4d8cabfff475f3b7b
|
||||
55
Runtime/Cloner/Helper/ShapeHelper.cs
Normal file
55
Runtime/Cloner/Helper/ShapeHelper.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
internal static class ShapeHelper
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static float Linear01DistanceToSphereCenter(float3 pointPosition, float3 spherePosition, float3 sphereSize)
|
||||
{
|
||||
var x = (pointPosition.x - spherePosition.x) / sphereSize.x;
|
||||
var y = (pointPosition.y - spherePosition.y) / sphereSize.y;
|
||||
var z = (pointPosition.z - spherePosition.z) / sphereSize.z;
|
||||
|
||||
var normalizedDistance = math.sqrt(x * x + y * y + z * z);
|
||||
|
||||
return math.saturate(normalizedDistance);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static bool IsInsideSphere(float3 pointPosition, float3 spherePosition, float3 sphereSize)
|
||||
{
|
||||
sphereSize /= 2.0f;
|
||||
|
||||
var x = (pointPosition.x - spherePosition.x) / sphereSize.x;
|
||||
var y = (pointPosition.y - spherePosition.y) / sphereSize.y;
|
||||
var z = (pointPosition.z - spherePosition.z) / sphereSize.z;
|
||||
|
||||
return (x * x + y * y + z * z) <= 1.0f;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static bool IsInsideCylinder(float3 pointPosition, float3 cylinderPosition, float3 cylinderSize)
|
||||
{
|
||||
cylinderSize /= 2.0f;
|
||||
|
||||
var dx = (pointPosition.x - cylinderPosition.x) / cylinderSize.x;
|
||||
var dz = (pointPosition.z - cylinderPosition.z) / cylinderSize.z;
|
||||
var distanceSquared = dx * dx + dz * dz;
|
||||
|
||||
var withinRadius = distanceSquared <= 1.0f;
|
||||
|
||||
var withinHeight = pointPosition.y >= (cylinderPosition.y - cylinderSize.y) && pointPosition.y <= (cylinderPosition.y + cylinderSize.y);
|
||||
|
||||
return withinRadius && withinHeight;
|
||||
}
|
||||
|
||||
internal static bool IsInsideMesh(float3 pointPosition, float3 meshPosition, Mesh mesh)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Helper/ShapeHelper.cs.meta
Normal file
2
Runtime/Cloner/Helper/ShapeHelper.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11f9c68bdb3ebfa479f602ac3a988abe
|
||||
8
Runtime/Cloner/Jobs.meta
Normal file
8
Runtime/Cloner/Jobs.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e5501834c64c7945bf21962f03f129e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
78
Runtime/Cloner/Jobs/PointsGenerationJob.cs
Normal file
78
Runtime/Cloner/Jobs/PointsGenerationJob.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
public struct PointsGenerationJob : IJobParallelForBatch
|
||||
{
|
||||
public float4x4 worldMatrix;
|
||||
|
||||
public DistributionMode distributionMode;
|
||||
|
||||
public GridDistributionSetting gridDistributionSetting;
|
||||
|
||||
[WriteOnly]
|
||||
public NativeArray<float4x4> points;
|
||||
|
||||
public void Execute(int startIndex, int count)
|
||||
{
|
||||
switch (distributionMode)
|
||||
{
|
||||
case DistributionMode.Object:
|
||||
break;
|
||||
case DistributionMode.Linear:
|
||||
break;
|
||||
case DistributionMode.Grid:
|
||||
GridDistribution(startIndex, count);
|
||||
break;
|
||||
case DistributionMode.Radial:
|
||||
break;
|
||||
case DistributionMode.Honeycomb:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void GridDistribution(int startIndex, int count)
|
||||
{
|
||||
var xIndex = 0;
|
||||
var yIndex = 0;
|
||||
var zIndex = 0;
|
||||
|
||||
switch (gridDistributionSetting.shape)
|
||||
{
|
||||
case GridShape.Cube:
|
||||
|
||||
for (var i = startIndex; i < startIndex + count; i++)
|
||||
{
|
||||
yIndex = i / (gridDistributionSetting.count.x * gridDistributionSetting.count.z);
|
||||
var remain = i % (gridDistributionSetting.count.x * gridDistributionSetting.count.z);
|
||||
zIndex = remain / gridDistributionSetting.count.x;
|
||||
xIndex = remain % gridDistributionSetting.count.x;
|
||||
|
||||
var localPosition = new float3(xIndex * gridDistributionSetting.spacing.x, yIndex * gridDistributionSetting.spacing.y, zIndex * gridDistributionSetting.spacing.z);
|
||||
|
||||
localPosition.x -= (gridDistributionSetting.count.x - 1) * gridDistributionSetting.spacing.x / 2.0f;
|
||||
localPosition.y -= (gridDistributionSetting.count.y - 1) * gridDistributionSetting.spacing.y / 2.0f;
|
||||
localPosition.z -= (gridDistributionSetting.count.z - 1) * gridDistributionSetting.spacing.z / 2.0f;
|
||||
|
||||
var localMatrix = float4x4.TRS(localPosition, quaternion.identity, new float3(1.0f));
|
||||
|
||||
points[i] = math.mul(worldMatrix, localMatrix);
|
||||
}
|
||||
|
||||
break;
|
||||
case GridShape.Sphere:
|
||||
break;
|
||||
case GridShape.Cylinder:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Jobs/PointsGenerationJob.cs.meta
Normal file
2
Runtime/Cloner/Jobs/PointsGenerationJob.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3b40b764e1a7ee4cb60606f02dce34b
|
||||
24
Runtime/Cloner/Jobs/TransformAccessJob.cs
Normal file
24
Runtime/Cloner/Jobs/TransformAccessJob.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine.Jobs;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public struct TransformAccessJob : IJobParallelForTransform
|
||||
{
|
||||
public NativeArray<float4x4> points;
|
||||
|
||||
public void Execute(int index, TransformAccess transform)
|
||||
{
|
||||
if (index > points.Length || !transform.isValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MatrixHelper.DecomposeMatrix(points[index], out var position, out var rotation, out var scale);
|
||||
|
||||
transform.SetPositionAndRotation(position, rotation);
|
||||
transform.localScale = scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Jobs/TransformAccessJob.cs.meta
Normal file
2
Runtime/Cloner/Jobs/TransformAccessJob.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 56503ea812e8e9042aa36b3b6af0a9f7
|
||||
8
Runtime/Cloner/Models.meta
Normal file
8
Runtime/Cloner/Models.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d9a05cd9824f9c4f8cfb39eac01ff1c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Runtime/Cloner/Models/DistributionSetting.meta
Normal file
8
Runtime/Cloner/Models/DistributionSetting.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9634875f0aceb38448a7d6d08aca0386
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
[Serializable]
|
||||
public class GridDistributionSetting
|
||||
{
|
||||
public int3 count = new(3, 3, 3);
|
||||
public float3 spacing = new(1.0f, 1.0f, 1.0f);
|
||||
public GridShape shape;
|
||||
[Range(0.0f, 1.0f)]
|
||||
public float fill = 1.0f;
|
||||
|
||||
public int DistributionCount => count.x * count.y * count.z;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 117719617fb15994790913adcb8392ad
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
[Serializable]
|
||||
public class LinearDistributionSetting
|
||||
{
|
||||
public uint count = 10;
|
||||
public uint indexOffset = 0;
|
||||
|
||||
public float3 positionSpacing = new(0.0f, 1.0f, 0.0f);
|
||||
public float3 rotationSpacing = float3.zero;
|
||||
public float3 scaleSpacing = new(1.0f, 1.0f, 1.0f);
|
||||
|
||||
public float3 stepRotation = float3.zero;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e489bd7add88acc4cb2bf8c30c851653
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
[Serializable]
|
||||
public struct ObjectDistributionSetting
|
||||
{
|
||||
public MeshFilter meshFilter;
|
||||
public int count;
|
||||
public bool alignNormal;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 818f2d0001f1e8f439e23e34ed6ae898
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Splines;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
[Serializable]
|
||||
public class SplineDistributionSetting
|
||||
{
|
||||
public SplineContainer spline;
|
||||
|
||||
public int indexOffset;
|
||||
|
||||
public uint count = 10;
|
||||
public float spacing = 1.0f;
|
||||
|
||||
public bool isSpacingMode;
|
||||
|
||||
public int DistributionCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (isSpacingMode)
|
||||
{
|
||||
return Mathf.RoundToInt(spline.CalculateLength() / spacing) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b5cfd6221b6b9a45bba99cefb806ccc
|
||||
11
Runtime/Cloner/Models/EffectorData.cs
Normal file
11
Runtime/Cloner/Models/EffectorData.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
[Serializable]
|
||||
public class EffectorData
|
||||
{
|
||||
public bool enable = true;
|
||||
public EffectorBase effector;
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Models/EffectorData.cs.meta
Normal file
2
Runtime/Cloner/Models/EffectorData.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e8152eaeb656654cbbe7859b44b12bf
|
||||
13
Runtime/Cloner/Models/FieldData.cs
Normal file
13
Runtime/Cloner/Models/FieldData.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
[Serializable]
|
||||
public class FieldData
|
||||
{
|
||||
public bool enable = true;
|
||||
public FieldBase field;
|
||||
public BlendingMode blending;
|
||||
public float opacity = 1.0f;
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Models/FieldData.cs.meta
Normal file
2
Runtime/Cloner/Models/FieldData.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73bd368d309049d42be068896e7c1a58
|
||||
41
Runtime/Cloner/Models/InputObjectData.cs
Normal file
41
Runtime/Cloner/Models/InputObjectData.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
[Serializable]
|
||||
public class InputObjectData
|
||||
{
|
||||
public GameObject gameObject;
|
||||
public uint frequency = 1;
|
||||
|
||||
private Mesh _mesh;
|
||||
public Mesh Mesh
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_mesh == null)
|
||||
{
|
||||
_mesh = gameObject.GetComponentInChildren<MeshFilter>().sharedMesh;
|
||||
}
|
||||
|
||||
return _mesh;
|
||||
}
|
||||
}
|
||||
|
||||
private Material _material;
|
||||
public Material Material
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_material == null)
|
||||
{
|
||||
_material = gameObject.GetComponentInChildren<MeshRenderer>().sharedMaterial;
|
||||
_material.enableInstancing = true;
|
||||
}
|
||||
|
||||
return _material;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Models/InputObjectData.cs.meta
Normal file
2
Runtime/Cloner/Models/InputObjectData.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 852b6e461bca6b64e9e2cb2735de1a19
|
||||
31
Runtime/Cloner/Models/ObjectIdInfo.cs
Normal file
31
Runtime/Cloner/Models/ObjectIdInfo.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
public struct ObjectIdInfo : IDisposable
|
||||
{
|
||||
public NativeArray<int> instanceIdArray;
|
||||
public NativeArray<int> transformIdArray;
|
||||
|
||||
public bool IsCreated
|
||||
{
|
||||
get
|
||||
{
|
||||
return instanceIdArray.IsCreated && transformIdArray.IsCreated;
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectIdInfo(int size)
|
||||
{
|
||||
instanceIdArray = new(size, Allocator.Persistent);
|
||||
transformIdArray = new(size, Allocator.Persistent);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
instanceIdArray.Dispose();
|
||||
transformIdArray.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Models/ObjectIdInfo.cs.meta
Normal file
2
Runtime/Cloner/Models/ObjectIdInfo.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 198d97e9fb629864b910011c81d94375
|
||||
12
Runtime/Cloner/Models/PointData.cs
Normal file
12
Runtime/Cloner/Models/PointData.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
[Serializable]
|
||||
public struct PointData
|
||||
{
|
||||
public bool isValid;
|
||||
public float4x4 matrix;
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Models/PointData.cs.meta
Normal file
2
Runtime/Cloner/Models/PointData.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94a436dd2ba363746abf1f24efd1d021
|
||||
18
Runtime/Cloner/Models/RemappingSetting.cs
Normal file
18
Runtime/Cloner/Models/RemappingSetting.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace Misaki.ArtTool
|
||||
{
|
||||
[Serializable]
|
||||
public class RemappingSetting
|
||||
{
|
||||
public bool enable = true;
|
||||
|
||||
public float strength = 1.0f;
|
||||
public bool invert = false;
|
||||
|
||||
public float innerOffset = 0.0f;
|
||||
|
||||
public float min = 0.0f;
|
||||
public float max = 1.0f;
|
||||
}
|
||||
}
|
||||
2
Runtime/Cloner/Models/RemappingSetting.cs.meta
Normal file
2
Runtime/Cloner/Models/RemappingSetting.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 404cd8f4b1af1114aaa5dae86d4a9123
|
||||
Reference in New Issue
Block a user