Rotación alrededor de un punto diferente del origen

Estoy tratando de codificar una cámara con glTranslate / glRotate. Para implementar las funciones de buscar / mirar hacia abajo, necesito que todos los objetos en mi espacio de representación giren alrededor de un punto (es decir, donde está la "cámara"), punto que generalmente difiere del origen. Aún así, las cosas siguen girando alrededor del origen. ¿Hay alguna manera de especificar un punto diferente?

EDITAR: código agregado

Gracias por tu rápida respuesta. Parece que no puedo hacerlo funcionar sin importar qué, así que he decidido agregar mi código; Apreciaría mucho si alguien pudiera echarle un vistazo y decirme qué cambios son necesarios para traducir / rotar / traducir de nuevo.

#include <iostream>
#include <cmath>
#include <GLUT/GLUT.h>

const double roaming_step = .13;
double z_offset = .0;
double y_offset = .0;
double x_offset = .0;

const double angle_step = 1.5;
double angle_xz = .0;
double angle_yz = .0;

bool keyStates[256] = { false };

void drawFloor()
{
    glColor3f(1.0, 1.0, 1.0);

    glBegin(GL_QUADS);
        glVertex3f(-3.0, -1.0, 3.0);
        glVertex3f(-3.0, -1.0, -3.0);
        glVertex3f(3.0, -1.0, -3.0);
        glVertex3f(3.0, -1.0, 3.0);
    glEnd();
}

void drawBalls()
{           
    glTranslatef(-3.0, -.5, -3.0);
    glColor3f(.8, .1, .1);

    for(int i = 0; i < 3; i++)
    {
        glPushMatrix();

        glTranslatef(.0, -.5, i * 3);
,
        for(int j = 0; j < 3; j++)
        {
            glPushMatrix();

            glTranslatef(j * 3, .0, .0);
            glutSolidSphere(.5, 20, 20);

            glPopMatrix();
        }

        glPopMatrix();
    }
}

void keyPressed(unsigned char key, int x, int y)
{
    keyStates[key] = true;
}

void keyReleased(unsigned char key, int x, int y)
{
    keyStates[key] = false;
}

void keyboardOperations()
{   
    if(keyStates['w'])
        z_offset += roaming_step;

    if(keyStates['s'])
        z_offset -= roaming_step;

    if(keyStates['a'])
        x_offset += roaming_step;

    if(keyStates['d'])
        x_offset -= roaming_step;

    if(keyStates['i'])
    {
        angle_xz -= angle_step;

        if(angle_xz < .0)
            angle_xz += 360.0;
    }

    if(keyStates['o'])
    {
        angle_xz += angle_step;

        if(angle_xz >= 360.0)
            angle_xz -= 360.0;
    }

    if(keyStates['u'])
    {
        angle_yz -= angle_step;

        if(angle_yz < .0)
            angle_yz += 360.0;
    }

    if(keyStates['j'])
    {
        angle_yz += angle_step;

        if(angle_yz >= 360.0)
            angle_yz -= 360.0;
    }

    if(keyStates['q'])
        exit(0);
}

// I guess it has to be done in this function
// but didn't get how
void camera()
{
    glLoadIdentity();

    // Forward / Backward
    glTranslated(.0, .0, z_offset);

    // Left / Right
    glTranslated(x_offset, .0, .0);

    // XZ Rotation
    glRotated(angle_xz, .0, 1.0, .0);

    // YZ Rotation
    glRotated(angle_yz, 1.0, .0, .0);
}

void display(void)
{   
    keyboardOperations();

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    camera();

    drawFloor();
    drawBalls();

    glutSwapBuffers();
}

void reshape(int width, int height)
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glViewport(0, 0, width, height);

    GLdouble aspect = (GLdouble) width / (GLdouble) height;
    gluPerspective(60, aspect, 1, 100);

    glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char** argv)
{   
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

    glutInitWindowSize(500, 500);
    glutInitWindowPosition(0, 0);
    glutCreateWindow("openGLtest3");
    glClearColor(.0, .0, .0, .0);

    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_FLAT);

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutIdleFunc(display);

    glutIgnoreKeyRepeat(true);
    glutKeyboardFunc(keyPressed);
    glutKeyboardUpFunc(keyReleased);

    glutMainLoop();

    return 0;
}

Respuestas a la pregunta(1)

Su respuesta a la pregunta