From 23ddea2ebe2448c87642a2f74ae01982986f128a Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 19 Nov 2024 22:15:01 +0900 Subject: [PATCH] WIP parent length constraint --- .../Runtime/Jobs/RotateParticleJobSystem.cs | 274 +++++++++++------- .../RotateParticle/Runtime/Jobs/Types.cs | 199 ------------- .../RotateParticle/Runtime/Jobs/Types.cs.meta | 11 - .../VRM10Viewer/FaceCameraTarget.asset | 1 + 4 files changed, 165 insertions(+), 320 deletions(-) delete mode 100644 Assets/VRM10_Samples/ClothSample/RotateParticle/Runtime/Jobs/Types.cs delete mode 100644 Assets/VRM10_Samples/ClothSample/RotateParticle/Runtime/Jobs/Types.cs.meta diff --git a/Assets/VRM10_Samples/ClothSample/RotateParticle/Runtime/Jobs/RotateParticleJobSystem.cs b/Assets/VRM10_Samples/ClothSample/RotateParticle/Runtime/Jobs/RotateParticleJobSystem.cs index 2ad234231..5724fa253 100644 --- a/Assets/VRM10_Samples/ClothSample/RotateParticle/Runtime/Jobs/RotateParticleJobSystem.cs +++ b/Assets/VRM10_Samples/ClothSample/RotateParticle/Runtime/Jobs/RotateParticleJobSystem.cs @@ -16,170 +16,224 @@ namespace RotateParticle.Jobs { Vrm10Instance _vrm; - NativeArray _warpImmutables; - NativeArray _warpMutables; + // [Input] + // center + // rootParent + // root + // + // の入力(jobにわたす) + List _inputTransforms; + TransformAccessArray _inputTransformAccessArray; + public struct InputTransformData + { + public Matrix4x4 ToWorld; + public Matrix4x4 TOLocal; - TransformAccessArray _transformAccessArray; - NativeArray _particleImmutables; - NativeArray _particleMutables; + public InputTransformData(TransformAccess t) + { + ToWorld = t.localToWorldMatrix; + TOLocal = t.worldToLocalMatrix; + } + } + NativeArray _inputData; + public struct InputTransformJob : IJobParallelForTransform + { + [WriteOnly] public NativeArray InputData; + public void Execute(int index, TransformAccess transform) + { + InputData[index] = new InputTransformData(transform); + } + } - NativeArray _prevPositionsOnCenter; - NativeArray _currentPositions; + // [Output] + // root 回転のみ + // particle 回転 + 移動 + // を出力(jobから反映する) + List _outputTransforms; + List _positions; NativeArray _nextPositions; - // NativeArray _currentRotations; - NativeArray _nextRotations; + TransformAccessArray _outputTransformAccessArray; + public struct OutputTransformJob : IJobParallelForTransform + { + [ReadOnly] public NativeArray NextPositions; + public void Execute(int index, TransformAccess transform) + { + transform.position = NextPositions[index]; + } + } - bool _zeroVelocity = true; + public struct ParticleIndo + { + public int InputTransformIndex; + public int? ParentIndex; + public Vector3 InitLocalPosition; + // DragForce: 1 で即時停止 + public float DragForce; + } + NativeArray _particles; + + // [Init/State] + // 初期化時に値を作って毎フレーム更新していく + // output と同じ長さ index + NativeArray _currentPositions; + NativeArray _prevPositions; + public struct VerletJob : IJobParallelFor + { + public FrameInfo Frame; + [WriteOnly] public NativeArray NextPositions; + [ReadOnly] public NativeArray CurrentPositions; + [ReadOnly] public NativeArray PrevPositions; + [ReadOnly] public NativeArray Particles; + + public void Execute(int index) + { + var particle = Particles[index]; + if (particle.ParentIndex.HasValue) + { + var velocity = CurrentPositions[index] - PrevPositions[index]; + velocity *= (1 - particle.DragForce); + var newPosition = CurrentPositions[index] + velocity + Frame.Force * Frame.SqDeltaTime; + + var parentIndex = particle.ParentIndex.Value; + var parentPosition = CurrentPositions[parentIndex]; + + // 位置を長さで拘束 + newPosition = parentPosition + (newPosition - parentPosition).normalized * particle.InitLocalPosition.magnitude; + + NextPositions[index] = newPosition; + } + else + { + // kinematic + NextPositions[index] = CurrentPositions[index]; + } + } + } void IDisposable.Dispose() { - if (_transformAccessArray.isCreated) _transformAccessArray.Dispose(); - if (_warpImmutables.IsCreated) _warpImmutables.Dispose(); - - if (_warpMutables.IsCreated) _warpMutables.Dispose(); - if (_particleImmutables.IsCreated) _particleImmutables.Dispose(); - if (_particleMutables.IsCreated) _particleMutables.Dispose(); - - if (_prevPositionsOnCenter.IsCreated) _prevPositionsOnCenter.Dispose(); - if (_currentPositions.IsCreated) _currentPositions.Dispose(); - if (_nextPositions.IsCreated) _nextPositions.Dispose(); - // if (_currentRotations.IsCreated) _currentRotations.Dispose(); - if (_nextRotations.IsCreated) _nextRotations.Dispose(); } async Task IRotateParticleSystem.InitializeAsync(Vrm10Instance vrm, IAwaitCaller awaitCaller) { _vrm = vrm; - List warpImmutables = new(); - List warpMutables = new(); + _inputTransforms = new(); + _outputTransforms = new(); + _positions = new(); - List transforms = new(); - List particleImmutables = new(); - // List particleMutables = new(); + List particles = new(); var warpSrcs = vrm.GetComponentsInChildren(); for (int warpIndex = 0; warpIndex < warpSrcs.Length; ++warpIndex) { var warp = warpSrcs[warpIndex]; - warpImmutables.Add(new WarpImmutable - { + var inputCenterTransformIndex = GetInputTransformIndex(warp.Center); + var inputWarpRootParentTransformIndex = GetInputTransformIndex(warp.transform.parent); + Debug.Assert(inputWarpRootParentTransformIndex != -1); + var inputWarpRootTransformIndex = GetInputTransformIndex(warp.transform); + Debug.Assert(inputWarpRootParentTransformIndex != -1); - }); - warpMutables.Add(new WarpMutable + var ouputWarpRootTransformIndex = GetOutputTransformIndex(warp.transform); + particles.Add(new ParticleIndo { - - }); - - transforms.Add(warp.transform); - particleImmutables.Add(new ParticleImmutable - { - ParticleType = ParticleType.Root, - WarpIndex = warpIndex, + InputTransformIndex = inputWarpRootTransformIndex, }); + var parentIndex = ouputWarpRootTransformIndex; foreach (var particle in warp.Particles) { if (particle != null && particle.Transform != null) { - transforms.Add(particle.Transform); - particleImmutables.Add(new ParticleImmutable + var outputParticleTransformIndex = GetOutputTransformIndex(particle.Transform); + particles.Add(new ParticleIndo { - // TODO: ParticleType.Branch - ParticleType = ParticleType.Verlet, - WarpIndex = warpIndex, + ParentIndex = parentIndex, + InitLocalPosition = vrm.DefaultTransformStates[particle.Transform].LocalPosition, + DragForce = particle.GetSettings(warp.BaseSettings).DragForce, }); + parentIndex = outputParticleTransformIndex; } } await awaitCaller.NextFrame(); } + _inputTransformAccessArray = new(_inputTransforms.ToArray(), 128); + _inputData = new(_inputTransforms.Count, Allocator.Persistent); - _warpImmutables = new(warpImmutables.ToArray(), Allocator.Persistent); - _warpMutables = new(warpMutables.ToArray(), Allocator.Persistent); + _outputTransformAccessArray = new(_outputTransforms.ToArray(), 128); + var positions = _positions.ToArray(); + _currentPositions = new(positions, Allocator.Persistent); + _prevPositions = new(positions, Allocator.Persistent); + _nextPositions = new(positions, Allocator.Persistent); + _particles = new(particles.ToArray(), Allocator.Persistent); + } - _transformAccessArray = new TransformAccessArray(transforms.ToArray()); - _particleImmutables = new(particleImmutables.ToArray(), Allocator.Persistent); - _particleMutables = new(transforms.Count, Allocator.Persistent); + int GetInputTransformIndex(Transform t) + { + if (t == null) return -1; + var i = _inputTransforms.IndexOf(t); + if (i == -1) + { + i = _inputTransforms.Count; + _inputTransforms.Add(t); + } + return i; + } - _currentPositions = new(transforms.Count, Allocator.Persistent); - _prevPositionsOnCenter = new(transforms.Count, Allocator.Persistent); - _nextPositions = new(transforms.Count, Allocator.Persistent); - // _currentRotations = new(transforms.Count, Allocator.Persistent); - _nextRotations = new(transforms.Count, Allocator.Persistent); + int GetOutputTransformIndex(Transform t) + { + if (t == null) return -1; + var i = _outputTransforms.IndexOf(t); + if (i == -1) + { + i = _outputTransforms.Count; + _outputTransforms.Add(t); + _positions.Add(t.position); + } + return i; } void IRotateParticleSystem.Process(float deltaTime) { - Schedule( - new FrameInfo(deltaTime, Vector3.zero), - _transformAccessArray - ).Complete(); - } + var frame = new FrameInfo(deltaTime, Vector3.zero); - /// - /// INIT PROCESS - /// _transformAccessArray - /// 👇 - /// _currentPositions - /// _currentRotations - /// - private JobHandle Schedule( - in FrameInfo frame, - TransformAccessArray transformAccessArray - ) - { - JobHandle handle = default; - - // load transform - handle = new ReadTransformJob + // input + new InputTransformJob { - CurrentPositions = _currentPositions, - NextRotations = _nextRotations, - }.Schedule(_transformAccessArray, handle); + InputData = _inputData, + }.Schedule(_inputTransformAccessArray, default).Complete(); + + // update root position + for (int i = 0; i < _particles.Length; ++i) + { + var particle = _particles[i]; + if (!particle.ParentIndex.HasValue) + { + _currentPositions[i] = _inputData[particle.InputTransformIndex].ToWorld.GetPosition(); + } + } // verlet - handle = new VerletJob + new VerletJob { - ZeroVelocity = _zeroVelocity, Frame = frame, - WarpMutables = _warpMutables, - ParticleImmutables = _particleImmutables, - ParticleMutables = _particleMutables, - PrevPositionsOnCenter = _prevPositionsOnCenter, + Particles = _particles, + PrevPositions = _prevPositions, CurrentPositions = _currentPositions, NextPositions = _nextPositions, - }.Schedule(_currentPositions.Length, 128, handle); - _zeroVelocity = false; + }.Run(_particles.Length); - // local rotation constraint - handle = new LocalRotationConstraintJob - { - WarpImmutables = _warpImmutables, - ParticleImmutables = _particleImmutables, - Positions = _nextPositions, - Rotations = _nextRotations, - }.Schedule(_warpImmutables.Length, 1, handle); - - // update verlet - handle = new VerletStatusJob - { - WarpImmutables = _warpImmutables, - WarpMutables = _warpMutables, - CurrentPositions = _currentPositions, - PrevPositionsOnCenter = _prevPositionsOnCenter, - }.Schedule(_warpImmutables.Length, 1, handle); - - // writeback transform - handle = new WritebackTransformJob + // output + new OutputTransformJob { NextPositions = _nextPositions, - NextRotations = _nextRotations, - }.Schedule(_transformAccessArray, handle); + }.Schedule(_outputTransformAccessArray, default).Complete(); - return handle; + // update state + NativeArray.Copy(_currentPositions, _prevPositions); + NativeArray.Copy(_nextPositions, _currentPositions); } void IRotateParticleSystem.ResetInitialRotation() { - throw new NotImplementedException(); } void IRotateParticleSystem.DrawGizmos() diff --git a/Assets/VRM10_Samples/ClothSample/RotateParticle/Runtime/Jobs/Types.cs b/Assets/VRM10_Samples/ClothSample/RotateParticle/Runtime/Jobs/Types.cs deleted file mode 100644 index ad3a37edc..000000000 --- a/Assets/VRM10_Samples/ClothSample/RotateParticle/Runtime/Jobs/Types.cs +++ /dev/null @@ -1,199 +0,0 @@ -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, - } - - - /// - /// Reconstruct されるまで不変 - /// - public struct ParticleImmutable - { - public ParticleType ParticleType; - public int WarpIndex; - public int ParentIndex; - public float DistanceFromParent; - public Quaternion InitRotation; - public Vector3 InitTailLocalPosition; - } - - /// - /// 毎フレーム変化するかもしれない - /// - public struct ParticleMutable - { - public float DragForce; - } - - /// - /// Reconstruct されるまで不変 - /// - public struct WarpImmutable - { - public int ParentIndex; - public int BranchRootIndex; - public int Start; - public int End; - } - - /// - /// 毎フレーム変化するかもしれない - /// - public struct WarpMutable - { - /// - /// center が未指定ならば Vector3.zero - /// - public Vector3 Center; - } - - public struct ReadTransformJob : IJobParallelForTransform - { - [WriteOnly] public NativeArray CurrentPositions; - [WriteOnly] public NativeArray NextRotations; - public void Execute(int index, TransformAccess transform) - { - // TODO: ModelSpace - CurrentPositions[index] = transform.position; - NextRotations[index] = transform.rotation; - } - } - - public struct WritebackTransformJob : IJobParallelForTransform - { - [ReadOnly] public NativeArray NextPositions; - [ReadOnly] public NativeArray NextRotations; - public void Execute(int index, TransformAccess transform) - { - // TODO: ModelSpace - transform.position = NextPositions[index]; - transform.rotation = NextRotations[index]; - } - } - - struct VerletJob : IJobParallelFor - { - public bool ZeroVelocity; - [ReadOnly] public FrameInfo Frame; - - // [ReadOnly] public NativeArray WarpImmutables; - [ReadOnly] public NativeArray WarpMutables; - - [ReadOnly] public NativeArray ParticleImmutables; - [ReadOnly] public NativeArray ParticleMutables; - [ReadOnly] public NativeArray PrevPositionsOnCenter; - [ReadOnly] public NativeArray CurrentPositions; - [WriteOnly] public NativeArray NextPositions; - public void Execute(int index) - { - var particle = ParticleImmutables[index]; - var particleMutable = ParticleMutables[index]; - if (particle.ParticleType == ParticleType.Root) - { - // kinematic. not move - NextPositions[index] = CurrentPositions[index]; - } - else - { - var warp = WarpMutables[particle.WarpIndex]; - var velocity = ZeroVelocity - ? Vector3.zero - : CurrentPositions[index] - warp.Center - PrevPositionsOnCenter[index] - ; - velocity *= 1 - particleMutable.DragForce; - NextPositions[index] = CurrentPositions[index] + - velocity + Frame.Force * Frame.SqDeltaTime; - } - } - } - - /// - /// Warp毎に verlet の結果を拘束する - /// 1. 親子間の距離を一定に保つ - /// 2. 移動を親の回転に変換する - /// - struct LocalRotationConstraintJob : IJobParallelFor - { - [ReadOnly] public NativeArray WarpImmutables; - [ReadOnly] public NativeArray ParticleImmutables; - [NativeDisableParallelForRestriction] public NativeArray Positions; - [NativeDisableParallelForRestriction] public NativeArray Rotations; - - public void Execute(int warpIndex) - { - var warp = WarpImmutables[warpIndex]; - for (int i = warp.Start; i < warp.End; ++i) - { - var particle = ParticleImmutables[i]; - switch (particle.ParticleType) - { - case ParticleType.Root: - break; - - case ParticleType.Verlet: - if (i + 1 < warp.End) - { - var next = ParticleImmutables[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; - } - } - - struct VerletStatusJob : IJobParallelFor - { - [ReadOnly] public NativeArray WarpImmutables; - [ReadOnly] public NativeArray WarpMutables; - [ReadOnly] public NativeArray CurrentPositions; - [WriteOnly] public NativeArray PrevPositionsOnCenter; - - public void Execute(int warpIndex) - { - var warp = WarpImmutables[warpIndex]; - var warpMutable = WarpMutables[warpIndex]; - for (int i = warp.Start; i < warp.End; ++i) - { - PrevPositionsOnCenter[i] = CurrentPositions[i] - warpMutable.Center; - } - } - } -} \ No newline at end of file diff --git a/Assets/VRM10_Samples/ClothSample/RotateParticle/Runtime/Jobs/Types.cs.meta b/Assets/VRM10_Samples/ClothSample/RotateParticle/Runtime/Jobs/Types.cs.meta deleted file mode 100644 index 7c59093ea..000000000 --- a/Assets/VRM10_Samples/ClothSample/RotateParticle/Runtime/Jobs/Types.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 139cb8a384ad8c64abc4dcfab37bcaca -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/VRM10_Samples/VRM10Viewer/FaceCameraTarget.asset b/Assets/VRM10_Samples/VRM10Viewer/FaceCameraTarget.asset index c1311d8e0..dc5b55f8e 100644 --- a/Assets/VRM10_Samples/VRM10Viewer/FaceCameraTarget.asset +++ b/Assets/VRM10_Samples/VRM10Viewer/FaceCameraTarget.asset @@ -26,6 +26,7 @@ CustomRenderTexture: m_UseDynamicScale: 0 m_BindMS: 0 m_EnableCompatibleFormat: 1 + m_EnableRandomWrite: 0 m_TextureSettings: serializedVersion: 2 m_FilterMode: 1