Bullet
Created at 2017-07-15T11:37:25+09:00

Build system

$ mkdir -p out/Debug/_install
$ cd out/Debug
$ cmake -G Ninja -DBUILD_PYBULLET=OFF -DCMAKE_BUILD_TYPE=Debug ../..
$ ninaj -j4
$ ./examples/ExampleBrowser/App_ExampleBrowser

build outputs

  • separated shared libraries

ExampleBrowser (BasicExample)

(Some terminology)
- aabb (axix aligned bounding box)
- dbvt (dynamic bounding volume tree)


[ Data structure ]

OpenGLExampleBrowser
'-' OpenGLExampleBrowserInternalData
  '-' SimpleOpenGL3App (< CommonGraphicsApp) (available as static s_app)
    '-' X11OpenGLWindow (< CommonWindowInterface)
      '-' GLInstancingRenderer (< CommonRenderInterface)
        '-* b3GraphicsInstance (m_graphicsInstances)
          '-' GLuint m_cube_vao, m_index_vbo, m_textureIndex
        '-' InternalDataRenderer (< GLInstanceRendererInternalData)
          '-' GLuint m_vbo
          '-' m_lightPos
          '-' m_activeCamera
          '-' ...
      '-' GLPrimitiveRenderer (do we use it ?)
  '-' GwenOpenGL3CoreRenderer ?
  '-' GwenUserInterface ?


BasicExample < CommonRigidBodyBase < CommonExampleInterface
'-' btDiscreteDynamicsWorld (< btDynamicsWorld < btCollisionWorld)
  '-* btCollisionObject (m_collisionObjects)
'-* btCollisionShape (m_collision_shapes)
'-' btDbvtBroadphase (< btBroadphaseInterface)
  '-2 btDbvt (for dynamic ones and static ones)
    '-' btDbvtNode m_root
  '-* btDbvtProxy (m_stage_roots[..])
'-' btCollisionDispatcher
'-' btConstraintSolver
'-' btDefaultCollisionConfiguration
'-' OpenGLGuiHelper (< GUIHelperInterface)
  '-' OpenGLGuiHelperInternalData
    '-' SimpleOpenGL3App


btRigidBody (< btCollisionObject)
'-' btTransform    m_worldTransform
'-' btBoxShape (< btPolyhedralConvexShape < btConvexInternalShape < btConvexShape < btCollisionShape)
'-' btDbvtProxy (< btBroadphaseProxy)
  '-' btDbvtNode
    '-' btDbvtVolume (aka btDbvtAabbMm)
      '-' mi, mx
  '-' m_aabbMin,m_aabbMax
- (rigidbody members)
  '-' m_linearVelocity, m_angularVelocity
  '-' m_gravity, m_totalForce,


[ Procedure ]

(Main: gui setup and main loop)
- main =>
  - b3Clock clock
  - new OpenGLExampleBrowser
  - OpenGLExampleBrowser::init =>
    - (load 0_Bullet3Demo.txt and parse cmdline)
    - s_app = new SimpleOpenGL3App =>
      - new b3gDefaultOpenGLWindow (aka X11OpenGLWindow)
      - X11OpenGLWindow::createWindow
      - new GLInstancingRenderer, init
      - GLInstancingRenderer::InitShaders =>
        - glLinkProgram, glUseProgram: triangleShaderProgram, linesShader
        - glGenVertexArrays: triangleVertexArrayObject, lineVertexArrayObject
        - glGenBuffers: triangleVertexBufferObject, triangleIndexVbo, lineVertexBufferObject, lineIndexVbo
        - shadow things: useShadowMapInstancingShader, createShadowMapInstancingShader
        - ? instancingShader
        - glGenBuffers(1, &m_data->m_vbo)
    - (register ui event callbacks)
    - new GwenOpenGL3CoreRenderer => ?
    - new GwenUserInterface, GwenUserInterface::init => ?
    - selectDemo(firstAvailableDemoIndex) =>
      - new OpenGLGuiHelper => ?
      - sCurrentDemo = BasicExampleCreateFun (as func) => new BasicExample
      - BasicExample::initPhysics => (SEE BELOW)
  - clock.reset
  - loop
    - float deltaTimeInSeconds = clock.getTimeMicroseconds() / 1000000.f
    - clock.reset
    - OpenGLExampleBrowser::update(deltaTimeInSeconds) => (SEE BELOW)


