我试图在我的简单OpenGL场景中实现纯固定的聚光灯,而该场景不会随相机移动。它应该一直突出显示场景的中心位置(0,0,0的坐标),我将茶壶放在其中。
这是一个简化的代码:

#include <windows.h>
#define GLUT_DISABLE_ATEXIT_HACK
#include <gl/glut.h>
#include <gl/glu.h>
#include <gl/gl.h>
#include <math.h>
#include <iostream>

const int windowWidth = 640;
const int windowHeight = 480;

float alpha=0.0, alphaDelta=0.0, ratio, beta=0.0, betaDelta=0.0;
float x=0.0, y=1.75, z=5.0;
float lx=0.0, ly=0.0, lz=-1.0;
int moveDelta = 0;
float lastMouseX=windowWidth*0.5, lastMouseY=windowHeight*0.5;

void reshape(int w, int h){
   //...
}

// handles angle changes
void orientMe(float horizontalAngle, float verticalAngle) {
    lx = sin(horizontalAngle);
    if(beta > -1.5 && beta < 1.5)
        ly = sin(verticalAngle);
    lz = -cos(horizontalAngle);
    glLoadIdentity();
    gluLookAt(x, y, z,
              x + lx, y + ly, z + lz,
              0.0, 1.0, 0.0);
}

// handles x,y,z coords changes
void flatMovement(int i) {
    x = x + i*(lx)*0.1;
    z = z + i*(lz)*0.1;
    glLoadIdentity();
    gluLookAt(x, y, z,
              x + lx, y + ly, z + lz,
              0.0, 1.0, 0.0);
}

void display() {
    // orient observer
    if(moveDelta)
        flatMovement(moveDelta);

    if(alphaDelta || betaDelta) {
        alpha += alphaDelta;
        alphaDelta = 0;

        beta += betaDelta;
        betaDelta = 0;

        orientMe(alpha, beta);
    }

    glClearColor(1.0, 1.0, 1.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glColor3f(0,1,0);
    glBegin(GL_QUADS);
        glNormal3d(0,1,0);
        glVertex3f(-100.0, 0.0, -100.0);
        glVertex3f(-100.0, 0.0, 100.0);
        glVertex3f(100.0, 0.0, 100.0);
        glVertex3f(100.0, 0.0, -100.0);
    glEnd();

    glColor3f(1,0,0);
    glutSolidTeapot(1);

    glutSwapBuffers();
}

void pressSpecialKey(int key, int x, int y) {
    //...
}

void releaseSpecialKey(int key, int x, int y) {
    //...
}

static void idle(void)
{
    glutPostRedisplay();
}

void mouseMove(int x, int y) {
    //...
}

void setupLights() {
    GLfloat spotDirection[] = {0.0f, -1.0f, 0.0f, 1.0f};
    GLfloat spotPosition[] = {0.0f, 4.0f, 0.0f, 1.0f};

    glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 40);
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spotDirection);
    glLightfv(GL_LIGHT0, GL_POSITION, spotPosition);

    glEnable(GL_LIGHT0);
}

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitWindowSize(windowWidth,windowHeight);
    glutInitWindowPosition(10,10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("Spotlight");

    glutSpecialFunc(pressSpecialKey);
    glutSpecialUpFunc(releaseSpecialKey);
    glutPassiveMotionFunc(mouseMove);
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutIdleFunc(idle);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-5.0, 5.0, -5.0, 5.0, -5.0, 5.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glEnable(GL_LIGHTING);
    glEnable(GL_NORMALIZE);
    glEnable(GL_DEPTH_TEST);

    setupLights();

    glutMainLoop();

    return EXIT_SUCCESS;
}

不幸的是,聚光灯似乎随着相机的变化而变化,我不知道上面的代码有什么问题。

编辑

感谢@genpfault发布的内容,我已经整理了所有内容。

答案是仅将glEnable(GL_LIGHT0)留在main()函数中,并将负责照明的其余代码移到display()函数的最后(恰好在调用glutSwapBuffers()之前)。

