Search code examples
c++opengl3dcollision-detection

"Locking" Floor and Objects Beneath Feet of Moving Robot in OpenGL


I'm developing code for a simple walk about a 3D space. I've got a robot with movable limbs constructed already that is constructed on the xy plane and viewed down the z-axis, and some basic shapes (cubes) as obstacles to populate the floor of the area.

My problem is, I'm not sure why my floor is drawing in the middle of my robot. If you compile and run the code as I have, the arrow keys should move the space about the robot to give the illusion of movement, but he simply passes right through the floor/cubes. I want to have the cubes flush to the floor, and the floor flush to the robot's feet. I'm confused, as I have used local matrix sets for both, and would anticipate that they would be drawn in the correct position. Is it an issue of collision detection, or simply that my numbers are off? (The drawFloor function defines the floor as a 10 x 10 square in the xz plane.) So far I've tried changing the numbers to match the dimensions of the robot, but to no avail.

Aside: I've tried numerous orderings of the commands to get the coloring of the cubes to take effect, but they always seem to be overwritten by the grey color of the floor. Can anyone explain to me why this is?

Code below (somewhat lengthy - in process of refactoring to separate robot and scene drawing once I figure out what is wrong):

#define GLUT_DISABLE_ATEXIT_HACK

#include <GL/glut.h>
#include <GL/gl.h>
#include <math.h>

#define TORSO_HEIGHT 5.0
#define UPPER_ARM_HEIGHT 3.0
#define LOWER_ARM_HEIGHT 2.0
#define UPPER_LEG_RADIUS  0.5
#define LOWER_LEG_RADIUS  0.5
#define LOWER_LEG_HEIGHT 2.0
#define UPPER_LEG_HEIGHT 3.0
#define UPPER_LEG_RADIUS  0.5
#define TORSO_RADIUS 1.0
#define UPPER_ARM_RADIUS  0.5
#define LOWER_ARM_RADIUS  0.5
#define HEAD_HEIGHT 1.5
#define HEAD_RADIUS 1.0

double cubeX[] = { 5.0, 5.0, 5.0 };
double cubeY[] = { 3.0, 3.0, 3.0 };
double cubeZ[] = { 7.0, 5.0, 3.0 };
double cubeR[] = { 1.0, 0.0, 0.0 };
double cubeG[] = { 0.0, 1.0, 0.0 };
double cubeB[] = { 0.0, 0.0, 1.0 };

double xPos = 2.0, zPos = 5.0;
double eyeHeight = 4.5;
double eyeIncline = -0.5;
double lookAngle = 0.0; //In rads

double posIncr = 0.25;
double thetaIncr = 0.1;

typedef float point[3];

static GLfloat theta[11] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,
        180.0,0.0,180.0,0.0}; /* initial joint angles */
static GLint angle = 2;

GLUquadricObj *t, *h, *lua, *lla, *rua, *rla, *lll, *rll, *rul, *lul, *lf1, *lf2;

double size=1.0;

void torso()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(t,TORSO_RADIUS, TORSO_RADIUS, TORSO_HEIGHT,10,10);
glPopMatrix();
}

void head()
{
glPushMatrix();
glTranslatef(0.0, 0.5*HEAD_HEIGHT,0.0);
glScalef(HEAD_RADIUS, HEAD_HEIGHT, HEAD_RADIUS);
gluSphere(h,1.0,10,10);
glPopMatrix();
}

void left_upper_arm()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lua,UPPER_ARM_RADIUS, UPPER_ARM_RADIUS, UPPER_ARM_HEIGHT,10,10);
glPopMatrix();
}

void left_lower_arm()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lla,LOWER_ARM_RADIUS, LOWER_ARM_RADIUS, LOWER_ARM_HEIGHT,10,10);
glPopMatrix();
}

void left_finger1()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lf1,FINGER_1_RADIUS, FINGER_1_RADIUS, FINGER_1_HEIGHT,10,10);
glPopMatrix();
}

void left_finger2()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lla,LOWER_ARM_RADIUS, LOWER_ARM_RADIUS, LOWER_ARM_HEIGHT,10,10);
glPopMatrix();
} 

void right_upper_arm()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(rua,UPPER_ARM_RADIUS, UPPER_ARM_RADIUS, UPPER_ARM_HEIGHT,10,10);
glPopMatrix();
}

void right_lower_arm()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(rla,LOWER_ARM_RADIUS, LOWER_ARM_RADIUS, LOWER_ARM_HEIGHT,10,10);
glPopMatrix();
}

void left_upper_leg()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lul,UPPER_LEG_RADIUS, UPPER_LEG_RADIUS, UPPER_LEG_HEIGHT,10,10);
glPopMatrix();
}

void left_lower_leg()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lll,LOWER_LEG_RADIUS, LOWER_LEG_RADIUS, LOWER_LEG_HEIGHT,10,10);
glPopMatrix();
}

