OpenGL 无法从我的顶点数组中正确读取颜色

OpenGL does not read the colour correctly from my vertex array

使用 OpenGL 着色器,我想在屏幕上绘制一个三角形,其中顶点颜色在数据结构中与顶点坐标一起指定。该结构的每个顶点有 7 个浮点数 -- 3 个用于坐标,然后是 4 个用于颜色:

static std::vector<GLfloat> vertices = {
        -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
        1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
        0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f
    };

然后我告诉 OpenGL 如何使用 glVertexAttribPointer() 解释这个结构:

// Vertex coordinates
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), 0);
// Vertex colour
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3 * sizeof(float)));

然后告诉我的顶点着色器读取坐标和颜色:

layout (location = 0) in vec3 position;
layout (location = 1) in vec4 vertex_colour;

但是,无论我对颜色分量使用什么值,三角形总是以红色绘制。更改结构中的坐标会按预期影响图像,但更改结构中的颜色不会有任何效果。

我认为这是我的 C++ 代码的问题,而不是着色器代码的问题,因为我调试了着色器并且它总是读取 (1.0, 0.0, 0.0, 1.0) 颜色,即使我正在为每个顶点传递 (0.0, 0.0, 1.0, 1.0)。

对我做错了什么有什么想法吗?

这是我的完整代码:

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <cmath>
#include <assert.h>
#include <vector>

#include <GL/glew.h>
#include <GL/glut.h>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/ext.hpp>

GLuint buffer;
GLuint projection_matrix_location;
GLuint view_matrix_location;
glm::mat4 view_matrix;
glm::mat4 projection_matrix;
int num_vertices = 0;

static void RenderScene()
{
    // Clear the buffers.
    glClear(GL_COLOR_BUFFER_BIT);
    glClear(GL_DEPTH_BUFFER_BIT);

    // Set the matrices
    glUniformMatrix4fv(projection_matrix_location, 1, GL_FALSE, glm::value_ptr(projection_matrix));
    glUniformMatrix4fv(view_matrix_location, 1, GL_FALSE, glm::value_ptr(view_matrix));

    // Specify how to read the vertex buffer
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    // Vertex coordinates
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), 0);
    // Vertex colour
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3 * sizeof(float)));

    // Draw the vertex buffer
    glDrawArrays(GL_TRIANGLES, 0, num_vertices);
    glDisableVertexAttribArray(0);

    // Swap the buffers
    glutSwapBuffers();
}

static void MakeBuffers()
{
    // Set the vertices
    static std::vector<GLfloat> vertices = {
        -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
        1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
        0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f
    };
    num_vertices = (1.0 / 7.0) * vertices.size();

    // Fill the buffer with the vertices
    glGenBuffers(1, &buffer);
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    glBufferData(GL_ARRAY_BUFFER, num_vertices * 7 * sizeof(GL_FLOAT), &vertices[0], GL_STATIC_DRAW);
}


static GLuint MakeShader(GLenum shader_type, std::string shader_filename)
{
    // Load the source code
    std::ifstream file_in;
    file_in.open(&shader_filename[0]);
    std::stringstream file_stream;
    file_stream << file_in.rdbuf();
    std::string file_string = file_stream.str();
    const GLchar* ptr_file_string = &file_string[0];
    const GLchar** ptr_file_strings = &ptr_file_string;
    int string_lengths[] = {(int)file_string.length()};

    // Compile the shader
    GLuint shader = glCreateShader(shader_type);
    glShaderSource(shader, 1, ptr_file_strings, &string_lengths[0]);
    glCompileShader(shader);

    // Check
    GLint is_success;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &is_success);
    if (!is_success)
    {
        std::cerr << "Error" << std::endl;
        return -1;
    }

    return shader;
}


