Question

I am trying to render three points using array buffers, but I can't get anything rendered.
This is my code:

import java.nio.*;
import javax.media.opengl.*;

public class SimpleScene implements GLEventListener 
{
        private GL3 gl;
        int myIdentityShader;

        @Override
        public void display(GLAutoDrawable drawable) {
            gl.glClear(GL3.GL_COLOR_BUFFER_BIT);

            gl.glUseProgram(myIdentityShader);
            gl.glDrawArrays(GL3.GL_POINTS, 0, 3);
        }
        @Override
        public void dispose(GLAutoDrawable drawable) {
            gl.glDeleteProgram(myIdentityShader);
            gl.glDeleteVertexArrays(1, vertexArrayObject, 0);
        }

        @Override
        public void init(GLAutoDrawable drawable) {
            gl = drawable.getGL().getGL3();

            try {
                myIdentityShader = createShaderProgram();
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }

            gl.glPointSize(30);
            gl.glClearColor(0.7f, 0, 0, 1);

            float[] floatData = {
                    0.25f, -0.25f, 0.5f, 1.0f,
                    -0.25f, -0.25f, 0.5f, 1.0f,
                    0.25f, 0.25f, 0.5f, 1.0f
                    };

            FloatBuffer data = FloatBuffer.allocate(3 * 4); 
            for (int i=0;i<12;i++)
                data.put(floatData[i]);

            gl.glGenVertexArrays(1, vertexArrayObject, 0);
            gl.glBindVertexArray(vertexArrayObject[0]);

            int[] buffers = new int[1];
            gl.glGenBuffers(1, buffers, 0);
            gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, buffers[0]);
            gl.glBufferData(GL3.GL_ARRAY_BUFFER, data.capacity(), data, GL3.GL_STATIC_DRAW);

            gl.glVertexAttribPointer(2, 4, GL3.GL_FLOAT, false, 0, 0);
            gl.glEnableVertexAttribArray(2);
        }

        @Override
        public void reshape(GLAutoDrawable drawable, int arg1, int arg2, int arg3,
                int arg4) {
            // TODO Add reshape code

        }

        private String vertexShader = "#version 130                                                         \n" +
                                        "in vec4 position;                                                  \n" +
                                        "void main(void)                                                    \n" + 
                                        "{                                                                  \n" + 
                                        "    gl_Position = position;                                        \n" +
                                        "}                                                                  \n";

        private String fragmentShader = "#version 130                                                       \n" +
                                        "out vec4 vFragColor;                                               \n" +
                                        "void main(void)                                                    \n" + 
                                        "{                                                                  \n" + 
                                        "    vFragColor = vec4(0.0, 0.8, 1.0, 1.0);                         \n" +
                                        "}                                                                  \n";
        private int[] vertexArrayObject = new int[1];


        private int createShaderProgram() throws Exception
        {
            int hVertexShader, hFragmentShader, hShaderProgram;
            int[] successTest = new int[] {1};

            hVertexShader = gl.glCreateShader(GL3.GL_VERTEX_SHADER);
            hFragmentShader = gl.glCreateShader(GL3.GL_FRAGMENT_SHADER);

            gl.glShaderSource(hVertexShader, 1, new String[] {vertexShader}, null);
            gl.glShaderSource(hFragmentShader, 1, new String[] {fragmentShader}, null);

            gl.glCompileShader(hVertexShader);
            gl.glCompileShader(hFragmentShader);

            gl.glGetShaderiv(hVertexShader, GL3.GL_COMPILE_STATUS, successTest, 0);
            if (successTest[0] == 0)
            {
                byte[] infoLog = new byte[1024];
                gl.glGetShaderInfoLog(hVertexShader, 1024, null, 0, infoLog, 0);
                gl.glDeleteShader(hVertexShader);
                gl.glDeleteShader(hFragmentShader);
                throw new Exception("Vertex shader compilation failed with: " + new String(infoLog));
            }
            gl.glGetShaderiv(hFragmentShader, GL3.GL_COMPILE_STATUS, successTest, 0);
            if (successTest[0] == 0)
            {
                byte[] infoLog = new byte[1024];
                gl.glGetShaderInfoLog(hFragmentShader, 1024, null, 0, infoLog, 0);
                gl.glDeleteShader(hVertexShader);
                gl.glDeleteShader(hFragmentShader);
                throw new Exception("Fragment shader compilation failed with: " + new String(infoLog));
            }

            hShaderProgram = gl.glCreateProgram();
            gl.glAttachShader(hShaderProgram, hVertexShader);
            gl.glAttachShader(hShaderProgram, hFragmentShader);

            gl.glBindAttribLocation(hShaderProgram, 2, "position");

            gl.glLinkProgram(hShaderProgram);

            gl.glGetProgramiv(hShaderProgram, GL3.GL_LINK_STATUS, successTest, 0);
            if (successTest[0] == 0)
            {
                byte[] infoLog = new byte[1024];
                gl.glGetProgramInfoLog(hShaderProgram, 1024, null, 0, infoLog, 0);
                gl.glDeleteProgram(hShaderProgram);
                throw new Exception("Shader linking failed with: " + new String(infoLog);
            }

            gl.glDeleteShader(hVertexShader);
            gl.glDeleteShader(hFragmentShader);

            return hShaderProgram;

        }
    }

I am absolutely sure the shaders and the createShaderProgram method are correct. When I use glVertexAttrib4fv, all three points get rendered in the same location (as expected), but when I use glVertexAttribPointer nothing gets rendered and there’s no error (glGetError returns 0).
I discovered that glVertexAttrib4fv does not send the coordinates if the attribute index is 0, thus resulting in all points being rendered in the center of the screen. This doesn't happen with glVertexAttribPointer, so the coordinates are sent.

Was it helpful?

Solution

You are using Vertex Array Objects inefficiently. The whole point of using a VAO is so that you do not have to set your vertex attrib. pointer and enable / disable the pointers every time you draw something. Set the pointer when you initialize the VAO and since it keeps track of this state, all you have to do is change the bound VAO every time you want to draw something.

However, your actual problem is that you are never binding the vertex attribute position in your vertex shader to generic attribute location 2. Most GLSL implementations will automatically assign that vertex attribute location 0, though this is not required behavior (so do not rely on it). You can either query the location (glGetAttribLocation) of this attribute by name after you link your program, or you can bind the attribute location yourself (glBindAttribLocation). In either case, you must match the attribute location for your pointer to the attribute in the shader.

When I use glVertexAttrib4fv, all three points get rendered in the same location, but when I use glVertexAttribPointer nothing gets rendered and there’s no error (glGetError returns 0).

This is to be expected, glVertexAttrib4fv (...) sets up a constant value to use for EVERY vertex shader invocation that pulls data from that location. While it is true that it takes a pointer (in the C language bindings), that pointer is merely OpenGL's way of passing an array. If you change the value of the data pointed to after the call completes, nothing is going to happen. That is literally why there is a different class of functions to set vertex array pointers.

Update:

After seeing your updated code for this question, the real problem popped up. In Java, when you use FloatBuffer.put (...), it increments the base address of the buffer (which JOGL uses when you call glVertexAttribPointer (...)). You need to flip the buffer by calling FloatBuffer.flip (...), and this will effectively rewind the buffer so that JOGL will read beginning with the first element in the buffer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top