Как отправить массив int в мой шейдер - PullRequest
0 голосов
/ 23 мая 2018

Я делаю воксельный движок и могу рендерить кусок.Я использую рендеринг экземпляров, а это означает, что я могу рендерить весь блок одним вызовом отрисовки.Каждый блок чанка имеет один тип int (от 0 до 4095), который определяет тип его блока (0 для воздуха, 1 для грязи и т. Д.).Я хочу иметь возможность визуализировать мой блок, применяя хорошую текстуру в моем фрагментном шейдере.Мой блок содержит трехмерный массив:

uint8_t blocks[16][16][16]

Проблема в том, что я не могу найти способ отправить массив int в шейдер.Я пытался использовать VBO, но это не имеет смысла (я не получил никакого результата).Я также пытался отправить свой массив с помощью glUniform1iv (), но мне не удалось.

  • Можно ли отправить массив int в шейдер с помощью glUniformX ()?
  • Для того, чтобыпредотвратить сохранение больших данных, могу ли я установить байт (uint8_t) вместо int с помощью glUniformX ()?
  • Есть ли хороший способ отправить столько данных в мой шейдер?
  • Является ли экземплярный рисунокхороший способ нарисовать одну и ту же модель с разными текстурами / типами блоков.

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Я повторяю подход, изложенный в @ ответ 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.

0 голосов
/ 23 мая 2018

Для всех целей и целей данные этого типа должны обрабатываться как данные текстуры.Это означает не буквально загрузку их в качестве текстурных данных, а скорее то, что это тот образ мышления, который вам следует использовать при рассмотрении вопроса о том, как передать его.

Или, в более простых терминах:не пытайтесь передавать эти данные как единые данные.

Если у вас есть доступ к OpenGL 4.3+ (который является разумно безопасной ставкой для большинства аппаратных средств не старше 6-8 лет), то буферы хранения шейдеров будут самыми лаконичнымирешение:

//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 (или ваш предпочтительный метод обновления данных буфера), и тогда вы хорошоидти.

Если вы ограничены более старым оборудованием, у вас есть некоторые варианты, но они быстро становятся неуклюжими:

  • Вы можете использовать Унифицированные буферы, которые ведут себя очень похоже наБуферы хранения шейдера, но
    • имеют ограниченное пространство для хранения (65 КБ в большинстве реализаций)
    • имеют другие ограничения, которые могут иметь или не иметь отношение к вашему варианту использования
  • Вы можете использовать текстуры напрямую, где вы преобразуете данные местности в значения с плавающей запятой (или используете их как целые числа, если аппаратное обеспечение поддерживает целочисленные форматы внутри), а затем конвертируете обратно в шейдер
    • Совместим практически с любым оборудованием
    • Но требует дополнительной сложности и вычислений в коде вашего шейдера
...