This commit is contained in:
ousttrue
2024-11-18 02:31:11 +09:00
parent a39ed1594b
commit e339e2540b
4 changed files with 214 additions and 160 deletions

View File

@@ -16,164 +16,79 @@ namespace RotateParticle.Jobs
public class RotateParticleJobSystem : IRotateParticleSystem
{
Vrm10Instance _vrm;
TransformAccessArray _transformAccessArray;
NativeArray<BlittableTransform> _transforms;
enum ParticleType
{
// kinematic. not verlet move
Root,
// particle. verlet move
Verlet,
// branch. move same as 1st branch sibling
Branch,
}
struct ParticleInfo
{
public ParticleType ParticleType;
public int WarpIndex;
public int ParentIndex;
public float DistanceFromParent;
public Quaternion InitRotation;
public Vector3 InitTailLocalPosition;
}
struct WarpInfo
{
public Vector3 Center;
public float DragForce;
public Quaternion ParentRotation;
public int BranchRootIndex;
public int Start;
public int End;
}
NativeArray<WarpInfo> _warps;
TransformAccessArray _transformAccessArray;
NativeArray<ParticleInfo> _particles;
NativeArray<Vector3> _verletPrevOnCenter;
NativeArray<Vector3> _verletCurrent;
NativeArray<Vector3> _verletNext;
public IList<Warp> Warps => throw new NotImplementedException();
public IList<RectCloth> Cloths => throw new NotImplementedException();
struct VerletJob : IJobParallelFor
{
[ReadOnly] public FrameInfo Frame;
[ReadOnly] public NativeArray<WarpInfo> Warps;
[ReadOnly] public NativeArray<ParticleInfo> Particles;
[ReadOnly] public NativeArray<Vector3> PrevPositionsInCenter;
[ReadOnly] public NativeArray<Vector3> CurrentPositions;
[WriteOnly] public NativeArray<Vector3> NextPositions;
public void Execute(int index)
{
var particle = Particles[index];
if (particle.ParticleType == ParticleType.Root)
{
// kinematic. not move
NextPositions[index] = CurrentPositions[index];
}
else
{
var warp = Warps[particle.WarpIndex];
var velocity = CurrentPositions[index] - warp.Center - PrevPositionsInCenter[index];
velocity *= 1 - warp.DragForce;
NextPositions[index] = CurrentPositions[index] +
velocity + Frame.Force * Frame.SqDeltaTime;
}
}
}
/// <summary>
/// Warp毎に verlet の結果を拘束する
/// 1. 親子間の距離を一定に保つ
/// 2. 移動を親の回転に変換する
/// </summary>
struct LocalRotationConstraintJob : IJobParallelFor
{
[ReadOnly] public NativeArray<WarpInfo> Warps;
[ReadOnly] public NativeArray<ParticleInfo> Particles;
[NativeDisableParallelForRestriction] public NativeArray<Vector3> Positions;
[NativeDisableParallelForRestriction] public NativeArray<Quaternion> Rotations;
public void Execute(int index)
{
var warp = Warps[index];
for (int i = warp.Start; i < warp.End; ++i)
{
var particle = Particles[i];
switch (particle.ParticleType)
{
case ParticleType.Root:
break;
case ParticleType.Verlet:
if (i + 1 < warp.End)
{
var next = Particles[i + 1];
if (next.ParentIndex == i)
{
/// 1. 親子間の距離を一定に保つ
Positions[i + 1] = CalcPosition(Positions[i + 1],
Positions[i], next.DistanceFromParent);
// 2. 移動を親の回転に変換する
var rest = Rotations[i] * next.InitRotation;
Rotations[i] = rest * Quaternion.FromToRotation(
// 初期状態
rest * particle.InitTailLocalPosition,
// 現状
Positions[i + 1] - Positions[i]
);
}
}
break;
case ParticleType.Branch:
{
// TODO
break;
}
}
}
}
static Vector3 CalcPosition(in Vector3 pos, in Vector3 parent, float distance)
{
return pos + (pos - parent).normalized * distance;
}
}
NativeArray<Vector3> _prevPositionsOnCenter;
NativeArray<Vector3> _currentPositions;
NativeArray<Vector3> _nextPositions;
NativeArray<Quaternion> _currentRotations;
NativeArray<Quaternion> _nextRotations;
void IDisposable.Dispose()
{
throw new NotImplementedException();
if (_transformAccessArray.isCreated) _transformAccessArray.Dispose();
if (_warps.IsCreated) _warps.Dispose();
if (_particles.IsCreated) _particles.Dispose();
if (_prevPositionsOnCenter.IsCreated) _prevPositionsOnCenter.Dispose();
if (_currentPositions.IsCreated) _currentPositions.Dispose();
if (_nextPositions.IsCreated) _nextPositions.Dispose();
}
class LocalRotaionConstraintJOb : IJob
async Task IRotateParticleSystem.InitializeAsync(Vrm10Instance vrm, IAwaitCaller awaitCaller)
{
public void Execute()
{
_vrm = vrm;
List<Transform> transforms = new();
var warps = vrm.GetComponentsInChildren<Warp>();
foreach(var warp in warps)
{
}
await awaitCaller.NextFrame();
}
JobHandle Schedule(
in FrameInfo info,
void IRotateParticleSystem.Process(float deltaTime)
{
Schedule(
new FrameInfo(deltaTime, Vector3.zero),
_transformAccessArray
).Complete();
}
/// <summary>
/// INIT PROCESS
/// _transformAccessArray
/// 👇
/// _currentPositions
/// _currentRotations
/// </summary>
private JobHandle Schedule(
in FrameInfo frame,
TransformAccessArray transformAccessArray
)
{
JobHandle handle = default;
// load transform
handle = new LoadTransformJob
{
CurrentPositions = _currentPositions,
CurrentRotations = _currentRotations,
}.Schedule(_transformAccessArray, handle);
// verlet
handle = new VerletJob
{
}.Schedule(_verletCurrent.Length, 128, handle);
Frame = frame,
Warps = _warps,
Particles = _particles,
PrevPositionsOnCenter = _prevPositionsOnCenter,
CurrentPositions = _currentPositions,
NextPositions = _nextPositions,
}.Schedule(_currentPositions.Length, 128, handle);
// local rotation constraint
handle = new LocalRotationConstraintJob
@@ -187,22 +102,6 @@ namespace RotateParticle.Jobs
return handle;
}
async Task IRotateParticleSystem.InitializeAsync(Vrm10Instance vrm, IAwaitCaller awaitCaller)
{
_vrm = vrm;
var warps = vrm.GetComponentsInChildren<Warp>();
await awaitCaller.NextFrame();
throw new NotImplementedException();
}
void IRotateParticleSystem.Process(float deltaTime)
{
Schedule(
new FrameInfo(deltaTime, Vector3.zero),
_transformAccessArray
).Complete();
}
void IRotateParticleSystem.ResetInitialRotation()
{
throw new NotImplementedException();
@@ -210,7 +109,6 @@ namespace RotateParticle.Jobs
void IRotateParticleSystem.DrawGizmos()
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,148 @@
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.Jobs;
namespace RotateParticle.Jobs
{
public enum ParticleType
{
// kinematic. not verlet move
Root,
// particle. verlet move
Verlet,
// branch. move same as 1st branch sibling
Branch,
}
public struct ParticleInfo
{
public ParticleType ParticleType;
public int WarpIndex;
public int ParentIndex;
public float DistanceFromParent;
public Quaternion InitRotation;
public Vector3 InitTailLocalPosition;
}
public struct WarpInfo
{
public Vector3 Center;
public float DragForce;
public Quaternion ParentRotation;
public int BranchRootIndex;
public int Start;
public int End;
}
public struct LoadTransformJob : IJobParallelForTransform
{
// [ReadOnly] public NativeArray<ParticleInfo> Particles;
[WriteOnly] public NativeArray<Vector3> CurrentPositions;
[WriteOnly] public NativeArray<Quaternion> CurrentRotations;
public void Execute(int index, TransformAccess transform)
{
// TODO: ModelSpace
CurrentPositions[index] = transform.position;
CurrentRotations[index] = transform.rotation;
}
}
struct VerletJob : IJobParallelFor
{
[ReadOnly] public FrameInfo Frame;
[ReadOnly] public NativeArray<WarpInfo> Warps;
[ReadOnly] public NativeArray<ParticleInfo> Particles;
[ReadOnly] public NativeArray<Vector3> PrevPositionsOnCenter;
[ReadOnly] public NativeArray<Vector3> CurrentPositions;
[WriteOnly] public NativeArray<Vector3> NextPositions;
public void Execute(int index)
{
var particle = Particles[index];
if (particle.ParticleType == ParticleType.Root)
{
// kinematic. not move
NextPositions[index] = CurrentPositions[index];
}
else
{
var warp = Warps[particle.WarpIndex];
var velocity = CurrentPositions[index] - warp.Center - PrevPositionsOnCenter[index];
velocity *= 1 - warp.DragForce;
NextPositions[index] = CurrentPositions[index] +
velocity + Frame.Force * Frame.SqDeltaTime;
}
}
}
/// <summary>
/// Warp毎に verlet の結果を拘束する
/// 1. 親子間の距離を一定に保つ
/// 2. 移動を親の回転に変換する
/// </summary>
struct LocalRotationConstraintJob : IJobParallelFor
{
[ReadOnly] public NativeArray<WarpInfo> Warps;
[ReadOnly] public NativeArray<ParticleInfo> Particles;
[NativeDisableParallelForRestriction] public NativeArray<Vector3> Positions;
[NativeDisableParallelForRestriction] public NativeArray<Quaternion> Rotations;
public void Execute(int index)
{
var warp = Warps[index];
for (int i = warp.Start; i < warp.End; ++i)
{
var particle = Particles[i];
switch (particle.ParticleType)
{
case ParticleType.Root:
break;
case ParticleType.Verlet:
if (i + 1 < warp.End)
{
var next = Particles[i + 1];
if (next.ParentIndex == i)
{
/// 1. 親子間の距離を一定に保つ
Positions[i + 1] = CalcPosition(Positions[i + 1],
Positions[i], next.DistanceFromParent);
// 2. 移動を親の回転に変換する
var rest = Rotations[i] * next.InitRotation;
Rotations[i] = rest * Quaternion.FromToRotation(
// 初期状態
rest * particle.InitTailLocalPosition,
// 現状
Positions[i + 1] - Positions[i]
);
}
}
break;
case ParticleType.Branch:
{
// TODO
break;
}
}
}
}
static Vector3 CalcPosition(in Vector3 pos, in Vector3 parent, float distance)
{
return pos + (pos - parent).normalized * distance;
}
}
class LocalRotaionConstraintJob : IJob
{
public void Execute()
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 139cb8a384ad8c64abc4dcfab37bcaca
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,4 +1,4 @@
// #define USE_ROTATEPARTICLE_JOB
#define USE_ROTATEPARTICLE_JOB
using System;
using System.Threading.Tasks;
using UniGLTF;
@@ -11,10 +11,7 @@ namespace RotateParticle
{
public class RotateParticleSpringboneRuntime : IVrm10SpringBoneRuntime
{
Vrm10Instance _vrm;
Action<Vrm10Instance> _onInit;
IRotateParticleSystem _system;
public RotateParticleSpringboneRuntime(Action<Vrm10Instance> onInit = null)
@@ -24,20 +21,20 @@ namespace RotateParticle
public void Dispose()
{
if (_system != null)
{
_system.Dispose();
_system = null;
}
}
public async Task InitializeAsync(Vrm10Instance vrm, IAwaitCaller awaitCaller)
{
_vrm = vrm;
if (_onInit != null)
{
_onInit(vrm);
}
// var warps = vrm.GetComponentsInChildren<Warp>();
// var cloths = vrm.GetComponentsInChildren<RectCloth>();
// await awaitCaller.NextFrame();
#if USE_ROTATEPARTICLE_JOB
_system = new Jobs.RotateParticleJobSystem();
#else