OpenGL 试图渲染一个立方体,但平面之间有奇怪的线条

OpenGL Trying to render a cube but there are weird lines between planes

立方体渲染

嘿,我认为我将数据发送到顶点的方式或者我的索引使用 GL_CCW

排序的方式可能有误
struct Vertex
{
    glm::vec3 position;
    glm::vec3 color;
    glm::vec3 normal;
};

使用顶点结构的顶点

Vertex vertices[] =
{   
/*FRONT SQUARE*/
    ///BOTTOM LEFT
glm::vec3(-0.5f, -0.5f, 1.f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),

    ///bottom RIGHT
    glm::vec3(0.5f, -0.5f, 1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
    ////TOP RIGHT
    glm::vec3(0.5f, 0.5f, 1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
    ///TOP LEFT
    glm::vec3(-0.5f, 0.5f, 1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),

    ///BOTTOM LEFT
    glm::vec3(-0.5f, -0.5f, -1.f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),

    ///bottom RIGHT
    glm::vec3(0.5f, -0.5f, -1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
    ////TOP RIGHT
    glm::vec3(0.5f, 0.5f, -1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
    ///TOP LEFT
    glm::vec3(-0.5f, 0.5f, -1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f)

};

unsigned noOfVertices = sizeof(vertices) / sizeof(Vertex);

这是我的指数排序

GLuint indices[] =
{
    // /front face

    0, 1, 2,
    2, 3, 0,

    // right
    1, 5, 6,
    6, 2, 1,
    // back
    7, 6, 5,
    5, 4, 7,
    // left
    4, 0, 3,
    3, 7, 4,
    // bottom
    4, 5, 1,
    1, 0, 4,
    // top
    3, 2, 6,
    6, 7, 3


};

unsigned noOfIndices = sizeof(indices) / sizeof(GLuint);

主要功能和初始化window

  int main()
    {

启动window

    ///initialise GLFW for Window
    if (glfwInit() == GLFW_FALSE)
    {
        std::cout << "ERROR::GLFW-INTI::FAILED" << "\n";
        glfwTerminate();
    }

    ///Create window with functions
    GLFWwindow* window;
    const int window_height = 480;
    int window_width = 680;
    int framebuffer_height = window_height;
    int framebuffer_width = window_width;
    char* title = "mytutorial";

    int GLverMAJ = 3;
    int GLverMin = 3;

    ///sets how  the window should be drawn and which hints
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, GLverMAJ);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, GLverMin);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);

    ///create the window with the previously set options
    window = glfwCreateWindow(window_width, window_height, title, NULL, NULL);

    //checks if window created
    if (window == nullptr)
    {
        std::cout << "ERROR:::GLFWCREATEWINDOWFAILED" << "\n";
    }

    ///sets the frame buffer size
    glfwGetFramebufferSize(window, &framebuffer_width, &framebuffer_height);
    glfwMakeContextCurrent(window);

    //need to read on this part
    glewExperimental = GL_TRUE;

    //initiliase the glew
    if (glewInit() != GLEW_OK)
    {
        std::cout << "ERROR::GLEWINIT::FAILED" << "\n";
    }

初始化 opengl 选项

///enable functions first
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_BLEND);
        glEnable(GL_CULL_FACE);

        //initialise the enabled  functions
        glCullFace(GL_BACK);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glDepthFunc(GL_LESS);

        ///set the way its draw
        glFrontFace(GL_CCW);

        ///set the polygon mode and fill ////Set as GL_LINE TO LOOK AT CUBE MESH
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

这是我初始化视图、项目和模型矩阵的地方
///初始化矩阵

    ///view
    ///front, position, up then use in lookat
    glm::vec3 cameraPos(0.f, 0.f, 1.f);
    glm::vec3 cameraUp(0.f, 1.f, 0.f);
    glm::vec3 cameraFront(0.f, 0.f, -0.1f);

    glm::mat4 ViewMatrix(1.f);
    ViewMatrix = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);

    ///set up prespective projection

    float fov = 90.f;
    float nearPlane = -1.f;
    float farPlane = 1000.f;

    ///projection
    glm::mat4 ProjectionMatrix(1.f);
    ProjectionMatrix = glm::perspective(glm::radians(fov), static_cast<float>(framebuffer_width / framebuffer_height), nearPlane, farPlane);


    //Model Matrix
    glm::mat4 ModelMatrix(1.f);

