Hi Folks,
I am working on a simple shader and am encountering some unexpected behavior that I though one of you might be able to help me with. I have reduced the problem down to the simplest example I can think of.
My fragment shader simply runs a for loop over a specified uniform int (3 in this case) and sets the color for that index to 1.0. This should result in a white fragment. Instead, I get a yellow fragment, as if the passed value were 2 (red + green). I can hard code the value to 3 in the shader and everything works as expected.
As near as I can figure, my problem is one of these:
- Uniforms have trouble in for loops.
- I am not passing things right (even though I can read the 3 back).
- Something is wrong with how I am setting up the uniform variable.
- My GL implementation has a bug.
Please have a look if you don’t mind and let me know if you see anything wrong. At a minimum please run the program and post whether you get a white or a yellow rectangle (or something else–that would be bad.).
I tried to self-contain everything. The shader setup code is all in the setupShaderProgram function. The variable in question is “foo”.
Thanks for any help you can provide.
-Mark
import java.awt.BorderLayout;
import javax.media.opengl.*;
import javax.swing.JFrame;
import com.sun.opengl.util.Animator;
public class UniformTest extends JFrame implements GLEventListener
{
private static final long serialVersionUID = -3280170375188457053L;
private final GLCanvas canvas = new GLCanvas();
public UniformTest()
{
super("UniformTest App");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final Animator animator = new Animator(canvas);
canvas.addGLEventListener(this);
this.add(canvas, BorderLayout.CENTER);
setSize(800, 600);
animator.start();
setVisible(true);
}
/* (non-Javadoc)
* @see javax.media.opengl.GLEventListener#display(javax.media.opengl.GLAutoDrawable)
*/
public void display(GLAutoDrawable drawable)
{
GL gl = drawable.getGL();
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT);
//Just draw a square
gl.glBegin(GL.GL_QUADS);
gl.glVertex3f(-0.5f, -0.5f, 0.0f);
gl.glVertex3f( 0.5f, -0.5f, 0.0f);
gl.glVertex3f( 0.5f, 0.5f, 0.0f);
gl.glVertex3f(-0.5f, 0.5f, 0.0f);
gl.glEnd();
}
public void init(GLAutoDrawable drawable)
{
GL gl = drawable.getGL();
gl.setSwapInterval(1);
setupShaderProgram(gl);
}
private static void setupShaderProgram(GL gl)
{
//Just use the fixed function pipeline
String vs = "void main() { gl_Position = ftransform(); }";
int shaderIndex = gl.glCreateShader(GL.GL_VERTEX_SHADER);
gl.glShaderSource(shaderIndex, 1, new String[] { vs }, new int[] { vs.length() }, 0);
gl.glCompileShader(shaderIndex);
//This is the code block in question. If you replace "foo" with the
//number 3 rather than using the uniform variable, you get the expected
//behavior - A white fragment. For some reason I get a yellow one
//(red + green).
String fs =
"uniform int foo;" +
"void main()" +
"{" +
" int bar = 3;" +
" gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);" +
" for(int i = 0; i < foo; i++)" +
" {" +
" gl_FragColor[i] = 1.0;" +
" }" +
"}";
int fragmentIndex = gl.glCreateShader(GL.GL_FRAGMENT_SHADER);
gl.glShaderSource(fragmentIndex, 1, new String[] { fs }, new int[] { fs.length() }, 0);
gl.glCompileShader(fragmentIndex);
int programIndex = gl.glCreateProgram();
gl.glAttachShader(programIndex, shaderIndex);
gl.glAttachShader(programIndex, fragmentIndex);
gl.glLinkProgram(programIndex);
gl.glUseProgram(programIndex);
gl.glValidateProgram(programIndex);
//This should give a white fragment color using the above shader.
gl.glUniform1i(gl.glGetUniformLocation(programIndex, "foo"), 3);
//Just for grins, make sure that foo is 3
int[] foo = new int[1];
gl.glGetUniformiv(programIndex, gl.glGetUniformLocation(programIndex, "foo"), foo, 0);
System.out.println("foo is returned as " + foo[0]);
}
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
{
GL gl = drawable.getGL();
//Set the projection
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrtho(-1.0f, 1.0f, -1.0, 1.0, -1.0, 1.0);
//Go back to MV mode
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
}
/**
* @param args
*/
public static void main(String[] args)
{
Runnable runnable = new Runnable()
{
public void run()
{
new UniformTest();
}
};
new Thread(runnable, "UniformTest").start();
}
//Unused
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) { }
}