vertex shader problem

I have started learning modern opengl (version 3.3). I use JOGL2 RC2 Signed Released (jogl-2.0-b23-20110303-windows-i586). I have a problem with vertex shader - uniform vec2 offset doesn’t work. The triangle doesn’t move … My initShader function works properly. I don’t know what is wrong.

Tutorial: http://arcsynthesis.org/gltut/Positioning/Tut03%20A%20Better%20Way.html

Code:


public class Scene3D implements GLEventListener 
{
    private Frame frame;
    private FPSAnimator animator;
    private int vertexBufferObject;
    private int shaderProgramID;
    private FloatBuffer vertexDataBuffer;
    private float fXOffset = 0.01f; 
    private float fYOffset = 0.01f;
    private int offsetLocation;
    private float vertices[];

    private static String vertexShader =
    "#version 330" + "\n" +
    "layout (location = 0) in vec4 position;" + "\n" +
    "uniform vec2 offset;" + "\n" +       
    "void main()" + "\n" +
    "{" + "\n" +
    "vec4 totalOffset = vec4(offset.x, offset.y, 0.0, 0.0);" + "\n" +      
    "gl_Position = position + totalOffset;" + "\n" +
    "}";
    
    private static String fragmentShader =
    "#version 330" + "\n" +  
    "out vec4 outputColor;" + "\n" +
    "void main()" + "\n" +
    "{" + "\n" +       
    "outputColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);" + "\n" +
    "}";        
    
    public Scene3D(GLCapabilities capabilities)
    {
        GLCanvas glComponent = new GLCanvas(capabilities);
        glComponent.setFocusable(true);
        glComponent.addGLEventListener(this);
        
        frame = new JFrame("JOGL");
        frame.addWindowListener(new WindowAdapter()
        {
            @Override
            public void windowClosing(WindowEvent e)
            {
                runExit();
            }
        });
        frame.setLayout(new BorderLayout());
        glComponent.setPreferredSize(new Dimension(800, 600));
        frame.add(glComponent, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
        glComponent.requestFocus();
        animator = new FPSAnimator(glComponent, 60, true);
        animator.start();
    }

    public static void main(String[] args) 
    {
        
        GLProfile profile = GLProfile.get(GLProfile.GL3);
        final GLCapabilities capabilities = new GLCapabilities(profile);
        
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                new Scene3D(capabilities);
                
            }
        });
       
    }

    @Override
    public void init(GLAutoDrawable glad) 
    {
        GL3 gl = glad.getGL().getGL3();
        gl.setSwapInterval(1);
        gl.glEnable(GL3.GL_DEPTH_TEST);
        gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

        vertices = new float[]{0.0f, 0.5f, 0.0f, 1.0f,
                                       0.5f, -0.366f, 0.0f, 1.0f,
                                       -0.5f, -0.366f, 0.0f, 1.0f};
        
        vertexDataBuffer = Buffers.newDirectFloatBuffer(vertices.length);
        vertexDataBuffer.put(vertices);
        vertexDataBuffer.flip();

        initShaders(gl);
        initVBO(gl);
        offsetLocation = gl.glGetUniformLocation(shaderProgramID, "offset");
    }

    @Override
    public void dispose(GLAutoDrawable glad) 
    {
        
    }

    @Override
    public void display(GLAutoDrawable glad) 
    {
        GL3 gl = glad.getGL().getGL3();
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        gl.glUseProgram(shaderProgramID);
        gl.glUniform2f(offsetLocation, fXOffset, fYOffset);
        gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vertexBufferObject);
        gl.glEnableVertexAttribArray(0);
        gl.glVertexAttribPointer(0, 4, GL3.GL_FLOAT, false, 0, 0);
        gl.glDrawArrays(GL3.GL_TRIANGLES, 0, 3);
        gl.glDisableVertexAttribArray(0);
        gl.glUseProgram(0);
    }

    @Override
    public void reshape(GLAutoDrawable glad, int x, int y, int width, int height) 
    {
        
    }
    
    private void initVBO(GL3 gl)
    {
        int buffer[] = new int[1];
        gl.glGenBuffers(1, IntBuffer.wrap(buffer));
        vertexBufferObject = buffer[0];
        gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vertexBufferObject);
        gl.glBufferData(GL3.GL_ARRAY_BUFFER, Buffers.SIZEOF_FLOAT * vertexDataBuffer.capacity(), vertexDataBuffer, GL3.GL_STREAM_DRAW);
        gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0);
    }
    
    private void initShaders(GL3 gl)
    {
        shaderProgramID = gl.glCreateProgram();

        int vertexShaderID = gl.glCreateShader(GL3.GL_VERTEX_SHADER);
        gl.glShaderSource(vertexShaderID, 1, 
            new String[]{vertexShader}, null);
        gl.glCompileShader(vertexShaderID);
        gl.glAttachShader(shaderProgramID, vertexShaderID);
        gl.glDeleteShader(vertexShaderID);

        int fragmentShaderID = gl.glCreateShader(GL3.GL_FRAGMENT_SHADER);
        gl.glShaderSource(fragmentShaderID, 1, 
            new String[]{fragmentShader}, null);
        gl.glCompileShader(fragmentShaderID);
        gl.glAttachShader(shaderProgramID, fragmentShaderID);
        gl.glDeleteShader(fragmentShaderID);
        
        gl.glLinkProgram(shaderProgramID);
        gl.glValidateProgram(shaderProgramID);
        
    }

    private void runExit()
    {
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                animator.stop();
                System.exit(0);
            }
        }).start();
    }

}

