Switch points generation from managed thread to unmanaged thread; Change Spline to NativeSpline; Add converter for DistributionMode and update cloner editor ui; Add MeshData type for object distribution calculation; Add ObjectDistributionSetting and ObjectDistributionCalculation(Vertex and Edge Mode);

This commit is contained in:
Misaki
2024-09-17 18:27:35 +09:00
parent 1c39403cbf
commit 0ae44d6139
23 changed files with 559 additions and 148 deletions

View File

@@ -3,10 +3,13 @@ using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Splines;
using Random = Unity.Mathematics.Random;
namespace Misaki.ArtTool
@@ -22,6 +25,9 @@ namespace Misaki.ArtTool
public bool autoGenerate;
public bool isRenderInstancing;
public MeshFilter inputMeshFilter;
public ObjectDistributionSetting objectDistributionSetting;
public SplineContainer inputSplineContainer;
public SplineDistributionSetting splineDistributionSetting;
public LinearDistributionSetting linearDistributionSetting;
public GridDistributionSetting gridDistributionSetting;
@@ -128,16 +134,37 @@ namespace Misaki.ArtTool
switch (distributionMode)
{
case DistributionMode.Object:
if (inputMeshFilter == null)
{
throw new NullReferenceException();
}
objectDistributionSetting.meshData = new(inputMeshFilter, Allocator.TempJob);
break;
case DistributionMode.Spline:
if (inputSplineContainer == null)
{
throw new NullReferenceException();
}
splineDistributionSetting.splineWorldMatrix = inputSplineContainer.transform.localToWorldMatrix;
splineDistributionSetting.nativeSpline = new(inputSplineContainer.Spline, Allocator.TempJob);
splineDistributionSetting.splineLength = splineDistributionSetting.nativeSpline.CalculateLength(splineDistributionSetting.splineWorldMatrix);
_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:
@@ -146,6 +173,12 @@ namespace Misaki.ArtTool
break;
}
// Allocate a empty native spline to avoid job error
if (distributionMode != DistributionMode.Spline)
{
splineDistributionSetting.nativeSpline = new(new List<BezierKnot>(), false, transform.localToWorldMatrix, Allocator.TempJob);
}
if (_pointSize == 0)
{
return;
@@ -161,68 +194,66 @@ namespace Misaki.ArtTool
effectorData.effector.Initialize();
}
if (distributionMode == DistributionMode.Spline && splineDistributionSetting.spline != null)
{
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;
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].matrix = pointMatrix;
_points[i].isValid = isValid;
//}
});
//var pointsArray = new NativeArray<PointData>(_pointSize, Allocator.Temp);
//var pointsGenerationJob = new PointsGenerationJob()
//Parallel.For(0, _pointSize, i =>
////for (var i = 0; i < _pointSize; i++)
//{
// worldMatrix = worldMatrix,
// pointSize = _pointSize,
// 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;
// }
// distributionMode = distributionMode,
// pointMatrix = math.mul(worldMatrix, pointMatrix);
// splineDistributionSetting = splineDistributionSetting,
// linearDistributionSetting = linearDistributionSetting,
// gridDistributionSetting = gridDistributionSetting,
// _points[i].matrix = pointMatrix;
// _points[i].isValid = isValid;
// //}
//});
// points = pointsArray
//};
// Since NativeSpline is not available in managed thread, we have to use jobs
var pointsArray = new NativeArray<PointData>(_points.Length, Allocator.TempJob);
var pointsGenerationJob = new PointsGenerationJob()
{
worldMatrix = worldMatrix,
pointSize = _pointSize,
//var handle = pointsGenerationJob.ScheduleBatch(_pointSize, 64);
//handle.Complete();
distributionMode = distributionMode,
//pointsArray.CopyTo(_points);
//pointsArray.Dispose();
splineDistributionSetting = splineDistributionSetting,
linearDistributionSetting = linearDistributionSetting,
gridDistributionSetting = gridDistributionSetting,
points = pointsArray
};
var handle = pointsGenerationJob.Schedule(_pointSize, 64);
handle.Complete();
pointsArray.CopyTo(_points);
pointsArray.Dispose();
splineDistributionSetting.nativeSpline.Dispose();
objectDistributionSetting.meshData.Dispose();
// Switch to managed thread for effectors because of interface
Parallel.For(0, _pointSize, i =>
{
for (var e = 0; e < effectors.Count; e++)

View File

@@ -8,7 +8,7 @@ namespace Misaki.ArtTool
{
var random = Random.CreateFromIndex((uint)index);
var localPosition = GetCubePosition(index, setting.count) * setting.spacing;
var localPosition = ShapeHelper.GetCubePosition(index, setting.count) * setting.spacing;
switch (setting.shape)
{
@@ -17,13 +17,13 @@ namespace Misaki.ArtTool
break;
case GridShape.Sphere:
var isInsideSphere = ShapeHelper.IsInsideSphere(localPosition, 0.0f, setting.count * setting.spacing);
var isInsideSphere = ShapeHelper.IsPointInsideSphere(localPosition, 0.0f, setting.count * setting.spacing);
isValid = isInsideSphere;
break;
case GridShape.Cylinder:
var isInsideCylinder = ShapeHelper.IsInsideCylinder(localPosition, 0.0f, setting.count * setting.spacing);
var isInsideCylinder = ShapeHelper.IsPointInsideCylinder(localPosition, 0.0f, setting.count * setting.spacing);
isValid = isInsideCylinder;
break;
default:
@@ -38,18 +38,5 @@ namespace Misaki.ArtTool
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;
}
}
}
}

