Bullet物理引擎的安裝與使用


  圖形賦予游戲一種視覺的吸引力,但是能夠讓游戲的世界鮮活起來的還應該是內部的物理引擎。物理引擎是游戲引擎中的子模塊,是一種軟件組件,可仿真物理系統。它根據牛頓力學定律,計算游戲中物體的合理的物理位置,並將計算結果提供給渲染引擎,從而展示出真實的渲染效果。物理引擎的仿真包括柔性體和剛體力學、流體力學以及碰撞檢測。以游戲為中心的物理引擎側重於實時近似,而科學仿真中的物理引擎則更多地側重於精確計算以獲得高准確性。科學物理引擎依賴於超級計算機的處理能力,而游戲物理引擎則可運行於資源受限的平台(比如手持型游戲設備和移動手機)。

圖 1. 游戲應用中的物理引擎

  Bullet Physics SDK: real-time collision detection and multi-physics simulation for VR, games, visual effects, robotics, machine learning etc. 

  •  Build bullet

  下載Bullet的源代碼 https://github.com/bulletphysics/bullet3/releases/latest,然后將其解壓到合適的路徑下。可以選擇運行批處理文件生成VisualStudio工程,這里運行build_visual_studio.bat生成VS2010工程。

  在Debug模式下生成解決方案,解壓后的bullet3-2.86.1目錄中會出現bin文件夾,其中包含了生成的靜態庫文件和可執行文件。

  •  HelloWorld example

   新建一個空的控制台程序,然后在源文件目錄中加入HelloWorld.cpp文件:

#include <btBulletDynamicsCommon.h>  
#include <stdio.h>
#include <iostream>
#include <fstream> 
using namespace std;

/// This is a Hello World program for running a basic Bullet physics simulation