At first glance i cannot see where you check for compile or linking errors. When doing shaders you should always check. I use a method that i got off lwjgl wiki a while back IIRC. Here is the method:


private static void printLogInfo(int obj) {
		IntBuffer iVal =BufferUtils.createIntBuffer(1);
		ARBShaderObjects.glGetObjectParameterARB(obj, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB, iVal);

		int length =iVal.get();
		System.out.println("Info log length:" + length);
		if (length > 0) {
			// We have some info we need to output.
			ByteBuffer infoLog =BufferUtils.createByteBuffer(length);
			iVal.flip();
			ARBShaderObjects.glGetInfoLogARB(obj, iVal, infoLog);
			byte[] infoBytes =new byte[length];
			infoLog.get(infoBytes);
			String out =new String(infoBytes);

			System.out.println("Info log:\n" + out);
		}

		Util.checkGLError();
	}

I then call this after linking like so (simplified so you get the idea).


glLinkProgram(program);
glValidateProgram(program);
System.out.println("Log of vshader");
printLogInfo(vshader);
System.out.println("Log of fshader");
printLogInfo(fshader);
org.lwjgl.opengl.Util.checkGLError();

Then at least i can be confident about the shader compile process.

Ok, I added to my init shaders function simple error checking code and now I’m getting the message: “linker error: 0”. I still can’t understand what is wrong …


