Автор: Александр Залога

Опубликовано: 03.04.2007

Изменено: 03.04.2007

Постоянная ссылка

Комментарии [0]

Введение в физический движок AGEIA PhysX





Страницы: 1 2 3

13. Запуск процесса моделирования

В завершении мы запустим StartPhysics() для запуска следующего кадра симуляции.

void RenderCallback()
{
    ...
    if (gScene && !bPause)
    {
        ...
        StartPhysics();
    }
    ...
}

...

void StartPhysics()
{
    // Update the time step
    gDeltaTime = UpdateTime();

    // Start collision and dynamics for delta time since the last frame
    gScene->simulate(gDeltaTime);
    gScene->flushStream();
}

StartPhysics() вызывает UpdateTime(), которая дает deltaTime – время, которое прошло с момента последней сцены. Мы вызываем NxScene::simulate(deltaTime) и NxScene::flushStream() для запуска симуляции на этот отрезок времени.

NxScene::simulate() – это точка вхождения в физический ускоритель PhysX и сердце симуляции. SDK моделирует сцену, которую мы создаем за время deltaTime. Все вычисления для моделирования происходят с помощью "железа" (hardware) и их результат получают с помощью функции NxScene::fetchResults() которую мы вызываем из GetPhysicsResults().

14. Рисование объектов

После вызова GetPhysicsResults(), ProcessInputs(), и StartPhysics() в RenderCallback(), мы рисуем объекты на сцене, смотря на них из позиции gCameraPos (0,5,-15) в направлении gCameraForward (0,0,1). Т.е. мы на 5 м выше и на 15 м позади начала координат, и смотрим в направлении начала координат, в положительном направлении оси Z. Мы рисуем актеров и их тени на земле с помощью такого кода:

void RenderActors(bool shadows)
{
    // Render all the actors in the scene
    NxU32 nbActors = gScene->getNbActors();
    NxActor** actors = gScene->getActors();
    while (nbActors--)
    {
        NxActor* actor = *actors++;
        DrawActor(actor);

        // Handle shadows
        if (shadows)
        {
            DrawActorShadow(actor);
        }
    }
}

void RenderCallback()
{
    ...
    RenderActors(bShadows);
    ...
}

Функции DrawActor() и DrawActorShadow() вызываются для всех фигур в каждом из актеров, рисуется каждая форма и каждая тень. Код для рисования фигур различных типов расположен в файле DrawShapes.cpp. Вы можете посмотреть на него, но это сейчас не существенно для верного понимания урока. Просто знайте, откуда его можно достать.

15. Рисование сил

Сила, прикладываемая к ящику, возвращается в переменной gForceVec. В RenderCallback() мы вызываем функцию DrawForce() для рисования стрелки, изображающей силу, приложенную к ящику.

void ProcessForceKeys ()
{
    // Process force keys
    for (int i = 0; i < MAX_KEYS; i++)
    {     
        if (!gKeys[i])  { continue; }

        switch (i)
        {
        ...
        // Force controls
         case 'i': {gForceVec=ApplyForceToActor(box, NxVec3(0,0,1),  gForceStrength); break;}
         case 'k': {gForceVec=ApplyForceToActor(box, NxVec3(0,0,-1), gForceStrength); break;}
         case 'j': {gForceVec=ApplyForceToActor(box, NxVec3(1,0,0),  gForceStrength); break;}
         case 'l': {gForceVec=ApplyForceToActor(box, NxVec3(-1,0,0), gForceStrength); break;}
         case 'u': {gForceVec=ApplyForceToActor(box, NxVec3(0,1,0),  gForceStrength); break;}
         case 'm': {gForceVec=ApplyForceToActor(box, NxVec3(0,-1,0), gForceStrength); break;}
        }
    }
}
...
void ProcessInputs()
{
    ProcessForceKeys();
    ...
}
...
void DrawForce(NxActor* actor, NxVec3& forceVec, const NxVec3& color)
{
    // Draw only if the force is large enough
    NxReal force = forceVec.magnitude();
    if (force < 0.1f)  return;

    forceVec = 3*forceVec/force;

    NxVec3 pos = actor->getCMassGlobalPosition();
    DrawArrow(pos, pos + forceVec, color);
}
...
void RenderCallback()
{
    ...

    if (gScene && !bPause)
    {
        ...
        ProcessInputs();
        ...
    }
    ...
    DrawForce(box, gForceVec, NxVec3(1,1,0));
    gForceVec = NxVec3(0,0,0);
    ...
}

Этот код рисует желтую стрелку, направленную из центра масс ящика на 3 метра вдоль оси приложения силы.

16. Перезапуск сцены и завершение работы

Запустите симуляцию на некоторое время и нажмите "F10". Вы заметите, что ящик вернулся в начальную позицию и снова падает на землю. Нажатие "F10" перезапускает сцену, вызывая функцию ResetNx(), которая вызывает ReleaseNx(), чтобы завершить работу SDK, и затем вызывает InitNx(), чтобы запустить SDK снова.

// Physics SDK globals
NxPhysicsSDK* gPhysicsSDK = NULL;
NxScene* gScene = NULL;
...

void SpecialCallback(int key, int x, int y)
{
    switch (key)
    {
        // Reset PhysX
        case GLUT_KEY_F10: ResetNx(); return;
    }
}

void ReleaseNx()
{
    if (gScene)
    {
        GetPhysicsResults();  // Make sure to fetchResults() before shutting down
        gPhysicsSDK->releaseScene(*gScene);
    }
    if (gPhysicsSDK)  gPhysicsSDK->release();
}

