Войти
ПрограммированиеФорумФизика

Вопрос по PhysX (суставы)

#0
22:12, 1 апр. 2019

Мне надо симитировать кабель (веревку, цепочку). Нашел, что для этого годятся D6 joint. Взял пример из SDK, все вроде просто.
Кабель составил из 20 цилиндров, подвесит его вертикально, создал суставы, запустил - кебель висит, только вначале немного прыгает вверх-вниз как пружина. Потом он успокаивается. Если толкнуть - очень правдоподобно качается.
Но мне надо втыкать этот кабель в гнездо, для чего я тащу силой (setLinearVelocity) его последнее звено (т.е тащу не жестко). Вот тут начинаются странности:

Во первых элементы кабеля начинают растягиваться, между звеньями появляются зазоры.
Во вторых если потянуть сильнее, то начинается "полтергейст" - звенья начинают летать по всей сцене. Если нажим снять, то все постепенно успокаивается.
Кто нибудь знает что это за фигня и как с этим можно бороться?

И еще одно - мне надо перемещать всю цепочку, как это сделать? Я пробовал двигать первое звено, но оно просто уходит в сторону, создается зазор и в конце концов наступает "полтергейст". А как можно двигать целиком всю цепочку суставов?

Вот как я создаю суставы:

void Room_Scene::createChain(int length)
{

  PxRigidDynamic* prev = NULL;
  Component* cap = new Component("Chain", "", this, vec3(0, 2.0, 5.5), false);
  cap->CreateDynamic(1.0f);

  auto ankor = reinterpret_cast<PxRigidDynamic*>(cap->body);

  ankor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true); // первое звено кинематическое
  ankor->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true);

  PxTransform start = ankor->getGlobalPose();
  PxVec3 offset(0, -cap->dimension.y/2, 0);
  PxTransform localTm(offset);
  m_Chain.push_back(cap);

  Component *c = cap;
  for (PxU32 i = 0; i < length; i++)
  {
    m_Chain.push_back(c);
    m_Component.push_back(c);

    PxRigidDynamic* current = reinterpret_cast<PxRigidDynamic*>(c->body);
    PxRigidBodyExt::updateMassAndInertia(*current, 1.0); 

    PxD6Joint* joint = PxD6JointCreate(*m_Physic->gPhysics, prev, prev ? PxTransform(offset) : start, current, PxTransform(-offset));

    joint->setMotion(PxD6Axis::eSWING1, PxD6Motion::eFREE);
    joint->setMotion(PxD6Axis::eSWING2, PxD6Motion::eFREE);
    joint->setMotion(PxD6Axis::eTWIST, PxD6Motion::eFREE);
    joint->setDrive(PxD6Drive::eSLERP, PxD6JointDrive(0, 100000, FLT_MAX, true));

    m_Physic->gScene->addActor(*current);

    prev = current;

    c = cap->Clone(true);
    c->Pos(m_Chain[i]->Pos() + vec3(0, offset.y, 0));
}

Кстати если вместо updateMassAndInertia() поставить просто current->SetMass(1.0), то поведение резко меняется.
Тогда полтергейст уже не наступает, хотя звенья растягиваются до весьма больших значений. Но в этом случае при движении звенья занимают неправильную ориентацию, т.е не стоят жестко "нос в хвост", а занимают эту позицию с задержкой, что выгладит очень некрасиво. По ходу дела они могут вообще оказаться перпендикулярно цепочке.  Я бы пережил растягивание звеньев, но только если бы они всегда корректно были направлены. Тогда я растянул бы геометрию шейдером и зазоры бы закрыл. Но если они стоят боком, то увы...

Возможно я вообще что-то криво делаю, у меня опыт в физике близок к нулю.
Короче если тут есть кто-то имевший дело с веревками/цепочками под PhysX, то был бы очень благодарен за консультацию.


#1
9:30, 2 апр. 2019

Ну, у всех итеративных движков такие проблемы)
В доках на Physx SDK раздел есть с советами по увеличению стабильности джойнтов
http://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxguid… -are-unstable

Есть возможности позволяют, можно articulations использовать. Они много стабильнее обычных джойнтов

#2
15:35, 2 апр. 2019

Меня даже не столько стабильность смущает, как то, что звенья растягиваются. По идее сустав это жесткое соединение, почему он у меня как пружина работает? Может я что-то принципиально неправильно делаю?

