You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenGL投影矩阵异常:透视/正交投影下模型显示怪异求助

投影与视图矩阵异常导致3D模型显示问题

我正在使用讲师提供的LookAt()函数构建视图矩阵,Ortho()和Perspective()函数构建投影矩阵,并将这些矩阵传入着色器,通过GLUT提供的glutWireTeapot()、glutWireCube()、glutWireSphere()等线框模型进行测试。尽管我认为参数设置合理,但程序显示的模型效果怪异:透视投影始终无法正常显示,正交投影仅偶尔显示正常。我尝试过修改LookAt()、Perspective()、Ortho()的参数,以及调整着色器中矩阵乘法的顺序(如改为gl_Vertex * Mv * Proj等组合),但问题仍未解决。以下是我的代码实现及异常显示效果:

键盘回调函数

用于切换投影模式和3D模型。

void keyboard(unsigned char key, int x, int y)
{
    // ToDo
    if(key == 'p') {
        isPerspective = true;
    }
    else if (key == 'o') {
        isPerspective = false;
    }
    else if(key == 'm') {
        currentobject = (currentobject + 1) % numObjects;
    }

    glutPostRedisplay();
}

渲染回调函数

当前正交和透视投影均显示怪异效果。

void renderScene(void) 
{
    // ToDo
    glUseProgram(p);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    viewMatrix = LookAt(vec4(0, 0, 5, 1), vec4(0.0, 0.0, 0.0, 1), vec4(0.0, 1.0, 0.0, 0.0));

    if (!isPerspective) {
        projMatrix = Ortho(-1.0, 1.0, -1.0, 1.0, -1, 10);
    }
    else {
        projMatrix = Perspective(45, 1.0, -2, 10);
    }

    glUniformMatrix4fv(glGetUniformLocation(p, "Proj"), 1, GL_FALSE, projMatrix);
    glUniformMatrix4fv(glGetUniformLocation(p, "Mv"), 1, GL_FALSE, viewMatrix);

    // x轴(红色)
    glColor3f(1.0, 0.0, 0.0);
    glBegin(GL_LINES);
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, 0.0);
    glEnd();

    // y轴(绿色)
    glColor3f(0.0, 1.0, 0.0);
    glBegin(GL_LINES);
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(0.0, 1.0, 0.0);
    glEnd();

    // z轴(蓝色)
    glColor3f(0.0, 0.0, 1.0);
    glBegin(GL_LINES);
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(0.0, 0.0, 1.0);
    glEnd();

    glColor3f(1, 0, 0);

    switch (currentobject) {
    case 0:
        glutWireTeapot(0.5);
        break;
    case 1:
        glutWireCube(0.5);
        break;
    case 2:
        glutWireSphere(0.5, 20, 20);
        break;
    }

    glutSwapBuffers();
    glUseProgram(0);
}

透视投影效果

透视投影效果

正交投影效果

正交投影效果

初始化函数

