Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GLSL Issue when using pow()

I'm currently implementing a shader for doing some Directional Lights. I'm following the tutorial at Lighthouse 3d (http://www.lighthouse3d.com/tutorials/glsl-core-tutorial/directional-lights-per-pixel/)

The issue I'm having is in the following few lines:

vec3 h  = normalize(l_dir + e); 
float intSpec  = max(dot(h, n), 0.0);
float specularPower = pow(intSpec, shininess);

If I leave the "float specularPower" line in - then the shader no longer 'works'.... I say 'works' in quotations, because I get no output or errors from the Shader Log, however, now the uniform locations for my all return -1 and I can't set my texture locations, etc.

If I remove it, the rest of the shader works as expected (but producing incorrect results as a result of missing the Specular Power).

What's even more curious, is that if I have the nVidia Nsight Debugger attached, then I get output on screen and it appears to 'work', but if I just use VS2012 in Debug mode I get nothing displayed on screen, and the following error message:

First-chance exception at 0x000000005EB066E6 (nvoglv64.dll) in application.exe: 0xC0000005: Access violation reading location 0x0000000000000008.
First-chance exception at 0x000000005EB066E6 (nvoglv64.dll) in application.exe: 0xC0000005: Access violation reading location 0x0000000000000008.

This behaviour has been witnessed on both a GTX 480 and a GTX 560 - on a PC running Windows 8 64-bit.

I'm aware that -1 returned as a Uniform location means either the name is wrong, or the compiler has optimised it away, however that makes no sense for adding in a single line, whose result is then not used at all afterwards. It makes even less sense that the behaviour is different when the NSight debugger is attached or not

What might I be doing wrong?

Edit:

Below are the simplest Vertex/Fragment shaders I could create that replicates the problem, whilst still being a 'real world' shader.

Vertex Shader:

// Default Vertex Shader

#version 430 core

uniform mat4 projMatrix;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;

in vec4 in_Position;
in vec3 in_Normal;
in vec2 in_TexCoords;

out vec2 pass_TexCoords;

out vec3 v;

out Data {
    vec3 normal;
    vec4 eye;
} DataOut;

void main(void)
{
    DataOut.normal = normalize(in_Normal);
    DataOut.eye = (viewMatrix * modelMatrix) * in_Position;

    pass_TexCoords = in_TexCoords;

    v = vec3(in_Position);

    gl_Position = projMatrix * viewMatrix * modelMatrix * in_Position;
}

Fragment Shader:

// Default Fragment Shader
#version 430 core

uniform sampler2D material[3];

in vec2 pass_TexCoords;


in Data {
    vec3 normal;
    vec4 eye;
} DataIn;

layout (location = 0) out vec4 out_Colour;

void main(void)
{
    float shininess         = 0.5;

    vec3 l_dir              = vec3(0.0, 0.0, 1.0);
    vec3 n                  = normalize(DataIn.normal);
    vec3 e                  = normalize(vec3(DataIn.eye));

    float intensity         = max(dot(n, l_dir), 0.0);
    float specularPower;

    if(intensity > 0.0) {
        vec3 h              = normalize(l_dir + e);     

        float dHN           = dot(h, n);
        float intSpec       = max(dHN, 0.0);

        float specularPower = pow(intSpec, shininess);
    } else {
        specularPower       = 1.0;
    }

    vec4 diffuse_Colour     = texture(material[0], pass_TexCoords);
    out_Colour              = diffuse_Colour * specularPower;
}

I have also checked the Program Info Log and it isn't returning any errors. Once again, with these shaders, it is failing (uniforms returning -1) when run via VS2012, but 'works' when the nVidia Nsight debugger is attached.

like image 610
Andy Esser Avatar asked Jan 23 '14 12:01

Andy Esser


1 Answers

There are some interesting things going on in this shader, and they all have to do with the fact that this line:

float specularPower = pow(intSpec, shininess);

Does absolutely nothing in the final compiled shader. You have shadowed a variable of the same name at function scope.

Here is what your shader actually does (as written):

// Default Fragment Shader
#version 430 core

uniform sampler2D material[3];

in vec2 pass_TexCoords;

in Data {
    vec3 normal;
    vec4 eye;
} DataIn;

layout (location = 0) out vec4 out_Colour;

void main(void)
{
    vec3 l_dir              = vec3(0.0, 0.0, 1.0);
    vec3 n                  = normalize(DataIn.normal);

    float intensity         = max(dot(n, l_dir), 0.0);
    float specularPower;

    if(intensity > 0.0) {
      // This branch did not affect anything outside of this scope, so it is gone...

      // specularPower is uninitialized if this branch is triggered
    } else {
        specularPower       = 1.0;
    }

    vec4 diffuse_Colour     = texture(material[0], pass_TexCoords);
    out_Colour              = diffuse_Colour * specularPower;
}

If you replace the first statement I mentioned with this:

specularPower = pow(intSpec, shininess);

Your shader will actually do something in the if (intensity > 0.0) { ... } branch.

Since shininess is a constant in this program you can also replace that statement like so:

specularPower = sqrt (intSpec);
like image 92
Andon M. Coleman Avatar answered Sep 28 '22 04:09

Andon M. Coleman