应用投影 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 个参数)。