PDA

View Full Version : cannot get uniform location



Xi Yang
05-25-2011, 02:42 AM
My problem is: glGetUniformLocation() always give me -1.
Althogh it fails to set the sampler, the shader program works almost correct, excepts only the first texture is working.

Thanks a lot!

This is the vertex program:

#version 130

uniform int test_var;

uniform sampler2D sp_surface;
uniform sampler2D sp_cloud;
uniform sampler2D sp_bump;

out vec3 normal_v;
out vec3 light_v;
out vec3 eye_v;

void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_FrontColor = gl_Color;

vec4 vertex_p = gl_ModelViewMatrix * gl_Vertex;
vec4 light_p = gl_LightSource[0].position;

normal_v = normalize(gl_NormalMatrix * gl_Normal);
light_v = normalize(gl_LightSource[0].position.xyz - vertex_p.xyz);
eye_v = normalize(-vertex_p.xyz);

gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_MultiTexCoord1;
}

And the fragment program:

#version 130
uniform sampler2D sp_surface;
uniform sampler2D sp_cloud;
uniform sampler2D sp_bump;

const vec3 atm_color = vec3(1,1,1);

in vec3 normal_v;
in vec3 light_v;
in vec3 eye_v;

void main() {
float Kd = max( dot(light_v,normal_v), 0.0 );
vec4 diffuse = Kd * gl_FrontLightProduct[0].diffuse;

vec3 half_v = normalize(light_v + eye_v);
float Ks = pow( max(dot(half_v,normal_v),0.0), gl_FrontMaterial.shininess );
float f = 1.0;
if (dot(normal_v,light_v)<0) f = 0;
vec4 specular = f * Ks * gl_FrontLightProduct[0].specular;

vec4 ambient = gl_FrontLightProduct[0].ambient;

// atmosphere effect
float atm_alpha = length(cross(normal_v,eye_v))/length(normal_v)/length(eye_v);
atm_alpha = pow(atm_alpha,100);

// calculate color
vec4 ground_color = texture(sp_surface,gl_TexCoord[0].st);
ground_color.rgb = ground_color.rgb*(1-atm_alpha) + atm_color*atm_alpha;

gl_FragColor = (ambient+diffuse) * ground_color + specular + gl_FrontMaterial.emission;
}


This is the part where uniforms are fetched and set.


// DBG
GLint addr_test = glGetUniformLocation(program,"test_var ");
cout<<"test variable addr: "<<addr_test<<endl;

// set texture sampler
// assume the surface is 0, cloud is 1, bump is 2
GLint addr_sampler_surface = glGetUniformLocation(program,"sp_surface");
GLint addr_sampler_cloud = glGetUniformLocation(program,"sp_cloud");
GLint addr_sampler_bump = glGetUniformLocation(program,"sp_bump");
if ( (addr_sampler_surface==-1)
|| (addr_sampler_cloud==-1)
|| (addr_sampler_bump==-1) )
{
cerr<<"invalid uniform address:\n";
cerr<<"\tsurface addr: "<<addr_sampler_surface<<"\n";
cerr<<"\tcloud addr: "<<addr_sampler_cloud<<"\n";
cerr<<"\tbump addr: "<<addr_sampler_bump<<"\n";
//throw "";
}
glUniform1i(addr_sampler_surface,GL_TEXTURE0);
glUniform1i(addr_sampler_cloud,GL_TEXTURE1);
glUniform1i(addr_sampler_bump,GL_TEXTURE2);

mobeen
05-25-2011, 02:54 AM
The glslcompiler would strip out the unused variables hence their locations will be -1. To resolve this, you must use the variable at hand. In your case, you are not using the sp_cloud and sp_bump samplers hence their locations will be -1.

To resolve this, u must use the sampler in the shader.
Another thing, you dont have to declare a uniform in the vertex shader if that uniform is only used in the fragment shader.

Alfonse Reinheart
05-25-2011, 03:02 AM
Did the shader compile correctly? Also, the trailing space in "test_var " should be removed.

Xi Yang
05-25-2011, 05:49 AM
Did the shader compile correctly? Also, the trailing space in "test_var " should be removed.
In a book I read, it provides an demo that has space after that...

Xi Yang
05-25-2011, 05:50 AM
The glslcompiler would strip out the unused variables hence their locations will be -1. To resolve this, you must use the variable at hand. In your case, you are not using the sp_cloud and sp_bump samplers hence their locations will be -1.

To resolve this, u must use the sampler in the shader.
Another thing, you dont have to declare a uniform in the vertex shader if that uniform is only used in the fragment shader.

Thanks a lot!
So my problem would be another one, that the sampler seems not working properly. I will do some work around that.

mobeen
05-25-2011, 06:28 AM
In a book I read, it provides an demo that has space after that...
But what Alfonse is saying is correct. Perhaps the book has a typo and adding in a space to the variable name will also give that variables location as -1 since the variable does not exist. Remove the trailing space.

Dan Bartlett
05-25-2011, 06:29 AM
From the spec:

Setting a samplerís value to i selects texture
image unit number i. The values of i ranges from zero to the implementation dependent
maximum supported number of texture image units.
So you should have:

