OpenGL正射投影被破坏

Posted

技术标签:

【中文标题】OpenGL正射投影被破坏【英文标题】:OpenGL ortho projection is broken 【发布时间】:2019-01-20 17:36:08 【问题描述】:

所以我只是在我的渲染中添加了正射投影,一切都停止了渲染......如果我删除它,它会再次工作。这是我的矩阵代码:

#include <stdlib.h>
#include <stdlib.h>
#include <math.h>


matrix4x4 init_matrix4x4() 
    matrix4x4 m = calloc(16, sizeof(float));

    m[0] = 1;    m[1] = 0;    m[2] = 0;    m[3] = 0;
    m[4] = 0;    m[5] = 1;    m[6] = 0;    m[7] = 0;
    m[8] = 0;    m[9] = 0;    m[10] = 1;   m[11] = 0;
    m[12] = 0;   m[13] = 0;   m[14] = 0;   m[15] = 1;

    return m;


void translate_matrix4x4(matrix4x4* matrix, float x, float y, float z) 
    matrix4x4 m = (*matrix);

    m[12] = m[0] * x + m[4] * y + m[8] * z + m[12];
    m[13] = m[1] * x + m[5] * y + m[9] * z + m[13];
    m[14] = m[2] * x + m[6] * y + m[10] * z + m[14];
    m[15] = m[3] * x + m[7] * y + m[11] * z + m[15]; 


void ortho_matrix4x4(matrix4x4* matrix, float left, float right, float bottom, float top, float near, float far) 
    matrix4x4 m = (*matrix);

    m[0] = 2 / (right-left);
    m[1] = 0;
    m[2] = 0;
    m[3] = 0;
    m[4] = 0;
    m[5] = 2 / (top - bottom);
    m[6] = 0;
    m[7] = 0;
    m[8] = 0;
    m[9] = 0;
    m[10] = 1 / (far - near);
    m[11] = 0;
    m[12] = (left + right) / (left - right);
    m[13] = (top + bottom) / (bottom - top);
    m[14] = near / (near - far);
    m[15] = 1;


void mat4_identity(matrix4x4* matrix) 
    matrix4x4 out = (*matrix);
    out[0] = 1;
    out[1] = 0;
    out[2] = 0;
    out[3] = 0;
    out[4] = 0;
    out[5] = 1;
    out[6] = 0;
    out[7] = 0;
    out[8] = 0;
    out[9] = 0;
    out[10] = 1;
    out[11] = 0;
    out[12] = 0;
    out[13] = 0;
    out[14] = 0;
    out[15] = 1;


void mat4_lookAtf(matrix4x4* matrix, float eye[3], float center[3], float up[3]) 
    matrix4x4 out = (*matrix);
    float x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
        eyex = eye[0],
        eyey = eye[1],
        eyez = eye[2],
        upx = up[0],
        upy = up[1],
        upz = up[2],
        centerx = center[0],
        centery = center[1],
        centerz = center[2];

    if (fabs(eyex - centerx) < 0.000001 &&
        fabs(eyey - centery) < 0.000001 &&
        fabs(eyez - centerz) < 0.000001) 
        mat4_identity(&out);
        return;
    

    z0 = eyex - centerx;
    z1 = eyey - centery;
    z2 = eyez - centerz;

    len = 1 / sqrt/*f*/(z0 * z0 + z1 * z1 + z2 * z2);
    z0 *= len;
    z1 *= len;
    z2 *= len;

    x0 = upy * z2 - upz * z1;
    x1 = upz * z0 - upx * z2;
    x2 = upx * z1 - upy * z0;
    len = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
    if (!len) 
        x0 = 0;
        x1 = 0;
        x2 = 0;
     else 
        len = 1 / len;
        x0 *= len;
        x1 *= len;
        x2 *= len;
    

    y0 = z1 * x2 - z2 * x1;
    y1 = z2 * x0 - z0 * x2;
    y2 = z0 * x1 - z1 * x0;

    len = sqrt(y0 * y0 + y1 * y1 + y2 * y2);
    if (!len) 
        y0 = 0;
        y1 = 0;
        y2 = 0;
     else 
        len = 1 / len;
        y0 *= len;
        y1 *= len;
        y2 *= len;
    

    out[0] = x0;
    out[1] = y0;
    out[2] = z0;
    out[3] = 0;
    out[4] = x1;
    out[5] = y1;
    out[6] = z1;
    out[7] = 0;
    out[8] = x2;
    out[9] = y2;
    out[10] = z2;
    out[11] = 0;
    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
    out[15] = 1;
;

这里是 main.c ,我渲染的地方:

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <stdlib.h>
#include "include/matrix.h"
#include "include/io.h"


const int WIDTH = 640;
const int HEIGHT = 480;

// called when user resizes window
void framebuffer_size_callback(GLFWwindow* window, int width, int height) 
    glViewport(0, 0, width, height);


// called when we receive input
void processInput(GLFWwindow *window) 
    if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, 1);


GLuint get_checker_texture() 
    unsigned char texDat[64];
    for (int i = 0; i < 64; ++i)
        texDat[i] = ((i + (i / 8)) % 2) * 128 + 127;

    //upload to GPU texture
    GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 8, 8, 0, GL_RED, GL_UNSIGNED_BYTE, texDat);
    glGenerateMipmap(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 0);

    return tex;


//void render_box(renderable* this, unsigned int vbo, unsigned int vao, unsigned int ebo) 
//    draw_texture(this->texture, this->x, this->y, this->z, vbo, vao, ebo);
//