View File

@@ -0,0 +1,13 @@
using System;
using Unity.Mathematics;
namespace Misaki.ArtTool
{
public static partial class Distribution
{
public static void ObjectDistribution(int index, ObjectDistributionSetting setting, out float4x4 localMatrix, out bool isValid)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0bed43825cb2cca49b6b7adfe693a5e2

View File

@@ -17,7 +17,6 @@ namespace Misaki.ArtTool
return;
}
var spline = setting.spline;
float t;
if (setting.isSpacingMode)
@@ -29,7 +28,7 @@ namespace Misaki.ArtTool
t = pointIndex / (float)(pointSize - 1);
}
if (SplineUtility.Evaluate(spline.Spline, t, out var position, out var normal, out var upVector))
if (SplineUtility.Evaluate(setting.nativeSpline, t, out var position, out var normal, out var upVector))
{
var localRotation = quaternion.LookRotationSafe(normal, upVector);

View File

@@ -0,0 +1,11 @@
namespace Misaki.ArtTool
{
public enum ObjectDistributionMode
{
Surface,
Volume,
Vertex,
Edge,
PolygonCenter
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f378e3924b6a5c34fa1eab8b8c87dc4f

View File

@@ -11,7 +11,6 @@ namespace Misaki.ArtTool
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));
@@ -19,7 +18,6 @@ namespace Misaki.ArtTool
var inverseBoolToDisplayGroup = new ConverterGroup("InverseBoolToDisplayConverter");
inverseBoolToDisplayGroup.AddConverter((ref bool v) => InverseBoolToDisplayConverter.ConvertTo(v));
inverseBoolToDisplayGroup.AddConverter((ref StyleEnum<DisplayStyle> v) => InverseBoolToDisplayConverter.ConvertBack(v));
@@ -27,7 +25,6 @@ namespace Misaki.ArtTool
var float2ToVector2Group = new ConverterGroup("Float2ToVector2Converter");
float2ToVector2Group.AddConverter((ref float2 v) => Float2ToVector2Converter.ConvertTo(v));
float2ToVector2Group.AddConverter((ref Vector2 v) => Float2ToVector2Converter.ConvertBack(v));
@@ -35,11 +32,50 @@ namespace Misaki.ArtTool
var float3ToVector3Group = new ConverterGroup("Float3ToVector3Converter");
float3ToVector3Group.AddConverter((ref float3 v) => Float3ToVector3Converter.ConvertTo(v));
float3ToVector3Group.AddConverter((ref Vector3 v) => Float3ToVector3Converter.ConvertBack(v));
ConverterGroups.RegisterConverterGroup(float3ToVector3Group);
var int2ToVector2IntGroup = new ConverterGroup("int2ToVector2IntConverter");
int2ToVector2IntGroup.AddConverter((ref int2 v) => Int2ToVector2IntConverter.ConvertTo(v));
int2ToVector2IntGroup.AddConverter((ref Vector2Int v) => Int2ToVector2IntConverter.ConvertBack(v));
ConverterGroups.RegisterConverterGroup(int2ToVector2IntGroup);
var int3ToVector3IntGroup = new ConverterGroup("int3ToVector3IntConverter");
int3ToVector3IntGroup.AddConverter((ref int3 v) => Int3ToVector3IntConverter.ConvertTo(v));
int3ToVector3IntGroup.AddConverter((ref Vector3Int v) => Int3ToVector3IntConverter.ConvertBack(v));
ConverterGroups.RegisterConverterGroup(int3ToVector3IntGroup);
// Converter in ui-toolkit does not support converter parameters right now, we have to register all the types one by one
var objectModeToDisplayStyleGroup = new ConverterGroup("ObjectModeToDisplayStyleConverter");
objectModeToDisplayStyleGroup.AddConverter((ref DistributionMode v) => DistributionModeToDisplayStyleConverter.ObjectModeConvertTo(v));
var splineModeToDisplayStyleGroup = new ConverterGroup("SplineModeToDisplayStyleConverter");
splineModeToDisplayStyleGroup.AddConverter((ref DistributionMode v) => DistributionModeToDisplayStyleConverter.SplineModeConvertTo(v));
var linearModeToDisplayStyleGroup = new ConverterGroup("LinearModeToDisplayStyleConverter");
linearModeToDisplayStyleGroup.AddConverter((ref DistributionMode v) => DistributionModeToDisplayStyleConverter.LinearModeConvertTo(v));
var gridModeToDisplayStyleGroup = new ConverterGroup("GridModeToDisplayStyleConverter");
gridModeToDisplayStyleGroup.AddConverter((ref DistributionMode v) => DistributionModeToDisplayStyleConverter.GridModeConvertTo(v));
var radialModeToDisplayStyleGroup = new ConverterGroup("RadialModeToDisplayStyleConverter");
radialModeToDisplayStyleGroup.AddConverter((ref DistributionMode v) => DistributionModeToDisplayStyleConverter.RadialModeConvertTo(v));
var honeycombModeToDisplayStyleGroup = new ConverterGroup("HoneycombModeToDisplayStyleConverter");
honeycombModeToDisplayStyleGroup.AddConverter((ref DistributionMode v) => DistributionModeToDisplayStyleConverter.HoneycombModeConvertTo(v));
ConverterGroups.RegisterConverterGroup(objectModeToDisplayStyleGroup);
ConverterGroups.RegisterConverterGroup(splineModeToDisplayStyleGroup);
ConverterGroups.RegisterConverterGroup(linearModeToDisplayStyleGroup);
ConverterGroups.RegisterConverterGroup(gridModeToDisplayStyleGroup);
ConverterGroups.RegisterConverterGroup(radialModeToDisplayStyleGroup);
ConverterGroups.RegisterConverterGroup(honeycombModeToDisplayStyleGroup);
}
}
}

