/// <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) { dir = Vector3.zero; var ldir = GetLocalDir(); var l = ldir * Length; var tpos = transform.position; var trot = transform.rotation; var spos = trot * -l + tpos; // スケールは含めない var epos = trot * l + tpos; // スケールは含めない float t = MathUtility.ClosestPtPointSegmentRatio(pos, spos, epos); float cr = Mathf.Lerp(StartRadius, EndRadius, 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; } return(true); } else { dir = v.normalized; p = d + dir * cr; return(false); } }
void CapsuleColliderDetection(ref float3 nextpos, float3 oldpos, float radius, int cindex, float3 dir) { var cpos = nextPosList[cindex]; var crot = nextRotList[cindex]; // x = 長さ(片側) // y = 始点半径 // z = 終点半径 //var lpos = localPosList[cindex]; var cradius = radiusList[cindex]; // スケール var tindex = transformIndexList[cindex]; var cscl = boneSclList[tindex]; float scl = math.dot(cscl, dir); // dirの軸のスケールを使用する cradius *= scl; // カプセル始点と終点 float3 l = math.mul(crot, dir * cradius.x); float3 spos = cpos - l; float3 epos = cpos + l; float sr = cradius.y; float er = cradius.z; // 移動前のパーティクル位置から押し出し平面を求める //float3 c = 0, n = 0; float t = MathUtility.ClosestPtPointSegmentRatio(oldpos, spos, epos); float r = math.lerp(sr, er, t); float3 d = math.lerp(spos, epos, t); float3 v = oldpos - d; var len = math.length(v); float3 n = math.normalize(v); len = math.min(len, r + radius); len *= 0.999f; //float3 c = d + n * (r + radius); float3 c = d + n * len; // 平面衝突判定 float3 opos; if (MathUtility.IntersectSegmentPlane(oldpos, nextpos, c, n, out opos)) { nextpos = opos; } // c = 平面位置 // n = 平面方向 // 平面衝突判定と押し出し //return MathUtility.IntersectPointPlaneDist(c, n, nextpos, out nextpos); }
/// <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) { var cpos = nextPosList[cindex]; var crot = nextRotList[cindex]; // x = 長さ(片側) // y = 始点半径 // z = 終点半径 //var lpos = localPosList[cindex]; var cradius = radiusList[cindex]; // スケール var tindex = transformIndexList[cindex]; var cscl = boneSclList[tindex]; float scl = math.dot(math.abs(cscl), dir); // dirの軸のスケールを使用する cradius *= scl; float3 c = 0, n = 0; //if (keep) //{ // // 形状キープ // // 物理OFFの基本状態から拘束を決定 // var cbasepos = basePosList[cindex]; // var cbaserot = baseRotList[cindex]; // // カプセル始点と終点 // float3 l = math.mul(cbaserot, dir * cradius.x); // float3 spos = cbasepos - l; // float3 epos = cbasepos + l; // float sr = cradius.y; // float er = cradius.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 * cradius.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 * cradius.x); float3 spos = coldpos - l; float3 epos = coldpos + l; float sr = cradius.y; float er = cradius.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 * cradius.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)); }
/// <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); }