首页 > 解决方案 > 每当我使用矩阵乘法时,我都会出现黑屏

问题描述

我在尝试在 mac OS 上运行 OpenGl 代码时遇到了这个问题,所以我在屏幕上看到了一个三角形,但是每当我尝试乘以一个矩阵(那不是单位矩阵)时,我得到一个黑屏,所以我剥离了所有我的代码在寻找错误,但我仍然遇到同样的错误,然后我从 learnOpengl 获得了这个通用代码,我尝试运行它,但我遇到了同样的问题,所以我认为问题不在他的代码中,而是在这个我用来编译它的makefile。

CC := g++
SOURCE_DIR := Sources/ Includes/ Libs/ graphics/ Other/stb_image/ 
Includes/glm/gtc/ Includes/glm/ 
INCLUDE_DIR := -ILibs/ -IIncludes/ -IOther/ -ISources/ -Igraphics/ - 
Ishaders/ -I/usr/X11R6/include 
LIBS_DIR := -L/usr/local/Cellar/glfw/3.2.1 -lglfw3 
CFLAGS := $(CC) -std=c++14 -c  -Wall
LFLAGS := -o
FRAMEWORKS := -I/usr/X11R6/include -framework Cocoa -framework OpenGL - 
framework IOKit -framework CoreVideo -framework GLUT
EXE := App
APP_DIR := ApplicationDir/
OBJ_DIR := libraries/
SOURCE_FILES := $(foreach dir, $(SOURCE_DIR), $(wildcard $(dir)*.cpp))
OBJ_FILES := $(wildcard Objects/*)
SOURCE_FILES += Other/glad.c

 all : 
    make build ; \
    make run

build : $(EXE)
    $(EXE)

$(EXE): $(OBJ_FILES)
    $(CC) $(FRAMEWORKS) $(LIBS_DIR)  $(OBJ_FILES) $(LFLAGS) $(EXE)

 $(OBJ_FILES) : $(SOURCE_FILES) 
        for file in $(SOURCE_FILES) ; do  \
        $(CFLAGS) $(INCLUDE_DIR) $$file ; \
        mv *.o Objects ; \
     done 

 run:
    echo &&  ./$(EXE) && echo  


 clean :
    rm -f $(EXE) $(OBJ_FILES)

我的代码:

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

static const char *vertexShaderSource = R"(

#version 330 core

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;

out vec3 ourColor; 

uniform mat4 Model;
uniform mat4 View;
uniform mat4 Projection;
uniform vec4 Colour;
out vec4 unifColour;   

void main()
{
    mat4 transform = Projection;
    gl_Position = transform * vec4(aPos, 1.0);
    ourColor = aColor;
    unifColour = Colour;
} 
)";

const char *fragmentShaderSource = R"(

#version 330 core
out vec4 FragColor;

in vec3 ourColor;
in vec4 unifColour;

void main()
{
    FragColor = unifColour;
})";

int main()
{
    // glfw: initialize and configure
    // ------------------------------
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

    // std::cout << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;

   // glfw window creation
   // --------------------
   GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
   if (window == NULL)
   {
       std::cout << "Failed to create GLFW window" << std::endl;
       glfwTerminate();
       return -1;
   }
   glfwMakeContextCurrent(window);
   glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

   // glad: load all OpenGL function pointers
   // ---------------------------------------
   if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
   {
       std::cout << "Failed to initialize GLAD" << std::endl;
       return -1;
   }

   glEnable(GL_DEPTH_TEST);

   // build and compile our shader program
   // ------------------------------------
   // vertex shader
   int vertexShader = glCreateShader(GL_VERTEX_SHADER);
   glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
   glCompileShader(vertexShader);
   // check for shader compile errors
   int success;
   char infoLog[512];
   glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
   if (!success)
   {
       glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
       std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
   }
   // fragment shader
   int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
   glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
   glCompileShader(fragmentShader);
   // check for shader compile errors
   glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
   if (!success)
   {
       glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
       std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
   }
   // link shaders
   int shaderProgram = glCreateProgram();
   glAttachShader(shaderProgram, vertexShader);
   glAttachShader(shaderProgram, fragmentShader);
   glLinkProgram(shaderProgram);
   // check for linking errors
   glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
   if (!success) {
       glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
       std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
   }
   glDeleteShader(vertexShader);
   glDeleteShader(fragmentShader);

   // set up vertex data (and buffer(s)) and configure vertex attributes
   // ------------------------------------------------------------------
   float vertices[] = {
       // positions         // colors
       0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,  // bottom right
      -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,  // bottom left
       0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f   // top 
   };

   unsigned int VBO, VAO;
   glGenVertexArrays(1, &VAO);
   glGenBuffers(1, &VBO);
   // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
   glBindVertexArray(VAO);

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

   // position attribute
   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
   glEnableVertexAttribArray(0);
   // color attribute
   glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
   glEnableVertexAttribArray(1);

   // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
   // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
   // glBindVertexArray(0);

   // as we only have a single shader, we could also just activate our shader once beforehand if we want to 
   glUseProgram(shaderProgram);

   std::cout << shaderProgram << std::endl;
   // render loop
   // -----------
   while (!glfwWindowShouldClose(window))
   {
       // input
       // -----
       processInput(window);   

       // render
       // ------
       glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
       glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

       // render the triangle
       glBindVertexArray(VAO);
       glDrawArrays(GL_TRIANGLES, 0, 3);

       glm::mat4 Model(1.0f);
       glm::mat4 View(1.0f);
       glm::mat4 Projection(1.0f);

       Projection = glm::perspective(glm::radians(55.0f), 800.0f/600.0f, 0.01f, 100.0f);
       Model = glm::scale(Model, glm::vec3(0.5f, 0.5f, 0.5f));

       unsigned int location = glGetUniformLocation(shaderProgram, "Colour");

       glm::vec4 colour =  glm::vec4(1.0, 0.0, 1.0, 1.0);
       glUniform4fv(location, 1, &colour[0]);

       glUseProgram(shaderProgram);

       GLint model = glGetUniformLocation(shaderProgram, "Model" );
       glUniformMatrix4fv(model, 1, GL_FALSE, glm::value_ptr(Model));

       GLint view = glGetUniformLocation(shaderProgram, "View" );
       glUniformMatrix4fv(view, 1, GL_FALSE, glm::value_ptr(View));

       GLint projection = glGetUniformLocation(shaderProgram, "Projection" );
       glUniformMatrix4fv(projection, 1, GL_FALSE, glm::value_ptr(Projection));

       glBindVertexArray(VAO);
       glDrawArrays(GL_TRIANGLES, 0, 3);

       // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
       // -------------------------------------------------------------------------------
       glfwSwapBuffers(window);
       glfwPollEvents();
    }

    // optional: de-allocate all resources once they've outlived their purpose:
    // ------------------------------------------------------------------------
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);

    // glfw: terminate, clearing all previously allocated GLFW resources.
    // ------------------------------------------------------------------
    glfwTerminate();
    return 0;
}

// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
         glfwSetWindowShouldClose(window, true);
}

// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and 
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
}

标签: c++openglmakefile

解决方案


您不使用视图矩阵,因此您必须设置模型在视图空间中的位置。在视图空间中,X 轴从左指向右,Y 轴从底部指向顶部。z 轴指向视口外(右手系统中 x 轴和 y 轴的叉积)。

这意味着您必须在近平面和远平面之间沿负 Z 轴移动网格,该平面由投影矩阵(在您的情况下为 [0.01, 100.0] )定义。

在片段着色器中使用Model,ViewProjection矩阵:

gl_Position = Projection * View * Model * vec4(aPos, 1.0);

设置沿负 Z 轴平移的模型矩阵(例如 -2.0):

glm::mat4 Model(1.0f);
Model = glm::translate(Model, glm::vec3(0.0f, 0.0f, -2.0f));

推荐阅读