// Magica Cloth. // Copyright (c) MagicaSoft, 2020-2022. // https://magicasoft.jp using Unity.Burst; using Unity.Collections; using Unity.Jobs; using Unity.Mathematics; using UnityEngine; using UnityEngine.Jobs; namespace MagicaCloth { /// /// パーティクルデータ /// public class PhysicsManagerParticleData : PhysicsManagerAccess { /// /// パーティクルフラグビット /// public const uint Flag_Enable = 0x00000001; // 有効フラグ public const uint Flag_Kinematic = 0x00000002; // 物理無効 public const uint Flag_Hold = 0x00000004; // ホールド中(これは固定化として扱われる) //public const uint Flag_Collision = 0x00000008; // コリジョン判定 public const uint Flag_Collider = 0x00000010; // コライダー public const uint Flag_Plane = 0x00000020; // プレーン public const uint Flag_CapsuleX = 0x00000040; // カプセルX軸方向 public const uint Flag_CapsuleY = 0x00000080; // カプセルY軸方向 public const uint Flag_CapsuleZ = 0x00000100; // カプセルZ軸方向 public const uint Flag_Box = 0x00000200; // ボックス(予約) public const uint Flag_TriangleRotation = 0x00000400; // TriangleWorkerによる回転制御 public const uint Flag_Transform_Read_Pos = 0x00001000; // posへトランスフォーム位置を読み込む public const uint Flag_Transform_Read_Rot = 0x00002000; // rotへトランスフォーム位置を読み込む public const uint Flag_Transform_Read_Base = 0x00004000; // basePos/baseRotへトランスフォーム位置を読み込む public const uint Flag_Transform_Read_Local = 0x00008000; // ローカル座標計算(=ワールドスケールが必要) public const uint Flag_Transform_Read_Scl = 0x00010000; // ワールドスケールが必要 public const uint Flag_Transform_Write = 0x00020000; // トランスフォームへpos/rotを書き戻す public const uint Flag_Transform_Restore = 0x00040000; // 実行前にトランスフォームlocalPos/localRotを復元 public const uint Flag_Transform_UnityPhysics = 0x00080000; // FixedUpdateでの更新 public const uint Flag_Transform_Parent = 0x00100000; // 親トランスフォームを参照している public const uint Flag_Step_Update = 0x01000000; // Old -> Base を補間して現在姿勢とする public const uint Flag_Reset_Position = 0x02000000; // 位置回転速度をBaseにリセットする //public const uint Flag_Friction = 0x04000000; // 摩擦(コリジョン判定あり) /// /// パーティクルフラグ状態 /// public struct ParticleFlag { /// /// フラグビットデータ /// public uint flag; /// /// コンストラクタ /// /// public ParticleFlag(params uint[] flags) { flag = 0; foreach (var f in flags) flag |= f; } /// /// フラグ判定 /// /// /// public bool IsFlag(uint flag) { return (this.flag & flag) != 0; } /// /// フラグ設定 /// /// /// public void SetFlag(uint flag, bool sw) { if (sw) this.flag |= flag; else this.flag &= ~flag; } /// /// データが有効か判定する /// /// public bool IsValid() { return (flag & Flag_Enable) != 0; } /// /// 有効フラグの設定 /// /// public void SetEnable(bool sw) { if (sw) flag |= Flag_Enable; else flag &= ~Flag_Enable; } /// /// このパーティクルが固定化されているか判定する /// /// public bool IsFixed() { return (flag & (Flag_Kinematic | Flag_Hold)) != 0; } /// /// このパーティクルが移動できるか判定する /// /// public bool IsMove() { return (flag & (Flag_Kinematic | Flag_Hold)) == 0; } /// /// このパーティクルが物理無効化されているか判定する /// /// public bool IsKinematic() { return (flag & Flag_Kinematic) != 0; } /// /// このパーティクルがコリジョン判定を行うか判定する /// /// //public bool IsCollision() //{ // return (flag & Flag_Collision) != 0; //} /// /// このパーティクルがホールド中か判定する /// /// public bool IsHold() { return (flag & Flag_Hold) != 0; } /// /// このパーティクルがコライダーか判定する /// /// public bool IsCollider() { return (flag & Flag_Collider) != 0; } /// /// このパーティクルがトランスフォームの読込みを行うか判定する /// /// public bool IsReadTransform() { return (flag & (Flag_Transform_Read_Pos | Flag_Transform_Read_Rot | Flag_Transform_Read_Base)) != 0; } /// /// このパーティクルがトランスフォームの書き込みを行うか判定する /// /// public bool IsWriteTransform() { return (flag & Flag_Transform_Write) != 0; } /// /// このパーティクルがトランスフォームの復元を行うか判定する /// /// public bool IsRestoreTransform() { return (flag & Flag_Transform_Restore) != 0; //return (flag & (Flag_Transform_Restore_Pos | Flag_Transform_Restore_Rot)) != 0; } /// /// このパーティクルがFixedUpdateでトランスフォームの更新を行うか判定する /// /// public bool IsUnityPhysics() { return (flag & Flag_Transform_UnityPhysics) != 0; } /// /// このパーティクルがトランスフォームのスケール読み込みを行うか判定する /// /// public bool IsReadSclTransform() { return (flag & Flag_Transform_Read_Scl) != 0; } /// /// このパーティクルが親トランスフォームの参照を保持しているか判定する /// /// public bool IsParentTransform() { return (flag & Flag_Transform_Parent) != 0; } } //========================================================================================= // パーティクルデータ(すべてのインデックスは同期している) /// /// フラグリスト /// public FixedChunkNativeArray flagList; /// /// 所属するチームID(0=グローバル) /// public FixedChunkNativeArray teamIdList; /// /// 現在座標リスト /// public FixedChunkNativeArray posList; /// /// 現在回転リスト /// public FixedChunkNativeArray rotList; /// /// 1つ前の座標リスト /// public FixedChunkNativeArray oldPosList; /// /// 1つ前の回転リスト /// public FixedChunkNativeArray oldRotList; /// /// 1つ前の座標リスト(スロー再生用) /// public FixedChunkNativeArray oldSlowPosList; /// /// 本来のローカル位置リスト /// public FixedChunkNativeArray localPosList; /// /// 現在の基準位置リスト /// public FixedChunkNativeArray basePosList; /// /// 現在の基準回転リスト /// public FixedChunkNativeArray baseRotList; /// /// 本来の基準位置リスト /// public FixedChunkNativeArray snapBasePosList; /// /// 本来の基準回転リスト /// public FixedChunkNativeArray snapBaseRotList; /// /// 1つ前の基準位置リスト /// public FixedChunkNativeArray oldBasePosList; /// /// 1つ前の基準回転リスト /// public FixedChunkNativeArray oldBaseRotList; /// /// パーティクル深さリスト /// public FixedChunkNativeArray depthList; /// /// 半径リスト /// public FixedChunkNativeArray radiusList; /// /// 復元トランスフォームリストへのインデックス /// 不要な場合は(-1) /// public FixedChunkNativeArray restoreTransformIndexList; /// /// 読み込み/書き込みトランスフォームリストへのインデックス /// 不要な場合は(-1) /// public FixedChunkNativeArray transformIndexList; /// /// 現在の摩擦係数リスト /// public FixedChunkNativeArray frictionList; /// /// 現在の静止摩擦係数リスト /// public FixedChunkNativeArray staticFrictionList; /// /// 現在の速度リスト /// public FixedChunkNativeArray velocityList; /// /// 接触コライダーID(0=なし) /// public FixedChunkNativeArray collisionLinkIdList; /// /// 接触コライダーの衝突法線 /// public FixedChunkNativeArray collisionNormalList; /// /// 作業用座標リスト0 /// FixedChunkNativeArray nextPos0List; /// /// 作業用座標リスト1 /// FixedChunkNativeArray nextPos1List; /// /// 作業用座標リストの切り替えスイッチ /// int nextPosSwitch = 0; /// /// 作業用回転リスト0 /// FixedChunkNativeArray nextRot0List; /// /// 作業用回転リスト1 /// FixedChunkNativeArray nextRot1List; /// /// 作業用回転リストの切り替えスイッチ /// int nextRotSwitch = 0; //========================================================================================= /// /// コライダー数 /// private int colliderCount; //========================================================================================= /// /// 初期設定 /// public override void Create() { flagList = new FixedChunkNativeArray(); teamIdList = new FixedChunkNativeArray(); posList = new FixedChunkNativeArray(); rotList = new FixedChunkNativeArray(); oldPosList = new FixedChunkNativeArray(); oldRotList = new FixedChunkNativeArray(); oldSlowPosList = new FixedChunkNativeArray(); localPosList = new FixedChunkNativeArray(); basePosList = new FixedChunkNativeArray(); baseRotList = new FixedChunkNativeArray(); snapBasePosList = new FixedChunkNativeArray(); snapBaseRotList = new FixedChunkNativeArray(); oldBasePosList = new FixedChunkNativeArray(); oldBaseRotList = new FixedChunkNativeArray(); depthList = new FixedChunkNativeArray(); radiusList = new FixedChunkNativeArray(); restoreTransformIndexList = new FixedChunkNativeArray(); transformIndexList = new FixedChunkNativeArray(); frictionList = new FixedChunkNativeArray(); staticFrictionList = new FixedChunkNativeArray(); velocityList = new FixedChunkNativeArray(); collisionLinkIdList = new FixedChunkNativeArray(); collisionNormalList = new FixedChunkNativeArray(); nextPos0List = new FixedChunkNativeArray(); nextPos1List = new FixedChunkNativeArray(); nextRot0List = new FixedChunkNativeArray(); nextRot1List = new FixedChunkNativeArray(); // パーティクル[0]番を登録、以降この0番は無効扱いとする var c = CreateParticle(Flag_Kinematic, 0, 0, quaternion.identity, 0.0f, 1.0f, 0); SetEnable(c, false, null, null, null); } /// /// 破棄 /// public override void Dispose() { if (flagList == null) return; flagList.Dispose(); teamIdList.Dispose(); posList.Dispose(); rotList.Dispose(); oldPosList.Dispose(); oldRotList.Dispose(); oldSlowPosList.Dispose(); localPosList.Dispose(); basePosList.Dispose(); baseRotList.Dispose(); snapBasePosList.Dispose(); snapBaseRotList.Dispose(); oldBasePosList.Dispose(); oldBaseRotList.Dispose(); depthList.Dispose(); radiusList.Dispose(); restoreTransformIndexList.Dispose(); transformIndexList.Dispose(); frictionList.Dispose(); staticFrictionList.Dispose(); velocityList.Dispose(); collisionLinkIdList.Dispose(); collisionNormalList.Dispose(); nextPos0List.Dispose(); nextPos1List.Dispose(); nextRot0List.Dispose(); nextRot1List.Dispose(); } //========================================================================================= /// /// パーティクルを1つ作成 /// /// /// /// /// /// /// /// /// /// /// /// public ChunkData CreateParticle( uint flag, int team, float3 wpos, quaternion wrot, float depth, float3 radius, float3 targetLocalPos ) { flag |= Flag_Enable; // 有効フラグは必須 var pf = new ParticleFlag(flag); var c = flagList.Add(pf); teamIdList.Add(team); posList.Add(wpos); rotList.Add(wrot); oldPosList.Add(wpos); oldRotList.Add(wrot); oldSlowPosList.Add(wpos); localPosList.Add(targetLocalPos); basePosList.Add(wpos); baseRotList.Add(wrot); snapBasePosList.Add(wpos); snapBaseRotList.Add(wrot); oldBasePosList.Add(wpos); oldBaseRotList.Add(wrot); depthList.Add(depth); radiusList.Add(radius); frictionList.Add(0.0f); staticFrictionList.Add(0.0f); velocityList.Add(0); collisionLinkIdList.Add(0); collisionNormalList.Add(0); nextPos0List.Add(0); nextPos1List.Add(0); nextRot0List.Add(quaternion.identity); nextRot1List.Add(quaternion.identity); // トランスフォームアクセス int restoreTransformIndex = -1; int transformIndex = -1; restoreTransformIndexList.Add(restoreTransformIndex); transformIndexList.Add(transformIndex); // コライダーカウント if (pf.IsCollider()) colliderCount++; return c; } /// /// パーティクルをグループで作成 /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// public ChunkData CreateParticle( int team, int count, System.Func funcFlag, System.Func funcWpos, System.Func funcWrot, System.Func funcDepth, System.Func funcRadius, System.Func funcTargetLocalPos ) { var c = flagList.AddChunk(count); teamIdList.AddChunk(count); posList.AddChunk(count); rotList.AddChunk(count); oldPosList.AddChunk(count); oldRotList.AddChunk(count); oldSlowPosList.AddChunk(count); localPosList.AddChunk(count); basePosList.AddChunk(count); baseRotList.AddChunk(count); snapBasePosList.AddChunk(count); snapBaseRotList.AddChunk(count); oldBasePosList.AddChunk(count); oldBaseRotList.AddChunk(count); depthList.AddChunk(count); radiusList.AddChunk(count); frictionList.AddChunk(count); staticFrictionList.AddChunk(count); velocityList.AddChunk(count); collisionLinkIdList.AddChunk(count); collisionNormalList.AddChunk(count); nextPos0List.AddChunk(count); nextPos1List.AddChunk(count); nextRot0List.AddChunk(count); nextRot1List.AddChunk(count); restoreTransformIndexList.AddChunk(count); transformIndexList.AddChunk(count); teamIdList.Fill(c, team); nextRot0List.Fill(c, quaternion.identity); nextRot1List.Fill(c, quaternion.identity); for (int i = 0; i < count; i++) { int pindex = c.startIndex + i; uint flag = Flag_Enable; float3 wpos = 0; quaternion wrot = quaternion.identity; float3 tlpos = 0; float depth = 0; float3 radius = 0; int restoreTransformIndex = -1; int transformIndex = -1; if (funcFlag != null) flag |= funcFlag(i); var pf = new ParticleFlag(flag); if (funcWpos != null) wpos = funcWpos(i); if (funcWrot != null) wrot = funcWrot(i); if (funcTargetLocalPos != null) tlpos = funcTargetLocalPos(i); if (funcDepth != null) depth = funcDepth(i); if (funcRadius != null) radius = funcRadius(i); flagList[pindex] = pf; posList[pindex] = wpos; rotList[pindex] = wrot; oldPosList[pindex] = wpos; oldRotList[pindex] = wrot; oldSlowPosList[pindex] = wpos; localPosList[pindex] = tlpos; basePosList[pindex] = wpos; baseRotList[pindex] = wrot; snapBasePosList[pindex] = wpos; snapBaseRotList[pindex] = wrot; oldBasePosList[pindex] = wpos; oldBaseRotList[pindex] = wrot; depthList[pindex] = depth; radiusList[pindex] = radius; restoreTransformIndexList[pindex] = restoreTransformIndex; transformIndexList[pindex] = transformIndex; // コライダーカウント if (pf.IsCollider()) colliderCount++; } return c; } /// /// パーティクル削除 /// /// public void RemoveParticle(ChunkData c) { for (int i = 0; i < c.dataLength; i++) { int pindex = c.startIndex + i; var pf = flagList[pindex]; // コライダーカウント if (pf.IsCollider()) colliderCount--; } flagList.RemoveChunk(c); teamIdList.RemoveChunk(c); posList.RemoveChunk(c); rotList.RemoveChunk(c); oldPosList.RemoveChunk(c); oldRotList.RemoveChunk(c); oldSlowPosList.RemoveChunk(c); localPosList.RemoveChunk(c); basePosList.RemoveChunk(c); baseRotList.RemoveChunk(c); snapBasePosList.RemoveChunk(c); snapBaseRotList.RemoveChunk(c); oldBasePosList.RemoveChunk(c); oldBaseRotList.RemoveChunk(c); depthList.RemoveChunk(c); radiusList.RemoveChunk(c); frictionList.RemoveChunk(c); staticFrictionList.RemoveChunk(c); velocityList.RemoveChunk(c); collisionLinkIdList.RemoveChunk(c); collisionNormalList.RemoveChunk(c); nextPos0List.RemoveChunk(c); nextPos1List.RemoveChunk(c); nextRot0List.RemoveChunk(c); nextRot1List.RemoveChunk(c); restoreTransformIndexList.RemoveChunk(c); transformIndexList.RemoveChunk(c); } /// /// パーティクルの有効フラグ設定 /// /// /// public void SetEnable( ChunkData c, bool sw, System.Func funcTarget, System.Func funcLpos, System.Func funcLrot ) { for (int i = 0; i < c.dataLength; i++) { int index = c.startIndex + i; var flag = flagList[index]; flag.SetEnable(sw); if (sw) { // 有効化 // 位置リセットフラグも立てる flag.SetFlag(Flag_Reset_Position, true); // ボーン登録 if (funcTarget != null) { var target = funcTarget(i); if (target != null) { // 読み込みトランスフォーム登録 if (flag.IsReadTransform() && transformIndexList[index] == -1) { // パーティクル書き戻し判定 int windex = flag.IsWriteTransform() ? index : -1; // 親トランスフォームの参照の有無 bool parent = flag.IsParentTransform(); var transformIndex = Bone.AddBone(target, windex, parent); transformIndexList[index] = transformIndex; // ボーンのUnityPhysicsカウンタ if (flag.IsUnityPhysics()) Bone.ChangeUnityPhysicsCount(transformIndex, true); } // 復元トランスフォーム登録 if (flag.IsRestoreTransform() && restoreTransformIndexList[index] == -1) { float3 lpos = funcLpos != null ? funcLpos(i) : 0; quaternion lrot = funcLrot != null ? funcLrot(i) : quaternion.identity; restoreTransformIndexList[index] = Bone.AddRestoreBone(target, lpos, lrot, transformIndexList[index]); } } } } else { // 無効化 // ボーン登録解除 // 復元トランスフォーム解除 if (flag.IsRestoreTransform()) { var restoreTransformIndex = restoreTransformIndexList[index]; if (restoreTransformIndex >= 0) { Bone.RemoveRestoreBone(restoreTransformIndex); restoreTransformIndexList[index] = -1; } } // 読み込み/書き込みトランスフォーム解除 if (flag.IsReadTransform()) { var transformIndex = transformIndexList[index]; if (transformIndex >= 0) { // ボーンのUnityPhysicsカウンタ if (flag.IsUnityPhysics()) Bone.ChangeUnityPhysicsCount(transformIndex, false); // ボーン解除 int windex = flag.IsWriteTransform() ? index : -1; Bone.RemoveBone(transformIndex, windex); transformIndexList[index] = -1; } } } flagList[index] = flag; } } /// /// パーティクルの半径設定 /// /// /// public void SetRadius(int index, float3 radius) { radiusList[index] = radius; } /// /// パーティクルのローカル座標設定 /// /// /// public void SetLocalPos(int index, Vector3 lpos) { localPosList[index] = lpos; } /// /// パーティクルのコリジョン判定設定 /// /// /// //public void SetCollision(int index, bool sw) //{ // var flag = flagList[index]; // flag.SetFlag(Flag_Collision, sw); // flagList[index] = flag; //} /// /// 実際に利用されているパーティクル数を返す /// [0]はグローバル無効パーティクルなので-1する /// public int Count { get { if (flagList == null) return 0; return Mathf.Max(flagList.Count - 1, 0); } } /// /// パーティクル配列の要素数を返す /// public int Length { get { if (flagList == null) return 0; return flagList.Length; } } /// /// コライダーの数を返す /// public int ColliderCount { get { return colliderCount; } } /// /// インデックスのパーティクルが有効か判定する /// /// /// public bool IsValid(int index) { if (index < 0 || index >= Length) return false; return flagList[index].IsValid(); } public int GetTeamId(int index) { return teamIdList[index]; } /// /// 指定パーティクルに連動するトランスフォームの未来予測をリセットする /// /// public void ResetFuturePredictionTransform(int index) { var transformIndex = transformIndexList[index]; if (transformIndex >= 0) { Bone.ResetFuturePrediction(transformIndex); } } /// /// 指定パーティクルに連動するトランスフォームの未来予測をリセットする /// /// public void ResetFuturePredictionTransform(ChunkData c) { for (int i = 0, index = c.startIndex; i < c.dataLength; i++, index++) { ResetFuturePredictionTransform(index); } } //========================================================================================= // nextPosのダブルバッファ /// /// 入力用nextPosListを取得 /// public FixedChunkNativeArray InNextPosList { get { return nextPosSwitch == 0 ? nextPos0List : nextPos1List; } } /// /// 出力用nextPosListを取得 /// public FixedChunkNativeArray OutNextPosList { get { return nextPosSwitch == 0 ? nextPos1List : nextPos0List; } } /// /// 作業用nextPosListのIn/Out切り替え /// public void SwitchingNextPosList() { nextPosSwitch = (nextPosSwitch + 1) % 2; } //========================================================================================= // nextRotのダブルバッファ /// /// 入力用nextRotListを取得 /// public FixedChunkNativeArray InNextRotList { get { return nextRotSwitch == 0 ? nextRot0List : nextRot1List; } } /// /// 出力用nextRotListを取得 /// public FixedChunkNativeArray OutNextRotList { get { return nextRotSwitch == 0 ? nextRot1List : nextRot0List; } } /// /// 作業用nextRotListのIn/Out切り替え /// public void SwitchingNextRotList() { nextRotSwitch = (nextRotSwitch + 1) % 2; } //========================================================================================= /// /// ボーン姿勢をパーティクルにコピーする /// およびワールド移動影響更新 /// public void UpdateBoneToParticle() { if (Count == 0) return; var job = new CopyBoneToParticleJob() { teamData = Team.teamDataList.ToJobArray(), teamWorldInfluenceList = Team.teamWorldInfluenceList.ToJobArray(), flagList = flagList.ToJobArray(), depthList = depthList.ToJobArray(), transformIndexList = transformIndexList.ToJobArray(), localPosList = localPosList.ToJobArray(), teamIdList = teamIdList.ToJobArray(), velocityList = velocityList.ToJobArray(), bonePosList = Bone.bonePosList.ToJobArray(), boneRotList = Bone.boneRotList.ToJobArray(), boneSclList = Bone.boneSclList.ToJobArray(), posList = posList.ToJobArray(), oldPosList = oldPosList.ToJobArray(), oldRotList = oldRotList.ToJobArray(), oldSlowPosList = oldSlowPosList.ToJobArray(), rotList = rotList.ToJobArray(), //basePosList = basePosList.ToJobArray(), //baseRotList = baseRotList.ToJobArray(), snapBasePosList = snapBasePosList.ToJobArray(), snapBaseRotList = snapBaseRotList.ToJobArray(), oldBasePosList = oldBasePosList.ToJobArray(), oldBaseRotList = oldBaseRotList.ToJobArray(), nextPosList = InNextPosList.ToJobArray(), }; Compute.MasterJob = job.Schedule(Particle.Length, 64, Compute.MasterJob); } [BurstCompile] struct CopyBoneToParticleJob : IJobParallelFor { [Unity.Collections.ReadOnly] public NativeArray teamData; [Unity.Collections.ReadOnly] public NativeArray teamWorldInfluenceList; // パーティクルごと [Unity.Collections.ReadOnly] public NativeArray flagList; [Unity.Collections.ReadOnly] public NativeArray depthList; [Unity.Collections.ReadOnly] public NativeArray transformIndexList; [Unity.Collections.ReadOnly] public NativeArray localPosList; [Unity.Collections.ReadOnly] public NativeArray teamIdList; public NativeArray velocityList; // トランスフォームごと [Unity.Collections.ReadOnly] public NativeArray bonePosList; [Unity.Collections.ReadOnly] public NativeArray boneRotList; [Unity.Collections.ReadOnly] public NativeArray boneSclList; // パーティクルごと public NativeArray posList; public NativeArray oldPosList; public NativeArray oldRotList; public NativeArray oldSlowPosList; [Unity.Collections.WriteOnly] public NativeArray rotList; //[Unity.Collections.WriteOnly] //public NativeArray basePosList; //[Unity.Collections.WriteOnly] //public NativeArray baseRotList; [Unity.Collections.WriteOnly] public NativeArray snapBasePosList; [Unity.Collections.WriteOnly] public NativeArray snapBaseRotList; public NativeArray oldBasePosList; public NativeArray oldBaseRotList; [Unity.Collections.WriteOnly] public NativeArray nextPosList; // パーティクルごと public void Execute(int index) { var flag = flagList[index]; if (flag.IsValid() == false) return; float depth = depthList[index]; // ワールド移動影響更新 int teamId = teamIdList[index]; var tdata = teamData[teamId]; var wdata = teamWorldInfluenceList[teamId]; float moveInfluence = wdata.moveInfluence.Evaluate(depth); float rotInfluence = wdata.rotInfluence.Evaluate(depth); // 維持テレポートなら移動影響は0にする if (tdata.IsFlag(PhysicsManagerTeamData.Flag_Reset_Keep)) { moveInfluence = 0; rotInfluence = 0; } var oldpos = oldPosList[index]; float3 offset = 0; // 最大移動/最大回転影響 { // 影響値 float moveIgnoreRatio = wdata.moveIgnoreRatio; float rotationIgnoreRatio = wdata.rotationIgnoreRatio; // 移動影響 float moveRatio = (1.0f - moveIgnoreRatio) * (1.0f - moveInfluence) + moveIgnoreRatio; float3 offpos = wdata.moveOffset * moveRatio; // 回転影響 float rotRatio = (1.0f - rotationIgnoreRatio) * (1.0f - rotInfluence) + rotationIgnoreRatio; quaternion offrot = math.slerp(quaternion.identity, wdata.rotationOffset, rotRatio); // 一旦ローカル座標系に戻して計算 var lpos = oldpos - wdata.oldPosition; lpos = math.mul(offrot, lpos); lpos += offpos; var npos = wdata.oldPosition + lpos; offset = npos - oldpos; // 速度に回転影響を加える var vel = velocityList[index]; vel = math.mul(offrot, vel); velocityList[index] = vel; // 回転影響を回転に加える var oldrot = oldRotList[index]; oldrot = math.mul(offrot, oldrot); oldRotList[index] = oldrot; // 基準姿勢にも適用(v1.11.1) oldBasePosList[index] = oldBasePosList[index] + offset; var oldBaseRot = oldBaseRotList[index]; oldBaseRot = math.mul(offrot, oldBaseRot); oldBaseRotList[index] = oldBaseRot; } oldPosList[index] = oldpos + offset; oldSlowPosList[index] = oldSlowPosList[index] + offset; if (flag.IsFixed()) { // 固定パーティクルは前回位置をnextPosから計算するのでここにもオフセットを掛けておく(1.8.3) nextPosList[index] = oldpos + offset; } // ここからトランスフォーム読み込み if (flag.IsReadTransform() == false) return; // トランスフォームの最新の姿勢を読み込む var tindex = transformIndexList[index]; if (tindex < 0) { // この状況はDisable状態で配置されたコンポーネントなどで発生する可能性あり!(v1.12.0) return; } var bpos = bonePosList[tindex]; var brot = boneRotList[tindex]; // ローカル姿勢を考慮 if (flag.IsFlag(Flag_Transform_Read_Local)) { var bscl = boneSclList[tindex]; bpos = bpos + math.mul(brot, localPosList[index] * bscl); } // 原点として書き込み if (flag.IsFlag(Flag_Transform_Read_Base)) { //basePosList[index] = bpos; //baseRotList[index] = brot; snapBasePosList[index] = bpos; snapBaseRotList[index] = brot; } // 現在値として書き込み if (flag.IsFlag(Flag_Transform_Read_Pos)) { posList[index] = bpos; } if (flag.IsFlag(Flag_Transform_Read_Rot)) { rotList[index] = brot; } } } //========================================================================================= /// /// パーティクルの姿勢リセット更新 /// public void UpdateResetParticle() { if (Count == 0) return; var job = new ResetParticleJob() { teamData = Team.teamDataList.ToJobArray(), flagList = flagList.ToJobArray(), teamIdList = teamIdList.ToJobArray(), snapBasePosList = snapBasePosList.ToJobArray(), snapBaseRotList = snapBaseRotList.ToJobArray(), basePosList = basePosList.ToJobArray(), baseRotList = baseRotList.ToJobArray(), oldBasePosList = oldBasePosList.ToJobArray(), oldBaseRotList = oldBaseRotList.ToJobArray(), posList = posList.ToJobArray(), rotList = rotList.ToJobArray(), oldPosList = oldPosList.ToJobArray(), oldRotList = oldRotList.ToJobArray(), oldSlowPosList = oldSlowPosList.ToJobArray(), velocityList = velocityList.ToJobArray(), nextPosList = InNextPosList.ToJobArray(), nextRotList = InNextRotList.ToJobArray(), localPosList = localPosList.ToJobArray(), }; Compute.MasterJob = job.Schedule(Particle.Length, 64, Compute.MasterJob); } [BurstCompile] struct ResetParticleJob : IJobParallelFor { [Unity.Collections.ReadOnly] public NativeArray teamData; // パーティクルごと public NativeArray flagList; [Unity.Collections.ReadOnly] public NativeArray teamIdList; [Unity.Collections.ReadOnly] public NativeArray snapBasePosList; [Unity.Collections.ReadOnly] public NativeArray snapBaseRotList; [Unity.Collections.WriteOnly] public NativeArray basePosList; [Unity.Collections.WriteOnly] public NativeArray baseRotList; [Unity.Collections.WriteOnly] public NativeArray oldBasePosList; [Unity.Collections.WriteOnly] public NativeArray oldBaseRotList; [Unity.Collections.WriteOnly] public NativeArray posList; [Unity.Collections.WriteOnly] public NativeArray rotList; [Unity.Collections.WriteOnly] public NativeArray oldPosList; [Unity.Collections.WriteOnly] public NativeArray oldRotList; [Unity.Collections.WriteOnly] public NativeArray oldSlowPosList; [Unity.Collections.WriteOnly] public NativeArray velocityList; [Unity.Collections.WriteOnly] public NativeArray nextPosList; [Unity.Collections.WriteOnly] public NativeArray nextRotList; [Unity.Collections.WriteOnly] public NativeArray localPosList; // パーティクルごと public void Execute(int index) { var flag = flagList[index]; if (flag.IsValid() == false) return; // ワールド移動影響更新 int teamId = teamIdList[index]; var tdata = teamData[teamId]; if (tdata.IsPause()) return; // 姿勢リセット if (tdata.IsFlag(PhysicsManagerTeamData.Flag_Reset_Position) || flag.IsFlag(Flag_Reset_Position)) { //var basePos = basePosList[index]; //var baseRot = baseRotList[index]; var basePos = snapBasePosList[index]; var baseRot = snapBaseRotList[index]; basePosList[index] = basePos; baseRotList[index] = baseRot; oldBasePosList[index] = basePos; oldBaseRotList[index] = baseRot; posList[index] = basePos; rotList[index] = baseRot; oldPosList[index] = basePos; oldRotList[index] = baseRot; oldSlowPosList[index] = basePos; velocityList[index] = 0; nextPosList[index] = basePos; nextRotList[index] = baseRot; // 移動パーティクルはlocalPosに実際の移動速度が格納されている if (flag.IsKinematic() == false) { localPosList[index] = 0; } // フラグクリア flag.SetFlag(Flag_Reset_Position, false); flagList[index] = flag; } } } //========================================================================================= /// /// パーティクル姿勢をボーン姿勢に書き出す /// public bool UpdateParticleToBone() { if (Count > 0 && Bone.WriteBoneCount > 0) { var job = new CopyParticleToBoneJob() { flagList = flagList.ToJobArray(), posList = posList.ToJobArray(), rotList = rotList.ToJobArray(), transformParticleIndexMap = Bone.writeBoneParticleIndexMap.Map, writeBoneIndexList = Bone.writeBoneIndexList.ToJobArray(), bonePosList = Bone.bonePosList.ToJobArray(), boneRotList = Bone.boneRotList.ToJobArray(), }; Compute.MasterJob = job.Schedule(Bone.writeBoneList.Length, 64, Compute.MasterJob); return true; } return false; } [BurstCompile] struct CopyParticleToBoneJob : IJobParallelFor { // パーティクルごと [Unity.Collections.ReadOnly] public NativeArray flagList; [Unity.Collections.ReadOnly] public NativeArray posList; [Unity.Collections.ReadOnly] public NativeArray rotList; // トランスフォームごと [Unity.Collections.ReadOnly] public NativeMultiHashMap transformParticleIndexMap; [Unity.Collections.ReadOnly] public NativeArray writeBoneIndexList; [NativeDisableParallelForRestriction] [Unity.Collections.WriteOnly] public NativeArray bonePosList; [NativeDisableParallelForRestriction] [Unity.Collections.WriteOnly] public NativeArray boneRotList; // 書き込みトランスフォームごと public void Execute(int index) { int pindex; NativeMultiHashMapIterator iterator; if (transformParticleIndexMap.TryGetFirstValue(index, out pindex, out iterator)) { // パーティクルは登録されている中から最初にヒットしたものを採用する var flag = flagList[pindex]; if (flag.IsValid() == false) return; var pos = posList[pindex]; var rot = rotList[pindex]; // ボーン姿勢に書き戻す int bindex = writeBoneIndexList[index] - 1; // +1が入っているので-1する bonePosList[bindex] = pos; boneRotList[bindex] = rot; } } } } }