int main(int argc, char** argv)
{

    btBroadphaseInterface* broadphase = new btDbvtBroadphase();

    ///collision configuration contains default setup for memory, collision setup. Advanced users can create their own configuration.
    btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();
    
    ///use the default collision dispatcher. For parallel processing you can use a differnt dispatcher
    btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);

    ///the default constraint solver. For parallel processing you can use a different solver
    btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;

    ///instantiate the dynamics world
    btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);

    ///sets the gravity. We have chosen the Y axis to be "up".
    dynamicsWorld->setGravity(btVector3(0,-10,0));



    btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0, 1, 0), 1);
    btCollisionShape* fallShape = new btSphereShape(1);

    //The btDefaultMotionState provides a common implementation to synchronize world transforms with offsets.
    btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, -1, 0)));

    ///instantiate the ground. Its orientation is the identity, Bullet quaternions are specified in x,y,z,w form.
    btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI(0, groundMotionState, groundShape, btVector3(0, 0, 0));
    
    ///Bullet considers passing a mass of zero equivalent to making a body with infinite mass - it is immovable
    btRigidBody* groundRigidBody = new btRigidBody(groundRigidBodyCI);

    ///add the ground to the world
    dynamicsWorld->addRigidBody(groundRigidBody);


    //The btTransform class supports rigid transforms with only translation and rotation 
    btDefaultMotionState* fallMotionState = new btDefaultMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, 50, 0)));

    btScalar mass = 1;
    btVector3 fallInertia(0, 0, 0);
    fallShape->calculateLocalInertia(mass, fallInertia);

    ///when bodies are constructed, they are passed certain parameters. This is done through a special structure Bullet provides for this.
    ///rigid body is dynamic if and only if mass is non zero, otherwise static  
    btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(mass, fallMotionState, fallShape, fallInertia);
    btRigidBody* fallRigidBody = new btRigidBody(fallRigidBodyCI);
    dynamicsWorld->addRigidBody(fallRigidBody);

    ofstream outfile("C:\\Users\\KC\\Desktop\\height.csv", ios::out);
    for (int i = 0 ; i < 300 ; i++) {

        /*  prototype:
        btDynamicsWorld::stepSimulation(btScalar timeStep, int maxSubSteps=1,
                                            btScalar fixedTimeStep=btScalar(1.)/btScalar(60.));
        */

        //It's important that timeStep is always less than maxSubSteps*fixedTimeStep
        //The first and third parameters to stepSimulation are measured in seconds
        //By decreasing the size of fixedTimeStep, you are increasing the "resolution" of the simulation.
        //When you pass Bullet maxSubSteps > 1, it will interpolate movement for you
        dynamicsWorld->stepSimulation(1 / 60.f, 10);

        btTransform trans;
        fallRigidBody->getMotionState()->getWorldTransform(trans);

        std::cout << "sphere height: " << trans.getOrigin().getY() << std::endl;
        outfile<<trans.getOrigin().getY()<<endl;
    }

    outfile.close();

    delete fallShape;
    delete groundShape;

    
    delete dynamicsWorld;
    delete solver;
    delete dispatcher;
    delete collisionConfiguration;
    delete broadphase;

    printf("Press a key to exit\n");
    getchar();
}
View Code

  在項目屬性——>C/C++ ——>常規——>附加包含目錄中添加頭文件的路徑:D:\bullet3-2.86.1\src

  在C/C++ ——>常規——>代碼生成——>運行庫選項中選擇:多線程調試(/MTd)。Make sure the run-time library is the same as in your project. By default it is set to the multi-threaded, static version. 即之前在build bullet時默認生成的是靜態庫,則在編譯debug程序時應選擇/MTd。一個程序中若混合了不同的運行時庫(靜態庫和動態庫,調試庫和非調試庫),可能會產生沖突,所以一個程序中應該使用相同的運行時庫。

  在鏈接器——>常規——>附加庫目錄中輸入靜態庫路徑:D:\bullet3-2.86.1\bin

   然后在鏈接器——>輸入——>附加依賴項中添加必須的靜態庫(release版的靜態庫文件名中沒有_debug后綴)

   設置完成開始運行。上面的代碼將創建一個半徑為1的球體和一個靜態地面,球中心距地面高度為50m,球的質量為1Kg。然后模擬重力(重力加速度沿Y軸負方向,大小為10m/s2)作用下的自由落體運動,仿真步長為1/60s,即每秒計算60次,運行300步(5s)。雖然仿真需要大量的設置,但是當定義了仿真環境之后,物理引擎就會在幕后為你完成全部的繁重工作。仿真時每運行一步輸出球中心的高度數據:

   將數據記錄在CSV文件中,畫出高度隨時間變化的曲線如下圖所示:

 

  •  Build and install pybullet

  pybullet is an easy to use Python module for physics simulation, robotics and machine learning based on the Bullet Physics SDK. With pybullet you can load articulated bodies from URDF, SDF and other file formats. pybullet provides forward dynamics simulation, inverse dynamics computation, forward and inverse kinematics and collision detection and ray intersection queries. Aside from physics simulation, pybullet supports to rendering, with a CPU renderer and OpenGL visualization and support for virtual reality headsets.  安裝pybullet有好幾種方式,下面在https://pypi.python.org/pypi/pybullet網站上下載源文件pybullet-0.1.6.tar.gz並解壓,切換到原文件目錄中運行:python setup.py install。不過這時提示:Microsoft Visual C++ 9.0 is required Unable to find vcvarsall.bat,解決辦法是可以安裝一個Micorsoft Visual C++ Compiler for Python 2.7的包。經過一段時間編譯(中途會彈出好多警告),在源文件目錄的build\lib.win-amd64-2.7文件夾下可以找到pybullet.pyd,將其復制到C:\Python27\Lib\site-packages中。     

  下面的Python代碼運行時作為客戶端與Physics Engine服務端進行通信(pybullet is designed around a command-status driven API, with a client sending commands and a physics server returning the status. pybullet has some build-in physics servers: DIRECT and GUI. The DIRECT connection sends the commands directly to the physics engine, without using any transport layer, and directly returns the status after executing the command. The GUI connection will create a new graphical user interface with OpenGL rendering, within the same process space as pybullet

import pybullet as p
from time import sleep

physicsClient = p.connect(p.GUI)
p.setGravity(0,0,-10)

# The loadURDF will send a command to the physics server to load a physics model from a URDF File
planeId = p.loadURDF("D:/bullet3-2.86.1/data/plane.urdf")

cubeStartPos = [0,0,2]
cubeStartOrientation = p.getQuaternionFromEuler([0,0,0]) # The pybullet API uses quaternions to represent orientations. 
boxId = p.loadURDF("D:/bullet3-2.86.1/data/sphere2.urdf",cubeStartPos, cubeStartOrientation)


while 1:
    # stepSimulation will perform all the actions in a single forward dynamics simulation step such as collision detection, 
    # constraint solving and integration. By default, the physics server will not step the simulation, unless you explicitly 
    # send a 'stepSimulation' command. This way you can maintain control determinism of the simulation.
    p.stepSimulation()

    # reports the current position and orientation of the base of the body in Cartesian world coordinates
    # returns the position list of 3 floats and orientation as list of 4 floats in [x,y,z,w] order. 
    # Use getEulerFromQuaternion to convert the quaternion to Euler if needed.
    cubePos, cubeOrn = p.getBasePositionAndOrientation(boxId)
    print(cubePos,cubeOrn)
    sleep(0.01) # Time in seconds.

p.disconnect()  # disconnect from a physics server. A 'DIRECT' or 'GUI' physics server will shutdown

  運行時服務端將顯示對應的圖形界面,仿真每進行一步輸出球的質心位置和姿態

 

參考:

Creating a project from scratch

pybullet quickstart guide

開源物理引擎Bullet Physics下載與安裝

Bullet核心類介紹

Bullet 物理引擎 簡析

Bullet教程: Hello World 實例

Bullet物理引擎不完全指南

VS2010下配置Bullet開發環境

Visual Studio運行時庫MT、MTd、MD、MDd的研究

開源的物理引擎


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM