예제 #1
0
            /// <summary>
            /// 角度制限
            /// </summary>
            /// <param name="data"></param>
            /// <param name="cindex"></param>
            /// <param name="nextpos"></param>
            /// <param name="outpos"></param>
            /// <param name="ang"></param>
            /// <returns></returns>
            private bool AnglePenetration(ref PenetrationData data, int cindex, float3 nextpos, out float3 outpos, float ang)
            {
                var cpos = nextPosList[cindex];
                var crot = nextRotList[cindex];

                // スケール
                var tindex = transformIndexList[cindex];
                var cscl   = boneSclList[tindex];
                //float scl = cscl.x; // X軸を採用(基本的には均等スケールのみを想定)

                // 押し出し平面を求める
                var c = math.mul(crot, data.localPos * cscl) + cpos;
                var n = math.mul(crot, data.localDir);

                var v = nextpos - c;

                float3 v2;

                if (MathUtility.ClampAngle(v, n, ang, out v2))
                {
                    outpos = c + v2;
                    return(true);
                }

                outpos = nextpos;
                return(false);
            }
            // ボーン
            //[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;
            }
예제 #3
0
            // ルートラインごと
            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;
                }
            }