void right_upper_leg()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(rul,UPPER_LEG_RADIUS, UPPER_LEG_RADIUS, UPPER_LEG_HEIGHT,10,10);
glPopMatrix();
}

void right_lower_leg()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(rll,LOWER_LEG_RADIUS, LOWER_LEG_RADIUS, LOWER_LEG_HEIGHT,10,10);
glPopMatrix();
}

void drawCube( int i )
{
double x = cubeX[i];
double y = cubeY[i];
double z = cubeZ[i];

glColor3i(1, 0, 0); //Red cube
glPushMatrix();
glTranslatef(x,y,z);
glutSolidCube(1);
glPopMatrix();

glColor3i(0, 1, 0); //Green Cube
glPushMatrix();
glTranslatef(x,y,z);
glutSolidCube(1);
glPopMatrix();

glColor3i(0, 0, 1); //Blue Cube
glPushMatrix();
glTranslatef(x,y,z);
glutSolidCube(1);
glPopMatrix();

glColor3i(0, 1, 1);
glPushMatrix();
glTranslatef(x,y,z);
glutSolidCube(1);
glPopMatrix();

}

void drawCubes(void)
{

glLoadName(1);
drawCube(0);

glLoadName(2);
drawCube(1);

glLoadName(3);
drawCube(2);

/* Set name back to '0' to indicate background. */
glLoadName(0);
}

void drawFloor(void)
{
GLfloat mat_diffuse[] = { 0.5, 0.5, 0.5, 1.0 };
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glBegin(GL_POLYGON);
  glNormal3f(0.0, 1.0, 0.0);
  glVertex3f(-10.0, 0.0, -10.0);
  glVertex3f(10.0, 0.0, -10.0);
  glVertex3f(10.0, 0.0,  10.0);
  glVertex3f(-10.0, 0.0,  10.0);
glEnd();
}

void doDrawing(void)
{

drawCubes();

drawFloor();

/* Everything else is a lighter shade of grey. */
GLfloat mat_diffuse[] = { 0.8, 0.8, 0.8, 1.0 };
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
}

void drawEnviro(void)
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
double atx = xPos + cos(lookAngle);
double atz = zPos + sin(lookAngle);
double atHeight = eyeHeight + eyeIncline;
gluLookAt(xPos, eyeHeight, zPos, atx, atHeight, atz, 0.0, 1.0, 0.0);

glPushMatrix();
doDrawing();
glPopMatrix();
}

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawEnviro();
glLoadIdentity();
gluLookAt(0, 0, -20, 0, 0, -1, 0, 1, 0);
glColor3f(0.0, 0.0, 0.0);

glRotatef(theta[0], 0.0, 1.0, 0.0);
torso();
glPushMatrix();

glTranslatef(0.0, TORSO_HEIGHT+0.5*HEAD_HEIGHT, 0.0);
glRotatef(theta[1], 1.0, 0.0, 0.0);
glRotatef(theta[2], 0.0, 1.0, 0.0);
glTranslatef(0.0, -0.5*HEAD_HEIGHT, 0.0);
head();

glPopMatrix();
glPushMatrix();
glTranslatef(-(TORSO_RADIUS + UPPER_ARM_RADIUS), 0.9 * TORSO_HEIGHT, 0.0);
glRotatef(theta[3], 1.0, 0.0, 0.0);
left_upper_arm();

glTranslatef(0.0, UPPER_ARM_HEIGHT, 0.0);
glRotatef(theta[4], 1.0, 0.0, 0.0);
left_lower_arm();

glTranslatef(0.0, LOWER_ARM_HEIGHT, 0.0);
glRotatef(theta[11], 1.0, 0.0, 0.0);
left_finger1();

glPopMatrix();
glPushMatrix();
glTranslatef(TORSO_RADIUS+UPPER_ARM_RADIUS, 0.9*TORSO_HEIGHT, 0.0);
glRotatef(theta[5], 1.0, 0.0, 0.0);
right_upper_arm();

glTranslatef(0.0, UPPER_ARM_HEIGHT, 0.0);
glRotatef(theta[6], 1.0, 0.0, 0.0);
right_lower_arm();

glPopMatrix();
glPushMatrix();
glTranslatef(-(TORSO_RADIUS+UPPER_LEG_RADIUS), 0.1*UPPER_LEG_HEIGHT, 0.0);
glRotatef(theta[7], 1.0, 0.0, 0.0);
left_upper_leg();

glTranslatef(0.0, UPPER_LEG_HEIGHT, 0.0);
glRotatef(theta[8], 1.0, 0.0, 0.0);
left_lower_leg();

glPopMatrix();
glPushMatrix();
glTranslatef(TORSO_RADIUS+UPPER_LEG_RADIUS, 0.1*UPPER_LEG_HEIGHT, 0.0);
glRotatef(theta[9], 1.0, 0.0, 0.0);
right_upper_leg();

glTranslatef(0.0, UPPER_LEG_HEIGHT, 0.0);
glRotatef(theta[10], 1.0, 0.0, 0.0);
right_lower_leg();