(Physics and GL setup)
- BasicExample::initPhysics =>
  - createEmptyDynamicWorld =>
    - new btDefaultCollisionConfiguration =>
    - new CollisionDispacher =>
    - new btDbvtBroadphase =>
    - new btSequentialImpulseConstraintSolver =>
    - new btDiscreteDynamicsWorld, setGravity
  - OpenGLGuiHelper::createPhysiscsDebugDrawer =>
    - new MyDebugDrawer
    - btDiscreteDynamicsWorld::setDebugDrawer
  - (Create a huge box with mass 0 as floor)
    - groudShape = createBoxShape => new btBoxShape
    - m_collision_shapes.push_back(groundShape)
    - createRegidBody(mass, groundShape, transform, color) =>
      - new btDefaultMotionState
      - btRigidBodyConstructionInfo
      - body = new btRigidBody
      - btDiscreteDynamicsWorld::addRigidBody(body) =>
        - btCollisionObject::setActivationState(ISLAND_SLEEPING)
        - addCollisionObject(body) => btCollisionWorld::addCollisionObject =>
          - m_collision_objects.push_back(collisionObject)
          - btBoxShape::getAabb => ..
          - btDbvtBroadphase::createProxy =>
            - proxy = new btDbvtProxy
            - btDbvtVolume aabb
            - listappend(proxy, m_stage_roots[..])
            - btDbvtTreeCollider collider
            - btDbvt::collideTV(collider) => ..
          - btCollisionObject::setBroadPhaseHandle(proxy)
  - (Create a stack of small boxes (but this isDynamic since mass = 0))
    - createBoxShape, createRigidBody, ..
  - OpenGLGuiHelper::autogenerateGraphicsObjects =>
    - (for each object from btCollisionObjects)
    - (NOTE: this might be something tricky. m_graphicsInstances is flat structure
        but there's special gfxObj which corresponds to original collisionshape (or object) not a mesh part
        like, b3GraphicsInstance.m_numGraphicsInstances is too sketchy ..)
      - TODO: rebuildGraphicsInstances must be super important ..
    - createCollisionShapeGraphicsObject =>
      - btAlignedObjectArray<GLInstanceVertex> gfxVertices
      - btAlignedObjectArray<int> indices
      - CollisiontShape2TriangleMesh(.. indices) => ..
      - construct GLInstanceVertex.xzyw, normal, uv, depending on shape
      - registerGraphicsShape(gfxVertices .. indices .. B3_GL_TRIANGLES) =>
        - GLInstancingRenderer::registerShape(float* vertices .. int* indices ..) =>
          - gfxObj = new b3GraphicsInstance
          - m_graphicsInstances.push_back(gfxObj)
          - (verteces)
            - glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo)
            - glBufferSubData(GL_ARRAY_BUFFER .. vertices)
          - (GL_ELEMENT_ARRAY_BUFFER (aka vertex array indeces))
            - glGenBuffers(1, &gfxObj->m_index_vbo)
            - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gfxObj->m_index_vbo)
            - glBufferData(GL_ELEMENT_ARRAY_BUFFER, .. GL_STATIC_DRAW)
            - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, .. indices)
          - glGenVertexArrays(1, &gfxObj->m_cube_vao) ..
    - createCollisionObjectGraphicsObject =>
      - GLInstancingRenderer::registerGraphicsInstance(.. float* position, float* quaternion, float* color ..) =>
        - registerGraphicsInstanceInternal =>
          - add to GLInstanceRendererInternalData::m_instance_positions_ptr, m_instance_quaternion_ptr ..
          - (NOTE: difference from createCollisionShapeGraphicsObject is this is collision object itself instead of meshed version of it)


