我正在尝试使用OpenGL和GLUT渲染一个简单的(10x3x10大小)房间,用C语言编写。
我想制作一个简单的聚光灯,而我可以在房间里四处走动。
(最终目标是让天花板上的灯成为聚光灯)
问题是当我移动相机时光线会发生变化。
我从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()
来电的正确定位来解决。
无论我把它们放在哪里,当我移动相机时光线都会不断变化,或者根本没有光线。我只是想不出来。
这里有什么合适的解决方案?
提前致谢。
修改:
我已将initLight()
来电转移到gluLookAt()
来电之后,@ derhass建议如下。
当我四处走动时,灯光仍在变化。
下面有两个截图。
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;
}
答案 0 :(得分:3)
你的光 静止 - 但是相机。
固定功能OpenGL可以完成眼睛空间中的所有光照计算。在您指定灯光的modelView
时,它会在通话时根据当前modelView
矩阵进行变换,以获得眼睛空间位置。由于initLight()
设置为标识,因此无论您以后放置相机的位置,都会将光线设置为给定的眼睛空间位置。
要解决此问题,只需在gluLookAt
之后移动Static
。
然而。你根本不应该这样做。您正在使用已弃用的 OpenGL功能,您现在不应该使用十年。在现代GL中,该功能被完全删除。因此,如果您在2016年学习OpenGL,请帮自己一个忙,忘掉那个旧版本,直接学习着色器。