Reputation: 155
I'm trying to call glGetUniformLocation() on an array of struct. I read that I should use this name format: "uniformName[index].element", but the method always returns -1. I tried to delete the array and only use the structure and it worked so I guess that the problem might there. Here is the struct and the array in my fragment shader:
const int MAX_BLOCKS = 16;
struct sblock{
vec4 color;
float shineDamper;
float reflectivity;
};
uniform sblock blocks[MAX_BLOCKS];
And here is my call:
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 method:
protected int getUniformLocation(String uniformName) {
return GL20.glGetUniformLocation(programID, uniformName);
}
and this how I create programID (before anything else):
vertexShaderID = loadShader(vertexFile, GL20.GL_VERTEX_SHADER);
fragmentShaderID = loadShader(fragmentFile, GL20.GL_FRAGMENT_SHADER);
programID = GL20.glCreateProgram();
My question is what is happening here and what am I doing wrong? Thanks for your help.
EDIT 1:
Here is my full fragment shader:
#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);
}
EDIT 2:
Here is my 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);
}
Upvotes: 0
Views: 772
Reputation: 155
I think that @Rabbid76 answer is correct, but I found a more satisfying workaround. I defined the struct and the uniform in the vertex shader, and then pass the correct values for color, shinedamper and reflectivity to the fragment shader. This makes more sense since I only want to access the values for each vertex and they are going to be same in the fragment shader, so doing it 3 times for each triangle is better than doing it hundreds of times for each pixel.
Upvotes: 1
Reputation: 211176
From (most recent) OpenGL Shading Language 4.60 Specification (HTML) - 4.3.9. Interface Blocks
A uniform or shader storage block array can only be indexed with a dynamically uniform integral expression, otherwise results are undefined.
block_id_out
is fragment shader input (set by a vertex shader input) and not a Dynamically uniform expression. Hence blocks[block_id_out]
is undefined and is not guaranteed, that blocks[i]
becomes an active program resource.
I recommend to change the declaration. Do not create an array of uniforms. Create a single Uniform block:
const int MAX_BLOCKS = 16;
struct Block
{
vec4 color;
float shineDamper;
float reflectivity;
};
layout(std140) uniform Blocks
{
Block blocks[MAX_BLOCKS];
};
You have to create a Uniform Buffer Object to bind data to the uniform block.
Upvotes: 1