我正在制作一个体素引擎,我可以渲染一大块。我正在使用实例渲染,这意味着我可以使用单个绘制调用渲染所有块。块中的每个块都有一个int(从0到4095),用于定义块类型(0表示空气,1表示污垢等)。我想通过在片段着色器中应用好的纹理来渲染我的块。我的块包含一个三维数组:
uint8_t blocks[16][16][16]
问题是我找不到将我的int数组发送到着色器的方法。我尝试使用VBO,但没有任何意义(我没有得到任何结果)。我也尝试用glUniform1iv()发送我的数组但是我失败了。
答案 0 :(得分:3)
对于所有目的和意图,此类数据应被视为纹理数据。这并不意味着按字面意思将其作为纹理数据上传,而是考虑如何转移它时应该使用的思维框架。
或者,更基本的术语:不要尝试将此数据作为统一数据传递。
如果您可以访问OpenGL 4.3+(对于大多数不超过6 - 8年的硬件来说,合理安全的赌注),那么Shader存储缓冲区将是最简洁的解决方案:
//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
(或您更新缓冲区数据的首选方法),然后您就可以了
如果你只限于较旧的硬件,你确实有一些选择,但它们很快变得笨重:
答案 1 :(得分:1)
我按照@Xirema's answer中的方法做了第二种方法,但提出的建议略有不同。由于您的原始数据类型仅为uint8_t
,因此直接使用SSBO或UBO将要求每个元素浪费3个字节或手动将4个元素打包到单个uint
中。来自@Xirema的回答:
对于所有目的和意图,此类数据应被视为纹理数据。这并不意味着将其作为纹理数据逐字上传,而是在考虑如何转移它时应该使用的思维框架。
我完全同意。因此,我建议使用Texture Buffer Object (TBO), (a.k.a. "Buffer Texture")。
使用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以来可用的优势。