然后我创建我的着色器

    ///set up SHADERS
    char infolog[512];
    GLint success;

    GLuint Vertexshader = glCreateShader(GL_VERTEX_SHADER);
    ///std::string str_src = 

    std::string temp = "";
    std::string src = "";
    std::ifstream infile;
    infile.open("vert.glsl");
    if (infile.is_open())
    {
        while (std::getline(infile, temp))
            src += temp + "\n";

    }
    infile.close();

    const GLchar* source = src.c_str();

    ///link created shader with shader source
    glShaderSource(Vertexshader, 1, &source, NULL);
    glCompileShader(Vertexshader);

    ///error check compilation status
    glGetShaderiv(Vertexshader, GL_COMPILE_STATUS, &success);

    if (!success)
    {
        glGetShaderInfoLog(Vertexshader, 512, NULL, infolog);
        std::cout << infolog;
    }



    success = 0;

    GLuint FragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    ///std::string str_src = 

    temp = "";
    src = "";
    infile.open("frag.glsl");
    if (infile.is_open())
    {
        while (std::getline(infile, temp))
            src += temp + "\n";

    }
    infile.close();

    source = src.c_str();

    ///link created shader with shader source
    glShaderSource(FragmentShader, 1, &source, NULL);
    glCompileShader(FragmentShader);

    ///error check compilation status
    glGetShaderiv(FragmentShader, GL_COMPILE_STATUS, &success);

    if (!success)
    {
        glGetShaderInfoLog(FragmentShader, 512, NULL, infolog);
        std::cout << infolog;
    }

Link 使用程序创建的着色器

     ///create and link the program
    success = 0;
    GLuint programID;

    programID = glCreateProgram();

    glAttachShader(programID, Vertexshader);
    glAttachShader(programID, FragmentShader);

    glLinkProgram(programID);

    glGetProgramiv(programID, GL_LINK_STATUS, &success);
    if (!success)
    {
        glGetProgramInfoLog(programID, 512, NULL, infolog);
        std::cout << "ERROR::SHADER::COULD_NOT_LINK_PROGRAM" << "\n";
        std::cout << infolog << "\n";

    }

链接未使用和删除缓冲区后

///after linking we unuse the program and delete the shaders
    glUseProgram(0);
    glDeleteShader(Vertexshader);
    glDeleteShader(FragmentShader);

这是我初始化 VAO VBO 和 EBO 的地方

///vbo, ebo and vertex array
    GLuint VAO;
    GLuint VBO;
    GLuint EBO;

    //gen and bind vao
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);


    ///gen vbo
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, noOfVertices * sizeof(Vertex), vertices, GL_STATIC_DRAW);


    ///gen EBO
    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, noOfIndices * sizeof(GLuint), indices, GL_STATIC_DRAW);

这是我觉得可能有问题的部分

    ///tell  buffer where data is located
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, position));
    glEnableVertexAttribArray(0);

    //colour
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, color));
    glEnableVertexAttribArray(1);

    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, normal));
    glEnableVertexAttribArray(2);

    glBindVertexArray(0);

    ///use program send in uniforms to the shader.
    glUseProgram(programID);

    ///GLuint s = glGetUniformLocation(programID, "ViewMatrix");
    GLuint s = glGetUniformLocation(programID, "ModelMatrix");
    glUniformMatrix4fv(s, 1, GL_FALSE, glm::value_ptr(ModelMatrix));

    s = glGetUniformLocation(programID, "ProjectionMatrix");
    glUniformMatrix4fv(s, 1, GL_FALSE, glm::value_ptr(ProjectionMatrix));

    s = glGetUniformLocation(programID, "ViewMatrix");
    glUniformMatrix4fv(s, 1, GL_FALSE, glm::value_ptr(ViewMatrix));

    glUseProgram(0);
    ///main while loop
    while (!glfwWindowShouldClose(window))
    {
        //clear
        glClearColor(0.f, 0.f, 0.f, 1.f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

        ///draw
        glfwPollEvents();



        glUseProgram(programID);
        glBindVertexArray(VAO);


        glDrawElements(GL_TRIANGLES, noOfIndices, GL_UNSIGNED_INT, 0);

        ///flush

        glfwSwapBuffers(window);
        glFlush();


    ///unuse

        glBindVertexArray(0);
        glUseProgram(0);
    }



    return 0;
}

