顶点着色器:乘以投影矩阵给我空白屏幕

问题描述 投票:0回答:1

我正在尝试使用 OpenGL 制作一些 3D 图形,并使用 cglm 进行数学计算。
我遵循的指南引导我将顶点位置乘以 3 个矩阵:modelviewprojection
由于教程和我的语言不同,我无法一一遵循,所以我用我能找到的方式做了投影矩阵,用cglm

将顶点乘以这些矩阵给了我一个黑屏(对象未渲染),我注意到它只是由于投影矩阵而发生。

我检查了我的矩阵值,它们与我要求的一个投影矩阵匹配ChatGPT,但不起作用,所以我自己做了一个而不是使用cglm,并且它起作用了(有一些失真,但有效)。

我想知道为什么 cglm 失败了,因为我宁愿使用他们的。

这是一个重要的代码片段(C):

  mat4 model, view, proj;
  glm_mat4_identity(model);
  glm_mat4_identity(proj);

  glm_rotate(model, PI4, (vec3) { 1, 0, 0 });


  // glm_perspective(cam.fov, (f32) cam.width / cam.height, cam.near, cam.far, proj);
  proj[0][0] = PI4;
  proj[1][1] = PI4;
  proj[2][2] = (cam.far + cam.near) / (cam.near - cam.far);
  proj[2][3] = -1;
  proj[3][2] = 2 * cam.far * cam.near / (cam.near - cam.far);

  glUniformMatrix4fv(UNI(shader_program, "MODEL"), 1, GL_FALSE, (const f32*) { model[0] });
  glUniformMatrix4fv(UNI(shader_program, "PROJ"),  1, GL_FALSE, (const f32*) { proj[0] });

  while (!glfwWindowShouldClose(canvas.window)) {
    glm_mat4_identity(view);
    glm_translate(view, (vec3) { -cam.pos[0], -cam.pos[1], -cam.pos[2] });
    glUniformMatrix4fv(UNI(shader_program, "VIEW"),  1, GL_FALSE, (const f32*) { view[0] });

    canvas_clear((RGBA) { 0, 0, 0, 1 });
    glDrawArrays(GL_TRIANGLES, 0, 3);

    glfwSwapBuffers(canvas.window); 
    glfwPollEvents();    
    handle_inputs(canvas.window);    
  }

完整代码(C):

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <cglm/cglm.h>
#include <stdio.h>
#include "shader.h"
#include "misc.h"

#define ASSERT(x, str)    if (!(x)) {printf(str); exit(1);}
#define UNI(shader, name) (glGetUniformLocation(shader, name))
#define PI  3.14159
#define PI2 PI / 2
#define PI4 PI / 4
#define TAU PI * 2

#define VERTEX_SHADER   "shd/vertex.glsl"
#define FRAGMENT_SHADER "shd/fragment.glsl"
#define TEXTURE_0 "img/bills.ppm"
#define TEXTURE_1 "img/ilu.ppm"
#define WIDTH  800
#define HEIGHT 800
#define MOVEMENT_SPEED 0.01

typedef uint8_t  u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef int8_t   i8;
typedef int16_t  i16;
typedef int32_t  i32;
typedef float    f32;
typedef double   f64;

// --- Type

typedef struct { f32 R, G, B, A; } RGBA;

typedef struct {
  i16 width, height;
  f32 fov, near, far;

  f32 pos[3];
  f32 ang[2];
} Camera;

typedef struct {
  GLFWwindow* window;

  i16 width, height;
} Canvas;

u32 canvas_create_texture(GLenum unit, char path[], u32 shader, char uniform_name[], i32 uniform_value);
void canvas_config_texture(GLenum wrap_s, GLenum wrap_t, GLenum min_filter, GLenum mag_filter);
void key_callback(GLFWwindow* window, i32 key, i32 scancode, i32 action, i32 mods);
void handle_inputs(GLFWwindow* window);
void canvas_init(Canvas* canvas);
void canvas_clear(RGBA color);
u32 canvas_create_VBO();
u32 canvas_create_VAO();
u32 canvas_create_EBO();

// --- Setup

u8 wireframe_mode;

Canvas canvas = { NULL, WIDTH, HEIGHT };
Camera cam = { WIDTH, HEIGHT, PI4, 0.1, 100, { 0, 0, 0 }, { 0, 0 } };

f32 vertices[] = {
  +0.00, +0.45, 0,  0.5, 0.0,
  -0.50, -0.50, 0,  1.0, 1.0,
  +0.50, -0.50, 0,  0.0, 1.0,
};

// --- Main

i8 main() {
  canvas_init(&canvas);
  glfwSetKeyCallback(canvas.window, key_callback);

  u32 VBO = canvas_create_VBO();
  u32 VAO = canvas_create_VAO();

  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(f32), (void*) 0);
  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(f32), (void*) (sizeof(f32) * 3));
  glEnableVertexAttribArray(0);
  glEnableVertexAttribArray(1);

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

  u32 shader_program = shader_create_program(VERTEX_SHADER, FRAGMENT_SHADER);

  canvas_config_texture(GL_MIRRORED_REPEAT, GL_MIRRORED_REPEAT, GL_NEAREST, GL_NEAREST);
  canvas_create_texture(GL_TEXTURE0, TEXTURE_0, shader_program, "TEXTURE_0", 0);
  canvas_create_texture(GL_TEXTURE1, TEXTURE_1, shader_program, "TEXTURE_1", 1);

  mat4 model, view, proj;
  glm_mat4_identity(model);
  glm_mat4_identity(proj);

  glm_rotate(model, PI4, (vec3) { 1, 0, 0 });

  // glm_perspective(cam.fov, (f32) cam.width / cam.height, cam.near, cam.far, proj);
  proj[0][0] = PI4;
  proj[1][1] = PI4;
  proj[2][2] = (cam.far + cam.near) / (cam.near - cam.far);
  proj[2][3] = -1;
  proj[3][2] = 2 * cam.far * cam.near / (cam.near - cam.far);

  glUniformMatrix4fv(UNI(shader_program, "MODEL"), 1, GL_FALSE, (const f32*) { model[0] });
  glUniformMatrix4fv(UNI(shader_program, "PROJ"),  1, GL_FALSE, (const f32*) { proj[0] });

  while (!glfwWindowShouldClose(canvas.window)) {
    glm_mat4_identity(view);
    glm_translate(view, (vec3) { -cam.pos[0], -cam.pos[1], -cam.pos[2] });
    glUniformMatrix4fv(UNI(shader_program, "VIEW"),  1, GL_FALSE, (const f32*) { view[0] });

    canvas_clear((RGBA) { 0, 0, 0, 1 });
    glDrawArrays(GL_TRIANGLES, 0, 3);

    glfwSwapBuffers(canvas.window); 
    glfwPollEvents();    
    handle_inputs(canvas.window);    
  }

  glfwTerminate();
  return 0;
}

// --- Function

void canvas_init(Canvas* canvas) {
  glfwInit();
  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

  canvas->window = glfwCreateWindow(canvas->width, canvas->height, "Coordinate System", NULL, NULL);
  ASSERT(canvas->window, "Failed creating a window");
  glfwMakeContextCurrent(canvas->window);

  ASSERT(gladLoadGLLoader((GLADloadproc) glfwGetProcAddress), "Failed loading glad");
  glViewport(0, 0, WIDTH, HEIGHT);
}

void canvas_clear(RGBA color) {
  glClearColor(color.R, color.G, color.B, color.A);
  glClear(GL_COLOR_BUFFER_BIT);
}

void canvas_config_texture(GLenum wrap_s, GLenum wrap_t, GLenum min_filter, GLenum mag_filter) {
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
}