#3
10:44, 3 апр. 2019

То что растягивается - нормально. Чтобы компенсировать и увеличивают кол-во итераций, включают Joint Projection, уменьшают массу звеньев, и п.р.

#4
(Правка: 21:42) 20:54, 3 апр. 2019

Zogrim
> Есть возможности позволяют, можно articulations использовать.
Я попробовал. Сама по себе такая веревка работает, в смысле висит и качается. Но я упорно не могу сдвинуть ни всю её (двигая якорь), ни любое звено (ну типа как на видео).
Пытался двигать актор - ниакой реакции, тогда стал двигать сустав - тот же эффект. Точнее отсутствие оного.
Вот что я делаю:

            for (int i = 0; i < nbLinks; i++)
            {
              auto actor = reinterpret_cast<PxRigidActor*>(links[i]);
  
              Component *component = reinterpret_cast<Component *>(actor->userData);
              if (component == rScene->m_Component[catched])  // это я ищу какой элемент выбран для движения
              {
                PxTransform pose = actor->getGlobalPose();

                auto gDriveJoint = reinterpret_cast<PxArticulationJointReducedCoordinate*>(links[i]->getInboundJoint());
                if (gDriveJoint)
                {
                  gDriveJoint->setDriveTarget(PxArticulationAxis::eX, pos.x - pose.p.x);  // нормальной функции перемещения нет, потому такой изврат
                  gDriveJoint->setDriveTarget(PxArticulationAxis::eY, pos.y - pose.p.y);
                  gDriveJoint->setDriveTarget(PxArticulationAxis::eZ, pos.z - pose.p.z);
                }
                else if(i==0)  // это корневой узел, по идее должна двигаться вся цепочка.
                {
                  auto pose = actor->getGlobalPose();
                  pose.p.x = pos.x;
                  pose.p.z = pos.z;
                  actor->setGlobalPose(pose);
                }

                break;
              }
            }
И что не так? Как вообще двигать articulation ?
#5
(Правка: 6:17) 4:20, 5 апр. 2019

Продолжение (типа анекдота):
Вобщем сделал я эту «артикуляцию», собрал веревку из 40 звеньев. Ну сначала она просто висела вертикально, потом я ее толкнул другим предметом – стала качаться. Медленно, печально и очень натурально. Но я так и не понял как ее можно двигать, т.е. скажем перенести на другое место.

Но в процессе исследований случилось что-то совершенно странное.  Эта, абсолютно инертная прежде, веревка вдруг обалдела и стала бешено извиваться. Она со страшной скоростью крутилась, завивалась узлами, вид был совершенно жуткий – типа гнезда червей. Причем этот клубок ни на что не реагировал, принимая совершенно сюрреалистические формы. Я тупо на это смотрел и не мог ничего понять – вроде я не менял ничего. Я прошелся по коду – все вроде нормально. Запустил опять. В первый момент "червяк" висел вертикально но вдруг резко подпрыгнул (как будто попал в кипяток) и опять начал с дикой скоростью извиваться около точки закрепления, походу наплевав на закон тяготения.

Ну думаю ладно... ты значит так... издеваешься... И повесил червяку на хвост кирпич весом 50 килограмм.  Мол ага! Фиг ты теперь с кирпичем-то подрыгаешься!
Ничего подобного... стало только хуже. Теперь не только веревка, но и кирпич бурлили и летали по всей сцене. Я наверно час с этим боролся, пока на скришоте (когда снимаешь VR шлем то картинка замирает) не обнаружил, что кирпича-то два! Там все так быстро скакало, что в движении я это не заметил.

Короче оказалось что я повесил ДВЕ веревки на одно и то же место. Совершенно одинаковых. Причем хитрым образом – у звеньев оказались два rigibody но был один меш на двоих. Поэтому у веревок наступила смертельная схватка за жизненное пространство, которая не могла привести к победе ни одну из сторон, поскольку у них было общее тело.  Кирпичи только усугубили ситуацию, поскольку тянули веревки вниз, принуждая их слиться. В результате веревки с кирпичами пытались выйти сами из себя, что им никак не удавалось. Но они очень старались. :)

P.S.
Вопрос с движением артикуляции остался открытым. Как эту холеру можно двигать?

ПрограммированиеФорумФизика