int main(int argc, char* argv[]) 
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    #ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // only on MACOS
    #endif

    // creating the window
    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "OpenGL App", NULL, NULL);
    if (window == NULL) 
        printf("Failed to create GLFW window");
        glfwTerminate();
        return -1;
    

    glfwMakeContextCurrent(window);

    // hook on window resize
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) 
        printf("Failed to initialize GLAD");
        return -1;
    

    printf("OpenGL %d.%d\n", GLVersion.major, GLVersion.minor);

    glEnable(GL_DEPTH_TEST);

    glViewport(0, 0, WIDTH, HEIGHT);

    unsigned int tex = get_checker_texture();

    const char* vertex_shader_src = read_file("res/shaders/textured_and_positioned.vs.glsl");

    unsigned int vertex_shader;
    vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_shader, 1, &vertex_shader_src, NULL);
    glCompileShader(vertex_shader); 

    int  success;
    char infoLog[512];
    glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);

    if (!success) 
        glGetShaderInfoLog(vertex_shader, 512, NULL, infoLog);
        printf("%s\n", infoLog);
    

    const char* fragment_shader_src = read_file("res/shaders/textured_and_positioned.fs.glsl");

    unsigned int fragment_shader;
    fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_shader, 1, &fragment_shader_src, NULL);
    glCompileShader(fragment_shader);

    int  success0;
    char infoLog0[512];
    glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success0);

    if (!success0) 
        glGetShaderInfoLog(fragment_shader, 512, NULL, infoLog0);
        printf("%s\n", infoLog0);
    

    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();

    glAttachShader(shaderProgram, vertex_shader);
    glAttachShader(shaderProgram, fragment_shader);
    glLinkProgram(shaderProgram);

    unsigned uniform_sampler_ourTexture = glGetUniformLocation(shaderProgram, "ourTexture");
    unsigned uniform_mat4_model = glGetUniformLocation(shaderProgram, "model");
    unsigned uniform_mat4_view = glGetUniformLocation(shaderProgram, "view");
    unsigned uniform_mat4_perspective = glGetUniformLocation(shaderProgram, "perspective");

    int success1;
    char infoLog1[512];

    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success1);
    if(!success1) 
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog1);
        printf("%s\n", infoLog1);
    

    float vertices[] = 
         // positions          // colors           // texture coords
         0.1f,  0.1f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f,   // top right
         0.1f, -0.1f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f,   // bottom right
        -0.1f, -0.1f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f,   // bottom left
        -0.1f,  0.1f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0     // top left 
    ; 

    unsigned elements[] = 
        0, 1, 2, // triangle
        2, 3, 0 // triangle
    ;

    unsigned int vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    matrix4x4 model = init_matrix4x4();
    matrix4x4 view = init_matrix4x4();
    translate_matrix4x4(&view, 0.0f, 0.0f, 0.0f);


    float x = 0.0f;
    float y = 0.0f;
    float z = 0.0f;

    matrix4x4 perspective = calloc(16, sizeof(float));
    ortho_matrix4x4(&perspective, 0.0f, 640.0f, 0.0f, 480.0f, 0.1f, 100.0f);

    unsigned int vbo;
    glGenBuffers(1, &vbo);

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // positions
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(0 * sizeof(float)));
    glEnableVertexAttribArray(0);

    // colors
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    // texture coords
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);

    unsigned int ebo;
    glGenBuffers(1, &ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);

    glUseProgram(shaderProgram);

    glUniformMatrix4fv(uniform_mat4_view, 1, GL_FALSE, view);
    glUniformMatrix4fv(uniform_mat4_perspective, 1, GL_FALSE, perspective);


    // render loop
    while(!glfwWindowShouldClose(window)) 
        processInput(window);

        // render here
        glClearColor(
            0, 0, 0, 0
        );

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, tex);
        glUniform1i(uniform_sampler_ourTexture, 0);



        translate_matrix4x4(&model, x, y, z);
        glUniformMatrix4fv(uniform_mat4_model, 1, GL_FALSE, model);
        //x += 0.0001f;
        //y += 0.0001f;



        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        glfwSwapBuffers(window);
        glfwPollEvents();    
    

    glfwTerminate();
    return 0;

这是顶点着色器:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;

uniform mat4 model;
uniform mat4 view;
uniform mat4 perspective;

out vec3 ourColor;
out vec2 TexCoord;

void main()

    gl_Position = perspective * view * model * vec4(aPos, 1.0);
    ourColor = aColor;
    TexCoord = aTexCoord;

这是片段着色器:

#version 330 core
out vec4 FragColor;

in vec3 ourColor;
in vec2 TexCoord;

uniform sampler2D ourTexture;

void main()

    FragColor = vec4(vec3(texture(ourTexture, TexCoord).r), 1.);

现在,如果我从着色器(即正交矩阵)中删除 perspective 值,则方格纹理将按应有的方式渲染。 这里有什么问题? 是我的着色器还是矩阵正交函数?

【问题讨论】:

m[10] 看起来很可疑 - glOrtho 矩阵不应该是 -2 / (F - N) 吗?弄错 Z 的符号会让一切都“看不见”。 【参考方案1】:

您的矩阵存储在行优先中,将它们提交给制服而不进行转置,并在着色器中进行左关联计算。

你可以

按列主要顺序存储

加载到制服时转置

在着色器中切换到左关联乘法

每个效果都一样。

【讨论】:

以上是关于OpenGL正射投影被破坏的主要内容,如果未能解决你的问题,请参考以下文章

初识OpenGL (-)坐标空间

初识OpenGL (-)坐标空间

opengl两种投影类型

OpenGL投影裁剪

Model, View(Camera), Perspective

OpenGL中投影变换函数的实现