View File

@@ -1,7 +1,67 @@
using UnityEngine.UIElements;
namespace Misaki.ArtTool
{
public struct DistributionModeToDisplayStyleConverter
{
public static StyleEnum<DisplayStyle> ObjectModeConvertTo(DistributionMode mode)
{
if (mode == DistributionMode.Object)
{
return DisplayStyle.Flex;
}
return DisplayStyle.None;
}
public static StyleEnum<DisplayStyle> SplineModeConvertTo(DistributionMode mode)
{
if (mode == DistributionMode.Spline)
{
return DisplayStyle.Flex;
}
return DisplayStyle.None;
}
public static StyleEnum<DisplayStyle> LinearModeConvertTo(DistributionMode mode)
{
if (mode == DistributionMode.Linear)
{
return DisplayStyle.Flex;
}
return DisplayStyle.None;
}
public static StyleEnum<DisplayStyle> GridModeConvertTo(DistributionMode mode)
{
if (mode == DistributionMode.Grid)
{
return DisplayStyle.Flex;
}
return DisplayStyle.None;
}
public static StyleEnum<DisplayStyle> RadialModeConvertTo(DistributionMode mode)
{
if (mode == DistributionMode.Radial)
{
return DisplayStyle.Flex;
}
return DisplayStyle.None;
}
public static StyleEnum<DisplayStyle> HoneycombModeConvertTo(DistributionMode mode)
{
if (mode == DistributionMode.Honeycomb)
{
return DisplayStyle.Flex;
}
return DisplayStyle.None;
}
}
}

