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

@@ -14,6 +14,11 @@
<engine:VisualElement> <engine:VisualElement>
<engine:Label text="Parameter" class="SubHeader" /> <engine:Label text="Parameter" class="SubHeader" />
<engine:VisualElement class="PropertyContainer"> <engine:VisualElement class="PropertyContainer">
<engine:DropdownField label="Mode" choices="Push,Hide" index="0">
<Bindings>
<engine:DataBinding property="index" data-source-path="isHideMode" binding-mode="TwoWay" />
</Bindings>
</engine:DropdownField>
<engine:FloatField label="Radius" value="1"> <engine:FloatField label="Radius" value="1">
<Bindings> <Bindings>
<engine:DataBinding property="value" data-source-path="radius" binding-mode="TwoWay" /> <engine:DataBinding property="value" data-source-path="radius" binding-mode="TwoWay" />

View File

@@ -22,9 +22,9 @@ namespace Misaki.ArtTool
public bool autoGenerate; public bool autoGenerate;
public bool isRenderInstancing; public bool isRenderInstancing;
public SplineDistributionSetting splineDistributionSetting = new(); public SplineDistributionSetting splineDistributionSetting;
public LinearDistributionSetting linearDistributionSetting = new(); public LinearDistributionSetting linearDistributionSetting;
public GridDistributionSetting gridDistributionSetting = new(); public GridDistributionSetting gridDistributionSetting;
public List<EffectorData> effectors; public List<EffectorData> effectors;
@@ -161,16 +161,15 @@ namespace Misaki.ArtTool
effectorData.effector.Initialize(); effectorData.effector.Initialize();
} }
var splineLength = 0.0f;
var splineMatrix = float4x4.identity;
if (distributionMode == DistributionMode.Spline && splineDistributionSetting.spline != null) if (distributionMode == DistributionMode.Spline && splineDistributionSetting.spline != null)
{ {
splineLength = splineDistributionSetting.spline.CalculateLength(); splineDistributionSetting.splineWorldMatrix = splineDistributionSetting.spline.transform.localToWorldMatrix;
splineMatrix = splineDistributionSetting.spline.transform.localToWorldMatrix; splineDistributionSetting.splineLength = splineDistributionSetting.spline.CalculateLength();
} }
var worldMatrix = transform.localToWorldMatrix; var worldMatrix = transform.localToWorldMatrix;
Parallel.For(0, _pointSize, i => Parallel.For(0, _pointSize, i =>
//for (var i = 0; i < _pointSize; i++)
{ {
var pointMatrix = float4x4.identity; var pointMatrix = float4x4.identity;
var isValid = true; var isValid = true;
@@ -179,7 +178,7 @@ namespace Misaki.ArtTool
case DistributionMode.Object: case DistributionMode.Object:
break; break;
case DistributionMode.Spline: case DistributionMode.Spline:
Distribution.SplineDistribution(i, _pointSize, splineLength, splineMatrix, splineDistributionSetting, out pointMatrix, out isValid); Distribution.SplineDistribution(i, _pointSize, splineDistributionSetting, out pointMatrix, out isValid);
break; break;
case DistributionMode.Linear: case DistributionMode.Linear:
Distribution.LinearDistribution(i, linearDistributionSetting, out pointMatrix, out isValid); Distribution.LinearDistribution(i, linearDistributionSetting, out pointMatrix, out isValid);
@@ -199,8 +198,31 @@ namespace Misaki.ArtTool
_points[i].matrix = pointMatrix; _points[i].matrix = pointMatrix;
_points[i].isValid = isValid; _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 => Parallel.For(0, _pointSize, i =>
{ {
for (var e = 0; e < effectors.Count; e++) for (var e = 0; e < effectors.Count; e++)
@@ -215,7 +237,7 @@ namespace Misaki.ArtTool
continue; 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)) 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) public void Clear(bool isClearPoints = true, bool isClearObjects = true)
{ {
if (isClearPoints) if (isClearPoints && _points != null)
{ {
_pointPool.Return(_points, true); _pointPool.Return(_points, true);
} }

View File

@@ -56,7 +56,7 @@ namespace Misaki.ArtTool
effectorMatrix = transform.localToWorldMatrix; 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 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; var pointIndex = index + setting.indexOffset;
if (pointIndex > pointSize) if (pointIndex > pointSize)
{ {
localMatrix = float4x4.zero; localMatrix = float4x4.zero;
@@ -23,7 +22,7 @@ namespace Misaki.ArtTool
if (setting.isSpacingMode) if (setting.isSpacingMode)
{ {
t = (pointIndex * setting.spacing) / splineLength; t = (pointIndex * setting.spacing) / setting.splineLength;
} }
else else
{ {
@@ -34,7 +33,7 @@ namespace Misaki.ArtTool
{ {
var localRotation = quaternion.LookRotationSafe(normal, upVector); 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; isValid = true;
} }
else else

View File

@@ -21,16 +21,18 @@ namespace Misaki.ArtTool
public float3 scale; public float3 scale;
public float uniformScale; 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) if (!isEnablePosition && !isEnableRotation && !isEnableScale)
{ {
return; 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) if (weight == 0)
{ {
return; return;
@@ -48,7 +50,7 @@ namespace Misaki.ArtTool
newPosition += math.mul(effectorMatrix, new float4(this.position, 0)).xyz; newPosition += math.mul(effectorMatrix, new float4(this.position, 0)).xyz;
break; break;
case TransformSpace.Object: 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; break;
default: default:
break; break;
@@ -70,7 +72,7 @@ namespace Misaki.ArtTool
break; break;
case TransformSpace.Object: case TransformSpace.Object:
newRotation = math.mul(rotation, 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; break;
default: default:
break; break;
@@ -92,7 +94,9 @@ namespace Misaki.ArtTool
scale = math.lerp(scale, newScale, weight); 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 float radius = 1.0f;
public uint iteration = 10; public uint iteration = 10;
public bool isHideMode = false;
// TODO: Average the push direction and distance of each point for more consistence result // 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 currentPoint = points[index];
var weight = CalculateFieldsWeight(pointWorldMatrix.c3.xyz); var weight = CalculateFieldsWeight(currentPoint.matrix.c3.xyz);
if (weight == 0) if (weight == 0)
{ {
return; return;
@@ -23,21 +24,26 @@ namespace Misaki.ArtTool
{ {
for (var p = 0; p < points.Length; p++) for (var p = 0; p < points.Length; p++)
{ {
var targetPoint = points[p]; if (index == p)
if (ReferenceEquals(currentPoint, targetPoint))
{ {
continue; continue;
} }
var targetPoint = points[p];
var distance = math.distance(currentPoint.matrix.c3.xyz, targetPoint.matrix.c3.xyz); var distance = math.distance(currentPoint.matrix.c3.xyz, targetPoint.matrix.c3.xyz);
if (distance < radius) if (distance < radius)
{ {
var direction = math.normalizesafe(currentPoint.matrix.c3.xyz - targetPoint.matrix.c3.xyz); 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 float3 scaleMinMax;
public float uniformScaleMinMax; 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) if (!isEnablePosition && !isEnableRotation && !isEnableScale)
{ {
return; return;
} }
var currentPoint = points[index];
Random random; Random random;
if (synchronized) 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) if (weight == 0)
{ {
return; return;
@@ -68,7 +70,7 @@ namespace Misaki.ArtTool
newPosition = math.mul(effectorMatrix, new float4(newPosition, 0.0f)).xyz; newPosition = math.mul(effectorMatrix, new float4(newPosition, 0.0f)).xyz;
break; break;
case TransformSpace.Object: 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; break;
default: default:
break; break;
@@ -86,7 +88,7 @@ namespace Misaki.ArtTool
angle = math.mul(effectorMatrix, new float4(angle, 0.0f)).xyz; angle = math.mul(effectorMatrix, new float4(angle, 0.0f)).xyz;
break; break;
case TransformSpace.Object: 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; break;
default: default:
break; break;
@@ -117,7 +119,9 @@ namespace Misaki.ArtTool
scale = math.lerp(scale, scale + newScale, weight); 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,24 +9,35 @@ namespace Misaki.ArtTool
public struct PointsGenerationJob : IJobParallelForBatch public struct PointsGenerationJob : IJobParallelForBatch
{ {
public float4x4 worldMatrix; public float4x4 worldMatrix;
public int pointSize;
public DistributionMode distributionMode; public DistributionMode distributionMode;
public SplineDistributionSetting splineDistributionSetting;
public LinearDistributionSetting linearDistributionSetting;
public GridDistributionSetting gridDistributionSetting; public GridDistributionSetting gridDistributionSetting;
[WriteOnly] [WriteOnly]
public NativeArray<float4x4> points; public NativeArray<PointData> points;
public void Execute(int startIndex, int count) public void Execute(int startIndex, int count)
{ {
for (var i = startIndex; i < startIndex + count; i++)
{
var pointMatrix = float4x4.identity;
var isValid = true;
switch (distributionMode) switch (distributionMode)
{ {
case DistributionMode.Object: case DistributionMode.Object:
break; break;
case DistributionMode.Spline:
Distribution.SplineDistribution(i, pointSize, splineDistributionSetting, out pointMatrix, out isValid);
break;
case DistributionMode.Linear: case DistributionMode.Linear:
Distribution.LinearDistribution(i, linearDistributionSetting, out pointMatrix, out isValid);
break; break;
case DistributionMode.Grid: case DistributionMode.Grid:
GridDistribution(startIndex, count); Distribution.GridDistribution(i, gridDistributionSetting, out pointMatrix, out isValid);
break; break;
case DistributionMode.Radial: case DistributionMode.Radial:
break; break;
@@ -35,44 +46,17 @@ namespace Misaki.ArtTool
default: default:
break; break;
} }
}
private void GridDistribution(int startIndex, int count) pointMatrix = math.mul(worldMatrix, pointMatrix);
points[i] = new PointData()
{ {
var xIndex = 0; matrix = pointMatrix,
var yIndex = 0; isValid = isValid
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 namespace Misaki.ArtTool
{ {
[Serializable] [Serializable]
public class GridDistributionSetting public struct GridDistributionSetting
{ {
public int3 count = new(3, 3, 3); public int3 count;
public float3 spacing = new(1.0f, 1.0f, 1.0f); public float3 spacing;
public GridShape shape; public GridShape shape;
[Range(0.0f, 1.0f)] [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 namespace Misaki.ArtTool
{ {
[Serializable] [Serializable]
public class LinearDistributionSetting public struct LinearDistributionSetting
{ {
public uint count = 10; public uint count;
public uint indexOffset = 0; public uint indexOffset;
public float3 positionSpacing = new(0.0f, 1.0f, 0.0f); public float3 positionSpacing;
public float3 rotationSpacing = float3.zero; public float3 rotationSpacing;
public float3 scaleSpacing = new(1.0f, 1.0f, 1.0f); public float3 scaleSpacing;
public float3 stepRotation = float3.zero; public float3 stepRotation;
} }
} }

View File

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

View File

@@ -4,9 +4,38 @@ using Unity.Mathematics;
namespace Misaki.ArtTool namespace Misaki.ArtTool
{ {
[Serializable] [Serializable]
public struct PointData public struct PointData : IEquatable<PointData>
{ {
public bool isValid; public bool isValid;
public float4x4 matrix; 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);
}
} }
} }