Physics2DのPhysicsJointについて

概要

今回はJointについて。

PS Suite SDKの話。
Physics2Dのサンプルとしてある、Physics2DSample。
その中の、

  • JointScene(固定、回転、スライダージョイントの生成方法を示したシーンです。)
  • BallJointScene(基本的なボールジョイントを生成するサンプルシーンです。)
  • NonCenterJointScene(ジョイントの中心点をいろいろに設定できることを示したサンプルシーンです。)
  • SliderJointScene(基本的なスライダージョイントを生成するサンプルシーンです。)
  • AnyDirSliderScene(任意方向のスライダージョイントを生成するサンプルシーンです。)
  • ChainJointScene(基本的なチェーンをジョイントで生成するサンプルシーンです。)

について。

流れ
  1. ボールジョイント・BallJointScene
  2. ボールジョイント2・NonCenterJointScene
  3. スライダージョイント・SliderJointScene
  4. スライダージョイント2・AnyDirSliderScene
  5. ボールジョイントを使用してのチェーンの生成・ChainJointScene

ボールジョイント・BallJointScene

ここではボールジョイントを使用した固定ジョイント(位置が動かないものをそう呼んでいるらしい)について。
サンプルでは

173行目 Complete free Rotation 自由に回転
202行目 Locked rotation 一切回転しない
231行目 Limited free rotation 角度制限付き。それまでは自由に回転する
262行目 Loose restriction rotation 緩い回転?回転に重みがかかった感じ。


作り方

PhysicsJoint( PhysicsBody body1,PhysicsBody body2,Vector2 anchor, uint index1,uint index2 )

body1 ジョイントに接続された一方の剛体
body2 ジョイントに接続されたもう一方の剛体
anchor ジョイントの接続点。ジョイントの位置
index1 剛体1のインデックス
index2 剛体2のインデックス
PhysicsBody bodyA = sceneBodies[ objectA ]; //スタティック剛体
PhysicsBody bodyB = sceneBodies[ objectB ];
sceneJoints[numJoint] = new PhysicsJoint(bodyA, bodyB, bodyB.position, (uint)objectA, (uint)objectB);
sceneJoints[numJoint].axis1Lim = new Vector2(1.0f, 0.0f);
sceneJoints[numJoint].axis2Lim = new Vector2(0.0f, 1.0f);
//angleLimやangleLower、angleUpperを設定する。ここでは省略
numJoint++;

(剛体のインデックスが必要な意味がわかんないが。)

スタティック剛体にする

接続する剛体のどちらかはスタティック剛体にする。
そうすることで、ジョイントの位置が安定する。剛体がより大きくより近いほど安定しやすい。
両方アクティブ剛体だと、暴走する。(設定の問題?)

Aがスタティック剛体。ジョイントの位置をBの位置としたことで、
Bは完全(安定すれば)に位置を固定された状態になる。

axisLim

ここではともに初期設定のまま。

Vector2 axis1Lim = new Vector2(1, 0)
ジョイントの制御軸1は制御軸2と直行している必要がある
axis1Lim = new Vector2(1, 0) はX方向の移動をロックする
正規化されたベクトルであるとき、方向移動を完全にロックする

Vector2 axis2Lim = new Vector2(0, 1)
ジョイントの制御軸2は制御軸1と直行している必要がある
axis1Lim = new Vector2(1, 0) はY方向の移動をロックする
正規化されたベクトルであるとき、方向移動を完全にロックする

angleLim、angleLower、angleUpper

これらの値を変更することで、回転に制限をかけることができる。

float angleLim = 1.0f
ジョイントの回転制御
angleLim [0.0f - 1.0f]
回転のロック angleLim=1.0f
回転のフリー angleLim=0.0f

float angleLower = 0.0f 回転の下限値
float angleUpper = 0.0f 回転の上限値

angleLim = 0.0f Complete free Rotation 自由に回転
angleLim = 1.0f Locked rotation 一切回転しない
angleLower=45度・angleLower=45度 Limited free rotation 角度制限付き。それまでは自由に回転する
0<angleLim<1 Loose restriction rotation 緩い回転?回転に重みがかかった感じ。

となる。
仮に、

sceneJoints[numJoint].angleLim =0.5f;
sceneJoints[numJoint].angleLower = PhysicsUtility.GetRadian(-45.0f);
sceneJoints[numJoint].angleUpper = PhysicsUtility.GetRadian(45.0f);

とすると、
45度までは自由に回転するが、それ以降はangleLimによる制限がかかった回転をする。

ボールジョイント2・NonCenterJointScene


このサンプルでは、
agnleLim = 0.0fの状態で、

anchor ジョイントの接続点。ジョイントの位置

を変更している。
もちろん、接続されている剛体の一方はスタティック剛体。

そうすることで、
ジョイントを中心に回転する剛体が生成可能。

注意

But please notice that it may be unstable if the center of the joint is outside the rigid body
and it is far away from the center of the rigid body.

剛体の中心から離れてジョイントを作成が可能だが、
離れれば離れるほど数値誤差によって不安定になりますよ。

くどい程にこれに似た内容が書いてある。
実際上の画像の一番左は少しずれる。

スライダージョイント・SliderJointScene


ここで説明するのは

  • 垂直スライダー
  • 水平スライダー

ともに距離制限アリとナシをそれぞれ。

必要なもの

PhysicsJointの生成の所まではボールジョイントと同じ。
スライダージョイントの生成のために設定するのは、
axis1Lim,axis2Lim

axis1Lower,axis1Upper,axis2Lower,axis2Upper

Vector2 axis1Lim = new Vector2(1, 0)
ジョイントの制御軸1は制御軸2と直行している必要がある
axis1Lim = new Vector2(1, 0) はX方向の移動をロックする
正規化されたベクトルであるとき、方向移動を完全にロックする

