2013年10月27日 星期日

ODE教學<三>幾何繪圖

Drawing The Geoms

At the end of the SimLoop function, after advancing the simulation one step and then deleting the contact joints, we called a function called DrawGeom. This function serves as a generic rendering routine for all types of geoms, using a different rendering function for each class of geom. In keeping with the examples that came with the ODE library, the DrawGeom function takes four parameters. The first is the geom's ID, then its position vector, rotation matrix and lastly a flag used to toggle the rendering of the geoms axis aligned bounding box. 


void DrawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb)
{
    // If the geom ID is missing then return immediately.
    if (!g)
        return;

    // If there was no position vector supplied then get the existing position.

    if (!pos)
        pos = dGeomGetPosition (g);

    // If there was no rotation matrix given then get the existing rotation.
    if (!R)
        R = dGeomGetRotation (g);

    // Get the geom's class type.
    int type = dGeomGetClass (g);

    if (type == dBoxClass)
    {
        // Create a temporary array of floats to hold the box dimensions.
        dReal sides[3];
        dGeomBoxGetLengths(g, sides);

        // Now to actually render the box we make a call to DrawBox, passing the geoms 
        // dimensions, position vector and
        // rotation matrix. And this function is the subject of our next discussion. 
        DrawBox(sides, pos, R);
    }
}


Anyone who has worked with OpenGL before will see that there is nothing out of the ordinary here. After we push the modelview matrix onto the stack we want to transform it by the position and rotation of the geom. We do this by calling a member function of my matrix class called ODEtoOGL. It takes the position vector and rotation matrix used by the ODE library and converts it to an OpenGL compatible 4x4 matrix (I will cover the inner workings of this conversion routine at the end of this tutorial.) Once we have a suitable transformation matrix we simply call glMultMatrixf to transform the current modelview matrix and then continue rendering the triangles of a box as normal. 

