Iv'e exported a model in blender to a .obj file. Iv'e managed to create a very simple
class that loads vertices and indices to arrays. My problem is that i want the texture coordinates (vt) and normals (vn) as well. So for example, i would need 4 vertices * 6 faces for a simple cube to be able to use texture but i only get 8 in my .obj file, as well as i don't have a clue about how to handle the indices for vt since i can only have one array/buffer for indices but i get two different v/vt in .obj file.
Is there any loader out there that only returns arrays or similar for vertex, texture, normals, and one array of indices? Or examples of how to write one? Iv'e only found loaders in complete 3d engines so far and that is not what i want.
4 vertices * 6 faces is more than you need. Actually it will be not efficient. Exported vertices that you've got are optimized with indexes. Using Opengl-es you can point from where to get vertices(array) and then draw a vertices using their indexes in another array. In result you get 8 vertices versus possible 24 vertices, you need less memory to store. So efficience is 16/24 *100%. Imagine that you'll have a model with 1000 vertices.
Index of vertex means that in another array with a proper offset GPU will get a vertex (size_of_vertex(3 floats)*index) and a proper offset for UV coords (size_of_UVcoord(2 floats)*index)
this code for opengl ES 2.0 but you can get an idea:
GLES20.glUseProgram(programTextured);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
sqTex.getVertexBuffer().position(sqTex.VERT_OFFSET);
GLES20.glVertexAttribPointer(GLES20.glGetAttribLocation(programTextured, "aPosition") 3, GLES20.GL_FLOAT, false, 5 * 4, sqTex.getVertexBuffer()); GLES20.glEnableVertexAttribArray(GLES20.glGetAttribLocation(programTextured, "aPosition"));
sqTex.getVertexBuffer().position(sqTex.TEXT_OFFSET);
GLES20.glVertexAttribPointer(
GLES20.glGetAttribLocation(programTextured, "aTextureCoord"), 2,
GLES20.GL_FLOAT, false, 5 * 4, sqTex.getVertexBuffer());
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, sqTex.getIndexBuffer());
and sqTEx is a instance of TexturedSquare:
public class TexturedSquare {
// private float[] vertices=new float[4];
float vertices[] = { -1.0f, -1.0f, 0.0f,0.0f,0.0f, // 0, Top Left //x,y,z,u,v
1.0f, -1.0f, 0.0f,0.0f,1.0f, // 1, Bottom Left
1.0f, 1.0f, 0.0f,1.0f,1.0f, // 2, Bottom Right
-1.0f, 1.0f, 0.0f,1.0f,0.0f, // 3, Top Right
};
public static int VERT_OFFSET=0;
public static int TEXT_OFFSET=3;
short[] indices = { 0, 1, 2, 2, 3, 0 };;
// Our vertex buffer.
private FloatBuffer vertexBuffer;
// Our index buffer.
private ShortBuffer indexBuffer;
public TexturedSquare()
{
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
// short is 2 bytes, therefore we multiply the number if
// vertices with 2.
ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
ibb.order(ByteOrder.nativeOrder());
indexBuffer = ibb.asShortBuffer();
indexBuffer.put(indices);
indexBuffer.position(0);
}
FloatBuffer getVertexBuffer(){
return vertexBuffer;
}
ShortBuffer getIndexBuffer(){
return indexBuffer;
}
}
Look a jPCT (or jPCT-AE), it's an exellent 3D library for Java (and/or Android). It supports 3ds/obj loading out of the box.
Related
I'm just starting to learn OpenGL ES but am having some trouble understanding how the vertex and indices work. My current understanding is that a Vertex is a point on the shape itself, and that the indices represent the 'triangles' within the vertex points. I'm following a tutorial that has me define the vertex and indices points as below...
Vertex data
-1.0f, -1.0f
1.0f, -1.0f
-1.0f, 1.0f
1.0f, 1.0f
indices data
0,3,1,
0,2,3
I understand that defining indices should always start at one vertex but to me these numbers just dont add up. When I draw this on paper it looks like the actual image drawn should be two triangles together that create a 'crown' shape. Can someone explain why this is actually drawing a square instead of the 'crown' that I am expecting?
Source code for the Square class:
public class Square {
private FloatBuffer mFVertexBuffer;
private ByteBuffer mColorBuffer;
private ByteBuffer mIndexBuffer;
public Square() {
// 2D Points
float[] square = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
byte maxColor = (byte) 225;
/**
* Each line below represents RGB + Alpha transparency
*/
byte colors[] = {
0, maxColor, 0, maxColor,
0, maxColor, maxColor, maxColor,
0, 0, 0, maxColor,
maxColor, 0, maxColor, maxColor,
};
//triangles
byte[] indicies = {
0,3,1,
0,2,3
};
/**
* Make sure that bytes are in correct order, otherwise they might be
* drawn backwards
*/
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(square.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
mFVertexBuffer = byteBuffer.order(ByteOrder.nativeOrder())
.asFloatBuffer();
mFVertexBuffer.put(square);
mFVertexBuffer.position(0);
mColorBuffer = ByteBuffer.allocateDirect(colors.length);
mColorBuffer.put(colors);
mColorBuffer.position(0);
mIndexBuffer = ByteBuffer.allocateDirect(indicies.length);
mIndexBuffer.put(indicies);
mIndexBuffer.position(0);
}
public void draw(GL10 gl) {
/**
* Make open GL only draw the front of the triangle (GL_CW = Graphics
* Library Clockwise)
*
* Back of triangle will not be drawn
*/
gl.glFrontFace(GL11.GL_CW);
/**
* specifies number of elements per vertex
*
* specifies floating point type
*
* Sets stride = 0 bytes* (Stride allows to use different types of data
* interchangably with opengl )
*/
gl.glVertexPointer(2, GL11.GL_FLOAT, 0, mFVertexBuffer);
// 4 because we are using 4 colors in our color bufer array
gl.glColorPointer(4, GL11.GL_UNSIGNED_BYTE, 0, mColorBuffer);
/**
* draws the image
*
* first argument specifies geomety format
*/
gl.glDrawElements(GL11.GL_TRIANGLES, 6, GL11.GL_UNSIGNED_BYTE,
mIndexBuffer);
// Reset to CounterClockwise
gl.glFrontFace(GL11.GL_CCW);
}
}
Let me know if more info is needed...
You defined four vertices:
2 3
0 1
Your indices then defined two triangles, 0-3-1:
.
...
....
.....
and 0-2-3:
.....
....
...
.
put together they form a square.
I don't think your indexes are correct, try drawing the bottom line then moving to the top verts. If I am picturing your indexes correctly, they really are trying to draw a square.
Try:
0, 1, 3
0, 1, 2
Instead
Edit: Even I got the order mixed up, fixed for a mistake
I spend almost whole day trying to render simple polygon using opengl 1.1 and vertex buffers, but no luck. I searched and searched, but I haven't found much.
This is what i have so far:
public class Polygon {
int bufferId = 0;
private FloatBuffer vertexBuffer; // Buffer for vertex-array
private float[] vertices = { // Vertices for the square
-1.0f, -1.0f, 0.0f, // 0. left-bottom
1.0f, -1.0f, 0.0f, // 1. right-bottom
-1.0f, 1.0f, 0.0f, // 2. left-top
1.0f, 1.0f, 0.0f // 3. right-top
};
private ByteBuffer indexBuffer;
private byte[] indices = {0, 1, 2, 3}; // Indices to above vertices (in CCW)
// Constructor - Setup the vertex buffer
public Polygon() {
// Setup vertex array buffer. Vertices in float. A float has 4 bytes
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder()); // Use native byte order
vertexBuffer = vbb.asFloatBuffer(); // Convert from byte to float
vertexBuffer.put(vertices); // Copy data into buffer
vertexBuffer.position(0); // Rewind
indexBuffer = ByteBuffer.allocateDirect(indices.length);
indexBuffer.put(indices);
indexBuffer.position(0);
int[] buffers = new int[1];
GLES11.glGenBuffers(1, buffers, 0);
bufferId = buffers[0];
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, bufferId);
GLES11.glBufferData(GLES11.GL_ARRAY_BUFFER, vertices.length, vertexBuffer, GLES11.GL_STATIC_DRAW);
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, 0);
}
// Render the shape
public void draw(GL10 gl) {
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, bufferId);
GLES11.glEnableClientState(GL10.GL_VERTEX_ARRAY);
GLES11.glVertexPointer(3, GLES11.GL_FLOAT, 0, 0);
GLES11.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length);
GLES11.glDisableClientState(GL10.GL_VERTEX_ARRAY);
GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, 0);
}
}
It doesn't render anything and there is no relevant error in android logcat.
I ommited rest of the code. The problem is obviously in this class, since it works fine when I change draw method to this:
public void draw(GL10 gl) {
GLES11.glEnableClientState(GL10.GL_VERTEX_ARRAY);
GLES11.glVertexPointer(3, GLES11.GL_FLOAT, 0, vertexBuffer);
GLES11.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length);
GLES11.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
So, what am I doing wrong?
Don't look in the logCat for errors, you want to check for OpenGL errors with glGetError(), and check that the return value is zero (no error), or nonzero (error).
vertices.length is the wrong argument to glDrawArrays. You want to supply the number of vertices, not the number of floats. It should be vertices.length/3 (3 floats per vertex).
You're currently drawing way past your array into some garbage data, so I'm not sure what kind of consequences that could have.
I've been trying to use
gl.glDrawElements(GL10.GL_POINTS, 4, GL10.GL_UNSIGNED_BYTE, vertexBuffer);
to draw 4 points on my screen with a vertex buffer, but I can't get it to work. All I want to draw is points, because eventually I want to make a point cloud display. If I have a large number of points (eventually), is vertex buffer the way to go? They won't be changing, but I will want to change the perspective and scale at which they are viewed.
vertexBuffer setup:
private float vertices[] = {
-3.0f, 1.0f, -2.0f, // 0, Top Left
-3.0f, -1.0f, 0.0f, // 1, Bottom Left
-2.0f, -1.0f, -2.0f, // 2, Bottom Right
-2.0f, 1.0f, 0.0f, // 3, Top Right
};
// Our vertex buffer.
private FloatBuffer vertexBuffer;
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
This is my current draw call for my points (I don't want indices because shape drawing order doesn't matter to me):
public void draw(GL10 gl) {
// Enabled the vertices buffer for writing and to be used during
// rendering.
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glPointSize(3);
// Specifies the location and data format of an array of vertex
// coordinates to use when rendering.
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glDrawElements(GL10.GL_POINTS, 4,
GL10.GL_UNSIGNED_BYTE, vertexBuffer);
// Disable the vertices buffer.
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
// Disable face culling.
gl.glDisable(GL10.GL_CULL_FACE);
}
The program currently crashes when I call draw();
Thank you!
You make completely wrong use of glDrawElements. This function wants an index array containing indices into the vertex arrays and not the vertex data itself (that's what glVertexPointer is for). Either use
private unsigned byte indices[] = { 0, 1, 2, 3 };
...
gl.glDrawElements(GL10.GL_POINTS, 4, GL10.GL_UNSIGNED_BYTE, indices);
But in your case you just render all points and don't need any indices, so you can just call
gl.glDrawArrays(GL10.GL_POINTS, 0, 4);
instead of glDrawElements.
EDIT: The specific reason it crashes is that glDrawElements interprets the supplied vertexBuffer as an array of 4 bytes and these bytes reference vertices out of the range of your vertex data (0 to 3).
I'm working on my very first openGL game, inspired by the game "Greed Corp" on the playstation network. It's a turn based strategy game that is based on a hex grid. Each hexagon tile has it's own height and texture.
I'm currently drawing a hexagon based on some examples and tutorials I've read. Here's my hextile class:
public class HexTile
{
private float height;
private int[] textures = new int[1];
private float vertices[] = { 0.0f, 0.0f, 0.0f, //center
0.0f, 1.0f, 0.0f, // top
-1.0f, 0.5f, 0.0f, // left top
-1.0f, -0.5f, 0.0f, // left bottom
0.0f, -1.0f, 0.0f, // bottom
1.0f, -0.5f, 0.0f, // right bottom
1.0f, 0.5f, 0.0f, // right top
};
private short[] indices = { 0, 1, 2, 3, 4, 5, 6, 1};
//private float texture[] = { };
private FloatBuffer vertexBuffer;
private ShortBuffer indexBuffer;
//private FloatBuffer textureBuffer;
public HexTile()
{
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
ibb.order(ByteOrder.nativeOrder());
indexBuffer = ibb.asShortBuffer();
indexBuffer.put(indices);
indexBuffer.position(0);
/*ByteBuffer tbb = ByteBuffer.allocateDirect(texture.length * 4);
tbb.order(ByteOrder.nativeOrder());
textureBuffer = tbb.asFloatBuffer();
textureBuffer.put(texture);
textureBuffer.position(0);*/
}
public void setHeight(float h)
{
height = h;
}
public float getHeight()
{
return height;
}
public void draw(GL10 gl)
{
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
//gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
gl.glDrawElements(GL10.GL_TRIANGLE_FAN, indices.length, GL10.GL_UNSIGNED_SHORT, indexBuffer);
}
public void loadGLTexture(GL10 gl, Context context)
{
textures[0] = -1;
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.hex);
while(textures[0] <= 0)
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
}
}
Every frame I'm looping through all visible tiles to draw them, that would be 11 * 9 tiles MAX. This however drops my framerate to 38, and that is without even drawing textures on them, just the flat hexagons.
Now I'm trying to figure out how to increase performance. I figured drawing the whole grid at once could be faster, but I have no idea how to do that, since each tile can have a different height, and will most likely have a different texture than a neighboring tile.
I'd really appreciate some help on this, because I'd like to get started on the actual game ^.^
Assuming your hex grid is static you can just spin over all your hexagons once, generate their geometry, and append everything to one (or more, if you have more than 2^16 vertices) large VBO that you can draw in one go.
As far as textures go you may be able to use a texture atlas.
I'm currently learning OpenGL as well, I've produced one Android OpenGL application called 'Cloud Stream' where I found similar issues with performance.
As a general answer to performance concerns, there are a few things which can help. The Vertex pipeline for Graphics at a hardware level apparently is more efficient when passed larger amounts of vertices at once. Calling glVertexPointer for each Hex tile is not as efficient as calling it once with the vertices of all tiles.
This makes things harder to code as you essentially draw all your tiles at once, but it does seem to speed things up a bit. In my application, all of the clouds are drawn in the one call.
Other avenues to try would be to save the Vertice positions in a VBO which I found to be quite tricky, at least it was when trying to cater for 2.1 users. These days things might be easier, I'm not sure. With that the idea is to save the Vertice array for your tile into Video Memory and you get back a pointer like you do with your Textures. As you can imagine, not sending your Vertice Array Buffer up each frame speeds things up a little for each tile draw. Even if things aren't static its a good approach as I doubt things are changing for each frame.
Another suggestion I came across online was to use Short instead of Float for your Vertices. And then to change the scale of your finished rendering to get your desired size. This would lower the size of your vertices and speed things up a little... not a huge amount but still worth trying I would say.
One last thing I would like to add, if you end up using any Transparency... be aware that you must paint back to front for it to work which has a performance impact as well. If you draw front to back, the Rendering engine automatically knows not to draw when coordinates are not visible... drawing back to front means everything is drawn. Keep this in mind and always try to draw front to back when possible.
Good luck with your game, I'd love to know how you got on... I'm just starting my game and I'm quite excited to start. If you haven't already come across this... I think it's worth a read. http://www.codeproject.com/KB/graphics/hexagonal_part1.aspx
Im new to openGL, and im trying to map an texture to a square. I followed NeHe's tutorial on texture mapping here:
http://insanitydesign.com/wp/wp-content/uploads/lesson06.zip
Right now i see my image...but its not mapping correctly. Heres the original image:
http://ge.tt/2FzsdIx
...and heres what im seeing.
http://ge.tt/6y3cdIu
I used the vertices and texture arrays from this great iphone tutorial (link below) so im hoping they have been mapped correctly. Below is the link to my code in Square.java, thanks!
public class Square {
// Our vertices.
private float vertices[] = {
-1.0f, 1.0f, 0.0f, // 0, Top Left
-1.0f, -1.0f, 0.0f, // 1, Bottom Left
1.0f, -1.0f, 0.0f, // 2, Bottom Right
1.0f, 1.0f, 0.0f, // 3, Top Right
};
// The order we like to connect them.
private short[] indices = { 0, 1, 2, 0, 2, 3 };
// Our vertex buffer.
private FloatBuffer vertexBuffer;
// Our index buffer.
private ShortBuffer indexBuffer;
/** The buffer holding the texture coordinates */
private FloatBuffer textureBuffer;
//the texture pointer, holds the texture name which is actually a number.
private int[] textures = new int[1];
public Square() {
// a float is 4 bytes, therefore we multiply the number if
// vertices with 4.
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
// short is 2 bytes, therefore we multiply the number if
// vertices with 2.
ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
ibb.order(ByteOrder.nativeOrder());
indexBuffer = ibb.asShortBuffer();
indexBuffer.put(indices);
indexBuffer.position(0);
//plot our texture
float textCoords[]={
//Mapping coordinates for the vertices
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
ByteBuffer tbb = ByteBuffer.allocateDirect(textCoords.length * 4); tbb.order(ByteOrder.nativeOrder());
textureBuffer = tbb.asFloatBuffer(); textureBuffer.put(textCoords);
textureBuffer.position(0);
}
//load our texture(s)
static void loadTexture(GL10 gl, Context context, int resource) {
Bitmap bmp = BitmapFactory.decodeResource(context.getResources(),resource);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);
gl.glTexParameterx(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterx(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
bmp.recycle();
}
/**
* This function draws our square on screen.
* #param gl
*/
public void draw(GL10 gl) {
//use our textures
gl.glEnable(GL10.GL_TEXTURE_2D); // workaround bug 3623
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
// Counter-clockwise winding.
gl.glFrontFace(GL10.GL_CCW); // OpenGL docs
// Enable face culling.
gl.glEnable(GL10.GL_CULL_FACE); // OpenGL docs
// What faces to remove with the face culling.
gl.glCullFace(GL10.GL_BACK); // OpenGL docs
// Enabled the vertices buffer for writing and to be used during
// rendering.
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// OpenGL docs.
// Specifies the location and data format of an array of vertex
// coordinates to use when rendering.
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, // OpenGL docs
vertexBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,// OpenGL docs
GL10.GL_UNSIGNED_SHORT, indexBuffer);
// Disable the vertices buffer.
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); // OpenGL docs
// Disable face culling.
gl.glDisable(GL10.GL_CULL_FACE); // OpenGL docs
}
}
iPhone tutorial:
http://www.iphonemobilephones.com/opengl-es-from-the-ground-up-part-6-textures-and-texture-mapping.html
You can draw faster using a triangle fan, in the following order in your indices, faster.
01
32
Then you don't need to use drawElements or indices, you can just feed it to drawArrays and only need 4 elements.
Your bug is that the , the tex coords are wrong
tl is 0,0
bl is 0,1
br is 1,1
tr is 1,0
You have
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
So your UV is wrong.
Normally the rendering of a square in OpenGL looks something like this
gl.glLoadIdentity();
gl.glBindTexture(GL.GL_TEXTURE_2D,0);
gl.glBegin(GL_QUADS)
glVertex(x,y,z);
glTexcoord2f(s,t);
glVertex(-x,y,z);
glTexcoord2f(-s,t);
glVertex(-x,-y,z);
glTexcoord2f(-s,-t);
glVertex(x,-y,z);
glTexcoord2f(s,-t);
gl.glEnd();
I don't see anything like that, but I have never done GLES on Android before so I may be too old.
see https://github.com/ChrisLundquist/Asteroids/blob/master/src/ScenePanel.java#L277