OpenGL:移动相机时如何使光线静止?
Posted
技术标签:
【中文标题】OpenGL:移动相机时如何使光线静止?【英文标题】:OpenGL: How to make light stationary when moving the camera around? 【发布时间】:2016-12-18 19:09:26 【问题描述】:我正在尝试使用 C 语言编写的 OpenGL 和 GLUT 渲染一个简单(10x3x10 大小)的房间。
我想创建一个简单的静态聚光灯,同时我可以在房间里四处走动。
(最终目标是从天花板上的灯发出聚光灯)
问题是当我移动相机时光线会发生变化。
我正在从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()
调用来解决。
无论我把它们放在哪里,光线要么在我移动相机时不断变化,要么根本没有光线。我就是想不通。
这里有什么合适的解决方案?
提前致谢。
编辑:
正如@derhass 建议的那样,我已将initLight()
调用移至gluLookAt()
调用之后。
当我四处走动时,光线仍在变化。
下面有两张截图。
在第一个上,光线甚至不可见。当我稍微向右转时,它出现了。
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;
【问题讨论】:
如何让相机和灯光在同一个参考系中,这样你就能得到想要的效果? @LuisColorado 感谢您的回复。我怎么能做到这一点? 【参考方案1】:你的灯是静止的 - 但对着相机。
固定功能 OpenGL 在眼睛空间中进行所有光照计算。在您指定灯光的GL_POSITION
的那一刻,它会根据调用时的当前modelView
矩阵 进行变换,以获得眼睛空间位置。由于modelView
设置为身份,它总是将灯光设置到给定的眼睛空间位置 - 无论您以后将相机放置在哪里。
要解决此问题,只需将 initLight()
移动到 gluLookAt
之后。
但是。你根本不应该这样做。您正在使用 已弃用的 OpenGL 功能,十年后 就不应使用这些功能。在现代 GL 中,该功能已完全删除。因此,如果您在 2016 年学习 OpenGL,请帮自己一个忙,忘掉那些老东西,直接学习着色器。
【讨论】:
感谢您的回复。不幸的是,在gluLookAt()
调用之后移动initLight()
不起作用。有关屏幕截图,请参阅我编辑的问题。这是一项任务,我必须使用这些已弃用的功能。如果您有任何其他想法,为什么在移动时灯光仍然会变化,请告诉我。谢谢。
嗯,目前还不清楚我们在那里实际看到的内容。 “房间”是如何建模的?法线是如何设置的?照明不独立于观察位置——镜面反射分量总是依赖于视图。使用 gouraud 着色和面部上足够低的细分,结果甚至可能是正确的。我不知道这种不规则抖动是从哪里来的。这是什么类型的 GL 实现?
我在问题末尾添加了指向源代码的 pastebin 链接。将其剥离到最低限度,以使问题可重现。如果你有时间,请看看。谢谢你。我在我的 Debian 机器上使用默认的 OpenGL 实现。
不要链接到外部代码。将相关部分直接放入问题中。但是,您的法线在该链接中完全损坏。如果不提供适当的法线,您将永远无法获得适当的照明。
哦,那些glNormal
调用不应该出现在renderWalls()
函数中。使用正确的源代码编辑了问题。还是法线的问题?如果是这样,请指出我正确的方向。谢谢。以上是关于OpenGL:移动相机时如何使光线静止?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 C++ 中使用 sdl、opengl 移动相机时修复奇怪的相机旋转