u32 canvas_create_texture(GLenum unit, char path[], u32 shader, char uniform_name[], i32 uniform_value) {
  u32 texture_ID;
  glGenTextures(1, &texture_ID);
  glActiveTexture(unit);
  glBindTexture(GL_TEXTURE_2D, texture_ID);

  u16 width, height;
  get_image_size(path, &width, &height);
  f32* image_buffer = malloc(sizeof(f32) * width * height * 3);
  load_image(path, image_buffer, width * height);

  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, image_buffer);
  glGenerateMipmap(GL_TEXTURE_2D);
  glUniform1i(UNI(shader, uniform_name), uniform_value);

  free(image_buffer);
  return texture_ID;
}

void key_callback(GLFWwindow* window, i32 key, i32 scancode, i32 action, i32 mods) {
  if (action != GLFW_PRESS) return;

  switch (key) {
    case GLFW_KEY_ESCAPE:
      glfwSetWindowShouldClose(canvas.window, 1); 
      break;

    case GLFW_KEY_M:
      if (wireframe_mode) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
      else glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
      wireframe_mode = 1 - wireframe_mode;
  }
}

void handle_inputs(GLFWwindow* window) {
  if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
    cam.pos[2] += MOVEMENT_SPEED;
  if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
    cam.pos[2] -= MOVEMENT_SPEED;
  if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
    cam.pos[0] -= MOVEMENT_SPEED;
  if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
    cam.pos[0] += MOVEMENT_SPEED;
  if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS)
    cam.pos[1] += MOVEMENT_SPEED;
  if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
    cam.pos[1] -= MOVEMENT_SPEED;
}

u32 canvas_create_VBO() {
  u32 VBO;
  glGenBuffers(1, &VBO);
  glBindBuffer(GL_ARRAY_BUFFER, VBO);
  return VBO;
}

u32 canvas_create_VAO() {
  u32 VAO;
  glGenVertexArrays(1, &VAO);
  glBindVertexArray(VAO);
  return VAO;
}

u32 canvas_create_EBO() {
  u32 EBO;
  glGenBuffers(1, &EBO);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
  return EBO;
}

我的顶点着色器(GLSL):

# version 330 core

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTex;
uniform mat4 MODEL;
uniform mat4 VIEW;
uniform mat4 PROJ;
out vec2 _tex;

void main() {
  _tex = aTex;

  gl_Position = PROJ * VIEW * MODEL * vec4(aPos, 1);
}

我还打印了矩阵:

Mine
0.785398 0.000000 0.000000 0.000000 
0.000000 0.785398 0.000000 0.000000 
0.000000 0.000000 -1.002002 -1.000000 
0.000000 0.000000 -0.200200 1.000000 

CGLM
2.414216 0.000000 0.000000 0.000000 
0.000000 2.414216 0.000000 0.000000 
0.000000 0.000000 -1.002002 -1.000000 
0.000000 0.000000 -0.200200 0.000000 

我现在也注意到,我的错了,因为它不应该具有最后一个值1,它之所以发生是因为我之前正在做一个单位矩阵,当我删除那个1时,它停止工作

c opengl glsl glfw
1个回答
1
投票

透视投影矩阵的计算已完成。对称透视投影矩阵为:

column 0:    1/(ta*a)  0      0              0
column 1:    0         1/ta   0              0
column 2:    0         0     -(f+n)/(f-n)   -1
column 3:    0         0     -2*f*n/(f-n)    0

其中

a  = w / h
ta = tan(fov_y / 2)

对于您的代码来说,这意味着:

float aspect = (float)window_width / (float)wondow_height; 
proj[0][0] = 1 / (tan(PI4 / 2) * aspect);
proj[1][1] = 1 / tan(PI4 / 2);
proj[2][2] = (cam.far + cam.near) / (cam.near - cam.far);
proj[2][3] = -1;
proj[3][2] = 2 * cam.far * cam.near / (cam.near - cam.far);
proj[3][3] = 0;

注意,

glm_mat4_identity
用单位矩阵初始化矩阵。所以
proj[3][3]
需要设置为0。

© www.soinside.com 2019 - 2024. All rights reserved.