因此,最终的简化代码如下所示:
#include <windows.h>
#define GLUT_DISABLE_ATEXIT_HACK
#include <gl/glut.h>
#include <gl/glu.h>
#include <gl/gl.h>
#include <math.h>
#include <iostream>

const int windowWidth = 640;
const int windowHeight = 480;

float alpha=0.0, alphaDelta=0.0, ratio, beta=0.0, betaDelta=0.0;
float x=0.0, y=1.75, z=5.0;
float lx=0.0, ly=0.0, lz=-1.0;
int moveDelta = 0;
float lastMouseX=windowWidth*0.5, lastMouseY=windowHeight*0.5;

void reshape(int w, int h){
    //...
}

// handles angle changes
void orientMe(float horizontalAngle, float verticalAngle) {
    //...
}

// handles x,y,z coords changes
void flatMovement(int i) {
    //...
}

void setupLights() {
    //THE CONTENTS SLIGHTLY CHANGED HERE
    GLfloat spotPosition[] = {2.0f, 4.0f, 0.0f, 1.0f};
    GLfloat spotDirection[] = {0.0f, -1.0f, 0.0f, 1.0f};

    glLightfv(GL_LIGHT0, GL_POSITION, spotPos
    glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 40);ition);
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spotDirection);
}

void display() {
    // orient observer
    if(moveDelta)
        flatMovement(moveDelta);

    if(alphaDelta || betaDelta) {
        alpha += alphaDelta;
        alphaDelta = 0;

        beta += betaDelta;
        betaDelta = 0;

        orientMe(alpha, beta);
    }

    glClearColor(1.0, 1.0, 1.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glColor3f(0,1,0);
    glBegin(GL_QUADS);
        glNormal3d(0,1,0);
        glVertex3f(-100.0, 0.0, -100.0);
        glVertex3f(-100.0, 0.0, 100.0);
        glVertex3f(100.0, 0.0, 100.0);
        glVertex3f(100.0, 0.0, -100.0);
    glEnd();

    glColor3f(1,0,0);
    glutSolidTeapot(1);

    setupLights(); // PUT THE LIGHTING SETUP AT THE END OF DISPLAY()

    glutSwapBuffers();
}

void pressSpecialKey(int key, int x, int y) {
    //...
}

void releaseSpecialKey(int key, int x, int y) {
    //...
}

static void idle(void)
{
    glutPostRedisplay();
}

void mouseMove(int x, int y) {
   //...
}

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitWindowSize(windowWidth,windowHeight);
    glutInitWindowPosition(10,10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("Spotlight");

    glutSpecialFunc(pressSpecialKey);
    glutSpecialUpFunc(releaseSpecialKey);
    glutPassiveMotionFunc(mouseMove);
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutIdleFunc(idle);

    glEnable(GL_LIGHTING);
    glEnable(GL_NORMALIZE);
    glEnable(GL_DEPTH_TEST);

    glEnable(GL_LIGHT0); // IN THE MAIN, LEAVE ONLY THE ENABLING CALL

    glutMainLoop();

    return EXIT_SUCCESS;
}

最佳答案

设置相机变换后,设置灯光位置:

void display()
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-5.0, 5.0, -5.0, 5.0, -5.0, 5.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // orient observer
    if(moveDelta)
        flatMovement(moveDelta);

    if(alphaDelta || betaDelta)
    {
        alpha += alphaDelta;
        alphaDelta = 0;

        beta += betaDelta;
        betaDelta = 0;

        orientMe(alpha, beta);
    }

    setupLights();

    glClearColor(1.0, 1.0, 1.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glColor3f(0,1,0);
    glBegin(GL_QUADS);
        glNormal3d(0,1,0);
        glVertex3f(-100.0, 0.0, -100.0);
        glVertex3f(-100.0, 0.0, 100.0);
        glVertex3f(100.0, 0.0, 100.0);
        glVertex3f(100.0, 0.0, -100.0);
    glEnd();

    glColor3f(1,0,0);
    glutSolidTeapot(1);

    glutSwapBuffers();
}

参见here。您现有的代码遵循“将光源与视点一起移动”的调用顺序。

10-07 12:21