Home > Software design >  What is causing the lack of color from fragment shader output?
What is causing the lack of color from fragment shader output?

Time:12-18

I have a "Hello Triangle" program I'm working on and can't for the life of me figure out why there is no color coming from the fragment shader. What is causing all fragments to output as white? I'm on Visual Studio 2019, program compiles just fine, and stepping through the debugger yields no results. I'm assuming the error is either in GLSL or my vertex attribute plumbing. Vertex Shader:

#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;
}

Fragment Shader:

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

Main:

#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();
}

CodePudding user response:

That is just undefined behavoir:

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

You tell the GL to read sizeof(vertices) sizeof(colors) bytes beginning from the vertex array, but the memory after that array is completely unspecified. This might crash your program, or put random data into your buffer.

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

This will just generate a GL_INVALID_ENUM error as glBufferSubData's first parameter is the binding target (like GL_ARRAY_BUFFER). So you never transfer the color data into the buffer. You need to use the DSA variant glNamedBufferSubData here.

CodePudding user response:

Turns out the issue was with the program, when shaders were loaded it used a program variable that was baked into the load routine from the tutorial I used for that part, and I completely forgot about the program variable that passed as reference into the loadShaders function. Once the code was corrected to use the prog reference instead, all of the color came in!

  • Related