(Single frame routine)
- OpenGLExampleBrowser::update =>
  - GLInstancingRenderer::init => (some texture data things)
  - GLInstancingRenderer::updateCamera => ..
  - CommonRigidBodyBase::stepSimulation => btDiscreteDynamicsWorld::stepSimulation =>
    - saveKinematicState => .. (this example doesn't have btRigidBody which isKinematic)
    - applyGravity => for each btRigidBody in m_nonStaticRigidBodies, btRigidBody::applyGravity =>
      - applyCentralForce(m_gravity) => m_totalForce += m_gravity * m_linearFactor
    - internalSingleStepSimulation(btScalar timeStep) =>
      - predictUnconstraintMotion =>
        - for each btRigidBody
        - applyDamping => velocity = velocity * (1 - damping) ^ timestep
        - predictIntegratedTransform =>
          - update m_interpolationWorldTransform from m_worldTransform,m_linearVelocity,m_angularVelocity,timeStep
      - createPredictiveContacts => createPredictiveContactsInternal =>
        - some early testing based on m_interpolationWorldTransform ? ..
      - performDiscreteCollisionDetection =>
        - updateAabbs => for each btCollisionObject, updateSingleAabb =>
          - btCollisionShape::getAabb (if btRigidBody, use m_interpolationWorldTransform instead of m_worldTransform)
          - btBroadphasePhase::setAabb(btCollisionObject::getBroadphaseHandle (aka btDbvtProxy) ..) =>
            - aabb = btDbvtVolume::FromMM(minAabb, maxAabb)
            - if Intersect(proxy->leaf->volume, aabb)
              - btDbvt::update ..
            - update proxy's aabb and stage
            - ..
        - computeOverlappingPairs => btDbvtBroadPhase::calculateOverlappingPairs =>
          - collide =>
            - btDbvtTreeCollider collider .. ?
            - if not Intersect, removeOverlappingPair ..
          - performDeferredRemoval => ??
        - btCollisionDispatcher::dispatchAllCollisionPairs => btHashedOverlappingPairCache::processAllOverlappingPairs =>
          - btCollisionPairCallback
          - for each btBroadphasePair in m_overlappingPairArray
            - btCollisionPairCallback::processOverlap => btCollisionDispatcher::defaultNearCallback =>
              - btCollisionDispatcher::findAlgorithm => btBoxBoxCollisionAlgorithm::CreateFunc::CreateCollisionAlgorithm ..
              - btManifoldResult contactPointResult
              - btBoxBoxCollisionAlgorithm::processCollision(.. &btManifoldResult) =>
                - btBoxBoxDetector::getClosestPoints => dBoxBox2 .. calculation (TODO: follow more)
      - calculateSimulationIslands => ?
      - solveConstraints =>
        - InplaceSolverIslandCallback::processConstraints => btSequentialImpulseConstraintSolver::solveGroup =>
          - solveGroupCacheFriendlyIterations =>
            - solveGroupCacheFriendlySplitImpulseIterations => ?
            - solveSingleIteration =>
              - (.. looks complicated but ..)
              - btSolverConstraint solveManifold (this structure keeps necesssary data to handle contact impulse)
              - resolveSingleConstraintRowLowerLimit(btSolverBody, btSolverBody, solveManifold) =>
                - gResolveSingleConstraintRowLowerLimit_scalar_reference =>
                  - .. calculation (TODO: follow more)
                  - btSolverBody::internalApplyImpulse => ..
      - integrateTransforms =>
        - integrateTransformsInternal => for each btRigidBody
          - btRigidBody::predictIntegratedTransform
          - (can be complicated when useContinuous (whatever that is ..))
          - btRigidBody::proceedToTransform =>
            - update m_worldTransform and inertia tensor
      - (updateActions)
      - updateActivationState => (could make btRigidBody sleep)
    - synchronizeMotionStates =>
      - synchronizeSingleMotionState for each non-static btRigidBody => update m_graphicsWorldTrans
    - clearForces => reset btRigitBody::m_totalForce, Torgue
  - BasicExample::renderScene => CommonRigidBodyBase::renderScene =>
    - OpenGLGuiHelper::syncPhysicsToGraphics =>
      - for each btCollisionObject* colObj in btDiscreteDynamicsWorld::m_collisionObjects
        - GLInstancingRenderer::writeSingleInstanceTransformToCPU(colObj's origin, rotation, index) =>
          - update GLInstanceRendererInternalData::m_instance_positions_ptr, m_instance_quaternion_ptr
      - GLInstancingRenderer::writeTransforms =>
        - glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo)
        - glBufferSubData(GL_ARRAY_BUFFER, .. &m_data->m_instance_positions_ptr[0])
        - .. quaternion, color, scale as well
    - OpenGLGuiHelper::render => GLInstancingRenderer::renderScene =>
      - TODO: shadow stuff, a bunch of shaders
      - renderSceneInternal x 2 (B3_CREATE_SHADOWMAP_RENDERMODE and B3_USE_SHADOWMAP_RENDERMODE) =>
        - (if B3_CREATE_SHADOWMAP_RENDERMODE (i.e. only for first run))
          - glGenTextures(1, &m_data->m_shadowTexture), glBindTexture(GL_TEXTURE_2D ..)
          - new GLRenderToTexture, init(.. RENDERTEXTURE_DEPTH) =>
            - glGenFramebuffers(1, &m_framebufferName)
          - GLRenderToTexture::enable =>
            - glBindFramebuffer(GL_FRAMEBUFFER, m_framebufferName), glDrawBuffers
          - glViewport(0,0,shadowMapWidth,shadowMapHeight)
        - b3CreateOrtho => b3CreateDiagonalMatrix ..
        - SimpleCamera::getCameraProjectionMatrix, getCameraViewMatrix ..
        - glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo)
        - for each b3GraphicsInstance (gfxObj) in m_graphicsInstances
          - glBindVertexArray(gfxObj->m_cube_vao)
          - PointerCaster vertex, uv, normal and setup pointer from gfxObj
            - e.g. vertex.m_baseIndex = gfxObj->m_vertexArrayOffset*vertexStride
          - glVertexAttribPointer for vertex, uv, and normal
          - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gfxObj->m_index_vbo)
          - (if B3_CREATE_SHADOWMAP_RENDERMODE)
            - glUseProgram(createShadowMapInstancingShader) ..
            - glDrawElementsInstanced(GL_TRIANGLES, gfxObj->m_numIndices .. gfxObj->m_numGraphicsInstances)
          - (if B3_USE_SHADOWMAP_RENDERMODE)
            - glUseProgram(useShadowMapInstancingShader) .. something a lot here (camera, light, ..)
            - glDrawElementsInstanced(GL_TRIANGLES ..)
        - (if B3_CREATE_SHADOWMAP_RENDERMODE)
          - glBindFramebuffer( GL_FRAMEBUFFER, m_data->m_renderFrameBuffer)
          - glViewport(dims[0],dims[1],dims[2],dims[3])
  - SimpleOpenGL3App::swapBuffer =>
    - X11OpenGLWindow::endRendering => glXSwapBuffers
    - X11OpenGLWindow::startRendering => pumpMessage => .. ui event callback (e.g. MyKeyboardCallback)

TODO

  • Follow more concrete calculation part
    • contact detection and manifold (solver constraint) calculation: btBoxBoxDetector::getClosestPoints
    • contact impulse calculation: btSequentialImpulseConstraintSolver::gResolveSingleConstraintRowLowerLimit_scalar_reference
  • Follow more OpenGL drawing (vertex creation, shaders, shadow map, texture)
  • Blender integration

References