glGetUniformLocation возвращает -1 для массива struct в GLSL

#opengl #glsl #shader #lwjgl

#opengl #glsl #шейдер #lwjgl

Вопрос:

Я пытаюсь вызвать glGetUniformLocation() для массива struct . Я читал, что я должен использовать этот формат имени: «uniformName[index].element», но метод всегда возвращает -1. Я попытался удалить массив и использовать только структуру, и это сработало, поэтому я предполагаю, что проблема может быть там. Вот структура и массив в моем фрагментном шейдере:

 
const int MAX_BLOCKS = 16;

struct sblock{

    vec4 color;
    float shineDamper;
    float reflectivity;
};

uniform sblock blocks[MAX_BLOCKS];

  

И вот мой вызов:

 for(int i = 0; i < 16; i  ) {
            location_block_color[i] = super.getUniformLocation("blocks[" i "].color");
            location_block_reflectivity[i] = super.getUniformLocation("blocks[" i "].reflectivity");
            location_block_shineDamper[i] = super.getUniformLocation("blocks[" i "].shineDamper");
            System.out.println(location_block_color[i]   " "   location_block_reflectivity[i]   " "   location_block_shineDamper[i]); // prints -1 -1 -1 ...
        }

  

Метод getUniformLocation:

 protected int getUniformLocation(String uniformName) {
        return GL20.glGetUniformLocation(programID, uniformName);
    }
  

и вот как я создаю programID (прежде всего):

 vertexShaderID = loadShader(vertexFile, GL20.GL_VERTEX_SHADER);
        fragmentShaderID = loadShader(fragmentFile, GL20.GL_FRAGMENT_SHADER);
        programID = GL20.glCreateProgram();
  

Мой вопрос в том, что здесь происходит и что я делаю не так?
Спасибо за вашу помощь.

РЕДАКТИРОВАТЬ 1:

Вот мой полный фрагментный шейдер:

 
#version 400 core

const int MAX_LIGHTS = 16;
const int MAX_BLOCKS = 16;

struct sblock{

    vec4 color;
    float shineDamper;
    float reflectivity;
};

uniform sblock blocks[MAX_BLOCKS];


in int block_id_out;
in vec3 unitNormal;
in vec3 lightVector[MAX_LIGHTS];
in vec3 directionalLightFinalColour;
in vec3 directionalLightReflected;

in vec3 toCameraVector;

in float visibility;

out vec4 outColor;


uniform float ambientLight;
uniform vec3 skyColor;

uniform vec3 lightColour[MAX_LIGHTS];
uniform vec3 attenuation[MAX_LIGHTS];
uniform int lightCount;
uniform vec3 directionalLightColour;
uniform vec3 directionalLightDirection;

vec3 calculateDiffuse(vec3 unitNormal, vec3 unitLightVector, vec3 lightColour, float attFactor){
    float nDotl = dot(unitNormal,unitLightVector);
    float brightness = max(nDotl,0);
    return (brightness * lightColour) / attFactor;
}


vec3 calculateSpecular(vec3 unitNormal, vec3 unitLightVector, vec3 unitToCameraVector, float shineDamper, float reflectivity, vec3 lightColour, float attFactor){
    vec3 reflectedLightDirection = reflect(-unitLightVector,unitNormal);
    float specularFactor = max(dot(reflectedLightDirection, unitToCameraVector),0.0);
    float dampedFactor = pow(specularFactor,shineDamper);
    return (dampedFactor * reflectivity * lightColour) / attFactor;
}

void main(void){

    vec3 totalDiffuse = vec3(0.0);
    vec3 totalSpecular = vec3(0.0);
        
    vec3 unitToCameraVector = normalize(toCameraVector);

    for(int i = 0; i < lightCount;i  ){
        vec3 unitLightVector = normalize(lightVector[i]);
        float lightDistance = length(lightVector[i]);
        
        float attFactor = attenuation[i].x   attenuation[i].y*lightDistance   attenuation[i].z*lightDistance*lightDistance;
        
        totalSpecular  = calculateSpecular(unitNormal, unitLightVector, unitToCameraVector, blocks[block_id_out].shineDamper, blocks[block_id_out].reflectivity, lightColour[i], attFactor);
        totalDiffuse  = calculateDiffuse(unitNormal, unitLightVector, lightColour[i], attFactor);
    }
    
    totalDiffuse  = directionalLightFinalColour;
    totalSpecular  = pow(max(dot(directionalLightReflected,unitToCameraVector),0.0),blocks[block_id_out].shineDamper)*blocks[block_id_out].reflectivity*directionalLightColour;
    totalDiffuse = max(totalDiffuse,ambientLight);
    
    outColor = vec4(totalDiffuse,1.0) * blocks[block_id_out].color   vec4(totalSpecular,1.0);
    outColor = mix(vec4(skyColor,1.0),outColor,visibility);
}

  