private void initShaders(GL3 gl)
    {
        shaderProgramID = gl.glCreateProgram();

        int vertexShaderID = gl.glCreateShader(GL3.GL_VERTEX_SHADER);
        gl.glShaderSource(vertexShaderID, 1, 
            new String[]{vertexShader}, null);
        gl.glCompileShader(vertexShaderID);
        
        
        
        int statusVertex[] = new int[1];
        gl.glGetShaderiv(vertexShaderID, GL3.GL_COMPILE_STATUS, IntBuffer.wrap(statusVertex));
        if(statusVertex[0] == GL3.GL_FALSE)
        {
            int infoLogLenght[] = new int[1];
            gl.glGetShaderiv(vertexShaderID, GL3.GL_INFO_LOG_LENGTH, IntBuffer.wrap(infoLogLenght));
            
            byte infLog[] = new byte[1];
            gl.glGetShaderInfoLog(vertexShaderID, infoLogLenght[0], null, ByteBuffer.wrap(infLog));
            System.out.println("vertex shader error:" + Byte.toString(infLog[0]));
            
        }
        
        
        
        gl.glAttachShader(shaderProgramID, vertexShaderID);
        gl.glDeleteShader(vertexShaderID);

        
        
        
        int fragmentShaderID = gl.glCreateShader(GL3.GL_FRAGMENT_SHADER);
        gl.glShaderSource(fragmentShaderID, 1, 
            new String[]{fragmentShader}, null);
        gl.glCompileShader(fragmentShaderID);
        
        
        
        int statusFragment[] = new int[1];
        gl.glGetShaderiv(fragmentShaderID, GL3.GL_COMPILE_STATUS, IntBuffer.wrap(statusFragment));
        if(statusFragment[0] == GL3.GL_FALSE)
        {
            int infoLogLenght[] = new int[1];
            gl.glGetShaderiv(fragmentShaderID, GL3.GL_INFO_LOG_LENGTH, IntBuffer.wrap(infoLogLenght));
            
            byte infLog[] = new byte[1];
            gl.glGetShaderInfoLog(fragmentShaderID, infoLogLenght[0], null, ByteBuffer.wrap(infLog));
            System.out.println("fragment shader error:" + Byte.toString(infLog[0]));
            
        }
        
        
        
        gl.glAttachShader(shaderProgramID, fragmentShaderID);
        gl.glDeleteShader(fragmentShaderID);
        
        gl.glLinkProgram(shaderProgramID);
        
        
        
        int statusLinker[] = new int[1];
        gl.glGetShaderiv(shaderProgramID, GL3.GL_LINK_STATUS, IntBuffer.wrap(statusLinker));
        if(statusLinker[0] == GL3.GL_FALSE)
        {
            int infoLogLenght[] = new int[1];
            gl.glGetShaderiv(shaderProgramID, GL3.GL_INFO_LOG_LENGTH, IntBuffer.wrap(infoLogLenght));
            
            byte infLog[] = new byte[1];
            gl.glGetShaderInfoLog(shaderProgramID, infoLogLenght[0], null, ByteBuffer.wrap(infLog));
            System.out.println("linker error:" + Byte.toString(infLog[0]));
            
        }
        gl.glValidateProgram(shaderProgramID);
        
    }

Why do you call glDeleteShader()? I do not do this, and AFAIK should generally done once you are finished with your sharers. ie not using them anymore.

Also you never update xOffset or yoffset. You perhaps want to add a xoffset+=.01 or something.

First I had an another code for update vertices and vertex shader without uniform vec2 offset:

Vertex Shader


#version 330

layout(location = 0) in vec4 position;

void main()
{
	gl_Position = position;
}


Function for update vertices which was being executed in display:


private void adjustVertexData(GL3 gl)
{
         
     for(int i = 0; i < fNewData.capacity(); i += 4)
     {
          tempVertexData[i] += fXOffset;
          tempVertexData[i + 1] += fXOffset;
     }
        
        
     for(int i = 0; i < fNewData.capacity(); i++)
     {
          fNewData.put(tempVertexData[i]);
     }
        
     fNewData.rewind();
     gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vertexBufferObject);
     gl.glBufferSubData(GL3.GL_ARRAY_BUFFER, 0, Buffers.SIZEOF_FLOAT * fNewData.capacity(), fNewData);
     gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0);
}

Fields fXOffset and fYOffset was initialized ( private float fXOffset = 0.01f; private float fYOffset = 0.01f;) in both cases. I assumed that I don’t need update fXOffset and fYOffset in the next version of my program which has another vertex shader and use glUniform2f. Now everything works fine with fXOffset += 0.01f; and fYOffset += 0.01 at the begining of display. I don’t clearly understand why earlier my code doesn’t work properly. Is it because of uniform variable nature ?

With glDeleteShader the program also works. I saw this way of using glDeleteShaders in some sample program and I coded my program similar. Is it mistake ? When using glDeleteShader in that way can bring me some troubles ?

If I remember correctly, a shader won’t actually be deleted until it glDeleteShader has been called AND it has been unattached from all un-deleted programs. I think by calling glDeleteShader right after attaching will mean that when the glsl program object is deleted, all of its shaders will be cleaned up automatically.