Box2D回転ジョイントが分離する原因は何ですか?


7

ダイナミックボディ(長方形)とシンプルな回転ジョイント(低い角度と高い角度)を使用してラグドールを作成しました。ぼろ人形が地面(静的な物体)にぶつかると、身体がそわそわして関節が分離します。

ボディが地面にくっついているように見え、ラグドールの勢いが関節を引き離します(下のスクリーンショットを参照)。

代替テキスト

関連しているかどうかはわかりませんが、Box2DにBadlogic GDX Javaラッパーを使用しています。以下は、最も関連性の高いコードだと私が思うスニペットです。

private RevoluteJoint joinBodyParts(
    Body a, Body b, Vector2 anchor, 
    float lowerAngle, float upperAngle) {

    RevoluteJointDef jointDef = new RevoluteJointDef();

    jointDef.initialize(a, b, a.getWorldPoint(anchor));

    jointDef.enableLimit = true;
    jointDef.lowerAngle = lowerAngle;
    jointDef.upperAngle = upperAngle;

    return (RevoluteJoint)world.createJoint(jointDef);
}

private Body createRectangleBodyPart(
    float x, float y, float width, float height) {

    PolygonShape shape = new PolygonShape();
    shape.setAsBox(width, height);

    BodyDef bodyDef = new BodyDef();
    bodyDef.type = BodyType.DynamicBody;
    bodyDef.position.y = y;
    bodyDef.position.x = x;

    Body body = world.createBody(bodyDef);

    FixtureDef fixtureDef = new FixtureDef();
    fixtureDef.shape = shape;
    fixtureDef.density = 10;

    fixtureDef.filter.groupIndex = -1;
    fixtureDef.filter.categoryBits = FILTER_BOY;
    fixtureDef.filter.maskBits = FILTER_STUFF | FILTER_WALL;

    body.createFixture(fixtureDef);
    shape.dispose();

    return body;
}

頭を作成する方法は、長方形の方法とほぼ同じであるため、省略しました(ちょうど十字架の形状を使用します)。

これらのメソッドは次のように使用されます。

    torso = createRectangleBodyPart(x, y + 5, 0.25f, 1.5f);
    Body head = createRoundBodyPart(x, y + 7.4f, 1);

    Body leftLegTop = createRectangleBodyPart(x, y + 2.7f, 0.25f, 1);
    Body rightLegTop = createRectangleBodyPart(x, y + 2.7f, 0.25f, 1);
    Body leftLegBottom = createRectangleBodyPart(x, y + 1, 0.25f, 1);
    Body rightLegBottom = createRectangleBodyPart(x, y + 1, 0.25f, 1);

    Body leftArm = createRectangleBodyPart(x, y + 5, 0.25f, 1.2f);
    Body rightArm = createRectangleBodyPart(x, y + 5, 0.25f, 1.2f);

    joinBodyParts(torso, head, new Vector2(0, 1.6f), headAngle);

    leftLegTopJoint = joinBodyParts(torso, leftLegTop, new Vector2(0, -1.2f), 0.1f, legAngle);
    rightLegTopJoint = joinBodyParts(torso, rightLegTop, new Vector2(0, -1.2f), 0.1f, legAngle);
    leftLegBottomJoint = joinBodyParts(leftLegTop, leftLegBottom, new Vector2(0, -1), -legAngle * 1.5f, 0);
    rightLegBottomJoint = joinBodyParts(rightLegTop, rightLegBottom, new Vector2(0, -1), -legAngle * 1.5f, 0);

    leftArmJoint = joinBodyParts(torso, leftArm, new Vector2(0, 1), -armAngle * 0.7f, armAngle);
    rightArmJoint = joinBodyParts(torso, rightArm, new Vector2(0, 1), -armAngle * 0.7f, armAngle);

物理シミュレーションを固定タイムステップで実行しますか?そうでない場合は、必ず最初にそれを行う必要があります。
bummzack

回答:


5

Box2Dは、閉じたフォームソルバーではなく、反復を使用します。つまり、すべての制約はややソフトです。Box2Dはあなたが言うことを非常に一生懸命に試みますが、不正確さが発生します。

これを最小限に抑えるために、重要な順に、いくつかのことができます。

  • 固定サイズのタイムステップを使用します(の最初の引数Step)。これにより、ソルバーがより安定します-あなたの不正確さが互いに打ち消し合う可能性が高くなるか、少なくとも毎回同じように動作します。
  • より小さいタイムステップを使用します(1/30ではなく、1/60または1/120)。タイムステップが小さいほど、不正確さが小さくなります。
  • より多くのソルバー反復を使用します(の2番目と3番目の引数Step)。あなたは、それぞれの少なくとも10を取得しようとする必要があります。ソルバーの反復回数が多いほど、安定性を見つけて制約を正しく満たす機会がタイムステップごとに増えることになります。ただし、より小さく、より安定したタイムステップは、より多くの反復よりも優れています。十分に複雑な制約があると、100%正しく解決できない可能性があるため、反復を増やす前にタイムステップを減らしてみてください。
  • 密度の低い形状を使用します。密度10はかなり重いです。デフォルトの密度として、1などの小さいものを標準化してみてください。

こんにちはジョー、アドバイスありがとう。私はあなたの提案をすべて試しましたが、残念ながらこれは違いをもたらすようには見えませんでした。これが完全なソースコードです(現時点ではハックなプロトタイプです)-pastebin.com/F6YX3AyV
Nick Bolton
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.