【问题标题】:What is causing the lack of color from fragment shader output?是什么导致片段着色器输出缺少颜色?
【发布时间】:2022-01-20 19:06:31
【问题描述】:

我正在开发一个“Hello Triangle”程序,但我终其一生都无法弄清楚为什么片段着色器没有颜色。是什么导致所有片段输出为白色?我在 Visual Studio 2019 上,程序编译得很好,单步调试调试器不会产生任何结果。我假设错误是在 GLSL 或我的顶点属性管道中。 顶点着色器:

#version 450 core
layout (location = 0) in vec4 vPosition;
layout (location = 1) in vec4 color;
out vec4 fColor;
void main() {
    fColor = color;
    gl_Position = vPosition;
}

片段着色器:

#version 450 core
in vec4 fColor;
out vec4 fragColor;
void main() {
    //fColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
    fragColor = fColor;
}

主要:

#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <cstdlib>
#include <string>
#include <GL/gl3w.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
std::string readFile(const char* filePath) {
    std::string content;
    std::ifstream fileStream(filePath, std::ios::in);
    if (!fileStream.is_open()) {
        std::cerr << "Could not read file " << filePath << ". File does not exist." << std::endl;
        return "";
    }
    std::string line = "";
    while (!fileStream.eof()) {
        std::getline(fileStream, line);
        content.append(line + "\n");
    }
    fileStream.close();
    return content;
}
void loadShaders(std::string filedir, GLenum type, GLuint &prog) {
    GLenum errorVal;
    std::string vertexSource = readFile("./vert.vert");
    std::string fragmentSource = readFile("./frag.frag");
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    const GLchar* source = (const GLchar*)vertexSource.c_str();
    glShaderSource(vertexShader, 1, &source, 0);
    glCompileShader(vertexShader);
    GLint isCompiled = 0;
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &isCompiled);
    if (isCompiled == GL_FALSE)
    {
        GLint maxLength = 0;
        glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &maxLength);
        // The maxLength includes the NULL character
        std::vector<GLchar> infoLog(maxLength);
        glGetShaderInfoLog(vertexShader, maxLength, &maxLength, &infoLog[0]);
        // We don't need the shader anymore.
        glDeleteShader(vertexShader);
        // Use the infoLog as you see fit.
        // In this simple program, we'll just leave
        return;
    }
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    source = (const GLchar*)fragmentSource.c_str();
    glShaderSource(fragmentShader, 1, &source, 0);
    glCompileShader(fragmentShader);
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &isCompiled);
    if (isCompiled == GL_FALSE)
    {
        GLint maxLength = 0;
        glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &maxLength);
        // The maxLength includes the NULL character
        std::vector<GLchar> infoLog(maxLength);
        glGetShaderInfoLog(fragmentShader, maxLength, &maxLength, &infoLog[0]);
        // We don't need the shader anymore.
        glDeleteShader(fragmentShader);
        // Either of them. Don't leak shaders.
        glDeleteShader(vertexShader);
        // Use the infoLog as you see fit.
        // In this simple program, we'll just leave
        return;
    }

    // Vertex and fragment shaders are successfully compiled.
    // Now time to link them together into a program.
    // Get a program object.
    GLuint program = glCreateProgram();
    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);
    glLinkProgram(program);
    GLint isLinked = 0;
    glGetProgramiv(program, GL_LINK_STATUS, (int*)&isLinked);
    if (isLinked == GL_FALSE)
    {
        GLint maxLength = 0;
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
        // The maxLength includes the NULL character
        std::vector<GLchar> infoLog(maxLength);
        glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
        // We don't need the program anymore.
        glDeleteProgram(program);
        // Don't leak shaders either.
        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);
        // Use the infoLog as you see fit.
        // In this simple program, we'll just leave
        return;
    }
    // Always detach shaders after a successful link.
    glDetachShader(program, vertexShader);
    glDetachShader(program, fragmentShader);
}
int main(int argc, char** argv) {
    GLenum errorVal;
    //glfw and gl3w initialization and window creation
    glfwInit();
    GLFWwindow* window = glfwCreateWindow(1920, 1080, "openGL bullshit", NULL, NULL);
    glfwMakeContextCurrent(window);
    gl3wInit();
    //do shit here
    GLuint VAOs[1];
    GLuint bufferNames[1];
    //vertices gets copied into the GPU, can be modified GPU-side using glMapData, glBufferSubData, or glNamedBufferStorage
    GLfloat vertices[12][4] = {
        { -1.0f, 1.0f, 0.0f, 1.0f }, // Triangle 1
        { -1.0f, -1.0f, 0.0f, 1.0f },
        { 1.0f, -1.0f, 0.0f, 1.0f },
        { 1.0f, -1.0f, 0.0f, 1.0f }, //Traingle 2
        { 1.0f, 1.0f, 0.0f, 1.0f },
        { -1.0f, 1.0f, 0.0f, 1.0f },
        {1.0f, 0.0f, 0.0f, 1.0f}, //colors
        {1.0f, 0.0f, 0.0f, 1.0f},
        {1.0f, 0.0f, 0.0f, 1.0f},
        {1.0f, 0.0f, 0.0f, 1.0f},
        {1.0f, 0.0f, 0.0f, 1.0f},
        {1.0f, 0.0f, 0.0f, 1.0f}
    };
    glCreateVertexArrays(1, VAOs);
    glCreateBuffers(1, bufferNames);
    glNamedBufferStorage(bufferNames[0], sizeof(vertices), vertices, GL_DYNAMIC_STORAGE_BIT + GL_MAP_WRITE_BIT);
    //glNamedBufferSubData(bufferNames[0], sizeof(GLfloat) * 12, sizeof(GLfloat)*24, colors);
    //insert shader shit here
    GLuint program = glCreateProgram();
    loadShaders("./vert.vert", GL_VERTEX_SHADER, program); //ignore the inputs, they aren't used. This one command loads both vertex and fragment shaders
    glUseProgram(program);
    //binding and plumbing
    glBindVertexArray(VAOs[0]);
    glBindBuffer(GL_ARRAY_BUFFER, bufferNames[0]);
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (void*)0);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)(sizeof(GLfloat) * 24));
    //glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(GLfloat) * 2));
    
    
    //main loop
    GLfloat debugArr[6][2];
    while (!glfwWindowShouldClose(window)) {
        static const float black[] = { 0.0f, 0.0f, 0.0f, 0.0f };
        vertices[0][0] += 0.0001f;
        void *pointer = glMapNamedBuffer(bufferNames[0], GL_WRITE_ONLY);
        memcpy(pointer, vertices, sizeof(vertices) / 12);
        glUnmapNamedBuffer(bufferNames[0]);
        glClearBufferfv(GL_COLOR, 0, black);
        glDrawArrays(GL_TRIANGLES, 0, 6);
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    //shutdown if main loop stops
    glfwDestroyWindow(window);
    glfwTerminate();
}

