使用片段着色器写入 1D 纹理后从 1D 纹理读回不起作用

Reading back from 1D textures after writing into it with a fragment shader is not working

本文关键字:1D 纹理 不起作用 片段      更新时间:2023-10-16

我正在尝试使用 imageStore(( 函数检索我在片段着色器中的 1D 纹理中写入的值。我正在生成随机点并在片段着色器中进行处理,以使用圆周生成 delaunay 三角测量。当我生成一定大小的点(小于 30(时,从纹理读取是有效的,但是当我增加大小时,它返回零。 这是我存储的片段着色器的一部分:

uniform layout(binding = 1, rgba32f) writeonly image1D tex1;
… // more code
if (flag)
{
color = vec3(0.0, 1.0, 0.0);
int index = 0;
for (int i = 0; i < b; i++)
index += (size - i - 1) * i;
index += a * (size - b - 1) + (i_uv.x + 1) - 1;
imageStore(tex1, index, vec4(a, b, c, 1.0));
}

我的应用代码是这样的:

imageSize = 0;
int stride{ size - 1 };
for (size_t i{ 0 }; i < size - 1; i++)
imageSize += (stride - i) * i;
glCreateTextures(GL_TEXTURE_1D, 1, &image);
glTextureStorage1D(image, 1, GL_RGBA32F, imageSize);
pixels = new vec4[imageSize];
//Reading back from texture (This part goes outside my game loop)
glBindImageTexture(1, image, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
shaderFBO.use();
shaderFBO.setUniformi(ShaderType::FRAGMENT_SHADER, 0, size);
shaderFBO.setUniform2v(ShaderType::FRAGMENT_SHADER, 1, vec2(Window::current->getWidth(), Window::current->getHeight()));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_TEXTURE_FETCH_BARRIER_BIT);
glBindTexture(GL_TEXTURE_1D, image);
glGetTexImage(GL_TEXTURE_1D, 0, GL_RGBA, GL_FLOAT, pixels);
std::cout << "nTexture valuesn";
size_t count{ 0 };
for (size_t i{ 0 }; i < imageSize; i++)
{
if (pixels[i].a != 0)
{
std::cout << pixels[i] << std::endl;
count++;
}
}
std::cout << count << std::endl;

编辑: 我将放置我的完整顶点和片段着色器,以及应用程序代码来帮助我检查我是否错过了相关内容

顶点着色器:

#version 450 core
out gl_PerVertex
{
vec4 gl_Position;
};
void main()
{
vec2 p[4] = vec2[4]
(
vec2(-1.0, -1.0),
vec2( 1.0, -1.0),
vec2(-1.0,  1.0),
vec2( 1.0,  1.0)
);
gl_Position = vec4(p[gl_VertexID], 0.0, 1.0);
}

片段着色器:

#version 450 core
out vec4 FragColor;
layout(binding = 0) uniform sampler1D tex0; // Buffer storing random points
uniform layout(binding = 1, rgba32f) writeonly image1D tex1; // Buffer to store the indices of legal triangles
layout(location = 0) uniform int size;
layout(location = 1) uniform vec2 u_resolution;
vec2 circumcenter(vec2 A, vec2 B, vec2 C, out bool f)
{
vec2 P1 = (A + B) / 2.0;
vec2 P2 = (A + C) / 2.0;
float a1 = -A.x + B.x;
float b1 = A.y - B.y;
float a2 = -A.x + C.x;
float b2 = A.y - C.y;
float c1 = a1*P1.x - b1*P1.y;
float c2 = a2*P2.x - b2*P2.y;
float det = a1*b2 - a2*b1;
vec2 circum = vec2(0.0);
f = false;
if (det != 0)
{
float x = (b2*c1 - b1*c2) / det;
float y = (a2*c1 - a1*c2) / det;
circum = vec2(x, y);
f = true;
}
return circum;
}
void main()
{
vec2 st = gl_FragCoord.xy / u_resolution;
ivec2 i_st = ivec2(floor(st * size));
vec2 f_st = fract(st * size);
vec3 color = vec3(0.0);
if (i_st.y > i_st.x && i_st.y < size - 1)
{
// Positions of the random points buffer (a, b, c)
int a = i_st.x;
int b = i_st.y;
ivec2 i_uv = ivec2(floor(f_st * (size - b - 1)));
int c = i_uv.x + b + 1;
// Points of the triangle
vec2 A = texelFetch(tex0, a, 0).xy;
vec2 B = texelFetch(tex0, b, 0).xy;
vec2 C = texelFetch(tex0, c, 0).xy;
bool flag;
vec2 cir = circumcenter(A, B, C, flag);
if (flag)
{
float radius = distance(cir, A);
// Checking if any other point is inside of the circumscribe circle
for (int i = 0; i < size; i++)
{
if (i == a || i == b || i == c)
continue;
vec2 P = texelFetch(tex0, i, 0).xy;
float dist = distance(cir, P);
if (dist < radius)
{
flag = false;
break;
}
}
if (flag)
{
color = vec3(0.0, 1.0, 0.0); // Painting the fargments that correspond to legal triangles
int index = 0;
for (int i = 0; i < b; i++)
index += (size - i - 1) * i;
index += a * (size - b - 1) + (i_uv.x + 1) - 1;
memoryBarrier();
imageStore(tex1, index, vec4(a, b, c, 1.0)); // Storing indices of legal triangles
}
}
}
else 
color += 1.0;
FragColor = vec4(color, 0.0);
}

应用代码:

#include "../../Classes/Renderer/Core.h"
#include "../../Classes/Renderer/Shader.h"
#include "../../Classes/Renderer/Input.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
class DT
: public Core
{
public:
virtual void Start() override
{
srand(time(nullptr));
shader.addShader("C:/dev/RendererOpenGL/RendererOpenGL/src/Tesis/simpleTri.vert", ShaderType::VERTEX_SHADER);
shader.addShader("C:/dev/RendererOpenGL/RendererOpenGL/src/Tesis/simpleTri.frag", ShaderType::FRAGMENT_SHADER);
// Compute Buffer size to store indices of legal triangles
imageSize = 0;
int stride{ size - 1 };
for (size_t i{ 0 }; i < size - 1; i++)
imageSize += (stride - i) * i;
glCreateTextures(GL_TEXTURE_1D, 1, &image);
glTextureStorage1D(image, 1, GL_RGBA32F, imageSize);
pixels = new vec4[imageSize];
glCreateTextures(GL_TEXTURE_1D, 1, &texture1D);
glTextureStorage1D(texture1D, 1, GL_RG32F, size);
data = new vec2[size];
// Genereating random points
for (size_t i{ 0 }; i < size; i++)
{
float x = static_cast<float>(rand()) / RAND_MAX;
float y = static_cast<float>(rand()) / RAND_MAX;
data[i] = vec2(x, y);
//std::cout << i << ": " << data[i] << std::endl;
}
glTextureSubImage1D(texture1D, 0, 0, size, GL_RG, GL_FLOAT, data);
glBindTextureUnit(0, texture1D);
glBindTexture(GL_TEXTURE_1D, texture1D);
glBindImageTexture(1, image, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
// Rendering once to compute legal triangles
shader.use();
shader.setUniformi(ShaderType::FRAGMENT_SHADER, 0, size);
shader.setUniform2v(ShaderType::FRAGMENT_SHADER, 1, vec2(Window::current->getWidth(), Window::current->getHeight()));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
glBindTexture(GL_TEXTURE_1D, image);
glGetTexImage(GL_TEXTURE_1D, 0, GL_RGBA, GL_FLOAT, pixels);

std::cout << "nTexture valuesn";
size_t count = 0;
for (size_t i{ 0 }; i < imageSize; i++)
{
if (pixels[i].a != 0)
{
std::cout << pixels[i] << std::endl;
count++;
}
}
std::cout << count << std::endl;
}
virtual void Update() override
{
}
virtual void End() override
{
shader.delete_shader();
glDeleteTextures(1, &texture1D);
glDeleteTextures(1, &imageSize);
delete[] data;
delete[] pixels;
}
private:
Shader shader;
vec2* data;
const int size{ 20 };
GLuint texture1D;
GLuint image;
size_t imageSize;
vec4 *pixels;
};
#if 1
CORE_MAIN(DT)
#endif

输出: 绿色矩形是合法三角形和 这是从 1D 纹理中检索到的值。glGetTexImage(( 不会检索任何超过 50 个点的数据,对于 30 到 49 个点,我丢失了数据,但少于 30 个点时,我得到了正确数量的三角形。

您使用了错误的内存屏障。您必须指定在屏障之后打算如何使用内存。

您正在使用glGetTexImage来访问数据,因此根据OpenGL 4.6核心配置文件规范第7.13节"着色器内存访问",您必须使用(强调我的(:

TEXTURE_UPDATE_BARRIER_BIT: 写入 通过Tex(Sub)Image*ClearTex*ImageCopyTex*CompressedTex*的纹理, 并在屏障不会执行后通过GetTexImage读取直到在屏障完成之前启动所有着色器写入。