0

If I had a syntax error in my GLSL, it would fail at link time, shouldn't it?

Anyway, I tried running my program in glslDevil (never used this program before) and it just keeps repeating wglGetCurrentContext(). I'm not sure if it's supposed to do that, or it's getting confused because it's a CLR app.

Is there an easier way to check for syntax errors in my GLSL code?

It appears to be the fragment shader that's causing the problem....here's the code if needed:

#version 330

const int MAX_POINT_LIGHTS = 2;

in vec2 TexCoord0;
in vec3 Normal0;
in vec3 WorldPos0;

out vec4 FragColor;

struct BaseLight
{
    vec3 Color;
    float AmbientIntensity;
    float DiffuseIntensity;
};

struct DirectionalLight
{
    struct BaseLight Base;
    vec3 Direction;
};

struct Attenuation
{
    float Constant;
    float Linear;
    float Exp;
};

struct PointLight
{
    struct BaseLight Base;
    vec3 Position;
    Attenuation Atten;
};

uniform int gNumPointLights;
uniform DirectionalLight gDirectionalLight;
uniform PointLight gPointLights[MAX_POINT_LIGHTS];
uniform sampler2D gSampler;
uniform vec3 gEyeWorldPos;
uniform float gMatSpecularIntensity;
uniform float gSpecularPower;

vec4 CalcLightInternal(struct BaseLight Light, vec3 LightDirection, vec3 Normal)
{
    vec4 AmbientColor = vec4(Light.Color, 1.0f) * Light.AmbientIntensity;
    float DiffuseFactor = dot(Normal, -LightDirection);

    vec4 DiffuseColor  = vec4(0, 0, 0, 0);
    vec4 SpecularColor = vec4(0, 0, 0, 0);

    if (DiffuseFactor > 0) {
        DiffuseColor = vec4(Light.Color, 1.0f) * Light.DiffuseIntensity * DiffuseFactor;

        vec3 VertexToEye = normalize(gEyeWorldPos - WorldPos0);
        vec3 LightReflect = normalize(reflect(LightDirection, Normal));
        float SpecularFactor = dot(VertexToEye, LightReflect);
        SpecularFactor = pow(SpecularFactor, gSpecularPower);
        if (SpecularFactor > 0) {
            SpecularColor = vec4(Light.Color, 1.0f) *
                            gMatSpecularIntensity * SpecularFactor;
        }
    }

    return (AmbientColor + DiffuseColor + SpecularColor);
}

vec4 CalcDirectionalLight(vec3 Normal)
{
    return CalcLightInternal(gDirectionalLight.Base, gDirectionalLight.Direction, Normal);
}

vec4 CalcPointLight(int Index, vec3 Normal)
{
    vec3 LightDirection = WorldPos0 - gPointLights[Index].Position;
    float Distance = length(LightDirection);
    LightDirection = normalize(LightDirection);

    vec4 Color = CalcLightInternal(gPointLights[Index].Base, LightDirection, Normal);
    float Attenuation =  gPointLights[Index].Atten.Constant +
                         gPointLights[Index].Atten.Linear * Distance +
                         gPointLights[Index].Atten.Exp * Distance * Distance;

    return Color / Attenuation;
}

void main()
{
    vec3 Normal = normalize(Normal0);
    vec4 TotalLight = CalcDirectionalLight(Normal);

    for (int i = 0 ; i < gNumPointLights ; i++) {
        TotalLight += CalcPointLight(i, Normal);
    }

    FragColor = texture2D(gSampler, TexCoord0.xy) * TotalLight;
}

Edit: Specifically, I get GL_INVALID_OPERATION when I call glUseProgram. The docs say:

GL_INVALID_OPERATION is generated if program is not a program object.

GL_INVALID_OPERATION is generated if program could not be made part of current state.

GL_INVALID_OPERATION is generated if glUseProgram is executed between the execution of glBegin and the corresponding execution of glEnd.

But I don't think it can be the first or last case, because the program ran fine until I tweaked the shader. "could not be made part of the current state" doesn't give me much to go on.

