制作聚光灯文具

时间:2013-12-12 15:34:02

标签: c++ opengl lighting freeglut

我试图在我的简单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;
}

1 个答案:

答案 0 :(得分:1)

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

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。您现有的代码遵循“将光源与您的Viewpoint一起移动”调用序列。