如何将 int 数组发送到我的着色器
How to send an array of int to my shader
我正在制作一个体素引擎,我可以渲染一个块。我正在使用实例化渲染,这意味着我可以通过单个绘制调用渲染所有块。块的每个块都有一个 int(从 0 到 4095(来定义他的块类型(0 表示空气,1 表示污垢等(。我希望能够通过在我的片段着色器中应用良好的纹理来渲染我的块。我的块包含一个三维数组:
uint8_t blocks[16][16][16]
问题是我找不到将我的 int 数组发送到着色器的方法。我尝试使用VBO,但它没有意义(我没有得到任何结果(。我也尝试用glUniform1iv((发送我的数组,但我失败了。
- 是否可以使用 glUniformX(( 将 int 数组发送到着色器?
- 为了防止存储大数据,我可以用glUniformX((设置一个字节(uint8_t(而不是int吗?
- 有没有一种好方法可以将这么多数据发送到我的着色器?
- 实例化绘制是绘制具有不同纹理/块类型的相同模型的好方法。
出于所有目的和意图,这种类型的数据应被视为纹理数据。这并不意味着从字面上将其作为纹理数据上传,而是在考虑如何传输它时应该使用的思维框架。
或者,用更基本的术语来说:不要尝试将此数据作为统一数据传递。
如果您可以访问OpenGL 4.3+(对于大多数不超过6-8年的硬件来说,这是一个相当安全的选择(,那么Shader Storage Buffers将是最简洁的解决方案:
//GLSL:
layout(std430, binding = 0) buffer terrainData
{
int data[16][16][16];
};
void main() {
int terrainType = data[voxel.x][voxel.y][voxel.z];
//Do whatever
}
//HOST:
struct terrain_data {
int data[16][16][16];
};
//....
terrain_data data = get_terrain_data();
GLuint ssbo;
GLuint binding = 0;//Should be equal to the binding specified in the shader code
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, GLsizeiptr size, data.data, GLenum usage);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
在此之后需要更新数据的任何时间点,只需绑定ssbo
,调用glBufferData
(或更新缓冲区数据的首选方法(,然后就可以开始了。
如果您仅限于较旧的硬件,则确实有一些选择,但它们很快就会变得笨重:
- 您可以使用统一缓冲区,其行为与着色器存储缓冲区非常相似,但
- 存储空间有限(大多数实现为 65kb(
- 有其他可能与您的用例相关也可能无关的限制
- 可以直接使用纹理,将地形数据转换为浮点值(如果硬件内部支持整数格式,则用作整数(,然后在着色器中转换回
- 与几乎任何硬件兼容
- 但着色器代码中需要额外的复杂性和计算
我支持@Xirema回答中列出的方法,但得出的建议略有不同。由于您的原始数据类型只是uint8_t
,因此直接使用 SSBO 或 UBO 将需要为每个元素浪费 3 个字节或手动将 4 个元素打包到一个uint
中。从@Xirema的回答:
出于所有目的和意图,此类数据应被视为纹理数据。这并不意味着从字面上将其作为纹理数据上传,而是在考虑如何传输它时应该使用的思维框架。
我完全同意这一点。因此,我建议使用纹理缓冲区对象(TBO((又名"缓冲区纹理"(。 使用glTexBuffer()
基本上可以将缓冲区对象重新解释为纹理。在您的情况下,您可以将uint8_t[16][16][16]
数组打包到缓冲区中,并将其解释为GL_R8UI
"纹理"格式,如下所示:
//GLSL:
uniform usamplerBuffer terrainData;
void main() {
uint terrainType = texelFetch(terrainData, voxel.z * (16*16) + voxel.y * 16 + voxel.x).r
//Do whatever
}
//HOST:
struct terrain_data {
uint8_t data[16][16][16];
};
//....
terrain_data data = get_terrain_data();
GLuint tbo;
GLuint tex;
glGenBuffers(1, &tbo);
glBindBuffer(GL_TEXTURE_BUFFER, tbo);
glBufferData(GL_TEXTURE_BUFFER, sizeof(terrain_data), data.data, usage);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_BUFFER, tex);
glTexBuffer(GL_TEXTURE_BUFFER, GL_R8UI, tbo);
请注意,这不会将数据复制到某个纹理对象。访问纹理意味着直接访问缓冲区的内存。
TBO还有一个优势,即它们从OpenGL 3.1开始可用。
- 我的 int main() 中出现堆栈溢出错误
- 我从int x[3]得到的一个非常奇怪的输出;
- 错误:从"int"到"int*"的转换无效[-允许].我在下面提供了我的代码,我
- 我的运算符重载没有在我的 int main 中返回?
- 为什么我的 std::atomic<int> 变量不是线程安全的?
- 如何将 int 数组发送到我的着色器
- 为什么我的 int 在 C++ 程序中间发生了变化?
- 当我使用长整型时,我的代码不起作用,它与 int 一起工作得很好
- 为什么我的代码无法将字符串正确转换为 int 数组?
- 我如何转换一个基于动态的,基于指针的int堆栈,以便将其打印成字符串
- 无法将 int 类型转换为时间类型(我的类类型)
- 如何让我的构造函数和函数工作,以便我的 main() 能够同时显示字符串和 int 数据
- 在我的项目中包括eigen将标准INT定义为eigen :: denseIndex-如何使用正常INT
- 为什么我的算术与长 int 的行为是这样的?
- Int 附加到字符,行为不符合我的预期
- 我应该把我的枚举放在我的 int main() 外面还是里面
- 如何将函数从另一个.cpp文件调用到我的 int main() 所在的文件中
- 我的 int main(){} 有问题
- c++字符串输入打破了我的int cin
- 我的int到hex函数出了什么问题