Tuesday, August 30, 2016

How should I represent a tile in OpenGL-es


Let me start with I am currently learning OpenGl-es using Android.


I have been having the hardest time trying to design a simple and logical way of making tiles (2d flat polygons). The tutorials tell me to just keep the polygon as a float array of veticies:


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

};

That in and of itself is easy enough. I modified the code to suit my desired polygon and it drew fantastic. Now I wanted to draw more tiles and have a scrolling feature (look around the world). But I'm not sure what's the best way to do so.


Should I leave every tile with a float array of indices and when it comes time to move the tile, directly modify thefloat values?


Is it a good idea to create an ArrayOfPoints (Point just being a container for exactly 3 float values) class to hold all of the points and then have methods that cycle through the points and change their values in a more safe fashion?


Does anyone have any tutorials on simple tile based map building so I can look at how they do their maps?


(Note: these questions are based on what I have read on animating. That is to say that you change the coordinates of the object in relation to the origin and leave the camera at 0,0,0. If it is more proper to just leave objects where they are, I guess my question loses value.)



Answer



I've tried lots of variations myself; the recipe I've found best is:


Put any tile textures into a texture atlas. In this way, you can draw your whole map in a single draw-op because they are all using the same texture.



Mipmap the texture atlas, natuarally. For a large number of tiles you may spill over one texture 'page' in the atlas and it turns into multiple pages. If you keep that in mind, it won't be a big deal to retrofit support for pages if you need it.


If your tiles are a nice fixed size then just use the smallest non-float data-type for the vertex components for the points that you can e.g. bytes if the map is less than 256x256. Texture coordinates also help not being float.


Now build your map VBO using interleaved texture coordinates and vertices for a GL_TRIANGLE_STRIP array. I imagine that each vertex data starting on a nice 4-byte boundary is a good idea, but I have no empirical data to support that. Its just a hunch. Avoid element index arrays.


It depends on the camera position and such, but I found the best performance is to regenerate the tile array to draw all visible tiles each time the camera moves! This has, in my code, won more framerate than approaches of keeping all vertices GPU-side in blocks or such and issuing multiple calls to draw all the bits that are visible.


So what I normally do is, if the camera moves, compute the visible tiles and make an array of them, that I draw. Then if the next frame the camera hasn't moved, at that point promote it to be the vbo for subsequent frames until the camera moves again.


You could use gl_VertexID in the vertex shader to avoid needing x and z components for your vertices at all. (I haven't tried that, I've had problems with gl_VertexID on integrated Intel drivers on the desktop, stopping my cross-platform efforts in that direction. But on Android (Imagination/NVidia/Mali) devices it likely works well and is well worth the effort.)


If your map has varying heights then you have to have three components (or, with gl_VertexID, one) for the vertices but otherwise you don't need that y and then you don't need to track the normals per vertex either.


I rather hope someone weighs in with sounder advice to try something I haven't thought of myself, so as to improve my engine too ;)


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...