OpenGL:如何在移动相机时使光线静止?

时间:2016-12-18 19:09:26

标签: c opengl glut

我正在尝试使用OpenGL和GLUT渲染一个简单的(10x3x10大小)房间,用C语言编写。

我想制作一个简单的聚光灯,而我可以在房间里四处走动。

(最终目标是让天花板上的灯成为聚光灯)

问题是当我移动相机时光线会发生变化。

我从main()调用以下函数:

void init() {
    glEnable(GL_TEXTURE_2D);

    loadTexture(); // loading some textures using SOIL
    loadModels(); // loading some OBJ models

    glShadeModel(GL_SMOOTH);
    glEnable(GL_NORMALIZE);
    glEnable(GL_AUTO_NORMAL);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_COLOR_MATERIAL);
    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
    glClearDepth(1);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glDepthFunc(GL_LEQUAL);
    glClearColor(0, 0, 0, 1);
}

我传递给glutDisplayFunc()的函数:

void display() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    initLight();

    gluLookAt(x, 1.5f, z, x + vX, 1.5f, z + vZ, 0.0f, 1.5f, 0.0f);

    // ...
    // drawing the ground, ceiling and the walls
    // no matrix transformations here, just simple glVertex () calls
    // ...

    glPushMatrix();

    // drawing a table
    glTranslatef(5, 0.842843, 5);
    glBindTexture(GL_TEXTURE_2D, texture[1]);
    draw_model(&modelTable);

    // drawing some chairs
    glTranslatef(0, -0.312053, chair1Position);
    glBindTexture(GL_TEXTURE_2D, texture[2]);
    draw_model(&modelChair1);
    glTranslatef(0, 0, chair2Position);
    draw_model(&modelChair2);

    glPopMatrix();

    glutSwapBuffers();
}

initLight()函数:

void initLight() {

    // i would like the light to originate from an upper corner
    // directed to the opposing lower corner (across the room basically)

    GLfloat lightPosition[] = { 10, 3, 0, 1 };
    GLfloat lightDirection[] = { 0, 0, 10, 0 };
    GLfloat ambientLight[] = { 0.3, 0.3, 0.3, 1 };
    GLfloat diffuseLight[] = { 1, 1, 1, 1 };

    glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
    glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
    glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 180);
    glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 64);
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, lightDirection);
}

我被告知这个问题可以通过glPushMatrix()glPopMatrix()来电的正确定位来解决。

无论我把它们放在哪里,当我移动相机时光线都会不断变化,或者根本没有光线。我只是想不出来。

这里有什么合适的解决方案?

提前致谢。

修改: 我已将initLight()来电转移到gluLookAt()来电之后,@ derhass建议如下。 当我四处走动时,灯光仍在变化。

下面有两个截图。

在第一个灯上甚至看不见灯。当我略微向右转时,它会出现。 enter image description here enter image description here

EDIT2

完整(精简)源代码:

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

GLfloat lightPosition[] = { 10, 3, 0, 1 };
GLfloat lightDirection[] = { 0, 0, 10, 0 };
GLfloat diffuseLight[] = { 0, 1, 0, 1 };
GLfloat ambientLight[] = { 0.2, 0.2, 0.2, 1 };

float x = 1.0f, z = 5.0f;
float vX = 1.0f, vZ = 0.0f;
float angle = 1.5f;

int windowWidth = 1024;
int windowHeight = 768;

char* textureFiles[13] = { "floortexture.png", "tabletexture.png",
        "chairtexture.png", "orange.png", "helptexture.png",
        "fridgetexture.png", "oven.png", "yellow.png", "dishwasher.png",
        "metallic.png", "cabinet.png", "wood.png", "cabinet2.png" };
GLuint texture[13];

void loadTexture() {
    for (int i = 0; i < 13; i++) {
        texture[i] = SOIL_load_OGL_texture(textureFiles[i], SOIL_LOAD_RGBA,
                SOIL_CREATE_NEW_ID, 0);

        glBindTexture(GL_TEXTURE_2D, texture[i]);

        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    }
}

void init() {
    glEnable(GL_TEXTURE_2D);

    loadTexture();

    glShadeModel(GL_SMOOTH);
    glEnable(GL_NORMALIZE);
    glEnable(GL_AUTO_NORMAL);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_COLOR_MATERIAL);
    glClearDepth(1);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glDepthFunc(GL_LEQUAL);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
    glClearColor(0, 0, 0, 1);
}

void processSpecialKeys(int key, int xx, int yy) {

    float moveFraction = 0.2f;
    float angleFraction = 0.1f;

    switch (key) {
    case GLUT_KEY_LEFT:
        angle -= angleFraction;
        vX = sin(angle);
        vZ = -cos(angle);
        break;
    case GLUT_KEY_RIGHT:
        angle += angleFraction;
        vX = sin(angle);
        vZ = -cos(angle);
        break;
    case GLUT_KEY_UP:
        x += vX * moveFraction;
        z += vZ * moveFraction;
        if (x < 1) {
            x = 1;
        }
        if (z < 1) {
            z = 1;
        }
        if (x > 9) {
            x = 9;
        }
        if (z > 9) {
            z = 9;
        }
        break;
    case GLUT_KEY_DOWN:
        x -= vX * moveFraction;
        z -= vZ * moveFraction;
        if (x < 1) {
            x = 1;
        }
        if (z < 1) {
            z = 1;
        }
        if (x > 9) {
            x = 9;
        }
        if (z > 9) {
            z = 9;
        }
        break;
    }
}

