3

これがプログラムのオーバーレイです。私は Visual Studio 10 、 c++ で opengl/glut を使用しています。迷路を作成しようとしています(入力ファイルから生成します)。次に、obj ローダー (glm) を使用して 3dstudio max から 2 つのモデルをインポートします。そしてモデルの1人(mo)が迷路の中を動き回ります。そこで、彼と迷宮の壁の周りにバウンディング ボックスを追加しました。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();
}
4

1 に答える 1

3

衝突の問題を解決する方法の概要を説明します。簡単にするために、次の仮定を行います。

  1. 迷路が存在する座標系があります。
  2. カメラとモデルの両方がこの座標系に変換されます。
  3. 壁をその座標系に合わせるために壁で実行される唯一の変換は、回転やスケーリングを行わない純粋な移動です。
  4. 文字は移動、回転、拡大縮小されます。
  5. 衝突するかどうかを確認するのではなく、衝突したかどうかを確認します。
  6. ベクトルと行列のライブラリを持っている、または作成する、または取得する

これらの仮定を使用すると、3D の長方形を使用して各壁を表すことができます。そして、迷路は回転も拡大縮小もされていないと仮定したので、一度実行して配列や B ツリーなどに保存することができます。(計算用にワールドを保存する適切なデータ構造を選択すると、パフォーマンスが大幅に向上することに注意してください)

キャラクターは迷路内を動き回り、回転とスケーリングの両方が可能であると想定しました。キャラクタが何かと衝突したかどうかを判断する最も簡単な方法は、オブジェクトの境界球を計算することです。取得したら、衝突検出のために 2 つのポイントだけを保存できます。球の中心点と球上の任意の点。

キャラクターが迷路内の正しい位置に移動したら、前述の 2 つのポイントにまったく同じ変換を適用します。マトリックス ライブラリを使用してこれを行うか、キャラクターを変換した後に MODELVIEW マトリックスを照会することができます。これを行うには、次のように「glGetFloatv」を呼び出します。

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

2 つのポイントを変換すると、それらの間の距離を見つけることができます。これは、衝突を避けるためにオブジェクトが変換された中心点から離れなければならない距離になります。

最後に、関連する平面を調べて、変換された中心点と計算された距離を使用して、点から平面への距離を確認します。次に、平面に投影された中心が長方形内にあることを確認する必要があります。

そして、これがプログラムの概要です(コメントと関数の抽象化だけで、実際のコードはありません)

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);

これがあなたを正しい軌道に乗せることを願っています

于 2012-11-27T22:05:40.703 に答える