Чтение image1d в проблеме фрагментного шейдера - PullRequest
0 голосов
/ 31 октября 2018

Я пытаюсь прочитать соответствующий цвет для каждой ячейки диаграммы Вороного в фрагментном шейдере из sampler1D, и в результате получается:

Voronoi Diagram

Затем я создаю матрицу обзора и перспективы и перемещаю камеру по оси z и x с помощью клавиатуры, и если я перемещаюсь по оси x, каждая ячейка по-прежнему имеет свой соответствующий цвет, но когда я двигаюсь по оси z похоже, он теряет индексы для созданного мной цветового буфера:

диаграмма Вороного перед перемещением по оси z Voronoi Diagram with camera, before moving on the z axis

Диаграмма Вороного после перемещения по оси z Voronoi Diagram with camera, after moving on the z axis

поэтому, чтобы проверить, теряю ли я индексы в фрагментном шейдере после перемещения по оси z с камерой, я попытался отладить свой фрагментный шейдер, используя индекс каждой точки (сгенерированный случайным образом на стороне клиента) в качестве цвет для каждой клетки, вот так (я генерирую 5 баллов):

диаграмма Вороного с камерой перед перемещением по оси z с использованием индекса в качестве цвета Voronoi Diagram with camera, before moving on the z axis using the index as the color

и

диаграмма Вороного с камерой, после перемещения по оси 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 голосов
/ 31 октября 2018

Ваша проблема возникает из-за того, что вы выбираете цвета на экранном пространстве, используя координаты фрагментов, которые останутся постоянными при любом увеличении (они всегда будут вашими оконными координатами). Таким образом, когда вы выполняете масштабирование, вы фактически не увеличиваете масштаб, а просто уменьшаете диапазон индексов, которые будут отсчитывать эти координаты фрагмента. На первом этапе вы должны сэмплировать цвета и сохранить их в буфере g, как это делается с индексами.

...