void ResetNx()
{
    ReleaseNx();
    InitNx();
}

ReleaseNx() вызывает функцию GetPhysicsResults(), которая вызывает NxScene::fetchResults(), которая ждет разрешения завершить сцену. Потом она вызывает NxPhysicsSDK::releaseScene(), которая удаляет все объекты со сцены и затем сцена удаляет сама себя. Потом она запускает NxPhysicsSDK::release(), которая завершает работу SDK.

ReleaseNx() также вызывается после glutMainLoop(), чтобы завершить работу SDK перед выходом из программы.

17. Важные функции приложения

Ниже приведены важные функции, участвующие в этом приложении.

RenderCallback()
Вызывает GetPhysicsResults(), ProcessInputs(), и StartPhysics() каждый кадр в процессе моделирования сцены. Размещает камеру через SetupCamera(). Рисует актеров на сцене через RenderActors(). Рисует силы, прикладываемые к объектам через DrawForce().

GetPhysicsResults()
Вызывает NxScene::fetchResults() чтобы извлечь результаты последнего кадра моделирования.

ProcessInputs()
Получает список нажатых клавиш из ProcessForceKeys(). Вызывает NxDebugRenderer::renderData() для рисования отладочных каркасов на актерах.

StartPhysics()
Вызывает UpdateTime() для получения gDeltaTime – количество времени, которое прошло с мометна рисования последнего кадра сцены. Вызывает NxScene::simulate(gDeltaTime) и NxScene::flushStream() для запуска симуляции за время gDeltaTime.

InitNx()
Инициализирует PhysX SDK через NxCreatePhysicsSDK(). Добавляет параметры, расширяющие симуляцию, через NxPhysicsSDK::setParameter(). Добавляет новые материалы к SDK, вызывая NxScene::getMaterialFromIndex() и устанавливает свойства материала, используя NxMaterial::setRestitution(), ::setStaticFriction(), и ::setDynamicFriction(). Создает сцену через NxPhysicsSDK::createScene(). Создает актеров на сцене с помощью CreateGroundPlane() и CreateBox(), которые обращаются к NxScene::createActor(). Устанавливает текущее время через UpdateTime(). Запускает процесс моделирования через StartPhysics().

gDebugRenderer.renderData()
Рисует каркасы на актерах – фигуры столкновения, а также оси актеров.

ReleaseNx()
Вызывает GetPhysicsResults(), чтобы завершить процесс моделирования. Вызывает NxPhysicsSDK::releaseScene(), чтобы завершить работу сцены и NxPhysicsSDK::release(), чтобы завершить работу SDK.

18. Выводы

Поздравляем! Вы познакомились с базовой программой PhysX SDK, и это только первый шаг в огромном мире физики. Поэкспериментируйте с вашим созданием. Используйте клавиши "u,m,i,j,k,l" - чтобы толкать ящик и клавиши "q,z,w,a,s,d" - чтобы перемещать вокруг него камеру.

Вот доля информации из этой лекции и она довольно обширно охватывает полную работу приложения с каждым из аспектов: инициализация SDK, инициализация сцены, создание актера, приложение силы к актеру через нажатие клавиш, рисование актера, запуск симуляции, рисование сил, приложенных к актеру, рисование отладочных каркасов для объектов. Не волнуйтесь, если сейчас вам что-то осталось непонятным. Всегда можно увидеть больше, практикуясь в использовании SDK.

В будущих лекциях мы будем использовать некоторые структуры, как в этой лекции и вводить одну или две новых возможности в каждой лекции, пока не охватим все возможности SDK.

19. Взаимосвязанные классы, функции и параметры

NxCreatePhysicsSDK()

NxPhysicsSDK
    createScene()
    setParameter()
    visualize()
    releaseScene()
    release()

NxMaterial
    setRestitution()
    setStaticFriction()
    setDynamicFriction()

NxSceneDesc
    gravity
    simType

NxScene
    getMaterialFromIndex()
    createActor()
    simulate()
    flushStream()
    fetchResults()

NxPlaneShapeDesc

NxBoxShapeDesc
    dimensions

NxBodyDesc

NxActorDesc
    shapes
    body
    density
    globalPose

NxActor
    setGlobalPosition()
    getCMassGlobalPosition()
    addForce()

NxDebugRenderable
    getNbPoints()
    getPoints()
    getNbLines()
    getLines()
    getNbTriangles()
    getTriangles()

NxDebugPoint
    color
    p

NxDebugLine
    color
    p0
    p1

NxDebugTriangle
    color
    p0
    p1
    p2

NxParameter
    NX_SKIN_WIDTH   
    NX_VISUALIZE_COLLISION_SHAPES
    NX_VISUALIZE_ACTOR_AXES

NxSimulationStatus
    NX_RIGID_BODY_FINISHED

Заключение

Вы можете посмотреть пример, ссылка на который дана в начале статьи. Кроме того, я рекомендую ознакомиться с документом "PhysX_Math_Primer.doc" (русский перевод), в котором описаны основные элементы трехмерных вычислений, используемые в PhysX SDK.

Удачи и успехов в написании красивых программ!

P.S. Все пожелания и предложения вы можете направлять мне, переводчику, по приведенному ниже адресу.

--
Александр Залога "Александр"
EMail: zaloga@yandex.ru
3 апреля 2007 года

Страницы: 1 2 3