0
\$\begingroup\$

I've been having trouble texturing a cube using vertex buffer objects.

EDIT: I updated/replaced my shaders to fit the right version. The program compiles and links, but it shuts down java in drawCubeVBO().

EDIT2: I simplified the shaders so I could figure out setting uniforms first. The program runs, but the VBO doesn't have any texture on it. Many examples I've seen do basically the same thing I am (I think). So I think the problem now could be something small or obvious that I'm not seeing.

EDIT3: Now I've been trying to convert from drawElements to drawArrays. I can't get the cube to render let alone render with textures. When I run this, there are clearly triangles being rendered, but I can't relate their position to the vertex array. For example, some of the triangles have points at 0,0,0 and there are no points 0,0,0 in vertexArray. I think I may be missing some glDrawArrays syntax or I left something from glDrawElements that shouldn't be there.

initVBO is called only once before rendering and drawCubeVBO is called every frame

    public void initVBO(GL2 gl, String textureFileName, String textureFileType) {



// cube ///////////////////////////////////////////////////////////////////////
//      v6----- v5
  //   /|      /|
  //  v1------v0|
  //  | |     | |
  //  | |v7---|-|v4
  //  |/      |/
  //  v2------v3

  // vertex coords array for glDrawArrays() =====================================
  // A cube has 6 sides and each side has 2 triangles, therefore, a cube consists
  // of 36 vertices (6 sides * 2 tris * 3 vertices = 36 vertices). And, each
  // vertex is 3 components (x,y,z) of floats, therefore, the size of vertex
  // array is 108 floats (36 * 3 = 108).

  float[] vertexArray = { 1, 1, 1,  -1, 1, 1,  -1,-1, 1,      // v0-v1-v2 (front)
                         -1,-1, 1,   1,-1, 1,   1, 1, 1,      // v2-v3-v0

                          1, 1, 1,   1,-1, 1,   1,-1,-1,      // v0-v3-v4 (right)
                          1,-1,-1,   1, 1,-1,   1, 1, 1,      // v4-v5-v0

                          1, 1, 1,   1, 1,-1,  -1, 1,-1,      // v0-v5-v6 (top)
                         -1, 1,-1,  -1, 1, 1,   1, 1, 1,      // v6-v1-v0

                         -1, 1, 1,  -1, 1,-1,  -1,-1,-1,      // v1-v6-v7 (left)
                         -1,-1,-1,  -1,-1, 1,  -1, 1, 1,      // v7-v2-v1

                         -1,-1,-1,   1,-1,-1,   1,-1, 1,      // v7-v4-v3 (bottom)
                          1,-1, 1,  -1,-1, 1,  -1,-1,-1,      // v3-v2-v7

                          1,-1,-1,  -1,-1,-1,  -1, 1,-1,      // v4-v7-v6 (back)
                         -1, 1,-1,   1, 1,-1,   1,-1,-1 };    // v6-v5-v4

        vertices = Buffers.newDirectFloatBuffer(vertexArray.length);
        vertices.put(vertexArray);
        vertices.flip();

        FloatBuffer textureData = Buffers.newDirectFloatBuffer(12);
        textureData.put(textureLeft);
        textureData.put(textureRight);
        textureData.put(textureBottom);
        textureData.put(textureTop);
        textureData.flip();

        int[] temp = new int[3];
        gl.glGenBuffers(3, temp, 0);

        VBOVertices = temp[0];
        gl.glBindBuffer(GL.GL_ARRAY_BUFFER, VBOVertices);
        gl.glBufferData(GL.GL_ARRAY_BUFFER, vertices.capacity()
                * Buffers.SIZEOF_FLOAT, vertices, GL.GL_STATIC_DRAW);
        gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);

        vboTextureCoordHandle = temp[2];
        gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vboTextureCoordHandle);
        gl.glBufferData(GL.GL_ARRAY_BUFFER, vboTextureCoordHandle, textureData, GL.GL_STAT

IC_DRAW);
            gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);

            shader = new Shader(gl);
            shader.bind(gl);
            shader.attachVertexShader(gl);
            shader.attachFragmentShader(gl);
            shader.link(gl);
            //shader.unbind(gl);
        }

        public void drawCubeVBO(GL2 gl, String textureFileName, String textureFileType) {


 //shader.bind(gl);

    //initializing textures
    this.textureFileName = textureFileName;
    this.textureFileType = textureFileType;


loadTexture(gl);
    texture.enable(gl);
    gl.glEnable(GL.GL_TEXTURE_2D);  

    //setting the uniform
    shader.setUniform(gl, "tex", 0);  

    //activating textures
    gl.glActiveTexture(GL2.GL_TEXTURE0 + 0);
    texture.bind(gl);      

    //drawing
    gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
    gl.glEnableClientState(GL2.GL_TEXTURE_COORD_ARRAY);

    /* Setup Position Pointer */
    gl.glBindBuffer    (GL.GL_ARRAY_BUFFER, VBOVertices);
    gl.glVertexPointer (3, GL.GL_FLOAT, 0, 0);

    /* Setup Texture Coordinate Pointer */
    gl.glBindBuffer      (GL.GL_ARRAY_BUFFER, vboTextureCoordHandle);
    gl.glTexCoordPointer (2, GL.GL_FLOAT, 0, 0);

//actual drawing
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, VBOVertices);
gl.glDrawArrays(GL.GL_TRIANGLES, (int) vertices.get(0), vertices.capacity());

