// 読み込みボーンごと public void Execute(int index, TransformAccess transform) { float3 pos = transform.position; quaternion rot = transform.rotation; var oldPos = basePosList[index]; var oldRot = baseRotList[index]; if (oldPos.y < -900000) { // リセット basePosList[index] = pos; baseRotList[index] = rot; bonePosList[index] = pos; boneRotList[index] = rot; } else { // 前回からの速度から未来予測の更新量を求める var velocityPos = (pos - oldPos) * ratio; var velocityRot = MathUtility.FromToRotation(oldRot, rot, ratio); basePosList[index] = pos; baseRotList[index] = rot; // 未来予測 pos += velocityPos; rot = math.mul(velocityRot, rot); bonePosList[index] = pos; boneRotList[index] = rot; } }
// 読み込みボーンごと public void Execute(int index, TransformAccess transform) { float3 pos = transform.position; quaternion rot = transform.rotation; var oldPos = basePosList[index]; var oldRot = baseRotList[index]; if (oldPos.y < -900000) { // リセット basePosList[index] = pos; baseRotList[index] = rot; bonePosList[index] = pos; boneRotList[index] = rot; } else { // 前回からの速度から未来予測の更新量を求める var velocityPos = (pos - oldPos) * ratio; var velocityRot = MathUtility.FromToRotation(oldRot, rot, ratio); basePosList[index] = pos; baseRotList[index] = rot; // 未来予測 pos += velocityPos; rot = math.mul(velocityRot, rot); bonePosList[index] = pos; boneRotList[index] = rot; } #if !(UNITY_2018 || UNITY_2019_1 || UNITY_2019_2_1 || UNITY_2019_2_2 || UNITY_2019_2_3 || UNITY_2019_2_4 || UNITY_2019_2_5 || UNITY_2019_2_6 || UNITY_2019_2_7 || UNITY_2019_2_8 || UNITY_2019_2_9 || UNITY_2019_2_10 || UNITY_2019_2_11 || UNITY_2019_2_12 || UNITY_2019_2_13) // lossyScale取得(現在はUnity2019.2.14以上のみ) // マトリックスから正確なスケール値を算出する(これはTransform.lossyScaleと等価) float4x4 m = transform.localToWorldMatrix; var irot = math.inverse(rot); var m2 = math.mul(new float4x4(irot, float3.zero), m); var scl = new float3(m2.c0.x, m2.c1.y, m2.c2.z); boneSclList[index] = scl; #endif }
// チームデータごと public void Execute(int teamId) { var tdata = teamData[teamId]; if (tdata.IsActive() == false || tdata.boneIndex < 0) { tdata.updateCount = 0; tdata.runCount = 0; teamData[teamId] = tdata; return; } // ワールド移動影響 WorldInfluence wdata = teamWorldInfluenceList[teamId]; var bpos = bonePosList[tdata.boneIndex]; var brot = boneRotList[tdata.boneIndex]; // 移動量算出 float3 movePos = bpos - wdata.oldPosition; quaternion moveRot = MathUtility.FromToRotation(wdata.oldRotation, brot); wdata.moveOffset = movePos; wdata.rotationOffset = moveRot; // テレポート判定 if (wdata.resetTeleport == 1) { if (math.length(movePos) >= wdata.teleportDistance || math.degrees(MathUtility.Angle(moveRot)) >= wdata.teleportRotation) { tdata.SetFlag(Flag_Reset_WorldInfluence, true); tdata.SetFlag(Flag_Reset_Position, true); } } bool reset = false; if (tdata.IsFlag(Flag_Reset_WorldInfluence) || tdata.IsFlag(Flag_Reset_Position)) { // リセット wdata.moveOffset = 0; wdata.rotationOffset = quaternion.identity; wdata.oldPosition = bpos; wdata.oldRotation = brot; // チームタイムリセット(強制更新) tdata.nowTime = updateDeltaTime; reset = true; } wdata.nowPosition = bpos; wdata.nowRotation = brot; // 時間更新(タイムスケール対応) // チームごとに固有の時間で動作する tdata.updateCount = 0; tdata.runCount = 0; float timeScale = tdata.timeScale * globalTimeScale; float addTime = dtime * timeScale; tdata.time += addTime; tdata.addTime = addTime; // 時間ステップ float nowTime = tdata.nowTime + addTime; while (nowTime >= updateDeltaTime) { nowTime -= updateDeltaTime; tdata.updateCount++; } // リセットフラグがONならば最低1回更新とする if (reset) { tdata.updateCount = Mathf.Max(tdata.updateCount, 1); } // 最大実行回数 //tdata.updateCount = math.min(tdata.updateCount, ups / 30); tdata.updateCount = math.min(tdata.updateCount, maxUpdateCount); tdata.nowTime = nowTime; // スタート時間(最初の物理更新が実行される時間) tdata.startTime = tdata.time - nowTime - updateDeltaTime * (tdata.updateCount - 1); // 補間再生判定 if (timeScale < 0.99f || unityTimeScale < 0.99f) { tdata.SetFlag(Flag_Interpolate, true); } else { tdata.SetFlag(Flag_Interpolate, false); } // リセットフラグOFF tdata.SetFlag(Flag_Reset_WorldInfluence, false); // 風 Wind(ref tdata, bpos); // 書き戻し teamData[teamId] = tdata; teamWorldInfluenceList[teamId] = wdata; }
// パーティクルごと public void Execute(int index) { // 初期化コピー var nextpos = nextPosList[index]; outNextPosList[index] = nextpos; var flag = flagList[index]; if (flag.IsValid() == false || flag.IsFixed()) { return; } // チーム var team = teamDataList[teamIdList[index]]; if (team.IsActive() == false || team.restoreRotationGroupIndex < 0) { return; } // 更新確認 if (team.IsUpdate() == false) { return; } int pstart = team.particleChunk.startIndex; int vindex = index - pstart; // クロスごとの拘束データ var gdata = groupList[team.restoreRotationGroupIndex]; if (gdata.active == 0) { return; } // 参照情報 var refdata = refDataList[gdata.refChunk.startIndex + vindex]; if (refdata.count > 0) { // power float depth = depthList[index]; float dataPower = gdata.restorePower.Evaluate(depth); // 補間力 // 90ups基準 float power = 1.0f - math.pow(1.0f - dataPower, updatePower); float3 addpos = 0; // 自身の基準位置 //float3 bpos = basePosList[index]; int dataIndex = gdata.dataChunk.startIndex + refdata.startIndex; for (int i = 0; i < refdata.count; i++, dataIndex++) { var data = dataList[dataIndex]; if (data.IsValid() == false) { continue; } // 親 int pindex = pstart + data.targetVertexIndex; quaternion prot = baseRotList[pindex]; // 常に本来の回転から算出する var ppos = nextPosList[pindex]; // 位置は現在の親の位置 //float3 pbpos = basePosList[pindex]; //var ppos = nextPosList[pindex]; // 本来の方向ベクトル //float3 tv = math.mul(prot, data.localPos); // v1.7.0 float3 tv = math.mul(prot, data.localPos * team.scaleDirection); // マイナススケール対応(v1.7.6) //float3 tv = bpos - pbpos; // 現在ベクトル float3 v = nextpos - ppos; // 球面線形補間 var q = MathUtility.FromToRotation(v, tv, power); v = math.mul(q, v); float3 gpos = ppos + v; // 加算位置 addpos += gpos - nextpos; } // 摩擦係数から移動率を算出 float friction = frictionList[index]; float moveratio = math.saturate(1.0f - friction * Define.Compute.FrictionMoveRatio); addpos *= moveratio; var opos = nextpos; nextpos += addpos / refdata.count; // 書き出し outNextPosList[index] = nextpos; // 速度影響 var av = (nextpos - opos) * (1.0f - gdata.velocityInfluence); posList[index] = posList[index] + av; } }
// ルートラインごと public void Execute(int rootIndex) { // チーム int teamIndex = rootTeamList[rootIndex]; if (teamIndex == 0) { return; } var team = teamDataList[teamIndex]; if (team.IsActive() == false || team.lineWorkerGroupIndex < 0) { return; } // グループデータ var gdata = groupList[team.lineWorkerGroupIndex]; // データ var rootInfo = rootInfoList[rootIndex]; int dstart = gdata.dataChunk.startIndex; int dataIndex = rootInfo.startIndex + dstart; int dataCount = rootInfo.dataLength; int pstart = team.particleChunk.startIndex; if (dataCount <= 1) { return; } for (int i = 0; i < dataCount; i++) { var data = dataList[dataIndex + i]; var pindex = data.vertexIndex; pindex += pstart; var flag = flagList[pindex]; if (flag.IsValid() == false) { continue; } // 自身の現在姿勢 var pos = posList[pindex]; var rot = rotList[pindex]; // 子の回転調整 if (data.childCount > 0) { // 子への平均ベクトル float3 ctv = 0; float3 cv = 0; for (int j = 0; j < data.childCount; j++) { var cdata = dataList[data.childStartDataIndex + dstart + j]; int cindex = cdata.vertexIndex + pstart; // 子の現在姿勢 var cpos = posList[cindex]; // 子の本来のベクトル float3 tv = math.normalize(math.mul(rot, cdata.localPos)); ctv += tv; // 子の現在ベクトル float3 v = math.normalize(cpos - pos); cv += v; // 回転 var q = MathUtility.FromToRotation(tv, v); // 子の姿勢確定 var crot = math.mul(rot, cdata.localRot); crot = math.mul(q, crot); rotList[cindex] = crot; } // 固定は回転させない判定(v1.5.2) if (team.IsFlag(PhysicsManagerTeamData.Flag_FixedNonRotation) && flag.IsKinematic()) { continue; } // 子の移動方向変化に伴う回転調整 var cq = MathUtility.FromToRotation(ctv, cv); // 回転補間 if (gdata.avarage == 1) { cq = math.slerp(quaternion.identity, cq, 0.5f); // 50% } rot = math.mul(cq, rot); rotList[pindex] = math.normalize(rot); // 正規化しないとエラーになる場合がある } } }
// ルートラインごと public void Execute(int rootIndex) { // チーム int teamIndex = rootTeamList[rootIndex]; if (teamIndex == 0) { return; } var team = teamDataList[teamIndex]; if (team.IsActive() == false || team.clampRotationGroupIndex < 0) { return; } // 更新確認 if (team.IsUpdate() == false) { return; } // グループデータ var gdata = groupList[team.clampRotationGroupIndex]; if (gdata.active == 0) { return; } // データ var rootInfo = rootInfoList[rootIndex]; int dataIndex = rootInfo.startIndex + gdata.dataChunk.startIndex; int dataCount = rootInfo.dataLength; int pstart = team.particleChunk.startIndex; // (1)現在の親からのベクトル長を保持する for (int i = 0; i < dataCount; i++) { var data = dataList[dataIndex + i]; int pindex = data.parentVertexIndex; if (pindex < 0) { continue; } var index = data.vertexIndex; index += pstart; pindex += pstart; var npos = nextPosList[index]; var ppos = nextPosList[pindex]; // 現在ベクトル長 float vlen = math.distance(npos, ppos); lengthBuffer[dataIndex + i] = vlen; } // (2)回転角度制限 for (int i = 0; i < dataCount; i++) { var data = dataList[dataIndex + i]; int pindex = data.parentVertexIndex; if (pindex < 0) { continue; } var index = data.vertexIndex; index += pstart; pindex += pstart; var flag = flagList[index]; if (flag.IsValid() == false) { continue; } var npos = nextPosList[index]; var nrot = nextRotList[index]; var opos = npos; var ppos = nextPosList[pindex]; var prot = nextRotList[pindex]; float depth = depthList[index]; //float stiffness = gdata.stiffness.Evaluate(depth); // 本来のローカルpos/rotを算出する //var bpos = basePosList[index]; //var brot = baseRotList[index]; //var pbpos = basePosList[pindex]; //var pbrot = baseRotList[pindex]; //float3 bv = math.normalize(bpos - pbpos); //var ipbrot = math.inverse(pbrot); //float3 localPos = math.mul(ipbrot, bv); //quaternion localRot = math.mul(ipbrot, brot); // 本来の方向ベクトル //float3 tv = math.mul(prot, localPos); //float3 tv = math.mul(prot, data.localPos); // v1.7.0 float3 tv = math.mul(prot, data.localPos * team.scaleDirection); // マイナススケール対応(v1.7.6) // ベクトル長 float vlen = math.distance(npos, ppos); // 最新の距離(※これは伸びる場合があるが、一番安定している) float blen = lengthBuffer[dataIndex + i]; // 計算前の距離 vlen = math.clamp(vlen, 0.0f, blen * 1.2f); // 現在ベクトル float3 v = math.normalize(npos - ppos); // ベクトル角度クランプ float maxAngle = gdata.maxAngle.Evaluate(depth); maxAngle = math.radians(maxAngle); float angle = math.acos(math.dot(v, tv)); if (flag.IsFixed() == false) { if (angle > maxAngle) { //v = MathUtility.ClampAngle(v, tv, maxAngle); MathUtility.ClampAngle(v, tv, maxAngle, out v); } var mv = (ppos + v * vlen) - npos; // 最大速度クランプ mv = MathUtility.ClampVector(mv, 0.0f, maxMoveLength); // debug //var ln = math.length(mv); //if (ln >= maxMoveLength) // Debug.Log($"mv={ln}"); var fpos = npos + mv; // 摩擦係数から移動率を算出 float friction = frictionList[index]; float moveratio = math.saturate(1.0f - friction * Define.Compute.FrictionMoveRatio); // 摩擦係数による移動制限(衝突しているパーティクルは動きづらい) npos = math.lerp(npos, fpos, moveratio); nextPosList[index] = npos; // 現在ベクトル更新(v1.8.0) v = math.normalize(npos - ppos); // 速度影響 var av = (npos - opos) * (1.0f - gdata.velocityInfluence); posList[index] = posList[index] + av; } // 回転補正 //nrot = math.mul(prot, localRot); //nrot = math.mul(prot, data.localRot); // v1.7.0 nrot = math.mul(prot, new quaternion(data.localRot.value * team.quaternionScale)); // マイナススケール対応(v1.7.6) var q = MathUtility.FromToRotation(tv, v); nrot = math.mul(q, nrot); nextRotList[index] = nrot; } }
// チームデータごと public void Execute(int teamId) { var tdata = teamData[teamId]; // グローバルチーム判定 bool isGlobal = teamId == 0; if (tdata.IsActive() == false || (isGlobal == false && tdata.boneIndex < 0)) { tdata.updateCount = 0; tdata.runCount = 0; teamData[teamId] = tdata; return; } if (isGlobal) { // グローバルチーム // 時間更新(タイムスケール対応) UpdateTime(ref tdata, false); } else { // チームボーン情報 var bpos = bonePosList[tdata.boneIndex]; var brot = boneRotList[tdata.boneIndex]; var bscl = boneSclList[tdata.boneIndex]; // チームスケール倍率算出 if (tdata.initScale.x > 0.0f) { tdata.scaleRatio = math.length(bscl) / math.length(tdata.initScale); } // マイナススケール対応 tdata.scaleDirection = math.sign(bscl); if (bscl.x < 0 || bscl.y < 0 || bscl.z < 0) { tdata.quaternionScale = new float4(-math.sign(bscl), 1); } else { tdata.quaternionScale = 1; } // ワールド移動影響 WorldInfluence wdata = teamWorldInfluenceList[teamId]; // 移動量算出 float3 moveVector = bpos - wdata.oldPosition; quaternion moveRot = MathUtility.FromToRotation(wdata.oldRotation, brot); // 移動影響(無視する移動量+考慮する移動量) var moveLen = math.length(moveVector); if (moveLen > 1e-06f) { float speed = moveLen / dtime; //const float maxspeed = 10.0f; // todo:最大速度テスト m/s float ratio = math.max(speed - wdata.maxMoveSpeed, 0.0f) / speed; wdata.moveIgnoreOffset = moveVector * ratio; wdata.moveOffset = moveVector - wdata.moveIgnoreOffset; } else { wdata.moveIgnoreOffset = 0; wdata.moveOffset = 0; } // 回転影響 wdata.rotationOffset = moveRot; // 速度ウエイト更新 if (tdata.velocityWeight < 1.0f) { float addw = tdata.velocityRecoverySpeed > 1e-6f ? dtime / tdata.velocityRecoverySpeed : 1.0f; tdata.velocityWeight = math.saturate(tdata.velocityWeight + addw); } // テレポート判定 if (wdata.resetTeleport == 1) { // テレポート距離はチームスケールを乗算する if (moveLen >= wdata.teleportDistance * tdata.scaleRatio || math.degrees(MathUtility.Angle(moveRot)) >= wdata.teleportRotation) { tdata.SetFlag(Flag_Reset_WorldInfluence, true); tdata.SetFlag(Flag_Reset_Position, true); } } bool reset = false; if (tdata.IsFlag(Flag_Reset_WorldInfluence) || tdata.IsFlag(Flag_Reset_Position)) { // リセット wdata.moveOffset = 0; wdata.moveIgnoreOffset = 0; wdata.rotationOffset = quaternion.identity; wdata.oldPosition = bpos; wdata.oldRotation = brot; // チームタイムリセット(強制更新) tdata.nowTime = updateDeltaTime; // 速度ウエイト tdata.velocityWeight = wdata.stabilizationTime > 1e-6f ? 0.0f : 1.0f; tdata.velocityRecoverySpeed = wdata.stabilizationTime; reset = true; } wdata.nowPosition = bpos; wdata.nowRotation = brot; // 書き戻し teamWorldInfluenceList[teamId] = wdata; // 時間更新(タイムスケール対応) UpdateTime(ref tdata, reset); // リセットフラグOFF tdata.SetFlag(Flag_Reset_WorldInfluence, false); // 風 Wind(ref tdata, bpos); } // 書き戻し teamData[teamId] = tdata; }
// パーティクルごと public void Execute(int index) { // 初期化コピー var nextpos = nextPosList[index]; outNextPosList[index] = nextpos; var flag = flagList[index]; if (flag.IsValid() == false || flag.IsFixed()) { return; } // チーム var team = teamDataList[teamIdList[index]]; if (team.IsActive() == false || team.restoreRotationGroupIndex < 0) { return; } // 更新確認 if (team.IsUpdate() == false) { return; } int pstart = team.particleChunk.startIndex; int vindex = index - pstart; // クロスごとの拘束データ var gdata = groupList[team.restoreRotationGroupIndex]; if (gdata.active == 0) { return; } // 参照情報 var refdata = refDataList[gdata.refChunk.startIndex + vindex]; if (refdata.count > 0) { // power float depth = depthList[index]; float dataPower = gdata.restorePower.Evaluate(depth); // 補間力 // 90ups基準 float power = 1.0f - math.pow(1.0f - dataPower, updatePower); float3 addpos = 0; // 自身の基準位置 float3 bpos = basePosList[index]; int dataIndex = gdata.dataChunk.startIndex + refdata.startIndex; for (int i = 0; i < refdata.count; i++, dataIndex++) { var data = dataList[dataIndex]; if (data.IsValid() == false) { continue; } // 親 int pindex = pstart + data.targetVertexIndex; float3 pbpos = basePosList[pindex]; var ppos = nextPosList[pindex]; // 本来の方向ベクトル float3 tv = bpos - pbpos; // 現在ベクトル float3 v = nextpos - ppos; // 球面線形補間 var q = MathUtility.FromToRotation(v, tv, power); v = math.mul(q, v); float3 gpos = ppos + v; // 加算位置 addpos += gpos - nextpos; } var opos = nextpos; nextpos += addpos / refdata.count; // 書き出し outNextPosList[index] = nextpos; // 速度影響 var av = (nextpos - opos) * (1.0f - gdata.velocityInfluence); posList[index] = posList[index] + av; } }