РЕДАКТИРОВАТЬ 2:

Вот мой VertexShader:

 
#version 400 core
const vec4 normals[] = vec4[6](vec4(1,0,0,0),vec4(0,1,0,0),vec4(0,0,1,0),vec4(-1,0,0,0),vec4(0,-1,0,0),vec4(0,0,-1,0));
const int MAX_LIGHTS = 16;

in vec3 position;
in int block_id;
in int normal;

out int block_id_out;
out vec3 unitNormal;
out vec3 lightVector[MAX_LIGHTS];
out vec3 directionalLightFinalColour;
out vec3 directionalLightReflected;
out vec3 toCameraVector;
out float visibility;

uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform vec3 lightPosition[MAX_LIGHTS];
uniform vec3 directionalLight;
uniform vec3 directionalLightColor;

uniform int lightCount;

uniform float fogDensity;
uniform float fogGradient;

void main(void){

    vec4 worldPosition = transformationMatrix * vec4(position,1.0);
    vec4 positionRelativeToCam = viewMatrix * worldPosition;
    
    gl_Position = projectionMatrix * positionRelativeToCam;
    block_id_out = block_id;
    unitNormal = normalize((transformationMatrix * normals[normal]).xyz);
    
    for(int i = 0; i < lightCount;i  ){
        lightVector[i] = lightPosition[i] - worldPosition.xyz;
    }
    directionalLightFinalColour = max(dot(unitNormal, directionalLight),0)*directionalLightColor;
    directionalLightReflected = reflect(-directionalLight,unitNormal);
    
    toCameraVector = (inverse(viewMatrix) * vec4(0.0,0.0,0.0,1.0)).xyz - worldPosition.xyz;
    
    visibility = clamp(exp(-pow(length(positionRelativeToCam.xyz)*fogDensity,fogGradient)),0.0,1.0);
}

  

Комментарии:

1. Используете ли вы элементы формы в шейдере? Форма становится активным программным ресурсом только в том случае, если она «используется» в программе шейдеров. В противном случае он будет пропущен из-за оптимизации.

2. да, это так, и снова, когда я удалил массив и сохранил только одну структуру, это сработало

3. @Rabbid76 Я отредактировал свой пост, я устанавливаю его в вершинном шейдере, но не с однородным

Ответ №1:

Из (самой последней) спецификации OpenGL Shading Language 4.60 (HTML) — 4.3.9. Интерфейсные блоки

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

block_id_out является вводом шейдера фрагмента (задается вводом вершинного шейдера), а не динамически однородным выражением. Следовательно blocks[block_id_out] , не определено и не гарантируется, что blocks[i] становится активным программным ресурсом.


Я рекомендую изменить объявление. Не создавайте массив униформ. Создайте единый унифицированный блок:

 const int MAX_BLOCKS = 16;

struct Block
{
    vec4 color;
    float shineDamper;
    float reflectivity;
};

layout(std140) uniform Blocks
{
    Block blocks[MAX_BLOCKS];
};
  

Для привязки данных к единому блоку необходимо создать объект Uniform Buffer .

Комментарии:

1. Хорошо, спасибо, но ввод вершинного шейдера есть? И как я могу тогда справиться со своей ситуацией?

2. @ThibaultAbry Создайте единый унифицированный блок. Смотрите ответ.

3. Я реализовал то, что вы написали, и для доступа к элементу блока я делаю это blocks.block[block_id_out].shineDamper и для получения единообразного местоположения this super.getUniformLocation("blocks.block[" i "].color"); , и оно по-прежнему возвращает -1

4. @ThibaultAbry Да, конечно, потому что now blocks не является единым в едином блоке по умолчанию. blocks является отдельным однородным блоком . Вы должны создать единый объект буфера .

Ответ №2:

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