обнаружение столкновений в ограниченной коробке в opengl

Вот наложение программы. Я работаю в Visual Studio 10, C ++ с OpenGL / Glut. Я пытаюсь создать лабиринт (который я генерирую из входного файла). Затем я импортирую две модели из 3dstudio max с загрузчиком obj (glm). И одна из моделей (мо) будет передвигаться по лабиринту. Поэтому я добавил ограничивающий прямоугольник вокруг него, а также вокруг стен лабиринта. Я также нарисовал прямоугольник вокруг mo, и он, кажется, двигался / вращался вместе с персонажем. Но по какой-то причине (может быть, я не делаю это в нужном месте) тест столкновения никогда ничего не обнаруживает. Я позволю коду говорить, и если у вас есть какие-либо вопросы, я буду рад их исправить. Подготовьтесь к коду сейчас.

//bounding boxes
struct BoundingBox
{
Vector3D max;
Vector3D min;
};
BoundingBox *box_mo;
BoundingBox *static_box[400];

void initbox(BoundingBox *b){
b->min.x=100000;
b->min.y=100000;
b->min.z=100000;
b->max.x=-100000;
b->max.y=-100000;
b->max.z=-100000;
}

BoundingBox *CreateCollisionBox(GLMmodel *model,GLMgroup *object){
/* GLM doesn't store each vertex together with the object that owns it. It doesn't have that notion. In GLM object don't have vertex, they have triangles. And each triangle is actually an index in the triangle list of the object.*/
BoundingBox *boxx=(BoundingBox*)malloc(sizeof(BoundingBox));
initbox(boxx);
for(int i=0;i<object->numtriangles;i++){
// for each vertex of the triangle pmodel1->triangles[object->triangles[i]]
// calculate min and max
for(int j=0;j<3;j++){
GLuint index=model->triangles[object->triangles[i]].vindices[j];
GLfloat x = model->vertices[index*3 +0];
GLfloat y = model->vertices[index*3 +1];
GLfloat z = model->vertices[index*3 +2];
if(boxx->min.x>x) boxx->min.x =x;
if(boxx->min.y>y) boxx->min.y =y;
if(boxx->min.z>z) boxx->min.z =z;

if(boxx->max.x<x) boxx->max.x =x;
if(boxx->max.y<y) boxx->max.y =y;
if(boxx->max.z<z) boxx->max.z =z;
}
}
return boxx;
}

void AddCollisionBox(GLMmodel *model,GLMgroup *object){
//box[boxindex]=CreateCollisionBox(model,object);
box_mo=CreateCollisionBox(model,object);
//boxindex++;
}
// A GLMmodel has a chained list of groups, each group representing an object.
// Each object has a name (the name you gave it in 3D Studio Max or Gmax).
// Let's you have 10 walls in your scene a few other objects as well and you want to
// create collision boxes just for the walls and you do not want to make a collision box
// for one of your objects. You could name all your walls
// like this: Wall1, Wall2, ..., Wall10. If you wanted to add collision boxes just to them
// you could go through all objects in the scene and if their name contains "Wall" add them.
// with this one: strstr
// Basicly this function does just that: if you want to add boxes for the walls you would call it like this: DefineCollisionBoxes(model,"Wall");
void DefineCollisionBoxes(GLMmodel *model,char *name){
GLMgroup *group = model->groups;
while(group){
if(strstr(group->name,name))
AddCollisionBox(model,group);
group=group->next;
}
}

bool Collision(BoundingBox *b,GLfloat x,GLfloat y,GLfloat z){
return x <= b->max.x && x>= b->min.x && y<= b->max.y && y>= b->min.y && z<= b->max.z && z >= b->min.z;
}

bool CollisionTest(BoundingBox *a,BoundingBox *b){
/*bool collision=false;
for(int i=0;i<static_boxes;i++){
for(float x=static_box[i]->min.x, y=static_box[i]->min.y,z=static_box[i]->min.z ;x<=static_box[i]->max.x && y<=static_box[i]->max.y && z<=static_box[i]->max.z;x+=0.1,y+=0.1,z+=0.1){
if(Collision(a,x,y,z) == true)
collision=true;
}
}
return collision;*/
if(a->min.x <= b->max.x && a->max.x >= b->min.x && a->min.z <= b->max.z && a->max.z >= b->min.z && a->min.y <= b->max.y && a->max.y >= b->min.y)
return true;
return false;
}