gl.glDisableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);

//shader.unbind(gl);

        }

    public void loadTexture(GL2 gl) {
                // Load texture from image
                try {
                    // Create a OpenGL Texture object from (URL, mipmap, file suffix)
                    // Use URL so that can read from JAR and disk file.
                    texture = TextureIO.newTexture(getClass().getClassLoader()
                            .getResource(textureFileName), // relative to project root
                            false, textureFileType);

                    // Use linear filter for texture if image is larger than the
                    // original texture
                    gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                    // Use linear filter for texture if image is smaller than the
                    // original texture
                    gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

                    // Texture image flips vertically. Shall use TextureCoords class to
                    // retrieve
                    // the top, bottom, left and right coordinates, instead of using
                    // 0.0f and 1.0f.
                    TextureCoords textureCoords = texture.getImageTexCoords();

                    textureTop = textureCoords.top();
                    textureBottom = textureCoords.bottom();
                    textureLeft = textureCoords.left();
                    textureRight = textureCoords.right();

                } catch (GLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

        }

And the shaders:

private String vertexShaderString =
        "#version 330 core\n"+

        "layout(location = 0) in vec2 pos;\n"+
        "layout(location = 1) in vec2 tex;\n"+

        "out vec2 texCoords;\n"+

        "void main()\n"+
        "{\n"+
            "texCoords = tex;\n"+
            "gl_Position = vec4(pos, 0.0, 1.0);\n"+
        "}";

private String fragmentShaderString = 
        "#version 330 core\n"+

        "uniform sampler2D tex;\n"+

        "in vec2 texCoords;\n"+
        "out vec4 outColor;\n"+

        "void main()\n"+
        "{\n"+
            "outColor = texture(tex, texCoords);\n"+
        "}";


    // ProgramID
    int programID;

    // Vertex Shader ID
    int vertexShaderID;

    // Fragment Shader ID
    int fragmentShaderID;

    public Shader(GL2ES2 gl) {
        programID = gl.glCreateProgram();
    }

    public void attachVertexShader(GL2ES2 gl) {

        // Create GPU shader handles
        // OpenGL ES retuns a index id to be stored for future reference.
        vertexShaderID = gl.glCreateShader(GL2ES2.GL_VERTEX_SHADER);

        // Load and compile the source
        String[] vlines = new String[] { vertexShaderString };
        int[] vlengths = new int[] { vlines[0].length() };
        gl.glShaderSource(vertexShaderID, vlines.length, vlines, vlengths, 0);
        gl.glCompileShader(vertexShaderID);

        //Check compile status for errors
        int[] compiled = new int[1];
        gl.glGetShaderiv(vertexShaderID, GL2ES2.GL_COMPILE_STATUS, compiled,0);
        if(compiled[0]!=0){System.out.println("Horray! vertex shader compiled");}
        else {
            int[] logLength = new int[1];
            gl.glGetShaderiv(vertexShaderID, GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0);

            byte[] log = new byte[logLength[0]];
            gl.glGetShaderInfoLog(vertexShaderID, logLength[0], (int[])null, 0, log, 0);

            System.err.println("Error compiling the vertex shader: " + new String(log));
            System.exit(1);
        }

        //Attach Shader
        gl.glAttachShader(programID, vertexShaderID);
    }

    public void attachFragmentShader(GL2ES2 gl) {

        // Create GPU shader handles
        // OpenGL ES retuns a index id to be stored for future reference.
        fragmentShaderID = gl.glCreateShader(GL2ES2.GL_FRAGMENT_SHADER);

        // Load and compile the source
        String[] vlines = new String[] { fragmentShaderString };
        int[] vlengths = new int[] { vlines[0].length() };
        gl.glShaderSource(fragmentShaderID, vlines.length, vlines, vlengths, 0);
        gl.glCompileShader(fragmentShaderID);

        //Check compile status for errors
        int[] compiled = new int[1];
        gl.glGetShaderiv(fragmentShaderID, GL2ES2.GL_COMPILE_STATUS, compiled,0);
        if(compiled[0]!=0){System.out.println("Horray! fragment shader compiled");}
        else {  
            int[] logLength = new int[1];
            gl.glGetShaderiv(fragmentShaderID, GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0);

            byte[] log = new byte[logLength[0]];
            gl.glGetShaderInfoLog(fragmentShaderID, logLength[0], (int[])null, 0, log, 0);

            System.err.println("Error compiling the fragment shader: " + new String(log));
            System.exit(1);
        }

        //Attach Shader
        gl.glAttachShader(programID, fragmentShaderID);

    }



public void link(GL2ES2 gl) {

    //link
    gl.glLinkProgram(programID);


    //check for errors
    int[] compiled = new int[1];
    gl.glGetProgramiv(programID, GL2ES2.GL_LINK_STATUS, compiled,0);
    if(compiled[0]!=0){System.out.println("Horray! Shader program linked!");}
    else {
        int[] logLength = new int[1];
        gl.glGetProgramiv(programID, GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0);

        byte[] log = new byte[logLength[0]];
        gl.glGetProgramInfoLog(programID, logLength[0], (int[])null, 0, log, 0);

        System.err.println("Error linking the program: " + new String(log));


          System.exit(1);
        }

/**
 * Sets the uniforms in this shader
 * 
 * @param name    The name of the uniform
 * @param values  The values of the uniforms (Max 4)
 */
public void setUniform(GL2ES2 gl, String name, float... values)
{
    if (values.length > 4)
    {
        System.err.println("Uniforms cannot have more than 4 values");
        System.exit(1);
    }

    // Get the location of the uniform
    int location = gl.glGetUniformLocation(programID, name);

    // Set the uniform values
    switch (values.length)
    {
        case 1:
            gl.glUniform1f(location, values[0]);
            break;                
        case 2:
            gl.glUniform2f(location, values[0], values[1]);
            break;                
        case 3:
            gl.glUniform3f(location, values[0], values[1], values[2]);
            break;                
        case 4:
            gl.glUniform4f(location, values[0], values[1], values[2], values[3]);
            break;
    }
}
\$\endgroup\$
  • \$\begingroup\$ Please post the shaders too. \$\endgroup\$ – Sri Harsha Chilakapati Jun 18 '14 at 17:03
  • \$\begingroup\$ confession time: I'm not really sure what shaders are. Are they for lighting, or rendering? I'm new to openGL \$\endgroup\$ – Nate Schultz Jun 18 '14 at 17:12
  • \$\begingroup\$ Shaders are small programs that run on the graphics card. They are really important to get anything rendered on the screen using modern programmable pipeline. \$\endgroup\$ – Sri Harsha Chilakapati Jun 18 '14 at 17:14
  • \$\begingroup\$ I haven't been using shaders. Could that be the problem? Do I need shaders? Before this, I was rendering with immediate mode/display lists, but that was too slow. \$\endgroup\$ – Nate Schultz Jun 18 '14 at 17:22
  • \$\begingroup\$ Yes. You can see my tutorial series here at goharsha.com/lwjgl-tutorial-series They are written for LWJGL, but you can translate them to JOGL with ease. \$\endgroup\$ – Sri Harsha Chilakapati Jun 18 '14 at 17:24
0
\$\begingroup\$

I should have read your post completely. Using glDrawElements is not a perfect fit for textured models because there can be shared vertices but those vertices cannot have same texture coordinates all the time. So you have to add all the vertices normally as you do in the case of using glDrawArrays. So using glDrawElements is useless in this case and it requires extra memory for the ebo.

\$\endgroup\$
  • \$\begingroup\$ thank you! However I've been struggling with converting to glDrawArrays: I updated my post \$\endgroup\$ – Nate Schultz Jun 29 '14 at 16:07
0
\$\begingroup\$

I figured out my "EDIT3" problem: I didn't look closely enough at the parameters of glDrawArrays(). Instead of saying gl.glDrawArrays(GL.GL_TRIANGLES, (int) vertices.get(0), vertices.capacity()); I should have been saying gl.glDrawArrays(GL.GL_TRIANGLES, 0, vertices.capacity()); because the middle parameter is the starting point.

After that, the cube rendered with a stretched out texture on it! I'm going to take that as answering my original question because technically, there is a texture on the cube. Also, there are several other posts having that same stretched out texture problem so I'm not going to continue that here. (https://stackoverflow.com/questions/10463384/vbo-with-texture-in-lwjgl?rq=1, https://stackoverflow.com/questions/16778687/vbo-texturing-dont-work-correctly-lwjgl?rq=1, https://stackoverflow.com/questions/19032136/opengl-texture-stretched-and-wrong-vbo-vertices-incorrect)

My original post is kindof a mess with edits. The problem was much bigger than I initially expected. To reiterate: my original goal was to render a textured cube with VBOs. I learned: I needed a shader(s), I had to set my uniforms, I had to use glDrawArrays instead of glDrawElements.

Thanks so much to Sri Harsha Chilakapati for helping me through this issue!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.