static void MakeShaderProgram()
{
    // Make the shaders
    GLuint vertex_shader = MakeShader(GL_VERTEX_SHADER, "../src/vertex-shader.glsl");
    GLuint fragment_shader = MakeShader(GL_FRAGMENT_SHADER, "../src/fragment-shader.glsl");

    // Create the program
    GLuint program = glCreateProgram();
    glAttachShader(program, vertex_shader);
    glAttachShader(program, fragment_shader);
    glLinkProgram(program);

    // Check
    GLint is_success = 0;
    glGetProgramiv(program, GL_LINK_STATUS, &is_success);
    if (!is_success)
    {
        std::cout << "Error" << std::endl;
        return;
    }
    glValidateProgram(program);
    glGetProgramiv(program, GL_VALIDATE_STATUS, &is_success);
    if (!is_success)
    {
        std::cout << "Error" << std::endl;
        return;
    }

    // Use the program
    glUseProgram(program);

    // Get the location of the uniform variables
    view_matrix_location = glGetUniformLocation(program, "view_matrix");
    assert(view_matrix_location != 0xFFFFFFFF);
    projection_matrix_location = glGetUniformLocation(program, "projection_matrix");
    assert(projection_matrix_location != 0xFFFFFFFF);
}


int main(int argc, char** argv)
{
    // Initialize GLUT
    glutInit(&argc, argv);

    // Configure some GLUT display options:
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // Specify the GLUT window parameters and create the window
    glutInitWindowSize(1000, 750);
    glutInitWindowPosition(500, 200);
    glutCreateWindow("Test");

    // Specify the display callback
    glutDisplayFunc(RenderScene);

    // Initialize GLEW, which must be done after GLUT is initialized.
    GLenum glut_result = glewInit();
    if (glut_result != GLEW_OK)
    {
        std::cout << "Error" << std::endl;
        return -1;
    }

    // Set the clear colour.
    glClearColor(0.5f, 0.5f, 0.5f, 0.0f);

    // Enable depth testing so that only the nearest vertex is sent to the colour buffer (also needed to read the depth of each pixel using glReadPixels())).
    glEnable(GL_DEPTH_TEST);

    // Make the vertex and index buffers.
    MakeBuffers();

    // Make the shader program.
    MakeShaderProgram();

    // Create the view matrix.
    glm::vec3 eye(0.0f, 0.0f, -3.0f);
    glm::vec3 centre(0.0f, 0.0f, 0.0f);
    glm::vec3 up(0.0f, 1.0f, 0.0f);
    view_matrix = glm::lookAt(eye, centre, up);

    // Create the projection matrix.
    float fov_y = 45.0;
    float aspect_ratio = 1.5;
    float near_clip = 1;
    float far_clip = 1000;
    projection_matrix = glm::perspective(fov_y, aspect_ratio, near_clip, far_clip);

    // Start the GLUT internal loop.
    glutMainLoop();
}

这是我的着色器代码:

// Vertex shader

#version 330

layout (location = 0) in vec3 position;
layout (location = 1) in vec4 vertex_colour;

uniform mat4 projection_matrix;
uniform mat4 view_matrix;

out vec4 frag_colour;

void main()
{
    gl_Position = projection_matrix * view_matrix * vec4(position, 1.0f);
    frag_colour = vertex_colour;
}


// Fragment shader

#version 330

in vec4 frag_colour;

void main()
{
    gl_FragColor = frag_colour;
}

我现在无法调试您的代码,但根据我在这里看到的情况,您忘记启用第二个属性 array.See this example 以供参考。 但即使我错了,我也想指出你在 code.You 中使用的 GL 3.3 中的一些不良做法,good.This 是现代 OpenGL baseline.But 你仍在混合旧的API(pre 3.3)用新的one.From结尾:

在您的片段着色器中,您应该使用自定义输出属性而不是 gl_FragColor 中内置的 GLSL。

 #version 330

 in smooth vec4 frag_colour;
 out vec4 frag_out;

 void main()
 {
    frag_out = frag_colour;
 }

现在,关于您的 OpenGL commands.You 不应直接绑定顶点缓冲区,而应使用 VAO 并将其绑定到 context.In 某些驱动程序版本(我在 NVIDIA 上体验过)产生的事实当 VAO 不与核心配置文件一起使用时,根本没有渲染结果。