View File

@@ -0,0 +1,31 @@
using Unity.Mathematics;
using UnityEngine;
namespace Misaki.ArtTool
{
public struct Int2ToVector2IntConverter
{
public static Vector2Int ConvertTo(int2 value)
{
return new Vector2Int(value.x, value.y);
}
public static int2 ConvertBack(Vector2Int value)
{
return new int2(value.x, value.y);
}
}
public struct Int3ToVector3IntConverter
{
public static Vector3Int ConvertTo(int3 value)
{
return new Vector3Int(value.x, value.y, value.z);
}
public static int3 ConvertBack(Vector3Int value)
{
return new int3(value.x, value.y, value.z);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c271b5a6b3fadff498bc8f938e501eee

View File

@@ -31,7 +31,7 @@ namespace Misaki.ArtTool
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)
internal static void DecomposeMatrixListAsSpan(in List<Matrix4x4> matrixList, Span<Vector3> positions, Span<Quaternion> rotations, Span<Vector3> scales)
{
if (matrixList.Count != positions.Length || matrixList.Count != rotations.Length || matrixList.Count != scales.Length)
{

View File

@@ -1,55 +0,0 @@
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();
}
}
}

View File

@@ -0,0 +1,51 @@
using Unity.Mathematics;
namespace Misaki.ArtTool
{
internal static partial class ShapeHelper
{
internal 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;
}
internal static bool GetMeshVertexPosition(int index, MeshData meshData, out float3 position)
{
if (!meshData.vertices.IsCreated || meshData.vertices.Length <= index)
{
position = float3.zero;
return false;
}
position = meshData.vertices[index];
return true;
}
internal static bool GetMeshEdgePosition(int index, MeshData meshData, out float3 position)
{
if (!meshData.edges.IsCreated || meshData.edges.Length <= index)
{
position = float3.zero;
return false;
}
var edge = meshData.edges[index];
if (meshData.vertices.Length <= edge.x || meshData.vertices.Length <= edge.y)
{
position = float3.zero;
return false;
}
position = (meshData.vertices[edge.x] + meshData.vertices[edge.y]) / 2.0f;
return true;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 36c7b9b7309ef1c4681c47a09154d5e1

View File

@@ -0,0 +1,82 @@
using Unity.Mathematics;
namespace Misaki.ArtTool
{
internal static partial class ShapeHelper
{
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);
}
internal static bool IsPointInsideSphere(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;
}
internal static bool IsPointInsideCylinder(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 IsPointInsideMesh(float3 pointPosition, float3 meshPosition, MeshData meshData)
{
var windingNumber = 0;
for (var i = 0; i < meshData.triangles.Length; i += 3)
{
var v1 = meshData.vertices[meshData.triangles[i]];
var v2 = meshData.vertices[meshData.triangles[i + 1]];
var v3 = meshData.vertices[meshData.triangles[i + 2]];
if (IsPointInsideTriangle(pointPosition, v1, v2, v3))
{
windingNumber++;
}
}
return windingNumber % 2 != 0;
}
private static bool IsPointInsideTriangle(float3 point, float3 a, float3 b, float3 c)
{
var v0 = c - a;
var v1 = b - a;
var v2 = point - a;
var dot00 = math.dot(v0, v0);
var dot01 = math.dot(v0, v1);
var dot02 = math.dot(v0, v2);
var dot11 = math.dot(v1, v1);
var dot12 = math.dot(v1, v2);
var invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
var u = (dot11 * dot02 - dot01 * dot12) * invDenom;
var v = (dot00 * dot12 - dot01 * dot02) * invDenom;
return (u >= 0) && (v >= 0) && (u + v < 1.0f);
}
}
}

View File

@@ -1,6 +1,5 @@
using System;
using Unity.Mathematics;
using UnityEngine;
namespace Misaki.ArtTool
{
@@ -10,7 +9,6 @@ namespace Misaki.ArtTool
public int3 count;
public float3 spacing;
public GridShape shape;
[Range(0.0f, 1.0f)]
public float fill;
public readonly int DistributionCount => count.x * count.y * count.z;

View File

@@ -1,13 +1,14 @@
using System;
using UnityEngine;
namespace Misaki.ArtTool
{
[Serializable]
public struct ObjectDistributionSetting
{
public MeshFilter meshFilter;
public MeshData meshData;
public ObjectDistributionMode mode;
public int count;
public uint seed;
public bool alignNormal;
}
}
}

View File

@@ -8,7 +8,7 @@ namespace Misaki.ArtTool
[Serializable]
public struct SplineDistributionSetting
{
public SplineContainer spline;
public NativeSpline nativeSpline;
public int indexOffset;
@@ -26,14 +26,9 @@ namespace Misaki.ArtTool
{
get
{
if (spline == null)
{
return 0;
}
if (isSpacingMode)
{
return Mathf.FloorToInt(spline.CalculateLength() / spacing) + 1;
return Mathf.FloorToInt(splineLength / spacing) + 1;
}
else
{

View File

@@ -0,0 +1,76 @@
using System;
using Unity.Collections;
using Unity.Mathematics;
using UnityEngine;
namespace Misaki.ArtTool
{
public struct MeshData : IDisposable
{
public Bounds bounds;
public NativeArray<int> triangles;
public NativeArray<float4> tangents;
public NativeArray<float3> vertices;
public NativeList<int2> edges;
public int vertexCount;
public float4x4 worldMatrix;
public MeshData(MeshFilter meshFilter, Allocator allocator)
{
var mesh = meshFilter.sharedMesh;
bounds = mesh.bounds;
triangles = new(mesh.triangles.Length, allocator);
for (var i = 0; i < triangles.Length; i++)
{
triangles[i] = mesh.triangles[i];
}
tangents = new(mesh.tangents.Length, allocator);
for (var i = 0; i < tangents.Length; i++)
{
tangents[i] = mesh.tangents[i];
}
vertices = new(mesh.vertices.Length, allocator);
for (var i = 0; i < vertices.Length; i++)
{
vertices[i] = mesh.vertices[i];
}
vertexCount = mesh.vertexCount;
edges = new((int)(vertexCount * 1.5f), allocator);
for (var i = 0; i < triangles.Length; i += 3)
{
AddEdge(edges, triangles[i], triangles[i + 1]);
AddEdge(edges, triangles[i + 1], triangles[i + 2]);
AddEdge(edges, triangles[i + 2], triangles[i]);
}
worldMatrix = meshFilter.transform.localToWorldMatrix;
static void AddEdge(NativeList<int2> edges, int a, int b)
{
if (a < b)
{
edges.Add(new int2(a, b));
}
else
{
edges.Add(new int2(b, a));
}
}
}
public void Dispose()
{
triangles.Dispose();
tangents.Dispose();
vertices.Dispose();
edges.Dispose();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 211ceb887d371d946b4b6617e565d329