Update effector base and push apart effector

This commit is contained in:
Misaki
2024-09-16 22:17:03 +09:00
parent 8374938734
commit 1c39403cbf
12 changed files with 167 additions and 103 deletions

View File

@@ -22,9 +22,9 @@ namespace Misaki.ArtTool
public bool autoGenerate;
public bool isRenderInstancing;
public SplineDistributionSetting splineDistributionSetting = new();
public LinearDistributionSetting linearDistributionSetting = new();
public GridDistributionSetting gridDistributionSetting = new();
public SplineDistributionSetting splineDistributionSetting;
public LinearDistributionSetting linearDistributionSetting;
public GridDistributionSetting gridDistributionSetting;
public List<EffectorData> effectors;
@@ -161,16 +161,15 @@ namespace Misaki.ArtTool
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;
splineDistributionSetting.splineWorldMatrix = splineDistributionSetting.spline.transform.localToWorldMatrix;
splineDistributionSetting.splineLength = splineDistributionSetting.spline.CalculateLength();
}
var worldMatrix = transform.localToWorldMatrix;
Parallel.For(0, _pointSize, i =>
//for (var i = 0; i < _pointSize; i++)
{
var pointMatrix = float4x4.identity;
var isValid = true;
@@ -179,7 +178,7 @@ namespace Misaki.ArtTool
case DistributionMode.Object:
break;
case DistributionMode.Spline:
Distribution.SplineDistribution(i, _pointSize, splineLength, splineMatrix, splineDistributionSetting, out pointMatrix, out isValid);
Distribution.SplineDistribution(i, _pointSize, splineDistributionSetting, out pointMatrix, out isValid);
break;
case DistributionMode.Linear:
Distribution.LinearDistribution(i, linearDistributionSetting, out pointMatrix, out isValid);
@@ -199,8 +198,31 @@ namespace Misaki.ArtTool
_points[i].matrix = pointMatrix;
_points[i].isValid = isValid;
//}
});
//var pointsArray = new NativeArray<PointData>(_pointSize, Allocator.Temp);
//var pointsGenerationJob = new PointsGenerationJob()
//{
// worldMatrix = worldMatrix,
// pointSize = _pointSize,
// distributionMode = distributionMode,
// splineDistributionSetting = splineDistributionSetting,
// linearDistributionSetting = linearDistributionSetting,
// gridDistributionSetting = gridDistributionSetting,
// points = pointsArray
//};
//var handle = pointsGenerationJob.ScheduleBatch(_pointSize, 64);
//handle.Complete();
//pointsArray.CopyTo(_points);
//pointsArray.Dispose();
Parallel.For(0, _pointSize, i =>
{
for (var e = 0; e < effectors.Count; e++)
@@ -215,7 +237,7 @@ namespace Misaki.ArtTool
continue;
}
effectors[e].effector.Operate(i, worldMatrix, _points, ref _points[i].matrix, ref _points[i].isValid);
effectors[e].effector.Operate(i, worldMatrix, _points);
}
if (math.all(_points[i].matrix.GetScale() == float3.zero))
@@ -344,7 +366,7 @@ namespace Misaki.ArtTool
public void Clear(bool isClearPoints = true, bool isClearObjects = true)
{
if (isClearPoints)
if (isClearPoints && _points != null)
{
_pointPool.Return(_points, true);
}

View File

@@ -56,7 +56,7 @@ namespace Misaki.ArtTool
effectorMatrix = transform.localToWorldMatrix;
}
public virtual void Operate(int index, float4x4 nodeWorldMatrix, ReadOnlySpan<PointData> points, ref float4x4 pointWorldMatrix, ref bool isValid)
public virtual void Operate(int index, float4x4 nodeWorldMatrix, Span<PointData> points)
{
}

View File

