无法弄清楚如何在 OpenGL 的 2D 片段着色器中从 1D 采样器采样

问题描述 投票:0回答:1

对于我正在使用 C++ 进行的 OpenGL 项目,我正在尝试将距离信息编码到一维缓冲区中,我真的很想为此使用无符号整数。我创建了一个调试步骤将缓冲区的内容导出到一个文件,这表明它正在成功写入,但是我无法从片段着色器中读取帧缓冲区纹理的内容。着色器本身都是接近文件的顶部。

对于这个测试程序,我的目标是绘制一个简单的渐变(用 UV 完成)到 1D 帧缓冲区,然后从片段着色器读取它并将它绘制到屏幕上。澄清一下,我知道如何制作基本的紫外线渐变。这不是我的实际目标,我的目标是写入无符号整数的一维缓冲区,然后从中读取。*

这是程序的实际输出:Output 这是我要复制的模型:Mockup 这是我渲染后写入的“buffer.bin”文件内容的截图:buffer.bin

这是一个 345 行的文件。抱歉缺乏可读性和大量冗余,为了减少潜在的错误来源,我创建了第二个项目。但是,我需要强调一点:此处发布的代码与我无法正常工作的代码完全相同,并且我没有为了保密而隐藏任何内容。鉴于安装了 SDL 和 GLEW,它应该在 Linux 或 Windows 上编译得很好(在 gcc 下测试)。

main.cpp(只有一个文件)

#include <iostream>
#include <SDL2/SDL.h>
#include <GL/glew.h>
#include <SDL_opengl.h>
#include <fstream>
#include <iostream>
#include <filesystem>
#include <initializer_list>
#include <exception>
#include <stdexcept>
#include <type_traits>
#include <SDL2/SDL.h>
#include <SDL2/SDL_main.h>
#include <GL/glew.h>

typedef union SizeVec2 {
    struct {
        size_t x = 0, y = 0;
    };
    struct { size_t w, h; };
} SizeVec2;

using namespace std;

SDL_Window* window = nullptr;
SDL_GLContext context;
bool isRunning = true;
SizeVec2 windowSize = { 640, 640 };

bool init() {
    if (SDL_Init(SDL_INIT_EVERYTHING) < 0 ) {
        SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize SDL: %s", SDL_GetError());
        return false;
    }
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
    window = SDL_CreateWindow("OpenGL Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, (int)windowSize.w, (int)windowSize.h, SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
    if (window == nullptr) {
        SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Failed to create window: %s", SDL_GetError());
        return false;
    }

    context = SDL_GL_CreateContext(window);
    if (context == nullptr) {
        SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Failed to create OpenGL context: %s", SDL_GetError());
        return false;
    }

    GLenum ret = glewInit();
    if (ret) {
        SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "glewInit() = %u", ret);
        return false;
    }

    return true;
}

const char* vertShaderSrc = "#version 330 core\n"
                            "layout (location = 0) in vec2 aPosition;\n"
                            "layout (location = 1) in vec2 aTexCoord;\n"
                            "out vec2 texCoord;\n"
                            "\n"
                            "void main() {\n"
                            "    texCoord = aTexCoord;\n"
                            "    gl_Position = vec4(aPosition, 0.0, 1.0);\n"
                            "}";

// ignore this
const char* fragShaderSrc_shadowPass1 = "#version 420 core\n"
                                        "in vec2 texCoord;\n"
                                        "out float fragColor;\n"
                                        "uniform sampler2D occludersTexture;\n";

const char* fragShaderSrc_shadowPass2 = "#version 420 core\n"

                                        "in vec2 texCoord;\n"
                                        "layout(location = 0) out uint fragDistance;\n"
                                        // NOTE: if it weren't for this being a test, this would be taking input from pass 1
                                        "uniform sampler2D polarOccludersTexture;\n"

                                        "void main() {\n"
                                        "    fragDistance = uint(texCoord.x * 256.0);\n"
                                        "}";

const char* fragShaderSrc_shadowPass3 = "#version 420 core\n"

                                        "in vec2 texCoord;\n"
                                        "out vec4 fragColor;\n"
                                        "uniform usampler1D shadowMap;\n"

                                        "void main() {\n"
                                        //                                        "    int shadowMapWidth = textureSize(shadowMap, 0);\n"
                                        "    uvec4 samp = texture(shadowMap, texCoord.x);\n"
                                        "    uint msamp = max(samp.r, max(samp.g, max(samp.b, samp.a)));"
                                        "    fragColor = vec4(float(samp.r) / 256.0, 0.1, 0.0, 1.0);\n"
                                        //                                        "    fragColor = vec4(texCoord, 0.0, 1.0);\n"
                                        //                                        "    fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
                                        "}";

