使聚光灯静止

Posted

技术标签:

【中文标题】使聚光灯静止【英文标题】:Making spotlight stationary 【发布时间】:2013-12-12 15:34:02 【问题描述】:

我正在尝试在我的简单 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 发布的内容,我已经整理好了。

答案是在main() 函数中只留下glEnable(GL_LIGHT0),并将负责照明的其余代码移到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】:

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

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

【讨论】:

它没有解决我的问题(盲目复制粘贴代码会导致相机出现奇怪的行为)。但是,重新阅读您附加的资源(我已经看过)真的很有用,让我整理一下。 对不起,我应该说你应该核对你的 reshape() 处理程序并每次通过你的 display() 回调重新做你的矩阵。

以上是关于使聚光灯静止的主要内容,如果未能解决你的问题,请参考以下文章

SceneKit - 为啥添加聚光灯会使地板变黑?

使 UIButton 在屏幕上保持静止

如何使OpenGL光定向?

unity2d 如何使角色静止

下拉悬停不会保持静止

英文“rest是啥意思意思”