opengl - 当我应用投影 OpenGL 时输出失真

标签 opengl graphics glut depth-buffer

我试图在一个简单的场景上实现相机功能,但输出失真。我认为这与透视投影有关,或者可能我错误地使用了 gluLookAt() 函数,但我似乎无法查明问题。每当我按箭头键放大相机时, View 就会不断扭曲。相机代码在另一个示例中运行良好。我使用了完全相同的代码,并为我的场景替换了显示屏。我尝试了 gluLookAt() 的不同参数,甚至尝试了正交投影,但似乎没有任何效果。

相机实现之前:

World View

相机实现后:

After trying camera

代码:

#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 顺序。

请注意,在 View 空间中,z 轴指向视口(viewport)之外。因此,如果一个对象的 z 坐标大于另一个对象的 z 坐标,则该对象位于另一个对象的前面。

只有当物体的深度不同时才能实现透视效果,使得后面的物体看起来比靠近视点(眼睛位置)的物体小。

但你必须确保对象没有被剪裁。
这意味着物体到眼睛位置的( View 空间)z 距离( gluLookAt 的前 3 个参数)必须位于近平面和远平面之间( gluPerspective 的最后 2 个参数)。

关于opengl - 当我应用投影 OpenGL 时输出失真,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53806263/

相关文章:

java - JPanel/Graphics 方法paintComponent 是什么?

java - Java中使用BufferedImage的双缓冲不显示图像

c++ - 在 OpenGL 中的一个窗口上显示两个不同的图像

c++ - 在 openGL 4 中呈现文本 - 不起作用

OpenGL翻转或镜像绘图对象

c++ - 在 opengl c++ 中计算顶点法线(gouraud 着色)

Java 图形无法更改字体

c - opengl+glut glutPostRedisplay在哪里?

OpenGL 和远程桌面

xcode - MacOS Mojave Xcode 10 + OpenGL 在初始化窗口后未绘制