// ルートラインごと public void Execute(int rootIndex) { // チーム int teamIndex = rootTeamList[rootIndex]; if (teamIndex == 0) { return; } var team = teamDataList[teamIndex]; if (team.IsActive() == false || team.clampDistance2GroupIndex < 0) { return; } // 更新確認 if (team.IsUpdate() == false) { return; } // グループデータ var gdata = groupList[team.clampDistance2GroupIndex]; 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; 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 || flag.IsFixed()) { continue; } var npos = nextPosList[index]; var opos = npos; var ppos = nextPosList[pindex]; // 現在のベクトル var v = npos - ppos; // 長さクランプ var len = data.length * team.scaleRatio; v = MathUtility.ClampVector(v, len * gdata.minRatio, len * gdata.maxRatio); npos = ppos + v; // 格納 nextPosList[index] = npos; // 速度影響 var av = (npos - opos) * (1.0f - gdata.velocityInfluence); posList[index] = posList[index] + av; } }
// パーティクルごと public void Execute(int index) { var flag = flagList[index]; if (flag.IsValid() == false || flag.IsFixed()) { return; } var team = teamDataList[teamIdList[index]]; if (team.IsActive() == false) { return; } if (team.clampPositionGroupIndex < 0) { return; } // 更新確認 if (team.IsUpdate() == false) { return; } // グループデータ var gdata = clampPositionGroupList[team.clampPositionGroupIndex]; if (gdata.active == 0) { return; } var nextpos = nextPosList[index]; var depth = depthList[index]; var limitLength = gdata.limitLength.Evaluate(depth); // baseposからの最大移動距離制限 var basepos = basePosList[index]; var v = nextpos - basepos; // nextpos // 摩擦係数から移動率を算出 var friction = frictionList[index]; float moveratio = math.saturate(1.0f - friction * Define.Compute.FrictionMoveRatio); if (gdata.IsAxisCheck()) { // 楕円体判定 float3 axisRatio = gdata.axisRatio; // 基準軸のワールド回転 quaternion rot = baseRotList[index]; // 基準軸のローカルベクトルへ変換 quaternion irot = math.inverse(rot); float3 lv = math.mul(irot, v); // Boxクランプ float3 axisRatio1 = axisRatio * limitLength; lv = math.clamp(lv, -axisRatio1, axisRatio1); // 基準軸のワールドベクトルへ変換 // 最終的に(v)が楕円体でクランプされた移動制限ベクトルとなる v = math.mul(rot, lv); } // nextposの制限 v = MathUtility.ClampVector(v, 0.0f, limitLength); // 最大速度クランプ v = (basepos + v) - nextpos; if (team.IsFlag(PhysicsManagerTeamData.Flag_IgnoreClampPositionVelocity) == false) { v = MathUtility.ClampVector(v, 0.0f, maxMoveLength); } // 移動位置 var opos = nextpos; var fpos = opos + v; // 摩擦係数による移動制限(衝突しているパーティクルは動きづらい) nextpos = math.lerp(opos, fpos, moveratio); // 書き込み nextPosList[index] = nextpos; // 速度影響 var av = (nextpos - opos) * (1.0f - gdata.velocityInfluence); posList[index] = posList[index] + av; }
/// <summary> /// 指定座標に最も近い衝突点pと、中心軸からのpへの方向dirを返す。 /// ※エディタ計算用 /// </summary> /// <param name="pos"></param> /// <param name="p"></param> /// <param name="dir"></param> public override bool CalcNearPoint(Vector3 pos, out Vector3 p, out Vector3 dir, out Vector3 d, bool skinning) { dir = Vector3.zero; var ldir = GetLocalDir(); var l = ldir * Length; //var tpos = transform.position; var tpos = transform.TransformPoint(Center); var trot = transform.rotation; float scl = GetScale(); l *= scl; var spos = trot * -l + tpos; var epos = trot * l + tpos; #if true // 半径分長さ拡張 if (skinning == false) { const float ratio = 0.5f; spos = trot * (-l - ldir * StartRadius * scl * ratio) + tpos; epos = trot * (l + ldir * EndRadius * scl * ratio) + tpos; } #endif float t = MathUtility.ClosestPtPointSegmentRatio(pos, spos, epos); #if true // 蓋の部分は無効とする if (skinning == false) { if (t < 0.0001f || t > 0.9999f) { p = Vector3.zero; d = Vector3.zero; return(false); } } #endif float cr = Mathf.Lerp(StartRadius * scl, EndRadius * scl, t); d = spos + (epos - spos) * t; // 中心軸位置 var v = pos - d; float vlen = v.magnitude; if (vlen < cr) { // 衝突している p = pos; if (vlen > 0.0f) { dir = v.normalized; } } else { dir = v.normalized; p = d + dir * cr; } return(true); }
// パーティクルごと 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; } }
// ボーン //[Unity.Collections.ReadOnly] //public NativeArray<quaternion> boneRotList; // パーティクルごと public void Execute(int index) { var flag = flagList[index]; if (flag.IsValid() == false) { return; } // チームデータ int teamId = teamIdList[index]; var teamData = teamDataList[teamId]; // ここからは更新がある場合のみ実行(グローバルチームは除く) if (teamId != 0 && teamData.IsUpdate() == false) { return; } var oldpos = oldPosList[index]; var oldrot = oldRotList[index]; float3 nextPos = oldpos; quaternion nextRot = oldrot; //if (flag.IsCollider()) //{ // // コライダー // // todo:こっちのほうがよい? // nextPos = basePosList[index]; // nextRot = baseRotList[index]; //} if (flag.IsFixed()) { // キネマティックパーティクル // nextPos/nextRotが前回の姿勢 var oldNextPos = nextPosList[index]; var oldNextRot = nextRotList[index]; // OldPos/Rot から BasePos/Rot に step で補間して現在姿勢とする #if true // 高フレームレートで位置がスキップされてしまう問題の対処(1.8.3) float stime = teamData.startTime + updateDeltaTime * teamData.runCount; float oldtime = teamData.oldTime; float interval = teamData.time - oldtime; float step = math.saturate((stime - oldtime) / interval); #else float stime = teamData.startTime + updateDeltaTime * teamData.runCount; float oldtime = teamData.time - teamData.addTime; float step = math.saturate((stime - oldtime) / teamData.addTime); #endif nextPos = math.lerp(oldpos, basePosList[index], step); nextRot = math.slerp(oldrot, baseRotList[index], step); // 前回の姿勢をoldpos/rotとしてposList/rotListに格納する if (flag.IsCollider() && teamId == 0) { // グローバルコライダー // 移動量と回転量に制限をかける(1.7.5) // 制限をかけないと高速移動/回転時に遠く離れたパーティクルが押し出されてしまう問題が発生する。 oldpos = MathUtility.ClampDistance(nextPos, oldNextPos, Define.Compute.GlobalColliderMaxMoveDistance); oldrot = MathUtility.ClampAngle(nextRot, oldNextRot, math.radians(Define.Compute.GlobalColliderMaxRotationAngle)); } else { oldpos = oldNextPos; oldrot = oldNextRot; } // debug //nextPos = basePosList[index]; //nextRot = baseRotList[index]; } else { // 動的パーティクル var depth = depthList[index]; var maxVelocity = teamMaxVelocityList[teamId].Evaluate(depth); var drag = teamDragList[teamId].Evaluate(depth); var gravity = teamGravityList[teamId].Evaluate(depth); var mass = teamMassList[teamId].Evaluate(depth); var velocity = velocityList[index]; // チームスケール倍率 maxVelocity *= teamData.scaleRatio; // massは主に伸縮を中心に調整されるので、フォース適用時は少し調整する mass = (mass - 1.0f) * teamData.forceMassInfluence + 1.0f; // 安定化用の速度ウエイト velocity *= teamData.velocityWeight; // 最大速度 velocity = MathUtility.ClampVector(velocity, 0.0f, maxVelocity); // 空気抵抗(90ups基準) // 重力に影響させたくないので先に計算する(※通常はforce適用後に行うのが一般的) velocity *= math.pow(1.0f - drag, updatePower); // フォース // フォースは空気抵抗を無視して加算する float3 force = 0; // 重力 // 重力は質量に関係なく一定 #if false // 方向減衰 if (teamData.IsFlag(PhysicsManagerTeamData.Flag_DirectionalDamping) && teamData.directionalDampingBoneIndex >= 0) { float3 dampDir = math.mul(boneRotList[teamData.directionalDampingBoneIndex], teamData.directionalDampingLocalDir); var dot = math.dot(dampDir, new float3(0, -1, 0)) * 0.5f + 0.5f; // 1.0(0) - 0.5(90) - 0.0(180) var damp = teamDirectionalDampingList[teamId].Evaluate(dot); gravity *= damp; } #endif // (最後に質量で割るためここでは質量をかける) force.y += gravity * mass; // 外部フォース if (loopIndex == 0) { switch (teamData.forceMode) { case PhysicsManagerTeamData.ForceMode.VelocityAdd: force += teamData.impactForce; break; case PhysicsManagerTeamData.ForceMode.VelocityAddWithoutMass: force += teamData.impactForce * mass; break; case PhysicsManagerTeamData.ForceMode.VelocityChange: force += teamData.impactForce; velocity = 0; break; case PhysicsManagerTeamData.ForceMode.VelocityChangeWithoutMass: force += teamData.impactForce * mass; velocity = 0; break; } // 外力 force += teamData.externalForce; } // 外力チームスケール倍率 force *= teamData.scaleRatio; // 速度計算(質量で割る) velocity += (force / mass) * updateDeltaTime; // 速度を理想位置に反映させる nextPos = oldpos + velocity * updateDeltaTime; } // 予定座標更新 ============================================================== // 摩擦減衰 var friction = frictionList[index]; friction = friction * Define.Compute.FrictionDampingRate; frictionList[index] = friction; //frictionList[index] = 0; // 移動前の姿勢 posList[index] = oldpos; rotList[index] = oldrot; // 予測位置 nextPosList[index] = nextPos; nextRotList[index] = nextRot; // コリジョン用 //velocityList[index] = nextPos; }
/// <summary> /// カプセル衝突判定 /// </summary> /// <param name="nextpos0">エッジの始点</param> /// <param name="nextpos1">エッジの終点</param> /// <param name="corr0"></param> /// <param name="corr1"></param> /// <param name="radius"></param> /// <param name="cindex"></param> /// <param name="dir"></param> /// <returns></returns> bool CapsuleColliderDetection(float3 nextpos0, float3 nextpos1, ref float3 corr0, ref float3 corr1, float radius, int cindex, float3 dir) //bool CapsuleColliderDetection(float3 nextpos0, float3 nextpos1, float3 oldpos0, float3 oldpos1, ref float3 corr0, ref float3 corr1, float radius, int cindex, float3 dir) { var cpos = nextPosList[cindex]; var crot = nextRotList[cindex]; var coldpos = posList[cindex]; var coldrot = rotList[cindex]; var lpos = localPosList[cindex]; // スケール var tindex = transformIndexList[cindex]; var cscl = boneSclList[tindex]; float scl = math.dot(cscl, dir); // dirの軸のスケールを使用する lpos *= scl; // lpos.x = 長さ(片側) // lpos.y = 始点半径 // lpos.z = 終点半径 // 移動前のコライダーに対するエッジの最近接点を求める float3 oldl = math.mul(coldrot, dir * lpos.x); float3 soldpos = coldpos - oldl; float3 eoldpos = coldpos + oldl; float3 c1, c2; float s, t; MathUtility.ClosestPtSegmentSegment(soldpos, eoldpos, nextpos0, nextpos1, out s, out t, out c1, out c2); //MathUtility.ClosestPtSegmentSegment(soldpos, eoldpos, oldpos0, oldpos1, out s, out t, out c1, out c2); float3 v = c2 - c1; // 現在のカプセル始点と終点 float3 l = math.mul(crot, dir * lpos.x); float3 spos = cpos - l; float3 epos = cpos + l; float sr = lpos.y; float er = lpos.z; // 移動後のコライダーのベクトルに変換する var iq = math.inverse(coldrot); float3 lv = math.mul(iq, v); v = math.mul(crot, lv); // コライダーの半径 float r = math.lerp(sr, er, s); // 平面方程式 float3 n = math.normalize(v); float3 q = math.lerp(spos, epos, s); float3 c = q + n * (r + radius); // c = 平面位置 // n = 平面方向 // 平面衝突判定と押し出し float3 outpos0, outpos1; bool ret0 = MathUtility.IntersectPointPlane(c, n, nextpos0, out outpos0); bool ret1 = MathUtility.IntersectPointPlane(c, n, nextpos1, out outpos1); if (ret0) { corr0 += outpos0 - nextpos0; } if (ret1) { corr1 += outpos1 - nextpos1; } return(ret0 || ret1); }
//public NativeArray<float> frictionList; // パーティクルごと public void Execute(int index) { // 初期化コピー float3 nextpos = nextPosList[index]; outNextPosList[index] = nextpos; var flag = flagList[index]; if (flag.IsValid() == false || flag.IsFixed() || flag.IsCollider()) { return; } // チーム var team = teamIdList[index]; var teamData = teamDataList[team]; if (teamData.IsActive() == false) { return; } if (teamData.penetrationGroupIndex < 0) { return; } // 更新確認 if (teamData.IsUpdate() == false) { return; } // グループデータ var gdata = groupList[teamData.penetrationGroupIndex]; if (gdata.active == 0) { return; } // データ参照情報 int vindex = index - teamData.particleChunk.startIndex; var refdata = refDataList[gdata.refDataChunk.startIndex + vindex]; if (refdata.count == 0) { return; } // depth var depth = depthList[index]; // move radius var moveradius = gdata.radius.Evaluate(depth); // 浸透距離 float distance = gdata.distance.Evaluate(depth); // チームスケール倍率 float3 scaleDirection = teamData.scaleDirection; float teamScale = teamData.scaleRatio; distance *= teamScale; moveradius *= teamScale; // モード別処理 var oldpos = nextpos; if (gdata.mode == 0) { // Surface Penetration // ベース位置から算出する var bpos = basePosList[index]; var brot = baseRotList[index]; int dindex = refdata.startIndex; var data = dataList[gdata.dataChunk.startIndex + dindex]; if (data.IsValid()) { //float3 n = math.mul(brot, data.localDir); float3 n = math.mul(brot, data.localDir * scaleDirection); // マイナススケール対応 // 球の位置 var c = bpos + n * (distance - moveradius); // 球内部制限 var v = nextpos - c; var len = math.length(v); if (len > moveradius) { v *= (moveradius / len); nextpos = c + v; } } } else if (gdata.mode == 1) { // Collider Penetration #if true // 球内制限 float3 c = 0; int ccnt = 0; int dindex = refdata.startIndex; for (int i = 0; i < refdata.count; i++, dindex++) { var data = dataList[gdata.dataChunk.startIndex + dindex]; if (data.IsValid()) { int cindex = colliderList[teamData.colliderChunk.startIndex + data.colliderIndex]; var cflag = flagList[cindex]; if (cflag.IsValid() == false) { continue; } // 球内部制限 c += InverseSpherePosition(ref data, teamScale, scaleDirection, distance, cindex, moveradius); ccnt++; } } if (ccnt > 0) { c /= ccnt; var opos = InverseSpherePenetration(c, moveradius, nextpos); var addv = (opos - nextpos); // stiffness test //addv *= 0.25f; // 摩擦を入れてみる //float friction = math.length(addv) * 10.0f; //frictionList[index] = math.max(friction, frictionList[index]); // 大きい方 nextpos += addv; } #else // 平面制限 float3 c = 0; float3 n = 0; int ccnt = 0; int dindex = refdata.startIndex; for (int i = 0; i < refdata.count; i++, dindex++) { var data = dataList[gdata.dataChunk.startIndex + dindex]; if (data.IsValid()) { int cindex = colliderList[teamData.colliderChunk.startIndex + data.colliderIndex]; // プレーン制限(今のところあまり有効性なし) float3 center, dir; InversePlanePosition(ref data, teamScale, distance, cindex, out center, out dir); c += center; n += dir; ccnt++; } } if (ccnt > 0) { c /= ccnt; n = math.normalize(n); // c = 平面位置 // n = 平面方向 // 平面衝突判定と押し出し float3 opos; MathUtility.IntersectPointPlane(c, n, nextpos, out opos); var addv = (opos - nextpos); // stiffness test //addv *= 0.25f; nextpos += addv; } #endif } // 速度影響はなし //posList[index] += (nextpos - oldpos); // 取りやめ、影響は100%にする(v1.8.0) // 書き戻し outNextPosList[index] = nextpos; }
// パーティクルごと 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.clampDistanceGroupIndex < 0) { return; } // 更新確認 if (team.IsUpdate() == false) { return; } int pstart = team.particleChunk.startIndex; int vindex = index - pstart; // クロスごとの拘束データ var gdata = groupList[team.clampDistanceGroupIndex]; if (gdata.active == 0) { return; } // 参照データ情報 var refdata = refDataList[gdata.refChunk.startIndex + vindex]; if (refdata.count > 0) { int dataIndex = gdata.dataChunk.startIndex + refdata.startIndex; ClampDistanceData data = clampDistanceList[dataIndex]; if (data.IsValid() == false) { return; } // ターゲット int pindex2 = pstart + data.targetVertexIndex; float3 nextpos2 = nextPosList[pindex2]; // 現在のベクトル float3 v = nextpos - nextpos2; // 復元長さ float length = data.length; // v1.7.0 length *= team.scaleRatio; // チームスケール倍率 //if (length == 0.0f) //{ // // 従来データ(basePosの長さから) // length = math.distance(basePosList[index], basePosList[pindex2]); //} // ベクトル長クランプ v = MathUtility.ClampVector(v, length * gdata.minRatio, length * gdata.maxRatio); // 位置 var opos = nextpos; nextpos = nextpos2 + v; // 摩擦係数から移動率を算出 float friction = frictionList[index]; float moveratio = math.saturate(1.0f - friction * Define.Compute.FrictionMoveRatio); nextpos = math.lerp(opos, nextpos, moveratio); // 書き出し outNextPosList[index] = nextpos; // 速度影響 var av = (nextpos - opos) * (1.0f - gdata.velocityInfluence); posList[index] = posList[index] + av; } }
/// <summary> /// カプセル衝突判定 /// </summary> /// <param name="nextpos"></param> /// <param name="pos"></param> /// <param name="radius"></param> /// <param name="cindex"></param> /// <param name="dir"></param> /// <param name="friction"></param> /// <returns></returns> float CapsuleColliderDetection(ref float3 nextpos, float3 basepos, float radius, int cindex, float3 dir, bool keep) { // lpos.x = 長さ(片側) // lpos.y = 始点半径 // lpos.z = 終点半径 var cpos = nextPosList[cindex]; var crot = nextRotList[cindex]; var lpos = localPosList[cindex]; // スケール var tindex = transformIndexList[cindex]; var cscl = boneSclList[tindex]; float scl = math.dot(cscl, dir); // dirの軸のスケールを使用する lpos *= scl; float3 c = 0, n = 0; if (keep) { // 形状キープ // 物理OFFの基本状態から拘束を決定 var cbasepos = basePosList[cindex]; var cbaserot = baseRotList[cindex]; // カプセル始点と終点 float3 l = math.mul(cbaserot, dir * lpos.x); float3 spos = cbasepos - l; float3 epos = cbasepos + l; float sr = lpos.y; float er = lpos.z; // 移動前のコライダー位置から押し出し平面を割り出す float t = MathUtility.ClosestPtPointSegmentRatio(basepos, spos, epos); float r = math.lerp(sr, er, t); float3 d = math.lerp(spos, epos, t); float3 v = basepos - d; // 移動前コライダーのローカルベクトル var iq = math.inverse(cbaserot); float3 lv = math.mul(iq, v); // 移動後コライダーに変換 l = math.mul(crot, dir * lpos.x); spos = cpos - l; epos = cpos + l; d = math.lerp(spos, epos, t); v = math.mul(crot, lv); n = math.normalize(v); c = d + n * (r + radius); } else { var coldpos = posList[cindex]; var coldrot = rotList[cindex]; // カプセル始点と終点 float3 l = math.mul(coldrot, dir * lpos.x); float3 spos = coldpos - l; float3 epos = coldpos + l; float sr = lpos.y; float er = lpos.z; // 移動前のコライダー位置から押し出し平面を割り出す float t = MathUtility.ClosestPtPointSegmentRatio(nextpos, spos, epos); float r = math.lerp(sr, er, t); float3 d = math.lerp(spos, epos, t); float3 v = nextpos - d; // 移動前コライダーのローカルベクトル var iq = math.inverse(coldrot); float3 lv = math.mul(iq, v); // 移動後コライダーに変換 l = math.mul(crot, dir * lpos.x); spos = cpos - l; epos = cpos + l; d = math.lerp(spos, epos, t); v = math.mul(crot, lv); n = math.normalize(v); c = d + n * (r + radius); } // c = 平面位置 // n = 平面方向 // 平面衝突判定と押し出し return(MathUtility.IntersectPointPlaneDist(c, n, nextpos, out nextpos)); }
// パーティクルごと 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.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; } }
/// <summary> /// ベジェ曲線から横軸位置(x=0.0~1.0)の縦軸値を取得する /// </summary> /// <param name="x">0.0~1.0</param> /// <returns></returns> public float Evaluate(float x) { return(MathUtility.GetBezierValue(StartValue, EndValue, CurveValue, Mathf.Clamp01(x))); }
// チームデータごと 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 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; } // 頂点がトライアングル回転姿勢制御されている場合はスキップする //if (flag.IsFlag(PhysicsManagerParticleData.Flag_TriangleRotation)) // 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 cflag = flagList[cindex]; // 子の現在位置 var cpos = posList[cindex]; // 子の本来のベクトル //float3 tv = math.normalize(math.mul(rot, cdata.localPos)); float3 tv = math.normalize(math.mul(rot, cdata.localPos * team.scaleDirection)); // マイナススケール対応(v1.7.6) ctv += tv; // 子の現在ベクトル float3 v = math.normalize(cpos - pos); cv += v; // 子頂点がトライアングル回転姿勢制御されている場合はスキップする if (cflag.IsFlag(PhysicsManagerParticleData.Flag_TriangleRotation)) { continue; } // 回転 var q = MathUtility.FromToRotation(tv, v); // 子の仮姿勢を決定 //var crot = math.mul(rot, cdata.localRot); var crot = math.mul(rot, new quaternion(cdata.localRot.value * team.quaternionScale)); // マイナススケール対応(v1.7.6) crot = math.mul(q, crot); rotList[cindex] = crot; } // 頂点がトライアングル回転姿勢制御されている場合はスキップする if (flag.IsFlag(PhysicsManagerParticleData.Flag_TriangleRotation)) { continue; } // 固定は回転させない判定(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); // 正規化しないとエラーになる場合がある } } }