我正在尝试从sampler1D读取片段着色器中的voronoi图的每个单元格对应的颜色,结果是:
然后,我创建一个外观和透视矩阵,并使用键盘在z和x轴上移动相机,如果我在x轴上移动,则每个单元格仍具有其相应的颜色,但是当我在z轴上移动时似乎它丢失了我创建的颜色缓冲区的索引:
所以要检查我在用相机在z轴上移动后是否丢失片段着色器中的索引,我尝试使用每个点的索引(在客户端随机生成)作为片段来调试片段着色器每个单元格的颜色,像这样(我正在生成5个点):
带照相机的Voronoi图,然后使用索引作为颜色在z轴上移动
和
它可以正常工作,并且不会丢失每个单元格的索引,但是我希望能够从我创建的纹理中读取颜色。
这是我的客户代码:
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
}
答案 0 :(得分:0)
发生您的问题是因为您正在使用碎片坐标对屏幕空间上的颜色进行采样,无论您执行什么缩放,碎片坐标都将保持不变(它们始终是窗口坐标)。因此,执行缩放时,不会得到实际的缩放,而只是减小这些片段坐标将采样的索引范围。您应该在第一阶段对颜色进行采样,然后像处理索引一样将它们存储在g缓冲区中。