glPopMatrix();

glFlush();
glutSwapBuffers();
}

void setProjection(void)
{
gluPerspective(60.0, 1.0, 0.1, 100.0);
}

void mouse(int btn, int state, int x, int y)
{
  if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN)
    {
    theta[angle] += 5.0;
    if( theta[angle] > 360.0 ) theta[angle] -= 360.0;
    }
  if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
    {
    theta[angle] -= 5.0;
    if( theta[angle] < 360.0 ) theta[angle] += 360.0;
    }
    display();
 }

void menu(int id)
{
if (id < 11 ) angle = id;
if (id == 11 ) exit(0);
}

void specialKey(int k, int x, int y)
{
/* Accept commands to move the viewpoint. */
switch (k) {
  case GLUT_KEY_UP:
     xPos += posIncr * cos(lookAngle);
     zPos += posIncr * sin(lookAngle);
     break;
  case GLUT_KEY_DOWN:
     xPos -= posIncr * cos(lookAngle);
     zPos -= posIncr * sin(lookAngle);
     break;
  case GLUT_KEY_LEFT:
     lookAngle -= thetaIncr;
     break;
  case GLUT_KEY_RIGHT:
     lookAngle += thetaIncr;
     break;
  case GLUT_KEY_PAGE_UP:
     eyeIncline += 0.5;
     break;
  case GLUT_KEY_PAGE_DOWN:
     eyeIncline -= 0.5;
     break;
  case GLUT_KEY_HOME:
     eyeHeight += 0.5;
     break;
  case GLUT_KEY_END:
     eyeHeight -= 0.5;
     break;
  default:
     return;
  }
  glutPostRedisplay();
 }

void reshape(int w, int h) 
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective (65.0, w/h, 1, 1000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

void init()
{
    GLfloat mat_specular[]={1.0, 1.0, 1.0, 1.0};
    GLfloat mat_diffuse[]={1.0, 1.0, 1.0, 1.0};
    GLfloat mat_ambient[]={1.0, 1.0, 1.0, 1.0};
    GLfloat mat_shininess={100.0};
    GLfloat light_ambient[]={0.0, 0.0, 0.0, 1.0};
    GLfloat light_diffuse[]={1.0, 1.0, 1.0, 1.0};
    GLfloat light_specular[]={1.0, 1.0, 1.0, 1.0};
    GLfloat light_position[]={10.0, 10.0, 10.0, 0.0};

    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);

    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess);

    glShadeModel(GL_SMOOTH);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);

    glClearColor(0.0, 0.0, 0.0, 0.0);
    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();
    setProjection();

    //Fill the body parts of the robot
    h=gluNewQuadric();
    gluQuadricDrawStyle(h, GLU_FILL);
    t=gluNewQuadric();
    gluQuadricDrawStyle(t, GLU_FILL);
    lua=gluNewQuadric();
    gluQuadricDrawStyle(lua, GLU_FILL);
    lla=gluNewQuadric();
    gluQuadricDrawStyle(lla, GLU_FILL);
    rua=gluNewQuadric();
    gluQuadricDrawStyle(rua, GLU_FILL);
    rla=gluNewQuadric();
    gluQuadricDrawStyle(rla, GLU_FILL);
    lul=gluNewQuadric();
    gluQuadricDrawStyle(lul, GLU_FILL);
    lll=gluNewQuadric();
    gluQuadricDrawStyle(lll, GLU_FILL);
    rul=gluNewQuadric();
    gluQuadricDrawStyle(rul, GLU_FILL);
    rll=gluNewQuadric();
    gluQuadricDrawStyle(rll, GLU_FILL);
    lf1=gluNewQuadric();
    gluQuadricDrawStyle(lf1, GLU_FILL);

 }

int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutCreateWindow("robot");
init();
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutSpecialFunc(specialKey);

glutCreateMenu(menu);
glutAddMenuEntry("torso", 0);
glutAddMenuEntry("head1", 1);
glutAddMenuEntry("head2", 2);
glutAddMenuEntry("right_upper_arm", 3);
glutAddMenuEntry("right_lower_arm", 4);
glutAddMenuEntry("left_upper_arm", 5);
glutAddMenuEntry("left_lower_arm", 6);
glutAddMenuEntry("right_upper_leg", 7);
glutAddMenuEntry("right_lower_leg", 8);
glutAddMenuEntry("left_upper_leg", 9);
glutAddMenuEntry("left_lower_leg", 10);
glutAddMenuEntry("quit", 11);
glutAttachMenu(GLUT_MIDDLE_BUTTON);

glutMainLoop();

return 0;
}

Solution

  • For the robot position:

    Your robot origin is at it's center, so you have to translate your floor or the robot half the robot's height.

    For the colors

    You are mixing glColor and glMaterial, the first is for non lighted scene while the second is for lighting enabled one.

    You may use glEnable(GL_COLOR_MATERIAL); to enable rendering of your glColor calls while lighting is enabled.

    (I'm not against several more points ;-))