glUniform1i(addr_sampler_surface, 0);
glUniform1i(addr_sampler_cloud, 1);
glUniform1i(addr_sampler_bump, 2);

Xi Yang
05-25-2011, 08:24 AM
From the spec:

Setting a samplerís value to i selects texture
image unit number i. The values of i ranges from zero to the implementation dependent
maximum supported number of texture image units.
So you should have:

glUniform1i(addr_sampler_surface, 0);
glUniform1i(addr_sampler_cloud, 1);
glUniform1i(addr_sampler_bump, 2);


My multilayer texture is still not working.

First of all, I'm sure the image is loaded correctly.
And the mixture mechanism in fragment shader is working correctly, while I've tested it using a const vec4 as cloud color.

But when I use the sampler of the cloud (should be GL_TEXTURE1), it always give me the color on the ground (GL_TEXTURE0). Is there anything wrong on the texture object?

This is the code when I draw a planet:


texture_ground.apply();
texture_cloud.apply();
texture_bump.apply();

glCallList(obj_id);

texture_ground.decline();
texture_cloud.decline();
texture_bump.decline();


And this is what my texture object looks like:


class SolarTexture
{
public:
SolarTexture(GLuint layer);
~SolarTexture();

void load_texture(FREE_IMAGE_FORMAT format, string file);
void apply();
void decline();

protected:
GLuint layer;
GLuint id;
};

void SolarTexture::apply() {
if (id!=0) {
glActiveTexture(layer);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_CO MBINE_ALPHA);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTE R,GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R,GL_LINEAR_MIPMAP_LINEAR);
glBindTexture(GL_TEXTURE_2D,id);
}
}

mobeen
05-25-2011, 08:53 AM
THe reason why your multitexturing is not working is b/c u have multiple textures. Now u r setting the sampler uniform locations to 0,1 and 2 so u must bind the textures to the texture targets 0 1 and 2 like this if ur shader is using three samplers,


glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, firstTexID);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, secondTexID);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, thirdTexID);

Alfonse Reinheart
05-25-2011, 09:07 AM
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R,GL_LINEAR_MIPMAP_LINEAR);


GL_LINEAR_MIPMAP_LINEAR is not a valid magnification filter. Your choices are GL_NEAREST or GL_LINEAR.

Dan Bartlett
05-25-2011, 10:09 AM
glTexParameteri affects the currently bound texture object for the active texture unit (ie. not the texture unit by itself), so you will need to bind the texture you want to modify before calling it.


glActiveTexture(GL_TEXTURE0+layer);
glBindTexture(GL_TEXTURE_2D,id);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTE R,GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R,GL_LINEAR);
Because texture parameters are stored with the texture object, you don't need to re-apply every time you bind the texture object in this way either, just once at texture initialization will do.

glEnable(GL_TEXTURE_2D) is no longer needed for shaders, since shader programs will use the texture bound to the texture unit whether you have enabled or disabled the texture unit for fixed-function. glTexEnvi is also deprecated in core OpenGL, and probably isn't needed if you are solely using shaders.

Xi Yang
05-25-2011, 05:27 PM
THe reason why your multitexturing is not working is b/c u have multiple textures. Now u r setting the sampler uniform locations to 0,1 and 2 so u must bind the textures to the texture targets 0 1 and 2 like this if ur shader is using three samplers,


glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, firstTexID);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, secondTexID);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, thirdTexID);



I have binded different layers, in a different way.
In my texture class, it has a layer property and a id property. In the "apply()" method of texture class, it has things like this:


glActiveTexture(layer);
glBindTexture(GL_TEXTURE_2D,id);


So if I call "apply()"method on 3 different texture objects that has different layer, they should be activated to those layers.

Alfonse Reinheart
05-25-2011, 08:07 PM
So if I call "apply()"method on 3 different texture objects that has different layer, they should be activated to those layers.

Is "layer" an OpenGL enumerator, or is it an integer starting at 0? Because if it's the latter, you need to do what Dan said and add GL_TEXTURE0 to the layer in your glActiveTexture call.

Xi Yang
05-25-2011, 08:43 PM
So if I call "apply()"method on 3 different texture objects that has different layer, they should be activated to those layers.

Is "layer" an OpenGL enumerator, or is it an integer starting at 0? Because if it's the latter, you need to do what Dan said and add GL_TEXTURE0 to the layer in your glActiveTexture call.

"layer" is an OpenGL enum.

This is where the texture objects were initialized:


SolarObj::SolarObj(lots_of_arguments):
...
texture_ground(GL_TEXTURE0),
texture_cloud(GL_TEXTURE1),
texture_bump(GL_TEXTURE2),
...
{
body
}


This is the constructor of SolarTexture:


SolarTexture::SolarTexture(GLuint layer):
id(0),
layer(layer)
{}


So you can see it should have provided correct value to glActiveTexture()

Dan Bartlett
05-26-2011, 04:45 AM
Are you correctly passing the values 0 to 2 as uniform values (layer - GL_TEXTURE0), rather than "layer" which is GL_TEXTURE0..GL_TEXTURE2.
ps. The OpenGL spec guarantees that
TEXTUREi = TEXTURE0+i (i is in the range 0 to k - 1, where k is the value of MAX_COMBINED_TEXTURE_IMAGE_UNITS).