error902's picture

GetUniformLocation() is returning -1

I am trying to render the Mandelbrot Set as described at http://www.opengl.org/sdk/docs/tutorials/TyphoonLabs/Chapter_4.pdf . Instead of rendering an image of the Mandelbrot Set, my program currently displays a black rectangle (quad). I have created the vertex and fragment shaders described in the tutorial, and am trying to set the uniform variables used in the fragment shader. Using the debugger, I found out that all of my GL.GetUniformLocation(..,..) calls are returning as -1. I am not sure what I am doing wrong, or what else I might need to add.

My vertex shader:

varying vec3  position; 
void main() 
{ 
  position = vec3(gl_MultiTexCoord0 - 0.5) * 5.0;
  gl_Position = ftransform(); 
}

My fragment shader:

varying vec3 position; 
uniform int maxIterations; 
uniform vec2 center; 
uniform vec3 outerColor1; 
uniform vec3 outerColor2; 
uniform float zoom; 
void main() 
{    
 float real  = position.x * (1.0/zoom) + center.x; 
 float imag  = position.y * (1.0/zoom) + center.y;         
 float cReal = real;    
 float cImag = imag;    
  float r2 = 0.0; 
int iter; 
  for (iter = 0; iter < maxIterations && r2 < 4.0; ++iter) 
  { 
    float tempreal = real;        
    real = (tempreal * tempreal) - (imag * imag) + cReal; 
    imag = 2.0 * tempreal * imag + cImag; 
  } 
  // Base the color on the number of iterations. 
  vec3 color; 
  if (r2 < 4.0) 
    color = vec3(0.0); 
  else
    color = mix(outerColor1, outerColor2, fract(float(iter)*0.05)); 
  gl_FragColor = vec4 (clamp(color, 0.0, 1.0), 1.0); 
}

I know that my shader is doing 'something', because I set my color pipeline to Red before creating my quad, and the shader is overriding that with black. Here is my program code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
 
namespace Mandelbrot
{
	// Render a Mandelbrot Set using a shader
	public class MandelbrotWindow : GameWindow
	{
		int frag_shader;
		int vertex_shader;
		int shader_prog;
 
        public MandelbrotWindow() : base(800, 600, GraphicsMode.Default, "Mandelbrot Shader")
        {
            VSync = VSyncMode.On;
        }
 
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
 
			GL.ClearColor(Color.White);
            GL.Enable(EnableCap.DepthTest);
 
			CreateShaders();
        }
 
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
 
            GL.Viewport(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height);
 