对我来说,您的程序似乎运行正常。如果我没记错的话,那么你的相机位于立方体内部,从其中一张脸的位置直视另一侧的脸。在这种情况下,您所看到的正是人们期望看到的。在图像的中央,您有两个三角形,它们构成了您正在看的脸的背面。您得到的 "weird lines" 只是构成其他面的三角形的边。由于您的相机位于立方体内部,因此这些面一定会一直延伸到您的相机后面,并且所有东西都会在近平面处被切断,这是您从 "encloses" 所有东西中获得外部矩形的地方。

因为这个

一切都有点压扁
static_cast<float>(framebuffer_width / framebuffer_height)

不会产生您最可能希望的效果。你这里还在做整数除法

此外,我不确定您对近平面使用负值的确切预期效果是什么。很可能,它也不是您真正想要的,我建议您使用一些正值,例如 0.1f 那里...

近平面和远平面都必须为正值,因为 glm::perspective 并且 static_cast<float>(framebuffer_width / framebuffer_height) 将是整数除法:

float fov = 90.f;
float nearPlane = 0.1f; // 0.1 instead of -1.0
float farPlane = 1000.f;

glm::mat4 ProjectionMatrix(1.f);
ProjectionMatrix = glm::perspective(glm::radians(fov), 
    static_cast<float>(framebuffer_width) / static_cast<float>(framebuffer_height),
    nearPlane, farPlane); 

glm::perspective:

GLM_FUNC_DECL mat<4, 4, T, defaultp> glm::perspective(
      T     fovy,
      T     aspect,
      T     near,
      T     far 
  )

[...]
near Specifies the distance from the viewer to the near clipping plane (always positive).
far Specifies the distance from the viewer to the far clipping plane (always positive).


glm 库提供与 OpenGL 和 GLSL 相关的矩阵运算。 glm API documentation refers to The OpenGL Shading Language specification 4.20

参见The OpenGL Shading Language 4.6, 5.4.2 Vector and Matrix Constructors, page 101:

To initialize a matrix by specifying vectors or scalars, the components are assigned to the matrix elements in column-major order.

mat4(float, float, float, float,  // first column
       float, float, float, float,  // second column
       float, float, float, float,  // third column
       float, float, float, float); // fourth column

这意味着顶点着色器中顶点坐标的变换必须是:

gl_Position = ProjectionMatrix * ViewMatrix * ModelMatrix * vec4(vertex_position,1.0);

另见 GLSL Programming/Vector and Matrix Operations:

通过将 glUniformMatrix4fv 的第 3 个参数设置为 GL_TRUE,当设置为 uniform 时矩阵可能会被转置:

GLuint s = glGetUniformLocation(programID, "ModelMatrix");
glUniformMatrix4fv(s, 1, GL_TRUE, glm::value_ptr(ModelMatrix));

s = glGetUniformLocation(programID, "ProjectionMatrix");
glUniformMatrix4fv(s, 1, GL_TRUE, glm::value_ptr(ProjectionMatrix));

s = glGetUniformLocation(programID, "ViewMatrix");
glUniformMatrix4fv(s, 1, GL_TRUE, glm::value_ptr(ViewMatrix));

并以相反的顺序计算顶点坐标变换:

gl_Position = vec4(vertex_position,1.0) * ModelMatrix * ViewMatrix * ProjectionMatrix;

另外,立方体a的面的缠绕顺序是顺时针的,所以必须是:

glFrontFace(GL_CCW);
glFrontFace(GL_CW);


将相机位置更改为

glm::vec3 cameraPos(0.f, 0.f, 2.f);

你会得到以下结果: