在片段着色器问题中读取image1d

时间:2018-10-31 04:01:34

标签: c++ opengl graphics glsl shader

我正在尝试从sampler1D读取片段着色器中的voronoi图的每个单元格对应的颜色,结果是:

Voronoi Diagram

然后,我创建一个外观和透视矩阵,并使用键盘在z和x轴上移动相机,如果我在x轴上移动,则每个单元格仍具有其相应的颜色,但是当我在z轴上移动时似乎它丢失了我创建的颜色缓冲区的索引:

沿z轴移动之前的Vooroioi图 Voronoi Diagram with camera, before moving on the z axis

沿z轴移动后的Voronoi图 Voronoi Diagram with camera, after moving on the z axis

所以要检查我在用相机在z轴上移动后是否丢失片段着色器中的索引,我尝试使用每个点的索引(在客户端随机生成)作为片段来调试片段着色器每个单元格的颜色,像这样(我正在生成5个点):

带照相机的Voronoi图,然后使用索引作为颜色在z轴上移动 Voronoi Diagram with camera, before moving on the z axis using the index as the color

带照相机的Voronoi图,使用索引作为颜色在z轴上移动后 Voronoi Diagram with camera, after moving on the z axis using the index as the color

它可以正常工作,并且不会丢失每个单元格的索引,但是我希望能够从我创建的纹理中读取颜色。

这是我的客户代码:

class VoronoiJFA
    : public Core
{
public:
    VoronoiJFA()
        : Core(512, 512, "VoronoiJFA"), size_space(512)
    {}

    virtual void Start() override
    {
        srand(time(nullptr));

        shader_points = new Shader("draw_points.vert", "draw_points.frag");
        shader_voronoi_jfa = new Shader("voronoi_jfa.vert", "voronoi_jfa.frag");
        shader_display_voronoi = new Shader("display_voronoi.vert", "display_voronoi.frag");

        size_points = 5;
        size_triangles = 16000;

        eye = vec3(0.0f, 0.0f, 3.0f);
        target = vec3(0.0f, 0.0f, -1.0f);
        up = vec3(0.0f, 1.0f, 0.0f);

        vec4* p = new vec4[size_points];
        vec4* c = new vec4[size_points];
        // Generating  random point for voronoi diagram
        for (size_t i{ 0 }; i < size_points; i++)
        {
            float x{ (float(rand()) / RAND_MAX * 2.0f - 1.0f) };
            float y{ (float(rand()) / RAND_MAX * 2.0f - 1.0f) };
            //the "i" variable is used to store the index of each point to reference the color in the display_voronoi.frag shader
            p[i] = vec4(x, y, 0.0f, i);

            float r{ float(rand()) / RAND_MAX };
            float g{ float(rand()) / RAND_MAX };
            float b{ float(rand()) / RAND_MAX };
            c[i] = vec4(r, g, b, 1.0f);
        }

        // The space_texture is where i'm gonna paint voronoi using offscreen rendering for voronoi JFA
        glCreateTextures(GL_TEXTURE_2D, 1, &space_texture);
        glTextureStorage2D(space_texture, 1, GL_RGBA32F, size_space, size_space);
        glBindImageTexture(0, space_texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);

        // Here i store the colors for each voronoi cell
        glCreateTextures(GL_TEXTURE_1D, 1, &colors_texture);
        glTextureStorage1D(colors_texture, 1, GL_RGBA32F, size_points);
        glTextureSubImage1D(colors_texture, 0, 0, size_points, GL_RGBA, GL_FLOAT, c);
        glBindTextureUnit(2, colors_texture);


        // This is the fbo for the offscreen rendering to draw generate voronoi
        glCreateFramebuffers(1, &framebuffer_object);
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
        glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, space_texture, 0);
        glDrawBuffer(GL_COLOR_ATTACHMENT0);

        glCreateBuffers(1, &vertex_buffer_points);
        glNamedBufferStorage(vertex_buffer_points, sizeof(vec4) * size_points, p, GL_DYNAMIC_STORAGE_BIT);
        glCreateVertexArrays(1, &vertex_array_points);
        glBindVertexArray(vertex_array_points);
        glVertexArrayAttribFormat(vertex_array_points, 0, 4, GL_FLOAT, GL_FALSE, 0);
        glEnableVertexArrayAttrib(vertex_array_points, 0);
        glVertexArrayAttribBinding(vertex_array_points, 0, 0);
        glVertexArrayVertexBuffer(vertex_array_points, 0, vertex_buffer_points, 0, sizeof(vec4));

        Window::current->setColor(vec4(-1000000000.0f));
        delete[] p;
        delete[] c;
    }

    virtual void Update() override
    {
        static float time{ 0.0f };
        time += Time::deltaTime;

        if (Input::getKeyDown(KeyCode::Escape))
            Window::current->shouldClose(true);

        // Camera controls
        if (Input::getKey(KeyCode::A))
            eye = eye - normalize(cross(target, up)) * Time::deltaTime * 1.0f;
        if (Input::getKey(KeyCode::D))
            eye = eye + normalize(cross(target, up)) * Time::deltaTime * 1.0f;
        if (Input::getKey(KeyCode::S))
            eye = eye - target * Time::deltaTime * 1.0f;
        if (Input::getKey(KeyCode::W))
            eye = eye + target * Time::deltaTime * 1.0f;

        mat4 M;
        mat4 V;
        V = mat4::lookAt(eye, eye + target, up); // Virtual camera
        mat4 P;
        P = mat4::perspective(radians(45.0f), float(Window::current->getWidth()) / Window::current->getHeight(), 0.1f, 100.0f); // projection matrix

        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
        vec4 distance(-1000000000.0f);
        glClearBufferfv(GL_COLOR, 0, &distance[0]);
        glViewport(0, 0, size_space, size_space);
        glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT | GL_TEXTURE_FETCH_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_TEXTURE_UPDATE_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT);
        shader_points->use(); // Here i just paint the points generated previously in a texture 2D
        glUniform1f(0, time);
        vec2 mouse = (vec2(Input::mousePosition.x, Input::mousePosition.y) / vec2(Window::current->getWidth(), Window::current->getHeight())) * 2.0f - 1.0f;
        glUniform2fv(1, 1, &mouse[0]);
        glUniformMatrix4fv(2, 1, GL_FALSE, &M[0][0]);
        glUniformMatrix4fv(3, 1, GL_FALSE, &V[0][0]);
        glUniformMatrix4fv(4, 1, GL_FALSE, &P[0][0]);
        glBindVertexArray(vertex_array_points);
        glDrawArrays(GL_POINTS, 0, size_points);
        glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT | GL_TEXTURE_FETCH_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_TEXTURE_UPDATE_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT);

        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glViewport(0, 0, size_space, size_space);
        int step{ size_space / 2 };
        while(step >= 1)
        {
            shader_voronoi_jfa->use(); // Here i compute the voronoi diagram using JFA
            glUniform1i(2, step);
            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
            glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT | GL_TEXTURE_FETCH_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_TEXTURE_UPDATE_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT);
            step /= 2;
        }
        step =  size_space / 2 ;
        while(step >= 1)
        {
            shader_voronoi_jfa->use(); // Again using JFA to eliminate "islands"
            glUniform1i(2, step);
            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
            glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT | GL_TEXTURE_FETCH_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_TEXTURE_UPDATE_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT);
            step /= 2;
        }

        glViewport(0, 0, Window::current->getWidth(), Window::current->getHeight());
        shader_display_voronoi->use(); // Display voronoi diagram
        glUniform1i(0, size_space);
        glUniform1i(1, size_points);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    virtual void End() override
    {
        delete shader_points;
        delete shader_voronoi_jfa;

        glDeleteBuffers(1, &vertex_buffer_points);
        glDeleteVertexArrays(1, &vertex_array_points);

        glDeleteTextures(1, &space_texture);
        glDeleteTextures(1, &colors_texture);


        glDeleteFramebuffers(1, &framebuffer_object);
    }

