应用投影 OpenGL 时输出失真
Distorted output when I apply projection OpenGL
我试图在一个简单的场景中实现相机功能,但输出失真。我认为这与透视投影有关,或者我可能错误地使用了 gluLookAt()
函数,但我似乎无法查明问题所在。每当我按下箭头键以增加相机时,视图就会不断扭曲。相机代码在另一个示例中运行良好。我使用了完全相同的代码,并为我的场景更换了显示器。我为 gluLookAt()
尝试了不同的参数,甚至尝试了正射投影,但似乎没有任何效果。
相机实现之前:
相机实施后:
代码:
#include <Windows.h>
#include <math.h>
#include "glut.h"
float angle = 0.0f;
float lx = 0.0f, lz = -0.1f;
float x = 0.0f, z = 0.5f;
float deltaAngle = 0.0f;
float deltaMove = 0;
double rot = 0;
double doorAngle = 0;
double carMove = -0.75; //Initially car positioned at the start of road
void myInit(void)
{
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(1000, 480);
glutInitWindowPosition(100, 150);
glutCreateWindow(" project part1 ");
glClearColor(0.333, 0.725, 0.905, 0);
glColor3f(0.0f, 0.0f, 0.0f);
}
void reshape(int w, int h) {
if (h == 0)
h = 1;
float ratio = w* 1.0 / h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h);
gluPerspective(45.0f, ratio, 0.1f, 20.0f);
glMatrixMode(GL_MODELVIEW);
}
void computePos(float deltaMove) //compute camera position
{
x += deltaMove * lx * 0.1f;
z += deltaMove * lz * 0.1f;
}
void computeDir(float deltaAngle)//compute camra direction
{
angle += deltaAngle;
lx = sin(angle);
lz = -cos(angle);
}
void display(void)
{
if (deltaMove)
computePos(deltaMove);
if (deltaAngle)
computeDir(deltaAngle);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(x, 0.0f, z, x + lx, 0.0f, z + lz, 0.0f, 1.0f, 0.0f);
//display quads road
glPushMatrix();
glLineWidth(3.0);
glColor3f(0.474, 0.552, 0.603);
glBegin(GL_QUADS);//grey road
glTexCoord2f(0.0, 0.0);
glVertex3f(-1, 0, 0);
glTexCoord2f(0.0, 1.0);
glVertex3f(1, 0, 0);
glTexCoord2f(1.0, 1.0);
glVertex3f(1, -1, 0);
glTexCoord2f(1.0, 0.0);
glVertex3f(-1, -1, 0);
glEnd();
//green grass above
glColor3f(0.305, 0.513, 0.341);
glBegin(GL_QUADS);
glVertex3f(-1, 0, 0);
glVertex3f(1, 0, 0);
glVertex3f(1, -0.1, 0);
glVertex3f(-1, -0.1, 0);
glEnd();
//green grass below
glColor3f(0.372, 0.407, 0.070);
glBegin(GL_QUADS);
glVertex3f(-1, -1, 0);
glVertex3f(1, -1, 0);
glVertex3f(1, -0.8, 0);
glVertex3f(-1, -0.8, 0);
glEnd();
//white lines on road
glColor3f(0.929, 0.850, 0.850);
glPointSize(5.0);
int factor = 10; GLushort pattern = 0x3333;
glEnable(GL_LINE_STIPPLE);
glLineStipple(factor, pattern);
glBegin(GL_LINES);
glVertex3f(1, -0.45, 0);
glVertex3f(-1, -0.45, 0);
glEnd();
glDisable(GL_LINE_STIPPLE);
glColor3f(0.929, 0.850, 0.850);
glPointSize(5.0);
glBegin(GL_LINES);
glVertex3f(1, -0.75, 0);
glVertex3f(-1, -0.75, 0);
glVertex3f(1, -0.15, 0);
glVertex3f(-1, -0.15, 0);
glEnd();
glPushMatrix();
glTranslatef(-0.8, 0.4, 0);
glScalef(0.5, 0.45, 0);
building(0, 0.17, 0.394);
glPopMatrix();
glPushMatrix();
glTranslatef(-0.35, 0.27, 0);
glScalef(0.55, 0.3, 0);
building(0.552, 0.266, 0.505);
glPopMatrix();
glPushMatrix();
//glLoadIdentity();
glTranslatef(0.2, 0.45, 0);
glScalef(1.2, 0.5, 0);
building(0.294, 0.337, 0.584);
glPopMatrix();
glPushMatrix();
glTranslatef(0.75, 0.27, 0);
glScalef(0.55, 0.3, 0);
building(0.309, 0.396, 0.427);
glPopMatrix();
//building bases
//car1
glPushMatrix();
glTranslatef(carMove, -0.2, 0);
glScalef(0.5, 0.5, 0.5);
car(0.65, 0, 0);
glPopMatrix();
glutSwapBuffers();
}
void pressKey(int key, int xx, int yy) {
switch (key) {
case GLUT_KEY_LEFT:
if (deltaAngle > 30)
break;
deltaAngle = -0.01f;
glutPostRedisplay();
break;
case GLUT_KEY_RIGHT: deltaAngle = 0.01f; break;
case GLUT_KEY_UP: deltaMove = 0.05f; break;
case GLUT_KEY_DOWN: deltaMove = -0.05f; break;
}
}
void releaseKey(int key, int x, int y) {
switch (key) {
case GLUT_KEY_LEFT:
case GLUT_KEY_RIGHT: deltaAngle = 0.0f; break;
case GLUT_KEY_UP:
case GLUT_KEY_DOWN: deltaMove = 0; break;
}
}
void main(int argc, char **argv)
{
glutInit(&argc, argv);
myInit();
glutDisplayFunc(display);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(display);
glutSpecialFunc(pressKey);
glutSpecialUpFunc(releaseKey);
glEnable(GL_DEPTH_TEST);
glutMainLoop();
}
注:
纹理映射汽车和建筑代码因太大而被排除在外,但它们工作正常,我不认为它们是问题所在。如果您需要完整的工作代码,请告诉我,我会上传它。我一直被困在这个问题上。感谢任何帮助
问题是 Z-fighting 问题。
要解决您的问题,您必须禁用 Depth Test 并将对象从背面绘制到正面:
glEnable(GL_DEPTH_TEST)
或者您必须使用不同的 z 坐标绘制对象,这定义了对象的 z 顺序。
请注意,在视图 space 中,z 轴指向视口之外。所以如果一个物体的z坐标大于另一个物体的z坐标,那么这个物体就在另一个物体的前面。
只有物体的深度不同才能实现透视效果,使得后面的物体看起来比靠近观察点(眼睛位置)的物体小。
但是你必须确保对象没有被剪裁。
这意味着对象到眼睛位置的 (view space) z 距离(gluLookAt
) has to be in between the near and far plane (last 2 parameters of gluPerspective
的前 3 个参数)。
我试图在一个简单的场景中实现相机功能,但输出失真。我认为这与透视投影有关,或者我可能错误地使用了 gluLookAt()
函数,但我似乎无法查明问题所在。每当我按下箭头键以增加相机时,视图就会不断扭曲。相机代码在另一个示例中运行良好。我使用了完全相同的代码,并为我的场景更换了显示器。我为 gluLookAt()
尝试了不同的参数,甚至尝试了正射投影,但似乎没有任何效果。
相机实现之前:
相机实施后:
代码:
#include <Windows.h>
#include <math.h>
#include "glut.h"
float angle = 0.0f;
float lx = 0.0f, lz = -0.1f;
float x = 0.0f, z = 0.5f;
float deltaAngle = 0.0f;
float deltaMove = 0;
double rot = 0;
double doorAngle = 0;
double carMove = -0.75; //Initially car positioned at the start of road
void myInit(void)
{
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(1000, 480);
glutInitWindowPosition(100, 150);
glutCreateWindow(" project part1 ");
glClearColor(0.333, 0.725, 0.905, 0);
glColor3f(0.0f, 0.0f, 0.0f);
}
void reshape(int w, int h) {
if (h == 0)
h = 1;
float ratio = w* 1.0 / h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h);
gluPerspective(45.0f, ratio, 0.1f, 20.0f);
glMatrixMode(GL_MODELVIEW);
}
void computePos(float deltaMove) //compute camera position
{
x += deltaMove * lx * 0.1f;
z += deltaMove * lz * 0.1f;
}
void computeDir(float deltaAngle)//compute camra direction
{
angle += deltaAngle;
lx = sin(angle);
lz = -cos(angle);
}
void display(void)
{
if (deltaMove)
computePos(deltaMove);
if (deltaAngle)
computeDir(deltaAngle);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(x, 0.0f, z, x + lx, 0.0f, z + lz, 0.0f, 1.0f, 0.0f);
//display quads road
glPushMatrix();
glLineWidth(3.0);
glColor3f(0.474, 0.552, 0.603);
glBegin(GL_QUADS);//grey road
glTexCoord2f(0.0, 0.0);
glVertex3f(-1, 0, 0);
glTexCoord2f(0.0, 1.0);
glVertex3f(1, 0, 0);
glTexCoord2f(1.0, 1.0);
glVertex3f(1, -1, 0);
glTexCoord2f(1.0, 0.0);
glVertex3f(-1, -1, 0);
glEnd();
//green grass above
glColor3f(0.305, 0.513, 0.341);
glBegin(GL_QUADS);
glVertex3f(-1, 0, 0);
glVertex3f(1, 0, 0);
glVertex3f(1, -0.1, 0);
glVertex3f(-1, -0.1, 0);
glEnd();
//green grass below
glColor3f(0.372, 0.407, 0.070);
glBegin(GL_QUADS);
glVertex3f(-1, -1, 0);
glVertex3f(1, -1, 0);
glVertex3f(1, -0.8, 0);
glVertex3f(-1, -0.8, 0);
glEnd();
//white lines on road
glColor3f(0.929, 0.850, 0.850);
glPointSize(5.0);
int factor = 10; GLushort pattern = 0x3333;
glEnable(GL_LINE_STIPPLE);
glLineStipple(factor, pattern);
glBegin(GL_LINES);
glVertex3f(1, -0.45, 0);
glVertex3f(-1, -0.45, 0);
glEnd();
glDisable(GL_LINE_STIPPLE);
glColor3f(0.929, 0.850, 0.850);
glPointSize(5.0);
glBegin(GL_LINES);
glVertex3f(1, -0.75, 0);
glVertex3f(-1, -0.75, 0);
glVertex3f(1, -0.15, 0);
glVertex3f(-1, -0.15, 0);
glEnd();
glPushMatrix();
glTranslatef(-0.8, 0.4, 0);
glScalef(0.5, 0.45, 0);
building(0, 0.17, 0.394);
glPopMatrix();
glPushMatrix();
glTranslatef(-0.35, 0.27, 0);
glScalef(0.55, 0.3, 0);
building(0.552, 0.266, 0.505);
glPopMatrix();
glPushMatrix();
//glLoadIdentity();
glTranslatef(0.2, 0.45, 0);
glScalef(1.2, 0.5, 0);
building(0.294, 0.337, 0.584);
glPopMatrix();
glPushMatrix();
glTranslatef(0.75, 0.27, 0);
glScalef(0.55, 0.3, 0);
building(0.309, 0.396, 0.427);
glPopMatrix();
//building bases
//car1
glPushMatrix();
glTranslatef(carMove, -0.2, 0);
glScalef(0.5, 0.5, 0.5);
car(0.65, 0, 0);
glPopMatrix();
glutSwapBuffers();
}
void pressKey(int key, int xx, int yy) {
switch (key) {
case GLUT_KEY_LEFT:
if (deltaAngle > 30)
break;
deltaAngle = -0.01f;
glutPostRedisplay();
break;
case GLUT_KEY_RIGHT: deltaAngle = 0.01f; break;
case GLUT_KEY_UP: deltaMove = 0.05f; break;
case GLUT_KEY_DOWN: deltaMove = -0.05f; break;
}
}
void releaseKey(int key, int x, int y) {
switch (key) {
case GLUT_KEY_LEFT:
case GLUT_KEY_RIGHT: deltaAngle = 0.0f; break;
case GLUT_KEY_UP:
case GLUT_KEY_DOWN: deltaMove = 0; break;
}
}
void main(int argc, char **argv)
{
glutInit(&argc, argv);
myInit();
glutDisplayFunc(display);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(display);
glutSpecialFunc(pressKey);
glutSpecialUpFunc(releaseKey);
glEnable(GL_DEPTH_TEST);
glutMainLoop();
}
注:
纹理映射汽车和建筑代码因太大而被排除在外,但它们工作正常,我不认为它们是问题所在。如果您需要完整的工作代码,请告诉我,我会上传它。我一直被困在这个问题上。感谢任何帮助
问题是 Z-fighting 问题。
要解决您的问题,您必须禁用 Depth Test 并将对象从背面绘制到正面:
glEnable(GL_DEPTH_TEST)
或者您必须使用不同的 z 坐标绘制对象,这定义了对象的 z 顺序。
请注意,在视图 space 中,z 轴指向视口之外。所以如果一个物体的z坐标大于另一个物体的z坐标,那么这个物体就在另一个物体的前面。
只有物体的深度不同才能实现透视效果,使得后面的物体看起来比靠近观察点(眼睛位置)的物体小。
但是你必须确保对象没有被剪裁。
这意味着对象到眼睛位置的 (view space) z 距离(gluLookAt
) has to be in between the near and far plane (last 2 parameters of gluPerspective
的前 3 个参数)。