void DrawBox(const float sides[3], const float pos[3], const float R[12])
{
    float mat_ambient[] = { 0.8, 0.8, 0.8, 1.0 };
    float mat_diffuse[] = { 0.8, 0.8, 0.8, 1.0 };
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);

    glBindTexture(GL_TEXTURE_2D, texture[0].TexID);

    glPushMatrix();
    GeomMatrix.ODEtoOGL(pos, R);
    glMultMatrixf(GeomMatrix.Element);
    glBegin(GL_TRIANGLES);
        // Front Face
        glNormal3fv(&polygon[0].Vertex[0].nx);
        glTexCoord2f(0.0f, 0.0f); 
        glVertex3fv(&polygon[0].Vertex[0].x);
        glTexCoord2f(1.0f, 0.0f); 
        glVertex3fv(&polygon[0].Vertex[1].x);
        glTexCoord2f(1.0f, 1.0f); 
        glVertex3fv(&polygon[0].Vertex[2].x);

        glTexCoord2f(0.0f, 0.0f); 
        glVertex3fv(&polygon[1].Vertex[0].x);
        glTexCoord2f(1.0f, 1.0f); 
        glVertex3fv(&polygon[1].Vertex[1].x);
        glTexCoord2f(0.0f, 1.0f); 
        glVertex3fv(&polygon[1].Vertex[2].x);

        // Back Face
        glNormal3fv(&polygon[2].Vertex[0].nx);
        glTexCoord2f(0.0f, 0.0f); 
        glVertex3fv(&polygon[2].Vertex[0].x);
        glTexCoord2f(1.0f, 0.0f); 
        glVertex3fv(&polygon[2].Vertex[1].x);
        glTexCoord2f(1.0f, 1.0f); 
        glVertex3fv(&polygon[2].Vertex[2].x);

        glTexCoord2f(0.0f, 0.0f); 
        glVertex3fv(&polygon[3].Vertex[0].x);
        glTexCoord2f(1.0f, 1.0f); 
        glVertex3fv(&polygon[3].Vertex[1].x);
        glTexCoord2f(0.0f, 1.0f); 
        glVertex3fv(&polygon[3].Vertex[2].x);

        // Top Face
        glNormal3fv(&polygon[4].Vertex[0].nx);
        glTexCoord2f(0.0f, 0.0f); 
        glVertex3fv(&polygon[4].Vertex[0].x);
        glTexCoord2f(1.0f, 0.0f); 
        glVertex3fv(&polygon[4].Vertex[1].x);
        glTexCoord2f(1.0f, 1.0f); 
        glVertex3fv(&polygon[4].Vertex[2].x);

        glTexCoord2f(0.0f, 0.0f); 
        glVertex3fv(&polygon[5].Vertex[0].x);
        glTexCoord2f(1.0f, 1.0f); 
        glVertex3fv(&polygon[5].Vertex[1].x);
        glTexCoord2f(0.0f, 1.0f); 
        glVertex3fv(&polygon[5].Vertex[2].x);

        // Bottom Face
        glNormal3fv(&polygon[6].Vertex[0].nx);
        glTexCoord2f(0.0f, 0.0f); 
        glVertex3fv(&polygon[6].Vertex[0].x);
        glTexCoord2f(1.0f, 0.0f); 
        glVertex3fv(&polygon[6].Vertex[1].x);
        glTexCoord2f(1.0f, 1.0f); 
        glVertex3fv(&polygon[6].Vertex[2].x);

        glTexCoord2f(0.0f, 0.0f); 
        glVertex3fv(&polygon[7].Vertex[0].x);
        glTexCoord2f(1.0f, 1.0f); 
        glVertex3fv(&polygon[7].Vertex[1].x);
        glTexCoord2f(0.0f, 1.0f); 
        glVertex3fv(&polygon[7].Vertex[2].x);

        // Right face
        glNormal3fv(&polygon[8].Vertex[0].nx);
        glTexCoord2f(0.0f, 0.0f); 
        glVertex3fv(&polygon[8].Vertex[0].x);
        glTexCoord2f(1.0f, 0.0f); 
        glVertex3fv(&polygon[8].Vertex[1].x);
        glTexCoord2f(1.0f, 1.0f); 
        glVertex3fv(&polygon[8].Vertex[2].x);

        glTexCoord2f(0.0f, 0.0f); 
        glVertex3fv(&polygon[9].Vertex[0].x);
        glTexCoord2f(1.0f, 1.0f); 
        glVertex3fv(&polygon[9].Vertex[1].x);
        glTexCoord2f(0.0f, 1.0f); 
        glVertex3fv(&polygon[9].Vertex[2].x);

        // Left Face
        glNormal3fv(&polygon[10].Vertex[0].nx);
        glTexCoord2f(0.0f, 0.0f); 
        glVertex3fv(&polygon[10].Vertex[0].x);
        glTexCoord2f(1.0f, 0.0f); 
        glVertex3fv(&polygon[10].Vertex[1].x);
        glTexCoord2f(1.0f, 1.0f); 
        glVertex3fv(&polygon[10].Vertex[2].x);

        glTexCoord2f(0.0f, 0.0f); 
        glVertex3fv(&polygon[11].Vertex[0].x);
        glTexCoord2f(1.0f, 1.0f); 
        glVertex3fv(&polygon[11].Vertex[1].x);
        glTexCoord2f(0.0f, 1.0f); 
        glVertex3fv(&polygon[11].Vertex[2].x);
    glEnd();
    glPopMatrix();
}


Note that in this example I have ignored the geom dimensions as the box is always a cube with side lengths of 2. 

If you don't want to use my matrix class then the following function will do the job. Just enter an array of 16 floats as the first argument when calling the function and use the same array when calling glMultMatrixf. 

void ODEtoOGL(float* M, const float* p, const float* R)
{
    M[0]  = R[0]; M[1]  = R[4]; M[2]  = R[8];  M[3]  = 0;
    M[4]  = R[1]; M[5]  = R[5]; M[6]  = R[9];  M[7]  = 0;
    M[8]  = R[2]; M[9]  = R[6]; M[10] = R[10]; M[11] = 0;
    M[12] = p[0]; M[13] = p[1]; M[14] = p[2];  M[15] = 1;
}

沒有留言:

張貼留言