private:
    Shader* shader_points;
    Shader* shader_voronoi_jfa;
    Shader* shader_display_voronoi;

    GLuint vertex_buffer_points;
    GLuint vertex_array_points;

    GLuint space_texture;
    GLuint colors_texture;

    GLuint framebuffer_object;

    int size_space;
    int size_points;
    int size_triangles;

    vec3 eye;
    vec3 target;
    vec3 up;
};

#if 1
CORE_MAIN(VoronoiJFA)
#endif

我的着色器是这些:

draw_points.vert

#version 450 core

layout(location = 0) in vec4 a_points;

layout(binding = 1, rgba32f) uniform image1D image_points;

layout(location = 0) uniform float u_time;
layout(location = 1) uniform vec2 u_mouse;
layout(location = 2) uniform mat4 M;
layout(location = 3) uniform mat4 V;
layout(location = 4) uniform mat4 P;

out vec4 color;

void main()
{
    vec4 vertex = a_points;
    gl_Position = P * V * M * vec4(vertex.xy, 0.0, 1.0);
    color.x = vertex.a; // here i put the index of each point to reference the color
}

draw_points.frag

#version 450 core

in vec4 color;
out vec4 FragColor;

void main()
{
    // Here i paint the points with its corresponding fragcoord and in the alpha i'm storing the index of each point
    FragColor = vec4(gl_FragCoord.xy, 0.0, color.x);
}

display_voronoi.vert

#version 450 core

out vec2 uv;

void main()
{
    vec2 v[4] = vec2[4]
    (
        vec2(-1.0, -1.0),
        vec2( 1.0, -1.0),
        vec2(-1.0,  1.0),
        vec2( 1.0,  1.0)
    );

    vec4 p = vec4(v[gl_VertexID], 0.9998, 1.0);
    gl_Position = p;
}

display_voronoi.frag

#version 450 core

layout(binding = 0, rgba32f) uniform image2D space; // here it's voronoi    
layout(binding = 2) uniform sampler1D colors; // color buffer


layout(location = 0) uniform int u_spaceSize;
layout(location = 1) uniform int points_size;

out vec4 FragColor;

void main()
{
    float index = imageLoad(space, ivec2(gl_FragCoord.xy)).a; // here i get the index of each cell
    vec4 color = texelFetch(colors, int(index), 0); // using the index to get color     
FragColor = color; //vec4(index / (points_size - 1)); The commented part is my "debugger" if i use the index divided by the number of points, it paints in gray scale
}

1 个答案:

答案 0 :(得分:0)

发生您的问题是因为您正在使用碎片坐标对屏幕空间上的颜色进行采样,无论您执行什么缩放,碎片坐标都将保持不变(它们始终是窗口坐标)。因此,执行缩放时,不会得到实际的缩放,而只是减小这些片段坐标将采样的索引范围。您应该在第一阶段对颜色进行采样,然后像处理索引一样将它们存储在g缓冲区中。