@@ -5,11 +5,10 @@ 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)
public static void SplineDistribution(int index, int pointSize, SplineDistributionSetting setting, out float4x4 localMatrix, out bool isValid)
{
var pointIndex = index + setting.indexOffset;
if (pointIndex > pointSize)
{
localMatrix = float4x4.zero;
@@ -23,7 +22,7 @@ namespace Misaki.ArtTool
if (setting.isSpacingMode)
{
t = (pointIndex * setting.spacing) / splineLength;
t = (pointIndex * setting.spacing) / setting.splineLength;
}
else
{
@@ -34,7 +33,7 @@ namespace Misaki.ArtTool
{
var localRotation = quaternion.LookRotationSafe(normal, upVector);
localMatrix = math.mul(splineWorldMatrix, float4x4.TRS(position, localRotation, new float3(1.0f)));
localMatrix = math.mul(setting.splineWorldMatrix, float4x4.TRS(position, localRotation, new float3(1.0f)));
isValid = true;
}
else

View File

@@ -21,16 +21,18 @@ namespace Misaki.ArtTool
public float3 scale;
public float uniformScale;
public override void Operate(int index, float4x4 nodeWorldMatrix, ReadOnlySpan<PointData> points, ref float4x4 pointWorldMatrix, ref bool isValid)
public override void Operate(int index, float4x4 nodeWorldMatrix, Span<PointData> points)
{
if (!isEnablePosition && !isEnableRotation && !isEnableScale)
{
return;
}
MatrixHelper.DecomposeMatrix(pointWorldMatrix, out var position, out var rotation, out var scale);
var currentPoint = points[index];
var weight = CalculateFieldsWeight(pointWorldMatrix.c3.xyz);
MatrixHelper.DecomposeMatrix(currentPoint.matrix, out var position, out var rotation, out var scale);
var weight = CalculateFieldsWeight(position);
if (weight == 0)
{
return;
@@ -48,7 +50,7 @@ namespace Misaki.ArtTool
newPosition += math.mul(effectorMatrix, new float4(this.position, 0)).xyz;
break;
case TransformSpace.Object:
newPosition += math.mul(pointWorldMatrix, new float4(this.position, 0)).xyz;
newPosition += math.mul(currentPoint.matrix, new float4(this.position, 0)).xyz;
break;
default:
break;
@@ -70,7 +72,7 @@ namespace Misaki.ArtTool
break;
case TransformSpace.Object:
newRotation = math.mul(rotation,
quaternion.EulerXYZ(math.mul(pointWorldMatrix, new float4(math.radians(this.rotation), 0)).xyz));
quaternion.EulerXYZ(math.mul(currentPoint.matrix, new float4(math.radians(this.rotation), 0)).xyz));
break;
default:
break;
@@ -92,7 +94,9 @@ namespace Misaki.ArtTool
scale = math.lerp(scale, newScale, weight);
}
pointWorldMatrix = float4x4.TRS(position, rotation, scale);
currentPoint.matrix = float4x4.TRS(position, rotation, scale);
points[index] = currentPoint;
}
}
}

View File

@@ -7,13 +7,14 @@ namespace Misaki.ArtTool
{
public float radius = 1.0f;
public uint iteration = 10;
public bool isHideMode = false;
// 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)
public override void Operate(int index, float4x4 nodeWorldMatrix, Span<PointData> points)
{
var currentPoint = points[index];
var weight = CalculateFieldsWeight(pointWorldMatrix.c3.xyz);
var weight = CalculateFieldsWeight(currentPoint.matrix.c3.xyz);
if (weight == 0)
{
return;
@@ -23,21 +24,26 @@ namespace Misaki.ArtTool
{
for (var p = 0; p < points.Length; p++)
{
var targetPoint = points[p];
if (ReferenceEquals(currentPoint, targetPoint))
if (index == p)
{
continue;
}
var targetPoint = points[p];
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;
currentPoint.matrix.c3.xyz += (radius - distance) * weight * direction;
//Debug.Log($"Push at index {index} with distance {radius - distance} and direction {direction}");
}
}
}
points[index] = currentPoint;
}
}
}

View File

@@ -26,13 +26,15 @@ namespace Misaki.ArtTool
public float3 scaleMinMax;
public float uniformScaleMinMax;
public override void Operate(int index, float4x4 nodeWorldMatrix, ReadOnlySpan<PointData> points, ref float4x4 pointWorldMatrix, ref bool isValid)
public override void Operate(int index, float4x4 nodeWorldMatrix, Span<PointData> points)
{
if (!isEnablePosition && !isEnableRotation && !isEnableScale)
{
return;
}
var currentPoint = points[index];
Random random;
if (synchronized)
{
@@ -50,9 +52,9 @@ namespace Misaki.ArtTool
}
}
MatrixHelper.DecomposeMatrix(pointWorldMatrix, out var position, out var rotation, out var scale);
MatrixHelper.DecomposeMatrix(currentPoint.matrix, out var position, out var rotation, out var scale);
var weight = CalculateFieldsWeight(pointWorldMatrix.c3.xyz);
var weight = CalculateFieldsWeight(position);
if (weight == 0)
{
return;
@@ -68,7 +70,7 @@ namespace Misaki.ArtTool
newPosition = math.mul(effectorMatrix, new float4(newPosition, 0.0f)).xyz;
break;
case TransformSpace.Object:
newPosition = math.mul(pointWorldMatrix, new float4(newPosition, 0.0f)).xyz;
newPosition = math.mul(currentPoint.matrix, new float4(newPosition, 0.0f)).xyz;
break;
default:
break;
@@ -86,7 +88,7 @@ namespace Misaki.ArtTool
angle = math.mul(effectorMatrix, new float4(angle, 0.0f)).xyz;
break;
case TransformSpace.Object:
angle = math.mul(pointWorldMatrix, new float4(angle, 0.0f)).xyz;
angle = math.mul(currentPoint.matrix, new float4(angle, 0.0f)).xyz;
break;
default:
break;
@@ -117,7 +119,9 @@ namespace Misaki.ArtTool
scale = math.lerp(scale, scale + newScale, weight);
}
pointWorldMatrix = float4x4.TRS(position, rotation, scale);
currentPoint.matrix = float4x4.TRS(position, rotation, scale);
points[index] = currentPoint;
}
}
}