void init()
{
    // 创建着色器程序
    p = createGLSLProgram("../vshader.vert", NULL, "../fshader.frag");

    glEnable(GL_DEPTH_TEST);
    glClearColor(1.0, 1.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

创建GLSL程序函数

GLuint createGLSLProgram(char *vs, char *gs, char *fs) 
{
    GLuint v, g, f, p;
    
    if( !vs && !gs && !fs ) return 0;
        
    p = glCreateProgram();
    
    if( vs ) 
    {
        v = loadShader( GL_VERTEX_SHADER, vs );
        glAttachShader(p,v);
    }
    if( gs )
    {
        g = loadShader( GL_GEOMETRY_SHADER_EXT, gs );
        glAttachShader(p,g);
    }
    if( fs )
    {
        f = loadShader( GL_FRAGMENT_SHADER, fs );
        glAttachShader(p,f);
    }

    glLinkProgram(p);

    // 验证程序
    GLint status;
    glGetProgramiv(p, GL_LINK_STATUS, &status);
    if(status == GL_FALSE)
    {
        GLint sizeLog;
        glGetProgramiv(p, GL_INFO_LOG_LENGTH, &sizeLog);
        char *log = new char[sizeLog + 1];
        glGetProgramInfoLog(p, sizeLog, NULL, log);
        std::cout << "程序链接错误: " << log << std::endl;
        delete [] log;
        assert( false );
    }
    
    glValidateProgram(p);
    glGetProgramiv(p, GL_VALIDATE_STATUS, &status);

    if (status == GL_FALSE)
    {
        std::cerr << "验证程序错误: "<< p << std::endl;
        assert( false );
    }

    // 验证通过,使用该程序
    glUseProgram(p);

    return p;
}

主函数

int main(int argc, char **argv) {

    // 初始化GLUT并创建窗口
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(600,600);
    glutCreateWindow("COSE436 - 作业1");

    // 注册回调函数
    glutDisplayFunc(renderScene);
    // glutIdleFunc(renderScene);
    glutReshapeFunc(changeSize);
    glutKeyboardFunc(keyboard);
    glutIdleFunc(idle);


    glewInit();
    if (glewIsSupported("GL_VERSION_3_3"))
        printf("已支持OpenGL 3.3\n");
    else {
        printf("不支持OpenGL 3.3\n");
        exit(1);
    }

    init();

    // 进入GLUT事件处理循环
    glutMainLoop();

    return 1;
}

空闲函数

void idle()
{
    glutPostRedisplay();
}

顶点着色器

#version 140
#extension GL_ARB_compatibility: enable

out vec4 color;

uniform mat4 Mv;  // 模型视图矩阵
uniform mat4 Proj; // 投影矩阵

void main() 
{
    // 组合模型视图和投影矩阵
    gl_Position =  Proj * Mv * gl_Vertex; // 顶点 -> Mv -> Proj
    color = gl_Color;
}

片段着色器

#version 140
#extension GL_ARB_compatibility: enable

in  vec4 color;
out vec4 fColor;

void main() 
{ 
    fColor = color; 
} 

讲师提供的矩阵函数

inline
mat4 LookAt( const vec4& eye, const vec4& at, const vec4& up )
{
    vec4 n = normalize(eye - at);
    vec4 u = vec4(normalize(cross(up,n)), 0.0);
    vec4 v = vec4(normalize(cross(n,u)), 0.0);
    vec4 t = vec4(0.0, 0.0, 0.0, 1.0);
    mat4 c = mat4(u, v, n, t);
    return c * Translate( -eye );
}

inline
mat4 Ortho( const GLfloat left, const GLfloat right,
        const GLfloat bottom, const GLfloat top,
        const GLfloat zNear, const GLfloat zFar )
{
    mat4 c;
    c[0][0] = 2.0/(right - left);
    c[1][1] = 2.0/(top - bottom);
    c[2][2] = 2.0/(zNear - zFar);
    c[3][3] = 1.0;
    c[0][3] = -(right + left)/(right - left);
    c[1][3] = -(top + bottom)/(top - bottom);
    c[2][3] = -(zFar + zNear)/(zFar - zNear);
    return c;
}

inline
mat4 Perspective( const GLfloat fovy, const GLfloat aspect,
          const GLfloat zNear, const GLfloat zFar)
{
    GLfloat top   = tan(fovy*DegreesToRadians/2) * zNear;
    GLfloat right = top * aspect;

    mat4 c;
    c[0][0] = zNear/right;
    c[1][1] = zNear/top;
    c[2][2] = -(zFar + zNear)/(zFar - zNear);
    c[2][3] = -2.0*zFar*zNear/(zFar - zNear);
    c[3][2] = -1.0;
    c[3][3] = 0.0;
    return c;
}

内容的提问来源于stack exchange,提问作者morjun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 02:12:02