Better way to generate tiles - android

I'll start by saying that i'm REALLY new to OpenGL ES (I started yesterday =), but I do have some Java and other languages experience.
I've looked a lot of tutorials, of course Nehe's ones and my work is mainly based on that.
As a test, I started creating a "tile generator" in order to create a small Zelda-like game (just moving a dude in a textured square would be awsome :p).
So far, I have achieved a working tile generator, I define a char map[][] array to store wich tile is on :
private char[][] map = {
{0, 0, 20, 11, 11, 11, 11, 4, 0, 0},
{0, 20, 16, 12, 12, 12, 12, 7, 4, 0},
{20, 16, 17, 13, 13, 13, 13, 9, 7, 4},
{21, 24, 18, 14, 14, 14, 14, 8, 5, 1},
{21, 22, 25, 15, 15, 15, 15, 6, 2, 1},
{21, 22, 23, 0, 0, 0, 0, 3, 2, 1},
{21, 22, 23, 0, 0, 0, 0, 3, 2, 1},
{26, 0, 0, 0, 0, 0, 0, 3, 2, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
};
It's working but I'm no happy with it, I'm sure there is a beter way to do those things :
1) Loading Textures :
I create an ugly looking array containing the tiles I want to use on that map :
private int[] textures = {
R.drawable.herbe, //0
R.drawable.murdroite_haut, //1
R.drawable.murdroite_milieu, //2
R.drawable.murdroite_bas, //3
R.drawable.angledroitehaut_haut, //4
R.drawable.angledroitehaut_milieu, //5
};
(I cutted this on purpose, I currently load 27 tiles)
All of theses are stored in the drawable folder, each one is a 16*16 tile.
I then use this array to generate the textures and store them in a HashMap for a later use :
int[] tmp_tex = new int[textures.length];
gl.glGenTextures(textures.length, tmp_tex, 0);
texturesgen = tmp_tex; //Store the generated names in texturesgen
for(int i=0; i < textures.length; i++)
{
//Bitmap bmp = BitmapFactory.decodeResource(context.getResources(), textures[i]);
InputStream is = context.getResources().openRawResource(textures[i]);
Bitmap bitmap = null;
try {
//BitmapFactory is an Android graphics utility for images
bitmap = BitmapFactory.decodeStream(is);
} finally {
//Always clear and close
try {
is.close();
is = null;
} catch (IOException e) {
}
}
// Get a new texture name
// Load it up
this.textureMap.put(new Integer(textures[i]),new Integer(i));
int tex = tmp_tex[i];
gl.glBindTexture(GL10.GL_TEXTURE_2D, tex);
//Create Nearest Filtered Texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
//Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
//Use the Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
}
I'm quite sure there is a better way to handle that... I just was unable to figure it. If someone has an idea, i'm all ears.
2) Drawing the tiles
What I did was create a single square and a single texture map :
/** The initial vertex definition */
private float vertices[] = {
-1.0f, -1.0f, 0.0f, //Bottom Left
1.0f, -1.0f, 0.0f, //Bottom Right
-1.0f, 1.0f, 0.0f, //Top Left
1.0f, 1.0f, 0.0f //Top Right
};
private float texture[] = {
//Mapping coordinates for the vertices
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
Then, in my draw function, I loop through the map to define the texture to use (after pointing to and enabling the buffers) :
for(int y = 0; y < Y; y++){
for(int x = 0; x < X; x++){
tile = map[y][x];
try
{
//Get the texture from the HashMap
int textureid = ((Integer) this.textureMap.get(new Integer(textures[tile]))).intValue();
gl.glBindTexture(GL10.GL_TEXTURE_2D, this.texturesgen[textureid]);
}
catch(Exception e)
{
return;
}
//Draw the vertices as triangle strip
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
gl.glTranslatef(2.0f, 0.0f, 0.0f); //A square takes 2x so I move +2x before drawing the next tile
}
gl.glTranslatef(-(float)(2*X), -2.0f, 0.0f); //Go back to the begining of the map X-wise and move 2y down before drawing the next line
}
This works great by I really think that on a 1000*1000 or more map, it will be lagging as hell (as a reminder, this is a typical Zelda world map : http://vgmaps.com/Atlas/SuperNES/LegendOfZelda-ALinkToThePast-LightWorld.png ).
I've read things about Vertex Buffer Object and DisplayList but I couldn't find a good tutorial and nodoby seems to be OK on wich one is the best / has the better support (T1 and Nexus One are ages away).
I think that's it, I've putted a lot of code but I think it helps.
Thanks in advance !

A couple of things:
There's no need to use a hashmap, just use a vector/list.
It may be faster/easier to have one large texture that contains all your tiles. Use appropriate texture coordinates to select the appropriate tile. You might have to be a little bit careful about texture filtering here. It sounds like you are doing a 2D game in which case you probably want to use nearest-neighbour filtering for the tiles and clamp the camera to integer pixel locations.
Wouldn't it be easier to use GL_QUADS rather than GL_TRIANGLE_STRIP. Not sure about your code there - you don't seem to use the 'texture' array.
The map size shouldn't make any difference, as long as you don't draw tiles that aren't on the screen. Your code should be something like:
.
int minX = screenLeft / tileSize;
int minY = screenBottom / tileSize;
int maxX = screenRight / tileSize;
int maxY = screenTop / tilesSize;
for (int x = minX; x <= maxX; ++x)
{
for (int y = minY; y < maxY; ++y)
{
...

Related

Render a 3D Object off the Center of the screen: ARTOOLKIT ANDROID

Hi I am working on a AR android app. I am using ARToolkit6. In this app I want to view my 3D object( A Cube) on left half of the screen. With this eventually I want to display 3 cubes on the screen each on 1/3 of the screen area.
I was able to scale the 3D object by tweaking ModelView Matrix. What I read so far, I think I need to tweak projection matrix to achieve my goal. I tried looking solutions online. But Couldn't get it to work. Can anyone direct me to right path?
for (int trackableUID : trackableUIDs) {
// If the marker is visible, apply its transformation, and render a cube
if (ARToolKit.getInstance().queryMarkerVisible(trackableUID)) {
float[] projectionMatrix = ARToolKit.getInstance().getProjectionMatrix();
float[] modelViewMatrix = ARToolKit.getInstance().queryMarkerTransformation(trackableUID);
float[] scalingMat = {1, 0, 0, 0, 0, 3.0f, 0, 0, 0, 0, 1.0f, 0, 0.0f, 0, 0, 1};
float[] newModelView = modelViewMatrix;
multiplyMM(newModelView, 0, modelViewMatrix, 0, scalingMat, 0);
cube.draw(projectionMatrix, newModelView);
}
I followed the this link Set origin to top-left corner of screen in OpenGL ES 2 and (OpenGL ES) Objects away from view centre are stretched. So I translated the modelView Matrix but it doesn't solve the problem, the 3D object appears at the center of the screen. Can you explain how should I approach this problem? Thanks
#Override
public void draw() {
super.draw();
GLES20.glEnable(GLES20.GL_CULL_FACE);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glFrontFace(GLES20.GL_CCW);
// Look for trackables, and draw on each found one.
for (int trackableUID : trackableUIDs) {
// If the marker is visible, apply its transformation, and render a cube
if (ARToolKit.getInstance().queryMarkerVisible(trackableUID)) {
float[] projectionMatrix = ARToolKit.getInstance().getProjectionMatrix();
float[] modelViewMatrix = ARToolKit.getInstance().queryMarkerTransformation(trackableUID);
float[] scalingMat = {1, 0, 0, 0, 0, 3.0f, 0, 0, 0, 0, 1.0f, 0, 0.0f, 0, 0, 1};
multiplyMM(modelViewMatrix, 0, scalingMat, 0, modelViewMatrix, 0);
float[] rightModelMatrix = new float[16];
Matrix.setIdentityM(rightModelMatrix, 0);
// Translate outer sphere by 5 in x.
Matrix.translateM(rightModelMatrix, 0, 5.0f, 0.0f, 0.0f);
Matrix.multiplyMM(modelViewMatrix, 0, rightModelMatrix, 0, modelViewMatrix, 0);
cube.draw(projectionMatrix, modelViewMatrix);
}
}
Also tried this but the object gets displayed at the center of the screen.
glMatrixMode(GL_PROJECTION);
glTranslatef(5f, 0f, 0f);

libgdx point light not working on generated mesh

I've been trying to illuminate plane meshes generated by the following:
private Model createPlane(float w, float h, Texture texture) {
Mesh mesh = new Mesh(true, 4, 6, new VertexAttribute(Usage.Position, 3, "a_position"),
new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoord0"),
new VertexAttribute(Usage.Normal, 3, "a_normal"));
float w2 = w * this.CELL_SIZE;
float h2 = h * this.CELL_SIZE;
mesh.setVertices(new float[]
{ w2, 0f, h2, 0, 0, 0, 1, 0,
w2, 0f, -h2, 0, h, 0, 1, 0,
-w2, 0f, h2, w, 0, 0, 1, 0,
-w2, 0f, -h2 , w,h, 0, 1, 0
});
mesh.setIndices(new short[] { 0, 1, 2, 1, 3, 2});
Model model = ModelBuilder.createFromMesh(mesh, GL10.GL_TRIANGLES, new Material(TextureAttribute.createDiffuse(texture)));
return model;
}
and are rendered using:
//the environment setup
env = new Environment();
env.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
env.add(new PointLight().set(Color.ORANGE, 5f, 1f, 5f, 10f));
env.add(new DirectionalLight().set(Color.WHITE, -1f, -0.8f, -0.2f));
...
//the render method
batch.begin();
batch.render(inst, env);//inst is a ModelInstance created using the Model generated from createPlane(...)
batch.end();
The meshes display correctly (UVs, textured) and seem to be properly affected by directional and ambient lighting.
When I try to add a point light (see above environment) none of the planes generated from createPlane(...) are affected. I've tried creating another bit of geometry using the ModelBuilder class's createBox(...) and it seems to properly respond to the point light. Because of that I'm assuming that I'm not generating the plane correctly, but the fact that it's apparently being affected by directional/ambient light is throwing me off a bit.
It's worth noting that the size of the planes generated vary, I'm not particularly sure if a point light would affect 4 vertices very much but I expected more than nothing. Moving the point light around (closer to certain vertices) doesn't do anything either.
Any help would be greatly appreciated.
Thanks!
It would be great to know which shader you are using. The default one? I am not sure if they fixed that already, they had a bug a while ago, where pointlightning was only working on some devices (this had something todo with the implementation of opengles by the manufacturer. I personally fixed this by using my own shader.
Edit: This seems to be fixed
I checked the code I am using. The problem was to determine the correct light array in the shader.
Did it like this in the end:
// on some devices this was working
int u_lightPosition = program.getUniformLocation("u_lightPosition[0]");
int u_lightColors = program.getUniformLocation("u_lightColor[0]");
if(u_lightPosition < 0 && u_lightColors < 0) {
// on others this was working
u_lightPosition = program.getUniformLocation("u_lightPosition");
u_lightColors = program.getUniformLocation("u_lightColor");
}
I hope this helps!

Get OpenGL LookAt Position

In Android OpenGL
it has the command setLookAtM to specific the position for the camera view
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY,
lookZ, upX, upY, upZ);
If I rotate camera, by using command rotateM
Matrix.rotateM(mViewMatrix, 0 , angle , 0.0f, 1.0f, 0.0f);
Then, How could I get the 'LookAt' the exact camera view from mViewMatrix ?
the camera view position, i want is x,y,z that camera look at
Be careful, as calling rotateM doesn't technically rotate the camera, it applies a rotation to any future objects drawn. (it doesn't mean the same thing).
However in general, if you have a view matrix, and you want to see which direction it is facing, you want to transform the eye space forward vector (0,0,1) by the inverse of the view matrix.
As the view matrix transforms vectors in world space into eye space, the inverse view matrix transforms vectors from eye space into world space.
So you can:
Apply arbitrary operations to the current view matrix
Take its inverse
Multiply the inverse matrix by (0,0,1,0). (note this is the same as just pulling out the third column of the inverse matrix).
After #3 you will have the direction of the camera eye in world space. Add this to the eye's position, and you should know at what point it is pointing.
I have finished my question
and this is my solution
first, I need to made this 3 matrix to get result of x, y, z position
private float[] mRotXMatrix = new float[] {
1, 0, 0, 0,
0, 0, 1, 0,
0, 1, 0, 0,
0, 0, 0, 1 };
private float[] mRotYMatrix = new float[] {
0, 0, 1, 0,
0, 1, 0, 0,
1, 0, 0, 0,
0, 0, 0, 1 };
private float[] mRotZMatrix = new float[] {
0, 1, 0, 0,
1, 0, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 };
Then in onSensorChanged(SensorEvent e) method I rotate all these 3 matrix together with my camera view like this
Matrix.multiplyMM(mViewMatrix, 0, deltaRotationMatrix, 0, mViewMatrix, 0);
Matrix.multiplyMM(mRotXMatrix, 0, deltaRotationMatrix, 0, mRotXMatrix, 0);
Matrix.multiplyMM(mRotYMatrix, 0, deltaRotationMatrix, 0, mRotYMatrix, 0);
Matrix.multiplyMM(mRotZMatrix, 0, deltaRotationMatrix, 0, mRotZMatrix, 0);
And to get the X, Y, Z of my camera view, just get it from these matrix
viewX = mRotXMatrix[2];
viewY = -mRotYMatrix[6]; // +/- up to your initial camera view
viewZ = mRotZMatrix[10];

opengl es position after glRotatef and glTranslatef

i'am new in OpenGL ES. Can you helps me to calculate world coordinates of cube after rotate and translate. For example:
first i rotate cube:
gl.glRotatef(90, 1, 0, 0);
than change his position
gl.glTranslatef(10, 0, 0);
How can i calculate his "new" world coordinates? I read about glGetFloatv(GL_MODELVIEW_MATRIX , matrix) but not understand it. Maybe someone can provide sample code.
EDIT:
I found solution. Android code
float[] matrix = new float[] {
1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1,
};
Matrix.rotateM(matrix, 0, rx, 1, 0, 0);
Matrix.rotateM(matrix, 0, ry, 0, 1, 0);
Matrix.rotateM(matrix, 0, rz, 0, 0, 1);
Matrix.translateM(matrix, 0, x, y, z);
x = matrix[12];
y = matrix[13];
z = matrix[14];
Thanks for answers.
Although you have an answer for the part you want, in terms of the rest of your question, you'd do something like (please forgive me if I make any Java errors, I'm not really an Android person):
float[] matrix = new float[16];
gl.glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
// check out matrix[12], matrix[13] and matrix[14] now for the world location
// that (0, 0, 0) [, 1)] would be mapped to
That getFloatv just reads back the current value of the modelview matrix into the float buffer specified. In OpenGL 4x4 matrices are specified so that index 0 is the top left, index 3 is the lowest number in the first column and 12 is the number furthest to the right in the first row. That's usually referred to as column-major layout, though the OpenGL FAQ isn't entirely happy with the term.

How to draw grid lines in OpenGL ES Android?

I want to draw 10 by 10 grid that defines ground plane such that the center is the origin of the world coordinates.
This is the code that is called for each line defined in the grid.
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVerticesBuffer);
gl.glTranslatef(x, y, z);
gl.glRotatef(rz, 0, 0, 1);
gl.glRotatef(rx, 1, 0, 0);
gl.glRotatef(ry, 0, 1, 0);
gl.glDrawArrays(GL10.GL_LINES, 0, 2);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
The problem is I only see one horizontal line. So I think something is wrong.
This is the code that defines the lines:
Line line;
for (int i = 0; i <= 10; i++) {
// horizontal lines
line = new Line(-50, 0, 0, 50, 0, 0, 0, 0, 1, 1); // blue line
line.z = (i * 100) - 50;
lines.add(line);
// draw perspective lines
line = new Line(-50, 0, 0, 50, 0, 0, 0, 0, 1, 1); // blue line
line.x = (i * 100) - 50;
line.ry = 90;
lines.add(line);
}
For each line in the lines collection I call the drawing code in onDrawFrame.
The reason is because you are only drawing one line. glDrawArrays basically draws opengl primitives from the data given. So the coordinates in your buffer mVerticesBuffer are being drawn once by glDrawArrays.
A simple way to do what you want is to:
Rotate/Translate to starting position
Draw your first line with glDrawArrays();
Use gl.glTranslatef(somenumber, 0, 0);
Draw again with the same call to glDrawArrays();
Use gl.glRotatef(90, 0, 1, 0); to rotate around the y-axis (Or whichever axis you are 0 in)
(Maybe translate back in an axis to get to the same start position)
Do the 2nd, 3rd and 4th bullet point again.
A much tidier and more efficient way of doing this would be with pushing and popping matrices but for simplicity this should work if you're new to opengl.
The solution given to you seems fine and should work to solve your problems.
Probably, the best solution is to generate vertices once and store it in a file, you can read the file once and render the grid in one go, that would be much better in terms of performance and speed.

Categories

Resources