View File

@@ -9,70 +9,54 @@ namespace Misaki.ArtTool
public struct PointsGenerationJob : IJobParallelForBatch
{
public float4x4 worldMatrix;
public int pointSize;
public DistributionMode distributionMode;
public SplineDistributionSetting splineDistributionSetting;
public LinearDistributionSetting linearDistributionSetting;
public GridDistributionSetting gridDistributionSetting;
[WriteOnly]
public NativeArray<float4x4> points;
public NativeArray<PointData> points;
public void Execute(int startIndex, int count)
{
switch (distributionMode)
for (var i = startIndex; i < startIndex + count; i++)
{
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;
var pointMatrix = float4x4.identity;
var isValid = true;
switch (distributionMode)
{
case DistributionMode.Object:
break;
case DistributionMode.Spline:
Distribution.SplineDistribution(i, pointSize, 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] = new PointData()
{
matrix = pointMatrix,
isValid = isValid
};
}
}
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;
}
}
}
}

View File

@@ -5,14 +5,14 @@ using UnityEngine;
namespace Misaki.ArtTool
{
[Serializable]
public class GridDistributionSetting
public struct GridDistributionSetting
{
public int3 count = new(3, 3, 3);
public float3 spacing = new(1.0f, 1.0f, 1.0f);
public int3 count;
public float3 spacing;
public GridShape shape;
[Range(0.0f, 1.0f)]
public float fill = 1.0f;
public float fill;
public int DistributionCount => count.x * count.y * count.z;
public readonly int DistributionCount => count.x * count.y * count.z;
}
}

View File

@@ -4,15 +4,15 @@ using Unity.Mathematics;
namespace Misaki.ArtTool
{
[Serializable]
public class LinearDistributionSetting
public struct LinearDistributionSetting
{
public uint count = 10;
public uint indexOffset = 0;
public uint count;
public uint indexOffset;
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 positionSpacing;
public float3 rotationSpacing;
public float3 scaleSpacing;
public float3 stepRotation = float3.zero;
public float3 stepRotation;
}
}

View File

@@ -1,28 +1,39 @@
using System;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Splines;
namespace Misaki.ArtTool
{
[Serializable]
public class SplineDistributionSetting
public struct SplineDistributionSetting
{
public SplineContainer spline;
public int indexOffset;
public uint count = 10;
public float spacing = 1.0f;
public uint count;
public float spacing;
public bool isSpacingMode;
[HideInInspector]
public float4x4 splineWorldMatrix;
[HideInInspector]
public float splineLength;
public int DistributionCount
{
get
{
if (spline == null)
{
return 0;
}
if (isSpacingMode)
{
return Mathf.RoundToInt(spline.CalculateLength() / spacing) + 1;
return Mathf.FloorToInt(spline.CalculateLength() / spacing) + 1;
}
else
{

View File

@@ -4,9 +4,38 @@ using Unity.Mathematics;
namespace Misaki.ArtTool
{
[Serializable]
public struct PointData
public struct PointData : IEquatable<PointData>
{
public bool isValid;
public float4x4 matrix;
public bool Equals(PointData other)
{
return isValid == other.isValid && Equals(matrix, other.matrix);
}
public override bool Equals(object obj)
{
if (obj is PointData other)
{
return Equals(other);
}
return false;
}
public override int GetHashCode()
{
return HashCode.Combine(isValid, matrix);
}
public static bool operator ==(PointData left, PointData right)
{
return left.Equals(right);
}
public static bool operator !=(PointData left, PointData right)
{
return !(left == right);
}
}
}
}