我试图用子弹物理仅供碰撞检测。 我并不需要它来移动任何物体对我或处理与回调渲染。 我只是想更新物体位置的每一帧,并用它来告诉我什么时候有冲突。 为了获得最简单的例子去,我试图找到btBoxShape对象作为它们的形状之间的碰撞。 一切都运行没有崩溃或明显的内存泄漏罚款,但我没有得到任何的碰撞,所以我必须做的地方一些错误。 我会尽力保持这个简短,因为我可以不留任何重要的东西出来。
这里是我的世界设定功能:
collisionConfig = new btDefaultCollisionConfiguration();
dispatcher = new btCollisionDispatcher(collisionConfig);
overlappingPairCache = new btDbvtBroadphase();
solver = new btSequentialImpulseConstraintSolver;
dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,
overlappingPairCache, solver, collisionConfig);
dynamicsWorld->setGravity(btVector3(0.0f, -9.8f, 0.0f));
现在我有型btCollisionObject的玩家和敌人的对象*。 我将它们设置是这样的:
mPlayerBox = new btBoxShape(btVector3(1,3,1));
mPlayerObject = new btCollisionObject();
mPlayerObject->setCollisionShape(mPlayerBox);
btTransform playerWorld;
playerWorld.setIdentity();
//playerPos is a D3DXVECTOR3 that holds the camera position.
playerWorld.setOrigin(btVector3(playerPos.x, playerPos.y, playerPos.z));
mPlayerObject->setWorldTransform(playerWorld);
mPlayerObject->forceActivationState(DISABLE_DEACTIVATION);//maybe not needed
dynamicsWorld->addCollisionObject(mPlayerObject);
我基本上做同样的事情与我的仇人对象。
然后每帧我更新所有我的是这样的对象:
btTransform updatedWorld;
updatedWorld.setIdentity();
updatedWorld.setOrigin(btVector3(position.x, position.y, position.z));
mPlayerObject->setWorldTransform(updatedWorld);
//do the same for my enemies, and then...
dynamicsWorld->performDiscreteCollisionDetection();
//Also tried doing this with stepSimulation(deltaTime, 7), but nothing changed.
//stepSimulation seems to only be for letting Bullet set world Transforms?
//check collisions with player
dynamicsWorld->contactTest(mPlayerObject, resultCallback);
int numManifolds = dynamicsWorld->getDispatcher()->getNumManifolds();
if(numManifolds > 0)
{
//there's a collision, execute blah blah blah
}
最后,这里是定义我的结果回调的结构:
struct rCallBack : public btCollisionWorld::ContactResultCallback
{
btScalar rCallback::addSingleResult(btManifoldPoint& cp, const btCollisionObject*
colObj0, int partId0, int index0, const btCollisionObject* colObj1, int partId1,
int index1)
{
btVector3 ptA = cp.getPositionWorldOnA();
btVector3 ptB = cp.getPositionWorldOnB();
return 0;
}
}
我看了很多的演示,但他们似乎大多离开运动达子弹,并且因为我在设定的速度移动的字符没有任何特殊的物理,当他们碰撞,我很难适应的例子为我的应用程序。 结果回调实际上是从这个职位来到论坛: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6816这是关于使用三角形网格,但它似乎最接近我试图实现。
无论如何,如果你读到这里,谢谢! 你能抽出任何意见或链接将非常感激。
我写这封信与flighter互相射击的3D场景的iOS应用。 我使用Bullet物理碰撞检测我设置flighter为运动对象,我的逻辑移动flighter,然后更新btMotionState worldTransform运动的对象。 我还没有得到任何碰撞检测,直到我改变,以下两个语句(设置掩蔽和组相同的两个玩家和敌人)
dynamicsWorld->addRigidBody(mPlayerObject,1,1);
dynamicsWorld->addRigidBody(mEnemyObject,1,1);
...
dynamicsWorld->setInternalTickCallback(myTickCallback);
然后我可以看到
void myTickCallback(btDynamicsWorld *world, btScalar timeStep) {
int numManifolds = world->getDispatcher()->getNumManifolds();
printf("numManifolds = %d\n",numManifolds);
}
numManifolds值成为1时物体碰撞。
您可以查看联系人信息,如解释在这里 :
联系信息
最好的办法,以确定是否冲突在世界上现有的对象之间发生的事情,是要遍历所有接触歧管。 这应该模拟刻度(分步骤)回调过程中完成的,因为接触可能会在一个stepSimulation调用若干子被添加和删除。 接触歧管是包含对碰撞对象之间的所有接触点的缓存。 一个好方法是遍历所有对象对整个碰撞/动态的世界:
//Assume world->stepSimulation or world->performDiscreteCollisionDetection has been called
int numManifolds = world->getDispatcher()->getNumManifolds();
for (int i=0;i<numManifolds;i++)
{
btPersistentManifold* contactManifold = world->getDispatcher()->getManifoldByIndexInternal(i);
btCollisionObject* obA = static_cast<btCollisionObject*>(contactManifold->getBody0());
btCollisionObject* obB = static_cast<btCollisionObject*>(contactManifold->getBody1());
int numContacts = contactManifold->getNumContacts();
for (int j=0;j<numContacts;j++)
{
btManifoldPoint& pt = contactManifold->getContactPoint(j);
if (pt.getDistance()<0.f)
{
const btVector3& ptA = pt.getPositionWorldOnA();
const btVector3& ptB = pt.getPositionWorldOnB();
const btVector3& normalOnB = pt.m_normalWorldOnB;
}
}
}
您可能感兴趣的btGhostObject保持跟踪自己的重叠对。
最小的可运行例子
球体落下,打在地上。
被检测和输出到stdout碰撞。
gnuplot的可视化:
在“碰撞”行云到1
每当球接触地面。
和对于较小的恢复系数( 0.5
和0.5
):
这球完全停止跳动,不断接触地面。
码:
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <btBulletDynamicsCommon.h>
#define PRINTF_FLOAT "%7.3f"
constexpr float gravity = -10.0f;
constexpr float initialY = 10.0f;
constexpr float timeStep = 1.0f / 60.0f;
// TODO some combinations of coefficients smaller than 1.0
// make the ball go up higher / not lose height. Why?
constexpr float groundRestitution = 0.9f;
constexpr float sphereRestitution = 0.9f;
constexpr int maxNPoints = 500;
std::vector<btVector3> collisions;
void myTickCallback(btDynamicsWorld *dynamicsWorld, btScalar timeStep) {
collisions.clear();
int numManifolds = dynamicsWorld->getDispatcher()->getNumManifolds();
for (int i = 0; i < numManifolds; i++) {
btPersistentManifold *contactManifold = dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
// TODO those are unused. What can be done with them?
// I think they are the same objects as those in the main loop
// dynamicsWorld->getCollisionObjectArray() and we could compare
// the pointers to see which object collided with which.
{
const btCollisionObject *objA = contactManifold->getBody0();
const btCollisionObject *objB = contactManifold->getBody1();
}
int numContacts = contactManifold->getNumContacts();
for (int j = 0; j < numContacts; j++) {
btManifoldPoint& pt = contactManifold->getContactPoint(j);
const btVector3& ptA = pt.getPositionWorldOnA();
const btVector3& ptB = pt.getPositionWorldOnB();
const btVector3& normalOnB = pt.m_normalWorldOnB;
collisions.push_back(ptA);
collisions.push_back(ptB);
collisions.push_back(normalOnB);
}
}
}
int main() {
int i, j;
btDefaultCollisionConfiguration *collisionConfiguration
= new btDefaultCollisionConfiguration();
btCollisionDispatcher *dispatcher = new btCollisionDispatcher(collisionConfiguration);
btBroadphaseInterface *overlappingPairCache = new btDbvtBroadphase();
btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;
btDiscreteDynamicsWorld *dynamicsWorld = new btDiscreteDynamicsWorld(
dispatcher, overlappingPairCache, solver, collisionConfiguration);
dynamicsWorld->setGravity(btVector3(0, gravity, 0));
dynamicsWorld->setInternalTickCallback(myTickCallback);
btAlignedObjectArray<btCollisionShape*> collisionShapes;
// Ground.
{
btTransform groundTransform;
groundTransform.setIdentity();
groundTransform.setOrigin(btVector3(0, 0, 0));
btCollisionShape* groundShape;
#if 1
// x / z plane at y = -1.
groundShape = new btStaticPlaneShape(btVector3(0, 1, 0), -1);
#else
// A cube of width 10 at y = -6.
// Does not fall because we won't call:
// colShape->calculateLocalInertia
// TODO: remove this from this example into a collision shape example.
groundTransform.setOrigin(btVector3(0, -6, 0));
groundShape = new btBoxShape(
btVector3(btScalar(5.0), btScalar(5.0), btScalar(5.0)));
#endif
collisionShapes.push_back(groundShape);
btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
btRigidBody::btRigidBodyConstructionInfo rbInfo(0, myMotionState, groundShape, btVector3(0, 0, 0));
btRigidBody* body = new btRigidBody(rbInfo);
body->setRestitution(groundRestitution);
dynamicsWorld->addRigidBody(body);
}
// Sphere.
{
btCollisionShape* colShape = new btSphereShape(btScalar(1.0));
collisionShapes.push_back(colShape);
btTransform startTransform;
startTransform.setIdentity();
startTransform.setOrigin(btVector3(0, initialY, 0));
btVector3 localInertia(0, 0, 0);
btScalar mass(1.0f);
colShape->calculateLocalInertia(mass, localInertia);
btDefaultMotionState *myMotionState = new btDefaultMotionState(startTransform);
btRigidBody *body = new btRigidBody(btRigidBody::btRigidBodyConstructionInfo(
mass, myMotionState, colShape, localInertia));
body->setRestitution(sphereRestitution);
dynamicsWorld->addRigidBody(body);
}
// Main loop.
std::printf("step body x y z collision a b normal\n");
for (i = 0; i < maxNPoints; ++i) {
dynamicsWorld->stepSimulation(timeStep);
for (j = dynamicsWorld->getNumCollisionObjects() - 1; j >= 0; --j) {
btCollisionObject *obj = dynamicsWorld->getCollisionObjectArray()[j];
btRigidBody *body = btRigidBody::upcast(obj);
btTransform trans;
if (body && body->getMotionState()) {
body->getMotionState()->getWorldTransform(trans);
} else {
trans = obj->getWorldTransform();
}
btVector3 origin = trans.getOrigin();
std::printf("%d %d " PRINTF_FLOAT " " PRINTF_FLOAT " " PRINTF_FLOAT " ",
i,
j,
float(origin.getX()),
float(origin.getY()),
float(origin.getZ()));
if (collisions.empty()) {
std::printf("0 ");
} else {
std::printf("1 ");
// Yes, this is getting reprinted for all bodies when collisions happen.
// It's just a quick and dirty way to visualize it, should be outside
// of this loop normally.
for (auto& v : collisions) {
std::printf(
PRINTF_FLOAT " " PRINTF_FLOAT " " PRINTF_FLOAT " ",
v.getX(), v.getY(), v.getZ());
}
}
puts("");
}
}
// Cleanup.
for (i = dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; --i) {
btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[i];
btRigidBody* body = btRigidBody::upcast(obj);
if (body && body->getMotionState()) {
delete body->getMotionState();
}
dynamicsWorld->removeCollisionObject(obj);
delete obj;
}
for (i = 0; i < collisionShapes.size(); ++i) {
delete collisionShapes[i];
}
delete dynamicsWorld;
delete solver;
delete overlappingPairCache;
delete dispatcher;
delete collisionConfiguration;
collisionShapes.clear();
}
基于: http://www.bulletphysics.org/mediawiki-1.5.8/index.php
这个版本集中在区分哪个对象触及哪个对象: https://gamedev.stackexchange.com/a/120881/25171
GitHub的上游: https://github.com/cirosantilli/cpp-cheat/blob/503a3b6487ccb75334798839b5ed912270446d14/bullet/ground_ball.cpp
在测试了子弹2.83,Ubuntu的15.10。