GLuint vertexShader = 0, fragShader_shadowPass1 = 0, fragShader_shadowPass2 = 0, fragShader_shadowPass3 = 0;
GLuint prog_shadowPass1 = 0, prog_shadowPass2 = 0, prog_shadowPass3 = 0;

GLuint fbo_shadowPass[] = { 0, 0, 0 };
GLuint fbt_shadowPass[] = { 0, 0, 0 };

GLfloat screenVertices[16] = {
    -1.f, 1.f,    0.0f, 0.0f, // tl
    1.f, 1.f,     1.0f, 0.0f, // tr
    -1.f, -1.f,   0.0f, 1.0f, // bl
    1.f, -1.f,    1.0f, 1.0f, // br
};

GLuint screenIndices[] = {
    0, 1, 2, // tl
    3, 2, 1, // br
};

GLuint screenVao = 0, screenVbo = 0, screenEbo = 0;

void tick() {

    SDL_Event ev;
    while (SDL_PollEvent(&ev)) {
        switch (ev.type) {
            case SDL_QUIT: {
                isRunning = false;
                return;
                break;
            }
        }
    }

    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_shadowPass[1]);
    glDisable(GL_BLEND);
    GLenum a = GL_COLOR_ATTACHMENT0;
    glDrawBuffers(1, &a);
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, fbt_shadowPass[0]);
    glUseProgram(prog_shadowPass2);
    glUniform1i(glGetUniformLocation(prog_shadowPass2, "polarOccludersTexture"), 1);
    glBindVertexArray(screenVao);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);

    void* buf = malloc(sizeof(unsigned int) * windowSize.w);
    glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_shadowPass[1]);
//    glReadPixels(0, 0, 640, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, buf);
//    glReadPixels(0, 0, (GLsizei)windowSize.w, 1, GL_RED, GL_UNSIGNED_INT, buf);
    glReadPixels(0, 0, (GLsizei)windowSize.w, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, buf);
    ofstream writeout{"buffer.bin"};
    writeout.write((const char *)(buf), (streamsize)(sizeof(unsigned int) * windowSize.w));
    writeout.flush();
    writeout.close();
    free(buf);
    SDL_GL_SwapWindow(window);
    GLenum e = glGetError();
    if (e != 0) SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "%x %s", e, glewGetErrorString(e));

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_shadowPass[1]);
    glClearColor(0.0, 0.0, 0.5, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_1D, fbt_shadowPass[1]);
//    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glUniform1i(glGetUniformLocation(prog_shadowPass3, "shadowMap"), 2);
    glUseProgram(prog_shadowPass3);
    glBindVertexArray(screenVao);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);

    SDL_GL_SwapWindow(window);
    GLenum err = glGetError();
    if (err != 0) SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "%x %s", err, glewGetErrorString(err));

    SDL_Delay(5000);
    exit(0);
}

