3D обнаружение столкновений Java с Jbullet
Поэтому я потратил много времени, пытаясь с нуля создать систему обнаружения столкновений для собственного игрового движка, и из-за нехватки времени оказался бесплодным. Наконец я решил попытаться использовать Jbullet, чтобы сделать вещи быстрее. Теперь документация в основном бесполезна, и у меня возникли некоторые трудности, когда я пытаюсь перенести код маркера на Java (или то, что я передаю, не работает). Я рвал на себе волосы, пытаясь найти код библиотеки, но экономия времени, на которую я надеялся, оказалась практически бесполезной. Итак, я собираюсь объяснить, что я делаю, возможно, вы, ребята, можете мне помочь. Я только ищу простое обнаружение столкновения, как будто вы нажали что-то, а затем просто напечатали строку. Остальное я, наверное, смогу решить самостоятельно.
Итак, я создаю свой мир:
BroadphaseInterface broadphase = new DbvtBroadphase();
CollisionConfiguration collisionConfig = new DefaultCollisionConfiguration();
Dispatcher dispatcher = new CollisionDispatcher(collisionConfig);
ConstraintSolver solver = new SequentialImpulseConstraintSolver();
DynamicsWorld dynamicsWorld = new DiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfig);
return dynamicsWorld;
Итак, у меня есть свой класс сущностей, и там у меня есть еще один класс, в котором хранится вся информация для физического объекта, присоединенного к этой сущности. Это позволяет мне просто сделать: entity.getPhysics(). GetCollisionObject()/. SetPosition() и т. Д.
Затем я создаю свой объект CollisionObject в этом классе:
List<org.lwjgl.util.vector.Vector3f> mesh = model.getModel().getVertices();
ObjectArrayList<javax.vecmath.Vector3f> vertices = new ObjectArrayList<javax.vecmath.Vector3f>();
for(org.lwjgl.util.vector.Vector3f vertex:mesh){
javax.vecmath.Vector3f v = new javax.vecmath.Vector3f(vertex.x, vertex.y, vertex.z);
vertices.add(v);
}
ConvexHullShape shape = new ConvexHullShape(vertices);
ShapeHull hull = new ShapeHull(shape);
hull.buildHull(shape.getMargin());
ConvexHullShape newShape = new ConvexHullShape(hull.getVertexPointer());
CollisionObject result = newShape;
Я считаю, что это преобразует уже созданный меш, который я использую для рендеринга своей сущности, из Vector3f библиотеки LWJGL и Jbullets Vector3f. Затем он создает ConvexHullShape из этих вершин в сетке, и я считаю, что:
hull.buildHull(shape.getMargin());
должен упрощать сетку (из документации). Тогда я просто создаю объект столкновения. Довольно просто, я думаю...
Я создаю свое твердое тело (хотя я не уверен, что мне нужно твердое тело или просто объект столкновения, и если бы кто-то мог сообщить мне, если это правда, это было бы здорово):
//mass = 0, so that there is not any gravity application?
float mass = 0;
Transform transform = new Transform(new Matrix4f(new Quat4f(rotation.x, rotation.y, rotation.z, 1), position, scale));
this.transform = transform;
MotionState state = new DefaultMotionState(transform);
RigidBodyConstructionInfo info = new RigidBodyConstructionInfo(mass, state, shape);
RigidBody body = new RigidBody(info);
Затем я прохожу игровой цикл:
dynamicsWorld.stepSimulation(DisplayManager.getFrameTimeSeconds(), 7);
dynamicsWorld.performDiscreteCollisionDetection();
dynamicsWorld.setInternalTickCallback(new InternalTickCallback(){
@Override
public void internalTick(DynamicsWorld world, float delta) {
Dispatcher dispatcher = world.getDispatcher();
int manifoldCount = dispatcher.getNumManifolds();
for(int i = 0; i < manifoldCount; i ++){
PersistentManifold manifold = dispatcher.getManifoldByIndexInternal(i);
RigidBody object1 = (RigidBody)manifold.getBody0();
RigidBody object2 = (RigidBody)manifold.getBody1();
CollisionObject physicsObject1 = (CollisionObject)object1.getUserPointer();
CollisionObject physicsObject2 = (CollisionObject)object2.getUserPointer();
boolean contact = false;
javax.vecmath.Vector3f normal = null;
for (int j = 0; j < manifold.getNumContacts(); j++) {
ManifoldPoint contactPoint = manifold.getContactPoint(j);
if (contactPoint.getDistance() < 0.0f) {
contact = true;
normal = contactPoint.normalWorldOnB;
break;
}
}
if (contact) {
System.out.println("hit");
}
}
}
}, null);
Я получил это от кого-то... Я забыл, где, хотя. Итак, в основном ничего не происходит... Я не уверен, но, возможно, мне нужно добавить объекты в коллектор или что-то в этом роде. Не знаю как это сделать. Любая помощь?
РЕДАКТИРОВАТЬ: то, что я сделал сейчас, это создаю форму столкновения как окно произвольного размера:
CollisionShape result = new BoxShape(new Vector3f(10,10,10));
Затем я создаю Призрачное Тело:
Transform transform = new Transform(new Matrix4f(new Quat4f(rotation.x, rotation.y, rotation.z, 1), position, scale));
this.transform = transform;
transform.origin.set(position);
GhostObject body = new GhostObject();
body.setCollisionShape(shape);
body.setWorldTransform(transform);
тогда я просто делаю, как ты сказал, он все равно не возвращает "хит";
int overlaps = player.getPhysics().getBody().getNumOverlappingObjects();
for(int i = 0; i < overlaps; i++){
//player.getPhysics().getBody().getOverlappingObject(i).
System.out.println("hit");
}
РЕДАКТИРОВАТЬ 2:
Поэтому я создаю объект следующим образом в моем классе сущностей:
if(collision){
physics = new PhysicsEntity(dynamicsWorld, model,new javax.vecmath.Vector3f(position.x, position.y, position.z), new javax.vecmath.Vector3f(rotX, rotY, rotZ), scale);
physics.updatePosition(new javax.vecmath.Vector3f(position.x, position.y, position.z));
physics.updateRotation(new javax.vecmath.Vector3f(rotX, rotY, rotZ));
}
и обновить позицию и прочее:
public void increasePosition(float dx,float dy, float dz){
this.position.x += dx;
this.position.y += dy;
this.position.z += dz;
physics.updatePosition(new javax.vecmath.Vector3f(position.x, position.y, position.z));
}
public void increaseRotation(float dx, float dy, float dz){
this.rotX += dx;
this.rotY += dy;
this.rotZ += dz;
physics.updateRotation(new javax.vecmath.Vector3f(rotX, rotY, rotZ));
}
Итак, это мой класс PhysicsEntity, где я его настроил:
public PhysicsEntity(DynamicsWorld world, TexturedModel model, Vector3f position, Vector3f rotation, float scale){
this.model = model;
this.position = position;
this.rotation = rotation;
this.scale = scale;
shape = createShape();
body = createBody();
object = new CollisionObject();
object.setCollisionShape(shape);
world.addCollisionObject(body);
}
private GhostObject createBody(){
Transform transform = new Transform(new Matrix4f(new Quat4f(rotation.x, rotation.y, rotation.z, 1), position, scale));
this.transform = transform;
transform.origin.set(position);
GhostObject body = new GhostObject();
body.setCollisionShape(shape);
body.setWorldTransform(transform);
return body;
}
private CollisionShape createShape(){
CollisionShape result = new BoxShape(new Vector3f(10,10,10));
return result;
}
public void updatePosition(Vector3f position){
transform.origin.set(position);
body.setWorldTransform(transform);
}
public void updateRotation(Vector3f rotation){
transform.basis.set(new Quat4f(rotation.x, rotation.y, rotation.z, 1));
body.setWorldTransform(transform);
}
Спасибо,
1 ответ
Мой опыт работы с Bullet ограничен C++, но, возможно, я смогу помочь. Что вы имеете в виду, говоря, что ничего не происходит? Правильно ли действует гравитация на объект, но не вызывается обратный вызов столкновения или проблема в том, что он вообще не движется? Очевидно, он не будет двигаться, потому что его масса равна 0, поэтому он статичен. Объект с массой 0 также может быть кинематическим, если вы вызываете
body.setCollisionFlags(body .getCollisionFlags() | CollisionFlags.KINEMATIC_OBJECT);
body.setActivationState(CollisionObject.DISABLE_DEACTIVATION);
Как статические, так и кинематические объекты обнаруживают столкновения, но только с динамическими объектами (масса больше 0). Я предлагаю для начала использовать простую форму столкновения, такую как сфера. Таким образом, вы можете проверить, работает ли симуляция вообще. Выпуклые корпуса могут быть сложными. Начните с чего-то простого, чтобы привести рабочий пример. Теперь о методе обнаружения столкновений. Когда вы звоните dynamicsWorld.stepSimulation
прилагаются все силы, и происходит обнаружение и разрешение столкновений. Так что сразу после этого вы можете перебирать PersistentManifolds
так же, как вы делаете, чтобы проверить, какие объекты столкнулись друг с другом на этом этапе моделирования. Теперь я не уверен, но когда вы звоните dynamicsWorld.performDiscreteCollisionDetection();
вполне возможно, что столкновения не обнаружены, потому что все они были просто решены.
Почти во всех стандартных случаях вы хотите использовать RigidBody
, Исключение составляют мягкие тела, такие как одежда и призрачные объекты, которые можно использовать для обнаружения столкновений без каких-либо реакций.
РЕДАКТИРОВАТЬ.
В ситуации, когда не требуется никакого столкновения, только обнаружение удара, вы не хотите RigidBody
, Он может быть статическим, динамическим или кинематическим, но это не ваш случай. Вместо этого вы хотите использовать GhostObject
, Он просто обнаруживает столкновения, но не реагирует. Вы можете легко проверить, перекрывается ли это чем-то, сначала вызвав его getNumOverlappingObjects()
а потом getOverlappingObject(int index)
,
EDIT2.
Похоже, вы правильно создали объект. Если предположить, что преобразования верны и объект действительно должен перекрываться, то, что вы можете пропустить, dynamicsWorld.addCollisionObject(body);
Я пропустил это с первого взгляда, но похоже, что вы только создаете объект, но не добавляете его в мир, поэтому Bullet engine не знает о его существовании.
EDIT3.
Итак, еще несколько предложений, чтобы убедиться, что столкновение должно быть обнаружено. Сколько физических объектов (призраков или твердых тел) вы создали и добавили в мир (используя dynamicsWorld.add...
)? Если есть только один, очевидно, что столкновение не может быть обнаружено. Пуля не будет сталкивать физический объект с геометрией сцены, но только с другим физическим объектом. Не могли бы вы опубликовать свой код, где вы создаете и перемещаете эти объекты?
EDITn.
Итак, вы опубликовали функции, создающие PhysicsEntity, но я все еще не знаю, сколько сущностей вы создаете и с какими параметрами. Необходимо проверить, каковы их мировые координаты и проверить, действительно ли они должны столкнуться.
Ваше использование Quaternion немного беспокоит. Вы, вероятно, передаете аргументы x,y,z как вращение по оси x,y,z соответственно. Это не так, как это работает. Я бы посоветовал использовать другой конструктор, который принимает ось вращения и угол в качестве параметров.
Поскольку код и проблема очень сложны, и я не вижу прямой причины в опубликованном вами коде, я бы посоветовал использовать отладчик и просмотреть код, чтобы убедиться, что все объекты инициализированы правильно, их позиции как и ожидалось, и, наконец, войдите в код столкновения, чтобы понять, почему этого не происходит.