void drawBox(BoundingBox *b){
glColor3f(1,1,1);
glBegin(GL_LINE_LOOP);
glVertex3f(b->max.x,b->max.y,b->min.z);
glVertex3f(b->min.x,b->max.y,b->min.z);
glVertex3f(b->min.x,b->min.y,b->min.z);
glVertex3f(b->max.x,b->min.y,b->min.z);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex3f(b->max.x,b->min.y,b->max.z);
glVertex3f(b->max.x,b->max.y,b->max.z);
glVertex3f(b->min.x,b->max.y,b->max.z);
glVertex3f(b->min.x,b->min.y,b->max.z);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex3f(b->max.x,b->max.y,b->min.z);
glVertex3f(b->max.x,b->max.y,b->max.z);
glVertex3f(b->min.x,b->max.y,b->max.z);
glVertex3f(b->min.x,b->max.y,b->min.z);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex3f(b->max.x,b->min.y,b->max.z);
glVertex3f(b->min.x,b->min.y,b->max.z);
glVertex3f(b->min.x,b->min.y,b->min.z);
glVertex3f(b->max.x,b->min.y,b->min.z);
glEnd();
}//display function
void display(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//setup view
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
camera.render
//read from file, create walls and characters
//place model mo in front of the third person camera always
Vector3D positionn;
positionn = camera.position + camera.forward*5;

glPushMatrix();
glColor3f(0.88f,0.75f,0.49f);
//here i move my character and calculate bounding box at each frame for him
glTranslatef(positionn.x,-0.42f,positionn.z);
glScalef(0.7f,0.7f,0.7f);
glRotatef(angle,0,1,0);
drawMo();
DefineCollisionBoxes(pmodel1,"body"); // actual function call
drawBox(box_mo); //draw bounding box
glPopMatrix();

//test if the character collides with any of the walls - not working
for(int i=0;i<static_boxes;i++){
if(CollisionTest(box_mo,static_box[i]) == true){
printf("collision");
}
}//swap buffers
glutSwapBuffers();
}

2

Решение

Я постараюсь дать общее представление о том, как решить проблему столкновения. Для простоты сделаю следующие предположения:

  1. У нас есть система координат, в которой существует лабиринт.
  2. И камера, и модель преобразуются в эту систему координат.
  3. Единственное преобразование, выполненное на стенах для того, чтобы привести их в эту систему координат, — это чистый перевод без каких-либо поворотов или масштабирования.
  4. Персонаж будет переведен, повернут и масштабирован.
  5. Вы не хотите проверять, столкнетесь ли вы, но столкнулись ли вы.
  6. У вас есть или вы напишите или приобретете векторную и матричную библиотеку

Если мы используем эти предположения, мы можем представить каждую стену, используя прямоугольник в 3d. И так как мы предполагали, что лабиринт не вращается и не масштабируется, мы можем сделать это один раз и сохранить его в массиве, в B-дереве или в любом другом месте. (Обратите внимание, что выбор правильной структуры данных для хранения вашего мира для вычислений может значительно повысить производительность)

Персонаж перемещается по лабиринту, и мы предположили, что его можно поворачивать и масштабировать. Самый простой способ определить, столкнулся ли персонаж с чем-либо, — это рассчитать ограничивающую сферу объекта. После того, как у вас есть, вы можете ради обнаружения столкновения хранить только две точки. Центральная точка сферы и любая произвольная точка на сфере.

Как только персонаж переместится в правильную позицию в лабиринте, вы примените точно такое же преобразование к двум упомянутым точкам. Вы можете сделать это, используя свою матричную библиотеку, или можете запросить матрицу MODELVIEW после преобразования символа. Вы можете сделать это, вызвав ‘glGetFloatv` следующим образом:

GLfloat model[16];
glGetFloatv(GL_MODELVIEW_MATRIX, model);

После того, как вы преобразовали две точки, вы можете найти расстояние между ними — это будет расстояние, на которое объект должен быть удален от преобразованной центральной точки, чтобы избежать столкновения.

Теперь последнее, что нужно сделать, — это перейти по соответствующим плоскостям и проверить расстояние от точки до плоскости, используя преобразованную центральную точку и рассчитанное расстояние. Затем вам нужно убедиться, что проецируемый центр на плоскость попадает в прямоугольник.

А вот схема программы (здесь нет реального кода, только комментарии и абстракции функций)

void drawCharacter(Matrix4f const & charMatrix);
void drawMaze(Matrix4f const & mazeMatrix);
//Will return MAX_FLT to indicate out of rectangle condition
float distanceToRectangle(Vector3f const & point, Rectangle3df const & plane);
vector<Rectangle3df> wallPlanes;
Vector3f centerOfCharSphere;
Vector3f pointOnCharSphere;
//Initialization
/*
1. Go Over maze create planes for all walls
2. Calculate character sphere and extract two points: The center of the sphere and a point on the sphere
*/

//Render
/*
Calculate the charMatrix - The matrix that takes the character from object CRS to maze CRS
Calculate the translation matrix for the maze (mazeMatrix) - the matrix that translates the maze into place
*/

Vector3f transformedSphereCenter = charMatrix.transform(centerOfCharSphere);
Vector3f transformedPointOnSphere = charMatrix.transform(pointOnCharSphere);
Vector3f R = transformedPointOnSphere - transformedSphereCenter;
float safeDistance = R.length();
for(vector<Plane3f>::const_iterator it = wallPlanes.begin(); it != wallPlanes.end(); it++)
{
if(distanceToRectangle(transformedSphereCenter, *it) <= safeDistance)
printf("collided\n");
}

/*
Setup projection matrix
Setup the modelview matrix for the camera
*/
drawMaze(mazeMatrix);
drawCharacter(charMatrix);

Я надеюсь, что это ставит вас на правильный путь

2

Другие решения

Других решений пока нет …