            //Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, Width / (float)Height, 1.0f, 64.0f);
			//GL.Ortho(-800, 800, -600, 600, -1, 1);
			GL.Ortho(-7, 7, -6, 6, -1,1);
            GL.MatrixMode(MatrixMode.Projection);
        }
 
		protected override void OnUnload(EventArgs e)
		{
			if (vertex_shader != 0)
				GL.DeleteShader(vertex_shader);
			if (frag_shader != 0)
				GL.DeleteShader(vertex_shader);
			if (shader_prog != 0)
				GL.DeleteProgram(shader_prog);
			base.OnUnload(e);
		}
 
        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            base.OnUpdateFrame(e);
 
            //if (Keyboard[Key.Escape])
              //  Exit();
        }
 
        /// <summary>
        /// Called when it is time to render the next frame. Add your rendering code here.
        /// </summary>
        /// <param name="e">Contains timing information.</param>
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            base.OnRenderFrame(e);
 
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
			GL.Color3(Color.Red);
 
			float w2 = 6;
			float h2 = 5;
 
			// Create surface to shade
			GL.Begin(BeginMode.Quads);
 
			GL.Vertex3(-w2, h2, 0.0);
			GL.Vertex3(-w2, -h2, 0.0);
			GL.Vertex3(w2, -h2, 0.0);
			GL.Vertex3(w2, h2, 0.0);
 
			GL.End();
 
            SwapBuffers();
        }
 
		/// <summary>
		/// Create and implement a vertex and fragment shader
		/// </summary>
		private void CreateShaders()
		{
			frag_shader = GL.CreateShader(ShaderType.FragmentShader);
			vertex_shader = GL.CreateShader(ShaderType.VertexShader);
 
			using (StreamReader sr = new StreamReader("MandelbrotFragShader.glsl"))
			{
				GL.ShaderSource(frag_shader, sr.ReadToEnd());
			}
 
			using (StreamReader sr = new StreamReader("MandelbrotVertexShader.glsl"))
			{
				GL.ShaderSource(vertex_shader, sr.ReadToEnd());
			}
 
			GL.CompileShader(frag_shader);
			GL.CompileShader(vertex_shader);
 
			int result; // For debugging / error testing
 
			GL.GetShader(vertex_shader, ShaderParameter.CompileStatus, out result);
			if (result == 0)
			{
				Console.WriteLine("Failed to compile vertex shader!");
				Console.WriteLine(GL.GetShaderInfoLog(vertex_shader));
			}
			else Console.WriteLine("Vertex Shader Compiled!");
 
			GL.GetShader(frag_shader, ShaderParameter.CompileStatus, out result);
			if (result == 0)
			{
				Console.WriteLine("Failed to compile fragment shader!");
				Console.WriteLine(GL.GetShaderInfoLog(frag_shader));
			}
			else Console.WriteLine("Frag Shader Compiled!");
 
			shader_prog = GL.CreateProgram();
 
			GL.AttachShader(shader_prog, frag_shader);
			GL.AttachShader(shader_prog, vertex_shader);
 
			GL.LinkProgram(shader_prog);
			GL.UseProgram(shader_prog);
 
			GL.GetProgram(shader_prog, ProgramParameter.LinkStatus, out result);
			if (result == 0)
			{
				Console.WriteLine("Failed to link shader program!");
				Console.WriteLine(GL.GetProgramInfoLog(shader_prog));
			}
			else
			{
				Console.WriteLine("Both shaders compiled succesfully!");
				Console.WriteLine(GL.GetProgramInfoLog(shader_prog));
			}
 
			// variables to send as Uniform variables to the shader
			int maxIterations = 50;
			Vector2 center = new Vector2(0.0f, 0.0f);
			Vector3 outerColor1 = new Vector3(1.0f, 0.0f, 0.0f);
			Vector3 outerColor2 = new Vector3(0.0f, 1.0f, 0.0f);
			float zoom = 1;
 
			// GL.GetUniformLocation is returning with "-1" for every location
			int maxIterLoc = GL.GetUniformLocation(shader_prog, "maxIterations");
			GL.Uniform1(maxIterLoc,maxIterations);
 
			int centerLoc = GL.GetUniformLocation(shader_prog, "center");
			GL.Uniform2(centerLoc,center);
 
			int outerColor1Loc = GL.GetUniformLocation(shader_prog, "outerColor1");
			GL.Uniform3(outerColor1Loc, outerColor1);
 
			int outerColor2Loc = GL.GetUniformLocation(shader_prog, "outerColor2");
			GL.Uniform3(outerColor2Loc, outerColor2);
 
			int zoomLoc = GL.GetUniformLocation(shader_prog, "zoom");
			GL.Uniform1(zoomLoc, zoom);
		}
 
		// Main
		static void Main(string[] args)
		{
			using (MandelbrotWindow mw = new MandelbrotWindow())
			{
				mw.Run(30.0);
			}
		}
	}
}

Any help would be gladly appreciated.


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
mOfl's picture

Edit: Forget what I just wrote, major rollback commencing...

It looks like your video card is a lot smarter than you :) I expect that if you add the line gl_FragColor = vec4 (0.0, 1.0, 0.0, 1.0); at the very end of your fragment shader, your quad will be green, right? I assume that because the clever GLSL compiler discards all unnecessary information to optimize it. From bottom up: gl_FragColor depends on color, color depends on outerColor1, outerColor2 and iter OR on r2. As you set r2 = 0.0 and never change it, color is always (0.0, 0.0, 0.0). the rest of the shader is not necessary for color calculation and therefore discarded. After this step, the uniforms specified in the shader are no longer needed as well, because they are never referenced in the optimized code and are discarded as well. The result is that in the compiled shader, there are none of the defined uniforms and therefore the index is -1 if you try to get them.

This, however, is still true and can be helpful in any application:

It might help to add something like

string infoString = string.Empty;
int statusCode = 1;
 
GL.GetProgram(this.Program, ProgramParameter.ValidateStatus, out statusCode);
GL.GetProgramInfoLog(this.Program, out infoString);
 
if (statusCode != 1) {
    MessageBox("Error validating the shader: " + infoString);
}

after you link the shaders to see if your program is up.

KryThorne's picture

Oof, as condolences, this is one I wasted an afternoon trying to 'fix' one time without realising my graphics card was outsmarting me. :)

As mOfl stated, shader compilers are incredibly optimised and your card will work out that none of those variables effect the outcome and thus not assign locations for them.

error902's picture

Thanks for the responses!

After looking at the shader code, it becomes apparent that those variables are never used. With a little more research, I needed a line of "r2 = (real * real) + (imag * imag);" within my for loop to make it work.

aybe's picture

Thanks for sharing this !