Докуметация Cтарт Статьи Форум Лента Вход
Не официальное русскоязычное сообщество
Главная
    Документация jMonkeyEngine
        jMonkeyEngine Уроки и Документация
            Документация для продвинутых пользователей
                Физика Тряпичной куклы(Ragdoll)

Физика Тряпичной куклы(Ragdoll)

Опубликованно: 14.06.2017, 21:50
Последняя редакция, Andry: 02.07.2019 5:01

Ragdoll статья из Википедии

JMonkeyEngine3 имеет встроенную поддержку физики jBullet через пакет com.jme3.bullet. Физика не только несет ответственность за передачу столкновений, но и делает возможными шарниры и суставы. Один из примеров суставов физики — физика Тряпичной куклы(Ragdoll), показанная здесь.

ragdoll

Примеры кода

  • TestRagDoll.java (Совет: кликните что бы тянуть ragdoll)
  • Подготовка физики игры

    1. Создайте SimpleApplication с BulletAppState
      • Это дает нам PhysicsSpace для PhysicControl
    2. Добавить физический пол (фигура столкновений куб с массой ноль)

    Создание Ragdoll

    RagDoll — это простой «человек (манекен), который вы строите из фигур столкновения цилиндров. Ragdoll имеет 11 конечностей: 1 для плеч, 1 для тела, 1 для бедер; Плюс 2 руки и 2 ноги, которые состоят из двух конечностей. В вашей игре вы, скорее всего, замените цилиндры своими (лучше выглядящими) моделями конечности. В этом примере здесь мы просто используем простые цилиндры.

    Конечность

    Поскольку вы просто создаете ragdoll для этого примера, все конечности имеют одинаковую фигуру, и вы можете написать простой вспомогательный метод для их создания. Функция возвращает PhysicalControl с CollisionShape с указанием ширины, высоты, местоположения и вращения (по вертикали или по горизонтали), которые вы указываете. Вы выбираете CapsuleCollisionShape (цилиндр с закругленным верхом и снизу), чтобы конечности плавно сливались друг с другом.

    private Node createLimb(float width, float height, Vector3f location, boolean rotate) {
            int axis = rotate ? PhysicsSpace.AXIS_X : PhysicsSpace.AXIS_Y;
            CapsuleCollisionShape shape = new CapsuleCollisionShape(width, height, axis);
            Node node = new Node("Limb");
            RigidBodyControl rigidBodyControl = new RigidBodyControl(shape, 1);
            node.setLocalTranslation(location);
            node.addControl(rigidBodyControl);
            return node;
    }

    Вы пишете собственный вспомогательный метод для инициализации конечностей. Посмотрите на снимок экрана выше для ориентации.

    • Все цилиндры имеют одинаковый диаметр, 0,2f.
    • Вы делаете тело и плечи длиннее других конечностей, 1.0f вместо 0.5f.
    • Вы определяете координаты для размещения конечностей, чтобы сформировать человека.
    • Плечи и бедра — горизонтальные цилиндры, поэтому мы устанавливаем вращение в true.
    Node shoulders = createLimb(0.2f, 1.0f, new Vector3f( 0.00f, 1.5f, 0), true);
    Node     uArmL = createLimb(0.2f, 0.5f, new Vector3f(-0.75f, 0.8f, 0), false);
    Node     uArmR = createLimb(0.2f, 0.5f, new Vector3f( 0.75f, 0.8f, 0), false);
    Node     lArmL = createLimb(0.2f, 0.5f, new Vector3f(-0.75f,-0.2f, 0), false);
    Node     lArmR = createLimb(0.2f, 0.5f, new Vector3f( 0.75f,-0.2f, 0), false);
    Node      body = createLimb(0.2f, 1.0f, new Vector3f( 0.00f, 0.5f, 0), false);
    Node      hips = createLimb(0.2f, 0.5f, new Vector3f( 0.00f,-0.5f, 0), true);
    Node     uLegL = createLimb(0.2f, 0.5f, new Vector3f(-0.25f,-1.2f, 0), false);
    Node     uLegR = createLimb(0.2f, 0.5f, new Vector3f( 0.25f,-1.2f, 0), false);
    Node     lLegL = createLimb(0.2f, 0.5f, new Vector3f(-0.25f,-2.2f, 0), false);
    Node     lLegR = createLimb(0.2f, 0.5f, new Vector3f( 0.25f,-2.2f, 0), false);

    У вас теперь есть план человека. Но если вы сейчас запускаете приложение, отдельные конечности будут падать независимо друг от друга так как у ragdoll все еще не хватает суставов.

    Сустав

    Как и раньше, вы пишете небольшой вспомогательный метод. На этот раз его цель — быстро соединить две конечности A и B в точке соединения, которую мы укажем.

    • Преобразование A и B вектора connectionPoint из глобального координатного пространства в локальное координатное пространство.
    • Используйте ConeJoint, специальный сустав, который приближается к степени свободы, которую обычно имеют конечности. Конструктор ConeJoint требует наличия двух узлов и двух локальных опорных координат, которые мы только что определили.
    • Установите ограничения суставов, чтобы разрешить качание, но не скручивание.
    private PhysicsJoint join(Node A, Node B, Vector3f connectionPoint) {
            Vector3f pivotA = A.worldToLocal(connectionPoint, new Vector3f());
            Vector3f pivotB = B.worldToLocal(connectionPoint, new Vector3f());
            ConeJoint joint = new ConeJoint(A.getControl(RigidBodyControl.class),
                                            B.getControl(RigidBodyControl.class),
                                            pivotA, pivotB);
            joint.setLimit(1f, 1f, 0);
            return joint;
    }

    Используйте вспомогательный метод для соединения всех конечностей с суставами, которые находятся, на одном конце конечности.

    join(body,  shoulders, new Vector3f( 0.00f,  1.4f, 0));
    join(body,       hips, new Vector3f( 0.00f, -0.5f, 0));
    join(uArmL, shoulders, new Vector3f(-0.75f,  1.4f, 0));
    join(uArmR, shoulders, new Vector3f( 0.75f,  1.4f, 0));
    join(uArmL,     lArmL, new Vector3f(-0.75f,  0.4f, 0));
    join(uArmR,     lArmR, new Vector3f( 0.75f,  0.4f, 0));
    join(uLegL,      hips, new Vector3f(-0.25f, -0.5f, 0));
    join(uLegR,      hips, new Vector3f( 0.25f, -0.5f, 0));
    join(uLegL,     lLegL, new Vector3f(-0.25f, -1.7f, 0));
    join(uLegR,     lLegR, new Vector3f( 0.25f, -1.7f, 0));

    Теперь ragdoll связан. Если вы сейчас запустите приложение, кукла упадет, но конечности останутся вместе.

    Прикрепление всего к сцене

    Мы создаем один (без физики) Узел с именем ragDoll и присоединяем к нему все остальные узлы.

    ragDoll.attachChild(shoulders);
    ragDoll.attachChild(body);
    ragDoll.attachChild(hips);
    ragDoll.attachChild(uArmL);
    ragDoll.attachChild(uArmR);
    ragDoll.attachChild(lArmL);
    ragDoll.attachChild(lArmR);
    ragDoll.attachChild(uLegL);
    ragDoll.attachChild(uLegR);
    ragDoll.attachChild(lLegL);
    ragDoll.attachChild(lLegR);

    Чтобы использовать ragdoll в сцене, мы присоединяем его главный узел к rootNode и к PhysicsSpace.

    rootNode.attachChild(ragDoll);
    bulletAppState.getPhysicsSpace().addAll(ragDoll);

    Применение сил

    Чтобы тянуть куклу в верх, вы можете добавить обработчик ввода, который вызывает следующее действие:

    Vector3f upforce = new Vector3f(0, 200, 0);
    shoulders.applyContinuousForce(true, upforce);

    Мы можем использовать действие, чтобы поднять куклу и вернуть ее на ноги, или что-то еще. Подробнее о Силах здесь.

    Обнаружение столкновений

    Ознакомьтесь с разделом PhysicsCollisionEvent в документации по общей физике о том, как обнаруживать столкновения. Вы можете обнаруживать столкновения конечностей с конечностями и полом и инициировать игровые события.

    Рекомендации

    Если вы получаете странное поведение у ragdoll — например, разрываетесь на куски, а затем снова собираете — проверьте свои формы столкновения. Убедитесь, что вы не расположили конечности слишком близко друг к другу, когда собираете ragdoll. Вы обычно видите, что узлы с физикой выбрасываются, когда их фигуры столкновения пересекаются, что ставит физику в невозможное состояние.

    Физика Ragdoll с использованием KinematicRagdollControl (устарела начиная с JMonkeyEngine v3.3)

    KinematicRagdollControl — незакончен и работа в процессе. Целью было автоматизировать создание конечностей и суставов для физики тряпичной куклы(ragdoll). Идея заключалась в том, чтобы создать control,

    ragdoll = new KinematicRagdollControl(0.5f);

    и добавьте его в управляемую модель, а также в пространство физики(physics space):

    model.addControl(ragdoll);
    getPhysicsSpace().add(ragdoll);

    Твердое тело и физики сустава будут создаваться автоматически для каждой кости в скелете или, в качестве альтернативы, можно только для костей указанных путем в вызове метода addBoneName(). Пока control находится в кинематическом режиме, физики объектов будут имитировать движение костей, включая анимацию скелета и вращение/перемещение модели. Когда пришло время имитировать тряпичную куклу, вы вызываете

    ragdoll.setRagdollMode();

    и после этого физические силы будут преобладать над любой скелетной анимацией.

    Примеры кода

    • v3.2-branch TestRagdollCharacter.java В этом примере control остается в кинематическом режиме. Удерживайте клавишу U, чтобы продвинуть модель к стене. Нажмите Пробел, чтобы воспроизвести анимацию «Slice». Когда модель соприкасается со стеной, блоки падают.
    • v3.2-branch TestBoneRagdoll.java Нажмите [ЛК Мыши], чтобы выстрелить в модель из пушечного ядра. Физика Ragdoll начинается, когда пушечное ядро касается модели. Нажмите Пробел, чтобы возобновить кинематический режим и заставить модель подняться на ноги.

    Физика Ragdoll с использованием DynamicAnimControl (JME 3.3 и более поздние версии)

    DynamicAnimControl является заменой для KinematicRagdollControl. Цель аналогична, за исключением того, что DynamicAnimControl может быть одновременно кинематическим для одних костей и динамическим для других. Кроме того, DynamicAnimControl можно настроить для работы с более широким спектром моделей, чем KinematicRagdollControl.

    Чтобы упростить реализацию, ragdoll, созданный DynamicAnimControl, состоит из «link»(связь). Подобно тому, как RigidBodyControl присоединяет твердое тело к spatial, а связь присоединяет твердое тело с одной или несколькими костями в скелет модели. Точно как и в RigidBodyControl, связь может быть в кинематическом или динамическом режиме.

    И так же, как кости в скелете располагаются в иерархии родитель/потомок, так же и связь в ragdoll DynamicAnimControl. В иерархии ragdoll есть только одна связь, у которой нет родителя; она называется «torso»(туловище). Любая другая связь является «связью кости», которая имеет другую связь в качестве родителя. Каждая связь кости присоединяет её к родителю с помощью физики сустава.

    Как и в случае с KinematicRagdollControl, вы начинаете с создания control,

    ragdoll = new DynamicAnimControl();

    но прежде чем добавить его в модель, вы должны настроить его, указав массу torso(туловища), а также массу и диапазон движения для каждой связанной кости:

    ragdoll.setMass(DacConfiguration.torsoName, 1f);
    ragdoll.link("Waist", 1f, new RangeOfMotion(1f, -0.4f, 0.8f, -0.8f, 0.4f, -0.4f));
    ...

    Вы, вероятно, не хотите связывать каждую кость в скелете модели. Например, если модель имеет сочлененные пальцы, вы, вероятно, хотите связать кости рук, но не отдельные кости пальцев. Несвязанные кости будут управляться ближайшим связанным предком, а torso(туловище) будет управлять всеми костями, с которыми не связан ни один предок. Если вы связываете слишком много костей, тряпичная кукла(ragdoll) может стать негибким или слишком дёрганым из-за столкновений между твердыми телами, которые не имеют общего физического соединения.

    Только после настройки control вы должны добавить его в модель и в пространство физики:

    model.addControl(ragdoll);
    getPhysicsSpace().add(ragdoll);

    Обратите внимание, что control должен быть добавлен в Spatial с помощью SkinningControl, который не обязательно является корневым spatial моделей.

    Пока связь находится в кинематическом режиме, физика её объектов будут имитировать движение костей, включая скелетную анимацию. Когда придёт время симулировать тряпичную куклу(ragdoll), вы можете вызвать

    ragdoll.setRagdollMode();

    что бы перевести все связи в динамический режим. После этого физические силы станут преобладать над любоё скелетноё анимацией.

    Примеры кода

    • master-branch TestBoneRagdoll.java Нажмите [ЛК Мыши], чтобы выстрелить в модель из пушечного ядра. Физика Ragdoll начнётся, когда пушечное ядро коснётся модели. Нажмите Пробел, чтобы возобновить кинематический режим и заставить модель подняться на ноги.

    Переведено для jmonkeyengine.ru, оригинал
    Автор перевода: Andry

    Добавить комментарий

jMonkeyEngine.ru © 2017. Все права сохранены.