int main(int argc, char* argv[]) {
    SDL_Log("running");
    if (!init()) return 1;
#ifdef NDEBUG
    SDL_LogSetAllPriority(SDL_LOG_PRIORITY_DEBUG);
#endif
    SDL_Log("initialized");

    size_t vertexCount = 16;
    size_t verticesSize = vertexCount * sizeof(GLfloat);
    size_t indexCount = 6;
    size_t indexesSize = indexCount * sizeof(GLuint);
    glGenVertexArrays(1, &screenVao);
    glGenBuffers(1, &screenVbo);
    glGenBuffers(1, &screenEbo);
    glBindVertexArray(screenVao);
    glBindBuffer(GL_ARRAY_BUFFER, screenVbo);
    glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)verticesSize, screenVertices, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screenEbo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)indexesSize, screenIndices, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, screenVbo);
    // specify vertex positions
    glVertexAttribPointer(
        0, // index
        2, // size
        GL_FLOAT, // type
        GL_FALSE, // normalized
        4 * sizeof(float), // stride
        nullptr // pointer
    );
    glEnableVertexAttribArray(0);
    // specify UV attribute
    glVertexAttribPointer(
        1, // index
        2, // size
        GL_FLOAT, // type
        GL_TRUE, // normalized
        4 * sizeof(float), // stride
        (void*)(2 * sizeof(float)) // pointer
    );
    glEnableVertexAttribArray(1);

    glGenFramebuffers(3, fbo_shadowPass);
    glGenTextures(3, fbt_shadowPass);

    glBindFramebuffer(GL_FRAMEBUFFER, fbo_shadowPass[1]);
    glBindTexture(GL_TEXTURE_1D,  fbt_shadowPass[1]);
    glTexImage1D(GL_TEXTURE_1D, 0, GL_R32UI, (GLsizei)windowSize.w, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, nullptr);
    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_1D, fbt_shadowPass[1], 0);
    if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) SDL_Log("Framebuffer 2 incomplete!");

    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    fragShader_shadowPass1 = glCreateShader(GL_FRAGMENT_SHADER);
    fragShader_shadowPass2 = glCreateShader(GL_FRAGMENT_SHADER);
    fragShader_shadowPass3 = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(vertexShader,           1, (const GLchar* const*)&vertShaderSrc,             nullptr);
    glCompileShader(vertexShader);
    glShaderSource(fragShader_shadowPass1, 1, (const GLchar* const*)&fragShaderSrc_shadowPass1, nullptr);
    glCompileShader(fragShader_shadowPass1);
    glShaderSource(fragShader_shadowPass2, 1, (const GLchar* const*)&fragShaderSrc_shadowPass2, nullptr);
    glCompileShader(fragShader_shadowPass2);
    glShaderSource(fragShader_shadowPass3, 1, (const GLchar* const*)&fragShaderSrc_shadowPass3, nullptr);
    glCompileShader(fragShader_shadowPass3);
    // check err
    prog_shadowPass1 = glCreateProgram();
    glAttachShader(prog_shadowPass1, vertexShader);
    glAttachShader(prog_shadowPass1, fragShader_shadowPass1);
    glLinkProgram(prog_shadowPass1);
    prog_shadowPass2 = glCreateProgram();
    glAttachShader(prog_shadowPass2, vertexShader);
    glAttachShader(prog_shadowPass2, fragShader_shadowPass2);
    glLinkProgram(prog_shadowPass2);
    prog_shadowPass3 = glCreateProgram();
    glAttachShader(prog_shadowPass3, vertexShader);
    glAttachShader(prog_shadowPass3, fragShader_shadowPass3);
    glLinkProgram(prog_shadowPass3);

    GLuint shaders[4] = { vertexShader, fragShader_shadowPass1, fragShader_shadowPass2,fragShader_shadowPass3};
    for (int i = 0; i < 4; i++) {
        GLint compiled = 0;
        glGetShaderiv(shaders[i], GL_COMPILE_STATUS, &compiled);
        if (!compiled) {
            GLint infoLen = 0;
            glGetShaderiv(shaders[i], GL_INFO_LOG_LENGTH, &infoLen);
            if (infoLen > 1) {
                char *infoLog = (char *) malloc(infoLen * sizeof(char));
                glGetShaderInfoLog(shaders[i], infoLen, nullptr, infoLog);
                SDL_Log("Error compiling shader %i: %s", i, infoLog);
                ::free(infoLog);
            } else SDL_Log("Error compiling shader %i (no further information)", i);
            return 1;
        }
    }

    GLuint progs[3] = { prog_shadowPass1, prog_shadowPass2, prog_shadowPass3};

    for (int i = 0; i < 3; i++) {
        GLint linked;
        glGetProgramiv(progs[i], GL_LINK_STATUS, &linked);
        if (!linked) {
            GLint infoLen = 0;
            glGetProgramiv(progs[i], GL_INFO_LOG_LENGTH, &infoLen);
            if (infoLen > 1) {
                char *infoLog = (char *) malloc(sizeof(char) * infoLen);
                glGetProgramInfoLog(progs[i], infoLen, nullptr, infoLog);
                SDL_Log("Error linking program %i: %s", i, infoLog);
                ::free(infoLog);
            }
            SDL_Log("Error linking program %i (no further information)", i);
            glDeleteProgram(progs[i]);
            return 1;
        }
    }

    while (isRunning) tick();

    SDL_Log("shutting down");

    SDL_Quit();

    SDL_Log("goodnight");
    return 0;
}
c++ opengl glsl sdl glew
1个回答
0
投票

罪魁祸首是

glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);

因为您只生成了 1D 纹理的基本级别,并且由于某种原因“最近的 mipmap”在渲染时不是级别 0,所以着色器尝试对未分配的数据进行采样,每次都为您提供 0 值。

手动生成 mipmap 或使用 glGenerateMipmap - OpenGL 4 参考页,或者将您的最小过滤器更改为

GL_NEAREST
.

© www.soinside.com 2019 - 2024. All rights reserved.