使聚光灯静止
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()
回调重新做你的矩阵。以上是关于使聚光灯静止的主要内容,如果未能解决你的问题,请参考以下文章