Vector2 axis2Lim = new Vector2(0, 1)
ジョイントの制御軸2は制御軸1と直行している必要がある
axis1Lim = new Vector2(1, 0) はY方向の移動をロックする
正規化されたベクトルであるとき、方向移動を完全にロックする

axis1Lower = 0.0f
axis2Lower = 0.0f
併進移動の下限値

axis1Upper= 0.0f
axis2Upper= 0.0f
併進移動の上限値

垂直スライダー・距離制限なし

上下に自由に動く。
片方をスタティック剛体と接続したりなどの
基本のPhysicsJointの生成部分は一緒。
大事なのはaxisLim。
ボールジョイントを生成した時は↓

sceneJoints[numJoint].axis1Lim = new Vector2(1.0f, 0.0f); 
sceneJoints[numJoint].axis2Lim = new Vector2(0.0f, 1.0f);

垂直スライダーでは↓。

sceneJoints[numJoint].axis1Lim = new Vector2(1.0f, 0.0f);
sceneJoints[numJoint].axis2Lim = new Vector2(0.0f, 0.0f); //制限をなくしている

axis1Limで水平方向の動きをロック(正規化されたベクトルなので)。
axis2Limを0にすることで、axis1Limの直行している方向、今回は垂直方向が自由に動く

水平スライダー・距離制限なし
sceneJoints[numJoint].axis1Lim = new Vector2(0.0f, 0.0f);
sceneJoints[numJoint].axis2Lim = new Vector2(0.0f, 1.0f); 

逆にするだけ。

Tip

このサンプルではY軸下方向に重力がかかっている。
ので、水平スライダーはその影響を受けず、滑る。減速しない。
止めるためには剛体に空気抵抗をつける。

bodyB.airFriction = 0.1f;

といった感じに。

float airFriction = 0.0f
Integrate Phaseで考慮される空気摩擦係数

垂直スライダー・水平スライダー・距離制限あり

垂直方向に動くが、距離の制限を付ける。
垂直スライダー距離制限アリは↓の設定。

sceneJoints[numJoint].axis1Lim = new Vector2(1.0f, 0.0f);
sceneJoints[numJoint].axis2Lim = new Vector2(0.0f, 1.0f);
sceneJoints[numJoint].axis2Lower = -10.0f;
sceneJoints[numJoint].axis2Upper = +10.0f;

axis1Lim・axis2Limはどちらもロック。
その上で、axis2Lower・axis2Upperに値を入れてあげる。

sceneJoints[numJoint].axis1Lower = -10.0f;
sceneJoints[numJoint].axis1Upper = +10.0f;

とすれば水平スライダー距離制限アリになる

スライダージョイント2・AnyDirSliderScene


任意の方向にスライドできますよ。というサンプル。

  • 189行目。基本
  • 245行目。距離制限。
  • 217行目。距離制限。(というより移動制限?)
189行目。基本
sceneJoints[numJoint].axis1Lim = (new Vector2(-1.0f, 2.0f)).Normalize();
sceneJoints[numJoint].axis2Lim = new Vector2(0.0f, 0.0f);

制御軸を変えるだけ。
この場合axis2Limをフリーにしているので
axis1Limに直行するVector2(2.0f, 1.0f)方向に自由にスライドする。

245行目。距離制限。
sceneJoints[numJoint].axis1Lim = (new Vector2(-1.0f, 2.0f)).Normalize();
sceneJoints[numJoint].axis2Lim = (new Vector2(2.0f, 1.0f)).Normalize();
sceneJoints[numJoint].axis2Lower = -10.0f;
sceneJoints[numJoint].axis2Upper = +10.0f;

axis2Lowerなどで制限を加える場合、
axis1Lim・axis2Limはしっかりと正規化し直行した軸を入れてロックする。

217行目。距離制限。(というより移動制限?)
sceneJoints[numJoint].axis1Lim = (new Vector2(-1.0f, 2.0f)).Normalize();
sceneJoints[numJoint].axis2Lim = (new Vector2(2.0f, 1.0f)).Normalize() * 0.01f;

もともと

正規化されたベクトルであるとき、方向移動を完全にロックする

とあるので、上の方法でも制限を加えることができるらしい。
詳しく解説がないので。。

ボールジョイントを使用してのチェーンの生成・ChainJointScene


チェーンの先頭をスタティック剛体と接続

PhysicsBody bodyA = sceneBodies[0]; //スタティック剛体
PhysicsBody bodyB = sceneBodies[numBody-1];

それ以降は一つ手前と接続。

PhysicsBody bodyA = sceneBodies[numBody-2];
PhysicsBody bodyB = sceneBodies[numBody-1];

他の値は全部基本通り。

sceneJoints[numJoint].axis1Lim = new Vector2(1.0f, 0.0f);
sceneJoints[numJoint].axis2Lim = new Vector2(0.0f, 1.0f);
sceneJoints[numJoint].angleLim =0;
冒頭の[Tips and notice]

Please take care about the mass of rigid body which is linked to the chain joint.
When the mass of sphere is very heavy,
Solver phase cannot solve the joint within pre-defined iteration num of calculation completely.

Please notice that there are no confliction between collision repluse & joint linkage.(collision repluse <-> joint linkage)
Two sceneBodies (which are very near) are linked to each other, it may be necessary to
set the collisionFilter or groupFilter properly to avoid the collision detection for this pair.

ちょっとよくわからないので、ほぼ全文そのまま載せた。

たぶん

  • 質量に気をつけてね。重すぎると計算しきれないよ。
  • 接続する剛体の距離には気をつかってね。どうしてもやりたいならcollisionFilterやgroupFilterを使う必要があるよ。

ってことかと。