【问题讨论】:

    标签: c++ opengl glsl glfw glm-math


    【解决方案1】:

    这只是未定义的行为:

    glNamedBufferStorage(bufferNames[0], sizeof(vertices) + sizeof(colors), vertices, GL_DYNAMIC_STORAGE_BIT + GL_MAP_WRITE_BIT);
    

    您告诉 GL 从 vertex 数组开始读取 sizeof(vertices) + sizeof(colors) 字节,但该数组之后的内存完全未指定。这可能会使您的程序崩溃,或将随机数据放入您的缓冲区。

    glBufferSubData(bufferNames[0], sizeof(GLfloat) * 12, sizeof(GLfloat)*24, colors);
    

    这只会产生GL_INVALID_ENUM 错误,因为glBufferSubData 的第一个参数是绑定目标(如GL_ARRAY_BUFFER)。因此,您永远不会将颜色数据传输到缓冲区中。您需要在此处使用 DSA 变体 glNamedBufferSubData

    【讨论】:

    • 切换到使用 glNamedBufferSubData 并没有解决问题,所以我认为结合顶点和颜色可能会更好,并通过将顶点数组设置为 6x4 而不是将顶点扩展为 vec4s 6x2,然后在最后添加颜色。通过这种方式,glNamedBufferStorage 无需在末尾添加颜色即可获得所有内容。
    • 更新了帖子以显示新代码,尽管它仍然没有颜色。
    【解决方案2】:

    原来问题出在程序上,当着色器被加载时,它使用了一个程序变量,该变量从我用于该部分的教程中被烘焙到加载例程中,我完全忘记了作为引用传递给的程序变量loadShaders 函数。一旦代码被改正为使用 prog 引用,所有的颜色都进来了!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-10
      • 2021-09-08
      • 1970-01-01
      • 2021-01-02
      • 1970-01-01
      • 1970-01-01
      • 2013-07-30
      • 2021-04-27
      相关资源
      最近更新 更多