2012-03-28 3 views
5

Допустим, у меня есть 2 вида, таких как люди и пони. У них разные скелетные системы, поэтому единый массив костной ткани должен быть разным для каждого вида. Должен ли я реализовывать две отдельные шейдерные программы, способные правильно отображать каждый массив костей или есть способ динамически объявлять единые массивы и перебирать через этот динамический массив?(OpenGL 3.1 - 4.2) Динамические равномерные массивы?

Имея в виду производительность (есть все шейдеры, сосать при разветвлении решения).

ответ

12

До OpenGL 4.3, массивы в GLSL должны были иметь фиксированный размер времени компиляции. 4.3 позволяет использовать объекты буфера хранения шейдеров, которые допускают «неограниченную» конечную длину. В принципе, вы можете сделать это:

buffer BlockName 
{ 
    mat4 manyManyMatrices[]; 
}; 

OpenGL будет выяснить, сколько матриц в этом массиве во время выполнения на основе того, как вы используете glBindBufferRange. Поэтому вы можете использовать manyManyMatrices.length() для получения длины, но это не будет константой времени компиляции.

Однако эта функция (во время этого редактирования) очень новая и реализована только в бета-версии. Он также требует оборудования класса GL 4.x (aka: Direct3D 11-классное оборудование). Наконец, поскольку он использует блоки хранения шейдеров, доступ к данным может быть медленнее, чем можно было бы надеяться.

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

10

Вы можете использовать n-by-1-Textures в качестве замены массивов. Размер текстуры можно указать во время выполнения. Я использую этот подход для передачи произвольного количества огней в мои шейдеры. Я удивлен, как быстро он работает, несмотря на множество циклов и ветвей. Для примера см. Файл shager polygon.f в jogl3.glsl.nontransp в источниках jReality.

uniform sampler2D sys_globalLights; 
uniform int sys_numGlobalDirLights; 
uniform int sys_numGlobalPointLights; 
uniform int sys_numGlobalSpotLights; 

...

int lightTexSize = sys_numGlobalDirLights*3+sys_numGlobalPointLights*3+sys_numGlobalSpotLights*5; 

    for(int i = 0; i < numDir; i++){ 
     vec4 dir = texture(sys_globalLights, vec2((3*i+1+0.5)/lightTexSize, 0)); 

...