Initial version of character controller and demo
This commit is contained in:
@@ -1,2 +1,2 @@
|
|||||||
SUBDIRS( OpenGL AllBulletDemos ConvexDecompositionDemo HelloWorld MultiThreadedDemo CcdPhysicsDemo ConstraintDemo GenericJointDemo RagdollDemo BasicDemo BspDemo MovingConcaveDemo VehicleDemo ColladaDemo UserCollisionAlgorithm )
|
SUBDIRS( OpenGL AllBulletDemos ConvexDecompositionDemo HelloWorld MultiThreadedDemo CcdPhysicsDemo ConstraintDemo GenericJointDemo RagdollDemo BasicDemo BspDemo MovingConcaveDemo VehicleDemo ColladaDemo UserCollisionAlgorithm CharacterDemo )
|
||||||
|
|
||||||
|
|||||||
65
Demos/CharacterDemo/CMakeLists.txt
Normal file
65
Demos/CharacterDemo/CMakeLists.txt
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# This is basically the overall name of the project in Visual Studio this is the name of the Solution File
|
||||||
|
|
||||||
|
|
||||||
|
# For every executable you have with a main method you should have an add_executable line below.
|
||||||
|
# For every add executable line you should list every .cpp and .h file you have associated with that executable.
|
||||||
|
|
||||||
|
|
||||||
|
# This is the variable for Windows. I use this to define the root of my directory structure.
|
||||||
|
SET(GLUT_ROOT ${BULLET_PHYSICS_SOURCE_DIR}/Glut)
|
||||||
|
|
||||||
|
# You shouldn't have to modify anything below this line
|
||||||
|
########################################################
|
||||||
|
|
||||||
|
|
||||||
|
# This is the shortcut to finding GLU, GLUT and OpenGL if they are properly installed on your system
|
||||||
|
# This should be the case.
|
||||||
|
INCLUDE (${CMAKE_ROOT}/Modules/FindGLU.cmake)
|
||||||
|
INCLUDE (${CMAKE_ROOT}/Modules/FindGLUT.cmake)
|
||||||
|
INCLUDE (${CMAKE_ROOT}/Modules/FindOpenGL.cmake)
|
||||||
|
|
||||||
|
|
||||||
|
IF (WIN32)
|
||||||
|
# This is the Windows code for which Opengl, and Glut are not properly installed
|
||||||
|
# since I can't install them I must cheat and copy libraries around
|
||||||
|
INCLUDE_DIRECTORIES(${GLUT_ROOT})
|
||||||
|
# LINK_DIRECTORIES(${GLUT_ROOT}\\lib)
|
||||||
|
IF (${GLUT_glut_LIBRARY} MATCHES "GLUT_glut_LIBRARY-NOTFOUND")
|
||||||
|
SET(GLUT_glut_LIBRARY ${BULLET_PHYSICS_SOURCE_DIR}/Glut/glut32.lib)
|
||||||
|
# LINK_LIBRARIES(${GLUT_ROOT}\\lib\\glut32 ${OPENGL_gl_LIBRARY} ${OPENGL_glU_LIBRARY})
|
||||||
|
# TARGET_LINK_LIBRARIES(table ${GLUT_ROOT}\\lib\\glut32)
|
||||||
|
#
|
||||||
|
# ADD_CUSTOM_COMMAND(TARGET table POST_BUILD COMMAND copy ${GLUT_ROOT}\\lib\\glut32.dll ${GLUT_ROOT}\\bin\\vs2005\\Debug
|
||||||
|
# COMMAND copy ${GLUT_ROOT}\\lib\\glut32.dll ${GLUT_ROOT}\\bin\\vs2003\\Debug
|
||||||
|
# COMMAND copy ${GLUT_ROOT}\\lib\\glut32.dll ${GLUT_ROOT}\\bin\\vs6\\Debug)
|
||||||
|
ELSE (${GLUT_glut_LIBRARY} MATCHES "GLUT_glut_LIBRARY-NOTFOUND")
|
||||||
|
# LINK_LIBRARIES(${GLUT_glut_LIBRARY} ${OPENGL_gl_LIBRARY} ${OPENGL_glU_LIBRARY})
|
||||||
|
# TARGET_LINK_LIBRARIES(table ${GLUT_glut_LIBRARY})
|
||||||
|
ENDIF(${GLUT_glut_LIBRARY} MATCHES "GLUT_glut_LIBRARY-NOTFOUND")
|
||||||
|
# TARGET_LINK_LIBRARIES(table ${OPENGL_gl_LIBRARY})
|
||||||
|
# TARGET_LINK_LIBRARIES(table ${OPENGL_glu_LIBRARY})
|
||||||
|
ELSE (WIN32)
|
||||||
|
# This is the lines for linux. This should always work if everything is installed and working fine.
|
||||||
|
# SET(CMAKE_BUILD_TYPE Debug)
|
||||||
|
# SET(CMAKE_CXX_FLAGS_DEBUG "-g")
|
||||||
|
INCLUDE_DIRECTORIES(/usr/include /usr/local/include ${GLUT_INCLUDE_DIR})
|
||||||
|
# TARGET_LINK_LIBRARIES(table ${GLUT_glut_LIBRARY} ${OPENGL_gl_LIBRARY} ${OPENGL_glU_LIBRARY})
|
||||||
|
# TARGET_LINK_LIBRARIES(checker ${GLUT_glut_LIBRARY} ${OPENGL_gl_LIBRARY} ${OPENGL_glU_LIBRARY})
|
||||||
|
ENDIF (WIN32)
|
||||||
|
|
||||||
|
INCLUDE_DIRECTORIES(
|
||||||
|
${BULLET_PHYSICS_SOURCE_DIR}/src ${BULLET_PHYSICS_SOURCE_DIR}/Demos/OpenGL }
|
||||||
|
)
|
||||||
|
|
||||||
|
LINK_LIBRARIES(
|
||||||
|
LibOpenGLSupport LibConvexHull LibBulletDynamics LibBulletCollision LibLinearMath ${GLUT_glut_LIBRARY} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY}
|
||||||
|
)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(CharacterDemo
|
||||||
|
CharacterController.cpp
|
||||||
|
CharacterController.h
|
||||||
|
CharacterDemo.cpp
|
||||||
|
CharacterDemo.h
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
191
Demos/CharacterDemo/CharacterController.cpp
Normal file
191
Demos/CharacterDemo/CharacterController.cpp
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
#include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
|
||||||
|
#include "BulletDynamics/Dynamics/btRigidBody.h"
|
||||||
|
#include "BulletDynamics/Dynamics/btDynamicsWorld.h"
|
||||||
|
#include "LinearMath/btDefaultMotionState.h"
|
||||||
|
#include "CharacterController.h"
|
||||||
|
|
||||||
|
CharacterController::CharacterController ()
|
||||||
|
{
|
||||||
|
m_rayLambda[0] = 1.0;
|
||||||
|
m_rayLambda[1] = 1.0;
|
||||||
|
m_halfHeight = 1.0;
|
||||||
|
m_turnAngle = 0.0;
|
||||||
|
m_maxLinearVelocity = 10.0;
|
||||||
|
m_walkVelocity = 8.0; // meters/sec
|
||||||
|
m_turnVelocity = 1.0; // radians/sec
|
||||||
|
m_shape = NULL;
|
||||||
|
m_rigidBody = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CharacterController::~CharacterController ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharacterController::setup (btDynamicsWorld* dynamicsWorld, btScalar height, btScalar width)
|
||||||
|
{
|
||||||
|
btVector3 spherePositions[2];
|
||||||
|
btScalar sphereRadii[2];
|
||||||
|
|
||||||
|
sphereRadii[0] = width;
|
||||||
|
sphereRadii[1] = width;
|
||||||
|
spherePositions[0] = btVector3 (0.0, (height/btScalar(2.0) - width), 0.0);
|
||||||
|
spherePositions[1] = btVector3 (0.0, (-height/btScalar(2.0) + width), 0.0);
|
||||||
|
|
||||||
|
m_halfHeight = height/btScalar(2.0);
|
||||||
|
|
||||||
|
m_shape = new btMultiSphereShape (btVector3(width/btScalar(2.0), height/btScalar(2.0), width/btScalar(2.0)), &spherePositions[0], &sphereRadii[0], 2);
|
||||||
|
|
||||||
|
btTransform startTransform;
|
||||||
|
startTransform.setIdentity ();
|
||||||
|
startTransform.setOrigin (btVector3(0.0, 2.0, 0.0));
|
||||||
|
btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
|
||||||
|
btRigidBody::btRigidBodyConstructionInfo cInfo(1.0, myMotionState, m_shape);
|
||||||
|
m_rigidBody = new btRigidBody(cInfo);
|
||||||
|
// kinematic vs. static doesn't work
|
||||||
|
//m_rigidBody->setCollisionFlags( m_rigidBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||||
|
m_rigidBody->setSleepingThresholds (0.0, 0.0);
|
||||||
|
m_rigidBody->setAngularFactor (0.0);
|
||||||
|
dynamicsWorld->addRigidBody (m_rigidBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharacterController::destroy (btDynamicsWorld* dynamicsWorld)
|
||||||
|
{
|
||||||
|
if (m_shape)
|
||||||
|
{
|
||||||
|
delete m_shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_rigidBody)
|
||||||
|
{
|
||||||
|
dynamicsWorld->removeRigidBody (m_rigidBody);
|
||||||
|
delete m_rigidBody;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
btRigidBody* CharacterController::getRigidBody ()
|
||||||
|
{
|
||||||
|
return m_rigidBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharacterController::preStep (btDynamicsWorld* dynamicsWorld)
|
||||||
|
{
|
||||||
|
btTransform xform;
|
||||||
|
m_rigidBody->getMotionState()->getWorldTransform (xform);
|
||||||
|
btVector3 down = -xform.getBasis()[1];
|
||||||
|
btVector3 forward = xform.getBasis()[2];
|
||||||
|
down.normalize ();
|
||||||
|
forward.normalize();
|
||||||
|
|
||||||
|
m_raySource[0] = xform.getOrigin();
|
||||||
|
m_raySource[1] = xform.getOrigin();
|
||||||
|
|
||||||
|
m_rayTarget[0] = m_raySource[0] + down * m_halfHeight * btScalar(1.1);
|
||||||
|
m_rayTarget[1] = m_raySource[1] + forward * m_halfHeight * btScalar(1.1);
|
||||||
|
|
||||||
|
class ClosestNotMe : public btCollisionWorld::ClosestRayResultCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ClosestNotMe (btRigidBody* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
|
||||||
|
{
|
||||||
|
m_me = me;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual btScalar AddSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
|
||||||
|
{
|
||||||
|
if (rayResult.m_collisionObject == m_me)
|
||||||
|
return 1.0;
|
||||||
|
|
||||||
|
return btCollisionWorld::ClosestRayResultCallback::AddSingleResult (rayResult, normalInWorldSpace
|
||||||
|
);
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
btRigidBody* m_me;
|
||||||
|
};
|
||||||
|
|
||||||
|
ClosestNotMe rayCallback(m_rigidBody);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
rayCallback.m_closestHitFraction = 1.0;
|
||||||
|
dynamicsWorld->rayTest (m_raySource[i], m_rayTarget[i], rayCallback);
|
||||||
|
if (rayCallback.HasHit())
|
||||||
|
{
|
||||||
|
m_rayLambda[i] = rayCallback.m_closestHitFraction;
|
||||||
|
} else {
|
||||||
|
m_rayLambda[i] = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharacterController::playerStep (btScalar dt,
|
||||||
|
int forward,
|
||||||
|
int backward,
|
||||||
|
int left,
|
||||||
|
int right)
|
||||||
|
{
|
||||||
|
btTransform xform;
|
||||||
|
m_rigidBody->getMotionState()->getWorldTransform (xform);
|
||||||
|
|
||||||
|
/* Handle turning */
|
||||||
|
if (left)
|
||||||
|
m_turnAngle -= dt * m_turnVelocity;
|
||||||
|
if (right)
|
||||||
|
m_turnAngle += dt * m_turnVelocity;
|
||||||
|
|
||||||
|
xform.setRotation (btQuaternion (btVector3(0.0, 1.0, 0.0), m_turnAngle));
|
||||||
|
|
||||||
|
btVector3 linearVelocity = m_rigidBody->getLinearVelocity();
|
||||||
|
btScalar speed = m_rigidBody->getLinearVelocity().length();
|
||||||
|
|
||||||
|
btVector3 forwardDir = xform.getBasis()[2];
|
||||||
|
forwardDir.normalize ();
|
||||||
|
btVector3 walkDirection = btVector3(0.0, 0.0, 0.0);
|
||||||
|
btScalar walkSpeed = m_walkVelocity * dt;
|
||||||
|
|
||||||
|
if (forward)
|
||||||
|
walkDirection += forwardDir;
|
||||||
|
if (backward)
|
||||||
|
walkDirection -= forwardDir;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (!forward && !backward && onGround())
|
||||||
|
{
|
||||||
|
/* Dampen when on the ground and not being moved by the player */
|
||||||
|
linearVelocity *= 0.2;
|
||||||
|
m_rigidBody->setLinearVelocity (linearVelocity);
|
||||||
|
} else {
|
||||||
|
if (speed < m_maxLinearVelocity)
|
||||||
|
{
|
||||||
|
btVector3 velocity = linearVelocity + walkDirection * walkSpeed;
|
||||||
|
m_rigidBody->setLinearVelocity (velocity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_rigidBody->getMotionState()->setWorldTransform (xform);
|
||||||
|
m_rigidBody->setCenterOfMassTransform (xform);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CharacterController::canJump () const
|
||||||
|
{
|
||||||
|
return onGround();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharacterController::jump ()
|
||||||
|
{
|
||||||
|
if (!canJump())
|
||||||
|
return;
|
||||||
|
|
||||||
|
btTransform xform;
|
||||||
|
m_rigidBody->getMotionState()->getWorldTransform (xform);
|
||||||
|
btVector3 up = xform.getBasis()[1];
|
||||||
|
up.normalize ();
|
||||||
|
btScalar magnitude = (btScalar(1.0)/m_rigidBody->getInvMass()) * btScalar(8.0);
|
||||||
|
m_rigidBody->applyCentralImpulse (up * magnitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CharacterController::onGround () const
|
||||||
|
{
|
||||||
|
return m_rayLambda[0] < btScalar(1.0);
|
||||||
|
}
|
||||||
47
Demos/CharacterDemo/CharacterController.h
Normal file
47
Demos/CharacterDemo/CharacterController.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#ifndef CHARACTER_CONTROLLER_H
|
||||||
|
#define CHARACTER_CONTROLLER_H
|
||||||
|
|
||||||
|
#include "LinearMath/btVector3.h"
|
||||||
|
|
||||||
|
class btCollisionShape;
|
||||||
|
class btRigidBody;
|
||||||
|
class btDynamicsWorld;
|
||||||
|
|
||||||
|
class CharacterController
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
btScalar m_halfHeight;
|
||||||
|
btCollisionShape* m_shape;
|
||||||
|
btRigidBody* m_rigidBody;
|
||||||
|
|
||||||
|
btVector3 m_raySource[2];
|
||||||
|
btVector3 m_rayTarget[2];
|
||||||
|
btScalar m_rayLambda[2];
|
||||||
|
btVector3 m_rayNormal[2];
|
||||||
|
|
||||||
|
btScalar m_turnAngle;
|
||||||
|
|
||||||
|
btScalar m_maxLinearVelocity;
|
||||||
|
btScalar m_walkVelocity;
|
||||||
|
btScalar m_turnVelocity;
|
||||||
|
public:
|
||||||
|
CharacterController ();
|
||||||
|
~CharacterController ();
|
||||||
|
void setup (btDynamicsWorld* dynamicsWorld, btScalar height = 2.0, btScalar width = 0.25);
|
||||||
|
void destroy (btDynamicsWorld* dynamicsWorld);
|
||||||
|
|
||||||
|
btRigidBody* getRigidBody ();
|
||||||
|
|
||||||
|
void preStep (btDynamicsWorld* dynamicsWorld);
|
||||||
|
void playerStep (btScalar dt,
|
||||||
|
int forward,
|
||||||
|
int backward,
|
||||||
|
int left,
|
||||||
|
int right);
|
||||||
|
bool canJump () const;
|
||||||
|
void jump ();
|
||||||
|
|
||||||
|
bool onGround () const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
522
Demos/CharacterDemo/CharacterDemo.cpp
Normal file
522
Demos/CharacterDemo/CharacterDemo.cpp
Normal file
@@ -0,0 +1,522 @@
|
|||||||
|
/*
|
||||||
|
Bullet Continuous Collision Detection and Physics Library
|
||||||
|
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// September 2006: CharacterDemo is work in progress, this file is mostly just a placeholder
|
||||||
|
/// This CharacterDemo file is very early in development, please check it later
|
||||||
|
/// One todo is a basic engine model:
|
||||||
|
/// A function that maps user input (throttle) into torque/force applied on the wheels
|
||||||
|
/// with gears etc.
|
||||||
|
#include "btBulletDynamicsCommon.h"
|
||||||
|
#include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
|
||||||
|
|
||||||
|
#include "GLDebugDrawer.h"
|
||||||
|
#include <stdio.h> //printf debugging
|
||||||
|
|
||||||
|
#include "GL_ShapeDrawer.h"
|
||||||
|
|
||||||
|
#include "GlutStuff.h"
|
||||||
|
#include "CharacterDemo.h"
|
||||||
|
#include "CharacterController.h"
|
||||||
|
|
||||||
|
const int maxProxies = 32766;
|
||||||
|
const int maxOverlap = 65535;
|
||||||
|
|
||||||
|
static int gForward = 0;
|
||||||
|
static int gBackward = 0;
|
||||||
|
static int gLeft = 0;
|
||||||
|
static int gRight = 0;
|
||||||
|
static int gJump = 0;
|
||||||
|
|
||||||
|
CharacterDemo::CharacterDemo()
|
||||||
|
:
|
||||||
|
m_cameraHeight(4.f),
|
||||||
|
m_minCameraDistance(3.f),
|
||||||
|
m_maxCameraDistance(10.f),
|
||||||
|
m_indexVertexArrays(0),
|
||||||
|
m_vertices(0)
|
||||||
|
{
|
||||||
|
m_character = 0;
|
||||||
|
m_cameraPosition = btVector3(30,30,30);
|
||||||
|
}
|
||||||
|
|
||||||
|
CharacterDemo::~CharacterDemo()
|
||||||
|
{
|
||||||
|
//cleanup in the reverse order of creation/initialization
|
||||||
|
if (m_character)
|
||||||
|
m_character->destroy (m_dynamicsWorld);
|
||||||
|
|
||||||
|
//remove the rigidbodies from the dynamics world and delete them
|
||||||
|
int i;
|
||||||
|
for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
|
||||||
|
{
|
||||||
|
btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
|
||||||
|
btRigidBody* body = btRigidBody::upcast(obj);
|
||||||
|
if (body && body->getMotionState())
|
||||||
|
{
|
||||||
|
delete body->getMotionState();
|
||||||
|
}
|
||||||
|
m_dynamicsWorld->removeCollisionObject( obj );
|
||||||
|
delete obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
//delete collision shapes
|
||||||
|
for (int j=0;j<m_collisionShapes.size();j++)
|
||||||
|
{
|
||||||
|
btCollisionShape* shape = m_collisionShapes[j];
|
||||||
|
delete shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete m_indexVertexArrays;
|
||||||
|
delete m_vertices;
|
||||||
|
|
||||||
|
//delete dynamics world
|
||||||
|
delete m_dynamicsWorld;
|
||||||
|
|
||||||
|
//delete solver
|
||||||
|
delete m_constraintSolver;
|
||||||
|
|
||||||
|
//delete broadphase
|
||||||
|
delete m_overlappingPairCache;
|
||||||
|
|
||||||
|
//delete dispatcher
|
||||||
|
delete m_dispatcher;
|
||||||
|
|
||||||
|
delete m_collisionConfiguration;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharacterDemo::initPhysics()
|
||||||
|
{
|
||||||
|
|
||||||
|
btCollisionShape* groundShape = new btBoxShape(btVector3(50,3,50));
|
||||||
|
m_collisionShapes.push_back(groundShape);
|
||||||
|
m_collisionConfiguration = new btDefaultCollisionConfiguration();
|
||||||
|
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
|
||||||
|
btVector3 worldMin(-1000,-1000,-1000);
|
||||||
|
btVector3 worldMax(1000,1000,1000);
|
||||||
|
m_overlappingPairCache = new btAxisSweep3(worldMin,worldMax);
|
||||||
|
m_constraintSolver = new btSequentialImpulseConstraintSolver();
|
||||||
|
m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_overlappingPairCache,m_constraintSolver,m_collisionConfiguration);
|
||||||
|
//m_dynamicsWorld->setGravity(btVector3(0,0,0));
|
||||||
|
btTransform tr;
|
||||||
|
tr.setIdentity();
|
||||||
|
|
||||||
|
//either use heightfield or triangle mesh
|
||||||
|
#define USE_TRIMESH_GROUND 1
|
||||||
|
#ifdef USE_TRIMESH_GROUND
|
||||||
|
int i;
|
||||||
|
|
||||||
|
const float TRIANGLE_SIZE=20.f;
|
||||||
|
|
||||||
|
//create a triangle-mesh ground
|
||||||
|
int vertStride = sizeof(btVector3);
|
||||||
|
int indexStride = 3*sizeof(int);
|
||||||
|
|
||||||
|
const int NUM_VERTS_X = 20;
|
||||||
|
const int NUM_VERTS_Y = 20;
|
||||||
|
const int totalVerts = NUM_VERTS_X*NUM_VERTS_Y;
|
||||||
|
|
||||||
|
const int totalTriangles = 2*(NUM_VERTS_X-1)*(NUM_VERTS_Y-1);
|
||||||
|
|
||||||
|
m_vertices = new btVector3[totalVerts];
|
||||||
|
int* gIndices = new int[totalTriangles*3];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for ( i=0;i<NUM_VERTS_X;i++)
|
||||||
|
{
|
||||||
|
for (int j=0;j<NUM_VERTS_Y;j++)
|
||||||
|
{
|
||||||
|
float wl = .2f;
|
||||||
|
//height set to zero, but can also use curved landscape, just uncomment out the code
|
||||||
|
float height = 20.f*sinf(float(i)*wl)*cosf(float(j)*wl);
|
||||||
|
#ifdef FORCE_ZAXIS_UP
|
||||||
|
m_vertices[i+j*NUM_VERTS_X].setValue(
|
||||||
|
(i-NUM_VERTS_X*0.5f)*TRIANGLE_SIZE,
|
||||||
|
(j-NUM_VERTS_Y*0.5f)*TRIANGLE_SIZE,
|
||||||
|
height
|
||||||
|
);
|
||||||
|
|
||||||
|
#else
|
||||||
|
m_vertices[i+j*NUM_VERTS_X].setValue(
|
||||||
|
(i-NUM_VERTS_X*0.5f)*TRIANGLE_SIZE,
|
||||||
|
height,
|
||||||
|
(j-NUM_VERTS_Y*0.5f)*TRIANGLE_SIZE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int index=0;
|
||||||
|
for ( i=0;i<NUM_VERTS_X-1;i++)
|
||||||
|
{
|
||||||
|
for (int j=0;j<NUM_VERTS_Y-1;j++)
|
||||||
|
{
|
||||||
|
gIndices[index++] = j*NUM_VERTS_X+i;
|
||||||
|
gIndices[index++] = j*NUM_VERTS_X+i+1;
|
||||||
|
gIndices[index++] = (j+1)*NUM_VERTS_X+i+1;
|
||||||
|
|
||||||
|
gIndices[index++] = j*NUM_VERTS_X+i;
|
||||||
|
gIndices[index++] = (j+1)*NUM_VERTS_X+i+1;
|
||||||
|
gIndices[index++] = (j+1)*NUM_VERTS_X+i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_indexVertexArrays = new btTriangleIndexVertexArray(totalTriangles,
|
||||||
|
gIndices,
|
||||||
|
indexStride,
|
||||||
|
totalVerts,(btScalar*) &m_vertices[0].x(),vertStride);
|
||||||
|
|
||||||
|
bool useQuantizedAabbCompression = true;
|
||||||
|
groundShape = new btBvhTriangleMeshShape(m_indexVertexArrays,useQuantizedAabbCompression);
|
||||||
|
|
||||||
|
tr.setOrigin(btVector3(0,-4.5f,0));
|
||||||
|
|
||||||
|
#else
|
||||||
|
//testing btHeightfieldTerrainShape
|
||||||
|
int width=128;
|
||||||
|
int length=128;
|
||||||
|
unsigned char* heightfieldData = new unsigned char[width*length];
|
||||||
|
{
|
||||||
|
for (int i=0;i<width*length;i++)
|
||||||
|
{
|
||||||
|
heightfieldData[i]=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* filename="heightfield128x128.raw";
|
||||||
|
FILE* heightfieldFile = fopen(filename,"r");
|
||||||
|
if (!heightfieldFile)
|
||||||
|
{
|
||||||
|
filename="../../heightfield128x128.raw";
|
||||||
|
heightfieldFile = fopen(filename,"r");
|
||||||
|
}
|
||||||
|
if (heightfieldFile)
|
||||||
|
{
|
||||||
|
int numBytes =fread(heightfieldData,1,width*length,heightfieldFile);
|
||||||
|
//btAssert(numBytes);
|
||||||
|
if (!numBytes)
|
||||||
|
{
|
||||||
|
printf("couldn't read heightfield at %s\n",filename);
|
||||||
|
}
|
||||||
|
fclose (heightfieldFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
btScalar maxHeight = 20000.f;
|
||||||
|
|
||||||
|
bool useFloatDatam=false;
|
||||||
|
bool flipQuadEdges=false;
|
||||||
|
|
||||||
|
btHeightfieldTerrainShape* heightFieldShape = new btHeightfieldTerrainShape(width,length,heightfieldData,maxHeight,upIndex,useFloatDatam,flipQuadEdges);;
|
||||||
|
groundShape = heightFieldShape;
|
||||||
|
|
||||||
|
heightFieldShape->setUseDiamondSubdivision(true);
|
||||||
|
|
||||||
|
btVector3 localScaling(20,20,20);
|
||||||
|
localScaling[upIndex]=1.f;
|
||||||
|
groundShape->setLocalScaling(localScaling);
|
||||||
|
|
||||||
|
tr.setOrigin(btVector3(0,-64.5f,0));
|
||||||
|
|
||||||
|
#endif //
|
||||||
|
|
||||||
|
m_collisionShapes.push_back(groundShape);
|
||||||
|
//create ground object
|
||||||
|
localCreateRigidBody(0,tr,groundShape);
|
||||||
|
|
||||||
|
m_character = new CharacterController ();
|
||||||
|
m_character->setup (m_dynamicsWorld);
|
||||||
|
|
||||||
|
#define CUBE_HALF_EXTENTS 0.5
|
||||||
|
#define EXTRA_HEIGHT 10.0
|
||||||
|
btBoxShape* boxShape = new btBoxShape (btVector3(1.0, 1.0, 1.0));
|
||||||
|
m_collisionShapes.push_back (boxShape);
|
||||||
|
#define DO_WALL
|
||||||
|
#ifdef DO_WALL
|
||||||
|
for (i=0;i<50;i++)
|
||||||
|
{
|
||||||
|
btCollisionShape* shape = boxShape;
|
||||||
|
//shape->setMargin(gCollisionMargin);
|
||||||
|
|
||||||
|
bool isDyna = i>0;
|
||||||
|
|
||||||
|
btTransform trans;
|
||||||
|
trans.setIdentity();
|
||||||
|
|
||||||
|
if (i>0)
|
||||||
|
{
|
||||||
|
//stack them
|
||||||
|
int colsize = 10;
|
||||||
|
int row = (i*CUBE_HALF_EXTENTS*2)/(colsize*2*CUBE_HALF_EXTENTS);
|
||||||
|
int row2 = row;
|
||||||
|
int col = (i)%(colsize)-colsize/2;
|
||||||
|
|
||||||
|
|
||||||
|
if (col>3)
|
||||||
|
{
|
||||||
|
col=11;
|
||||||
|
row2 |=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
btVector3 pos(col*2*CUBE_HALF_EXTENTS + (row2%2)*CUBE_HALF_EXTENTS,
|
||||||
|
row*2*CUBE_HALF_EXTENTS+CUBE_HALF_EXTENTS+EXTRA_HEIGHT,0);
|
||||||
|
|
||||||
|
trans.setOrigin(pos);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
trans.setOrigin(btVector3(0,EXTRA_HEIGHT-CUBE_HALF_EXTENTS,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
float mass = 1.f;
|
||||||
|
|
||||||
|
if (!isDyna)
|
||||||
|
mass = 0.f;
|
||||||
|
|
||||||
|
btRigidBody* body = localCreateRigidBody(mass,trans,shape);
|
||||||
|
#ifdef USE_KINEMATIC_GROUND
|
||||||
|
if (mass == 0.f)
|
||||||
|
{
|
||||||
|
body->setCollisionFlags( body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||||
|
body->setActivationState(DISABLE_DEACTIVATION);
|
||||||
|
}
|
||||||
|
#endif //USE_KINEMATIC_GROUND
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
clientResetScene();
|
||||||
|
|
||||||
|
setCameraDistance(26.f);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//to be implemented by the demo
|
||||||
|
void CharacterDemo::renderme()
|
||||||
|
{
|
||||||
|
|
||||||
|
updateCamera();
|
||||||
|
|
||||||
|
btScalar m[16];
|
||||||
|
int i;
|
||||||
|
DemoApplication::renderme();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharacterDemo::clientMoveAndDisplay()
|
||||||
|
{
|
||||||
|
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
float dt = getDeltaTimeMicroseconds() * 0.000001f;
|
||||||
|
|
||||||
|
/* Character stuff &*/
|
||||||
|
if (m_character)
|
||||||
|
{
|
||||||
|
m_character->preStep (m_dynamicsWorld);
|
||||||
|
m_character->playerStep (dt, gForward, gBackward, gLeft, gRight);
|
||||||
|
if (gJump)
|
||||||
|
{
|
||||||
|
gJump = 0;
|
||||||
|
m_character->jump ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_dynamicsWorld)
|
||||||
|
{
|
||||||
|
//during idle mode, just run 1 simulation step maximum
|
||||||
|
int maxSimSubSteps = m_idle ? 1 : 2;
|
||||||
|
if (m_idle)
|
||||||
|
dt = 1.0/420.f;
|
||||||
|
|
||||||
|
int numSimSteps = m_dynamicsWorld->stepSimulation(dt,maxSimSubSteps);
|
||||||
|
//optional but useful: debug drawing
|
||||||
|
m_dynamicsWorld->debugDrawWorld();
|
||||||
|
|
||||||
|
|
||||||
|
//#define VERBOSE_FEEDBACK
|
||||||
|
#ifdef VERBOSE_FEEDBACK
|
||||||
|
if (!numSimSteps)
|
||||||
|
printf("Interpolated transforms\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (numSimSteps > maxSimSubSteps)
|
||||||
|
{
|
||||||
|
//detect dropping frames
|
||||||
|
printf("Dropped (%i) simulation steps out of %i\n",numSimSteps - maxSimSubSteps,numSimSteps);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
printf("Simulated (%i) steps\n",numSimSteps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif //VERBOSE_FEEDBACK
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USE_QUICKPROF
|
||||||
|
btProfiler::beginBlock("render");
|
||||||
|
#endif //USE_QUICKPROF
|
||||||
|
|
||||||
|
|
||||||
|
renderme();
|
||||||
|
|
||||||
|
#ifdef USE_QUICKPROF
|
||||||
|
btProfiler::endBlock("render");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
glFlush();
|
||||||
|
glutSwapBuffers();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CharacterDemo::displayCallback(void)
|
||||||
|
{
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
renderme();
|
||||||
|
|
||||||
|
|
||||||
|
glFlush();
|
||||||
|
glutSwapBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CharacterDemo::clientResetScene()
|
||||||
|
{
|
||||||
|
m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(m_character->getRigidBody()->getBroadphaseHandle(),getDynamicsWorld()->getDispatcher());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharacterDemo::specialKeyboardUp(int key, int x, int y)
|
||||||
|
{
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case GLUT_KEY_UP:
|
||||||
|
{
|
||||||
|
gForward = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GLUT_KEY_DOWN:
|
||||||
|
{
|
||||||
|
gBackward = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GLUT_KEY_LEFT:
|
||||||
|
{
|
||||||
|
gLeft = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GLUT_KEY_RIGHT:
|
||||||
|
{
|
||||||
|
gRight = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DemoApplication::specialKeyboardUp(key,x,y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CharacterDemo::specialKeyboard(int key, int x, int y)
|
||||||
|
{
|
||||||
|
|
||||||
|
// printf("key = %i x=%i y=%i\n",key,x,y);
|
||||||
|
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case GLUT_KEY_UP:
|
||||||
|
{
|
||||||
|
gForward = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GLUT_KEY_DOWN:
|
||||||
|
{
|
||||||
|
gBackward = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GLUT_KEY_LEFT:
|
||||||
|
{
|
||||||
|
gLeft = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GLUT_KEY_RIGHT:
|
||||||
|
{
|
||||||
|
gRight = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GLUT_KEY_END:
|
||||||
|
{
|
||||||
|
if (m_character && m_character->canJump())
|
||||||
|
gJump = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DemoApplication::specialKeyboard(key,x,y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// glutPostRedisplay();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharacterDemo::updateCamera()
|
||||||
|
{
|
||||||
|
|
||||||
|
//#define DISABLE_CAMERA 1
|
||||||
|
#ifdef DISABLE_CAMERA
|
||||||
|
DemoApplication::updateCamera();
|
||||||
|
return;
|
||||||
|
#endif //DISABLE_CAMERA
|
||||||
|
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glLoadIdentity();
|
||||||
|
|
||||||
|
btTransform characterWorldTrans;
|
||||||
|
|
||||||
|
//look at the vehicle
|
||||||
|
m_character->getRigidBody()->getMotionState()->getWorldTransform(characterWorldTrans);
|
||||||
|
btVector3 up = characterWorldTrans.getBasis()[1];
|
||||||
|
btVector3 backward = -characterWorldTrans.getBasis()[2];
|
||||||
|
up.normalize ();
|
||||||
|
backward.normalize ();
|
||||||
|
|
||||||
|
m_cameraTargetPosition = characterWorldTrans.getOrigin();
|
||||||
|
m_cameraPosition = m_cameraTargetPosition + up * 5.0 + backward * 5.0;
|
||||||
|
|
||||||
|
//update OpenGL camera settings
|
||||||
|
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 10000.0);
|
||||||
|
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glLoadIdentity();
|
||||||
|
|
||||||
|
gluLookAt(m_cameraPosition[0],m_cameraPosition[1],m_cameraPosition[2],
|
||||||
|
m_cameraTargetPosition[0],m_cameraTargetPosition[1], m_cameraTargetPosition[2],
|
||||||
|
m_cameraUp.getX(),m_cameraUp.getY(),m_cameraUp.getZ());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
85
Demos/CharacterDemo/CharacterDemo.h
Normal file
85
Demos/CharacterDemo/CharacterDemo.h
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
Bullet Continuous Collision Detection and Physics Library
|
||||||
|
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
#ifndef CHARACTER_DEMO_H
|
||||||
|
#define CHARACTER_DEMO_H
|
||||||
|
|
||||||
|
class CharacterController;
|
||||||
|
|
||||||
|
class btCollisionShape;
|
||||||
|
|
||||||
|
|
||||||
|
#include "DemoApplication.h"
|
||||||
|
|
||||||
|
///CharacterDemo shows how to setup and use the built-in raycast vehicle
|
||||||
|
class CharacterDemo : public DemoApplication
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
CharacterController* m_character;
|
||||||
|
|
||||||
|
btAlignedObjectArray<btCollisionShape*> m_collisionShapes;
|
||||||
|
|
||||||
|
class btBroadphaseInterface* m_overlappingPairCache;
|
||||||
|
|
||||||
|
class btCollisionDispatcher* m_dispatcher;
|
||||||
|
|
||||||
|
class btConstraintSolver* m_constraintSolver;
|
||||||
|
|
||||||
|
class btDefaultCollisionConfiguration* m_collisionConfiguration;
|
||||||
|
|
||||||
|
class btTriangleIndexVertexArray* m_indexVertexArrays;
|
||||||
|
|
||||||
|
btVector3* m_vertices;
|
||||||
|
|
||||||
|
|
||||||
|
float m_cameraHeight;
|
||||||
|
|
||||||
|
float m_minCameraDistance;
|
||||||
|
float m_maxCameraDistance;
|
||||||
|
|
||||||
|
|
||||||
|
CharacterDemo();
|
||||||
|
|
||||||
|
virtual ~CharacterDemo();
|
||||||
|
|
||||||
|
virtual void clientMoveAndDisplay();
|
||||||
|
|
||||||
|
virtual void clientResetScene();
|
||||||
|
|
||||||
|
virtual void displayCallback();
|
||||||
|
|
||||||
|
///a very basic camera following the vehicle
|
||||||
|
virtual void updateCamera();
|
||||||
|
|
||||||
|
virtual void specialKeyboard(int key, int x, int y);
|
||||||
|
|
||||||
|
virtual void specialKeyboardUp(int key, int x, int y);
|
||||||
|
|
||||||
|
void renderme();
|
||||||
|
|
||||||
|
void initPhysics();
|
||||||
|
|
||||||
|
static DemoApplication* Create()
|
||||||
|
{
|
||||||
|
CharacterDemo* demo = new CharacterDemo();
|
||||||
|
demo->myinit();
|
||||||
|
demo->initPhysics();
|
||||||
|
return demo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //CHARACTER_DEMO_H
|
||||||
|
|
||||||
|
|
||||||
15
Demos/CharacterDemo/main.cpp
Normal file
15
Demos/CharacterDemo/main.cpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
#include "CharacterDemo.h"
|
||||||
|
#include "GlutStuff.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc,char** argv)
|
||||||
|
{
|
||||||
|
|
||||||
|
CharacterDemo* characterDemo = new CharacterDemo;
|
||||||
|
|
||||||
|
characterDemo->initPhysics();
|
||||||
|
|
||||||
|
return glutmain(argc, argv,640,480,"Bullet Character Demo. http://www.continuousphysics.com/Bullet/phpBB2/", characterDemo);
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user