4
  • 1
    I noticed a few "1f"s and "1.0f" (which aren't allowed) and "0"s. In general it's said to be safest to use "1.0" and "0.0" format always. As for verifying your shader I think I've read some people recommend using RenderMonkey. If you're running Windows that is. EDIT: pardon me, apparently "1f" is valid on newer shader versions, but still, for better compability (=ATI cards especially), I think I've read it's best to stick with "1.0" in any case. Commented Jan 8, 2012 at 20:18
  • @harism: Well, it wasn't the f's that were killing it, and I can't figure out how to open the shader editor in RenderMonkey for the life of me. Commented Jan 8, 2012 at 20:40
  • I think it might be the definition of these structs. In DirectionalLight, I've got struct BaseLight, but it's not a declaration, it's a usage. I got this from a tutorial, but I thought that looked funny.... Edit: Hah! It was. Commented Jan 8, 2012 at 20:45
  • 1
    So nothing in the compilation (glGetShaderInfoLog()) and link (glGetProgramInfoLog()) logs? Commented Jan 8, 2012 at 21:07

4 Answers 4

1

I think one possible explanation could be the for loop inside your code.

The for statement, in my humble experience, should be always avoided.

Consider that OpenGL ES supports only fixed number of iterations and, in your case, since you are basing it on a uniform, I would investigate on it.

Moreover, consider that many drivers unroll the for statement in order to optimize the generated code.

In other words, I would focus on a simpler version of your shader, something like the following:

if (gNumPointLights == 1) {
TotalLight += CalcPointLight(1, Normal);
} else if (gNumPointLights ==  2) {
TotalLight += CalcPointLight(1, Normal);
TotalLight += CalcPointLight(2, Normal);
} else if (gNumPointLights ==  3) {
TotalLight += CalcPointLight(1, Normal);
TotalLight += CalcPointLight(2, Normal);
TotalLight += CalcPointLight(3, Normal);
}

Obviously the code can be optmized in its style and efficiency but it is a quick starting point.

Anyway, realistically, you won't have thousands lights at the same time :)

Cheers

Sign up to request clarification or add additional context in comments.

5 Comments

Actually I plan on supporting hundreds.....as much as my computer can handle. It's for a game, and there will be many light sources. I'm not sure why I would want to manually unroll that loop unless it specifically causes an error. Especially if, as you said, the driver will do it for me. It'll be much harder to maintain.
Honestly I would like to advice you to avoid an high number of lights in your code since, depending on the complexity of your code, it practically kills the performances of your engine. Consider that fixed line OpenGL supports by default 8 lights since it is a very high number of lights in a common OpenGL scene. Now, you are in a programmable pipeline but the concept and the computing power required is very similar, I would avoid this kind of approach.
How do other games do it then? Torches, lamplights, car lights, flash lights, glowing blocks or armor, magic spells the cast light... is it all faked or what? I'll do performance testing anyway and figure out what works and what doesn't. Thanks for the advice.
@Mark: They use a technique called deferred shading. You render the geometry to output material data (shiny, diffuse, etc) and normal & world pos to several buffers, then "render" each light as a geometry corresponding to that light's volume. The light shader then reads from the previous buffers and renders the color output, with additive blending. Thus lighting calculations are only done to actually visible AND lit-for-this-lightsource pixels. Use depth-scissors to limit affected pixels in depth-space, not just screenspace.
@Macke: Thanks for the explanation. I will have to look into deferred shading some more when I come back to this.
1

The problem was this:

struct PointLight
{
    struct BaseLight Base;
    vec3 Position;
    Attenuation Atten;
};

Should be just BaseLight Base, no struct

And this:

vec4 CalcLightInternal(struct BaseLight Light, vec3 LightDirection, vec3 Normal)

Same problem.

Thought it looked funny, so I changed it, and it started working.

Comments

1

When a program object has been successfully linked, the program object can be made part of current state by calling glUseProgram.So you should call program link before use program

Comments

1

In my case, I had an extra tick mark at the end of a line. Fat thumb typing.

 gl_FragColor = vec4(0.6, 0.6, 0.6, 1.0);`

Removing the tick mark fixed the problem.

Weird that it gets all the way through compile, linking and throws the error when trying to use the program.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.