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;
}
}