void initLight() {
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
    glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
    glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 180);
    glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 128);
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, lightDirection);
}

void renderWalls() {
    // floor
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glBegin(GL_QUADS);

    glTexCoord2f(0, 0);
    glVertex3f(0.0f, 0.0f, 0.0f);

    glTexCoord2f(0, 8);
    glVertex3f(0.0f, 0.0f, 10.0f);

    glTexCoord2f(8, 8);
    glVertex3f(10.0f, 0.0f, 10.0f);

    glTexCoord2f(8, 0);
    glVertex3f(10.0f, 0.0f, 0.0f);

    glEnd();

    // walls
    glBindTexture(GL_TEXTURE_2D, texture[3]);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    // first wall
    glBegin(GL_QUADS);

    glTexCoord2f(0, 0);
    glVertex3f(0.0f, 0.0f, 0.0f);

    glTexCoord2f(0, 1);
    glVertex3f(0.0f, 3.0f, 0.0f);

    glTexCoord2f(1, 1);
    glVertex3f(10.0f, 3.0f, 0.0f);

    glTexCoord2f(1, 0);
    glVertex3f(10.0f, 0.0f, 0.0f);

    glEnd();

    // second wall
    glBegin(GL_QUADS);

    glTexCoord2f(0, 0);
    glVertex3f(10.0f, 0.0f, 0.0f);

    glTexCoord2f(0, 1);
    glVertex3f(10.0f, 3.0f, 0.0f);

    glTexCoord2f(1, 1);
    glVertex3f(10.0f, 3.0f, 10.0f);

    glTexCoord2f(1, 0);
    glVertex3f(10.0f, 0.0f, 10.0f);

    glEnd();

    // third wall
    glBegin(GL_QUADS);

    glTexCoord2f(0, 0);
    glVertex3f(10.0f, 0.0f, 10.0f);

    glTexCoord2f(0, 1);
    glVertex3f(10.0f, 3.0f, 10.0f);

    glTexCoord2f(1, 1);
    glVertex3f(0.0f, 3.0f, 10.0f);

    glTexCoord2f(1, 0);
    glVertex3f(0.0f, 0.0f, 10.0f);

    glEnd();

    // fourth wall
    glBegin(GL_QUADS);

    glTexCoord2f(0, 0);
    glVertex3f(0.0f, 0.0f, 0.0f);

    glTexCoord2f(0, 1);
    glVertex3f(0.0f, 3.0f, 0.0f);

    glTexCoord2f(1, 1);
    glVertex3f(0.0f, 3.0f, 10.0f);

    glTexCoord2f(1, 0);
    glVertex3f(0.0f, 0.0f, 10.0f);

    glEnd();

    // ceiling
    glBindTexture(GL_TEXTURE_2D, texture[7]);
    glBegin(GL_QUADS);

    glTexCoord2f(0, 0);
    glVertex3f(0.0f, 3.0f, 0.0f);

    glTexCoord2f(0, 1);
    glVertex3f(10.0f, 3.0f, 0.0f);

    glTexCoord2f(1, 1);
    glVertex3f(10.0f, 3.0f, 10.0f);

    glTexCoord2f(1, 0);
    glVertex3f(0.0f, 3.0f, 10.0f);

    glEnd();
}

void display() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    gluLookAt(x, 1.5f, z, x + vX, 1.5f, z + vZ, 0.0f, 1.5f, 0.0f);
    initLight();

    renderWalls();

    glutSwapBuffers();
}

void changeWindowSize(int width, int height) {
    if (height == 0) {
        height = 1;
    }

    float ratio = 1.0 * width / height;

    windowWidth = width;
    windowHeight = height;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glViewport(0, 0, width, height);

    gluPerspective(45.0f, ratio, 0.1f, 100.0f);

    glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char **argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowPosition(0, 0);
    glutInitWindowSize(windowWidth, windowHeight);
    glutCreateWindow("Kitchen");

    init();

    glutDisplayFunc(display);
    glutReshapeFunc(changeWindowSize);
    glutIdleFunc(display);
    glutSpecialFunc(processSpecialKeys);

    glutMainLoop();

    return 0;
}

1 个答案:

答案 0 :(得分:3)

你的光 静止 - 但是相机。

固定功能OpenGL可以完成眼睛空间中的所有光照计算。在您指定灯光的modelView时,它会在通话时根据当前modelView矩阵进行变换,以获得眼睛空间位置。由于initLight()设置为标识,因此无论您以后放置相机的位置,都会将光线设置为给定的眼睛空间位置。

要解决此问题,只需在gluLookAt之后移动Static

然而。你根本不应该这样做。您正在使用已弃用的 OpenGL功能,您现在不应该使用十年。在现代GL中,该功能被完全删除。因此,如果您在2016年学习OpenGL,请帮自己一个忙,忘掉那个旧版本,直接学习着色器。