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.
Related
I want to rotate an element around a specific point defined by me and dynamically changed.
I am orientating myself at the guidelines from the google developers site.
My first approach is this:
scratch = new float[16];
Matrix.setIdentityM(mRotationMatrix, 0);
Matrix.setRotateM(mRotationMatrix, 0, angle, 0, 0, 1f);
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
element.draw(scratch);
This rotates the object around the center of the screen.
What do I have to add/change to make the object rotate around some other point?
Add a translation operation.
Grafika's Sprite2d class provides an example:
/**
* Re-computes mModelViewMatrix, based on the current values for rotation, scale, and
* translation.
*/
private void recomputeMatrix() {
float[] modelView = mModelViewMatrix;
Matrix.setIdentityM(modelView, 0);
Matrix.translateM(modelView, 0, mPosX, mPosY, 0.0f);
if (mAngle != 0.0f) {
Matrix.rotateM(modelView, 0, mAngle, 0.0f, 0.0f, 1.0f);
}
Matrix.scaleM(modelView, 0, mScaleX, mScaleY, 1.0f);
mMatrixReady = true;
}
This positions the object, then rotates it around the center of the object.
You need to translate the matrix in the reverse direction of the point first, then rotate and then translate it back. Look at it as if the rotation is always rotating around the center of the world, and the translation moves the center of the world.
Something like this (untested):
scratch = new float[16];
Matrix.setIdentityM(mRotationMatrix, 0);
Matrix.translateM(mRotationMatrix, 0, -x, -y, -z);
Matrix.rotateM(mRotationMatrix, 0, angle, 0, 0, 1f);
Matrix.translateM(mRotationMatrix, 0, x, y, z);
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
element.draw(scratch);
The x, y and z values need to be calculated as the delta between the current position of the object in the world and the position of the point you want to rotate around. You need to do that calculation yourself, but that's pretty trivial.
I'm trying to work on some OpenGL stuff. What I've got up to now is a viewport, in which I'm drawing some imaginary "borders" by using GL_LINES. It looks like this, with setLookAt set as follows:
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 5, 0, 0, 0, 0, 1, 0);
My frustum is set: Matrix.frustumM(mProjectionMatrix, 0, -2, 2, -2, 2, 1, 11); so I'm positioned somewhere inside the "cube".
Now what I'm trying to achieve is let the user look around. I'm capturing onTouchEvents, passing any movement in x/y direction to the renderer. What I'm doing next is rotating all lines drawn by the specific angle I received from the touch listener.
It then looks like this:
So the cube is not rotated around the viewer or the eye-center, but instead around some point that I don't know where it's coming from.
My problem is: how can I rotate the object around the viewer's center/position? Do I have to rotate the mViewMatrix which comes from setLookAtM? If yes, simply by using Matrix.setRotateM(mViewMatrix, ...)?
The Line's drawing method looks like this:
public void draw(float[] mViewMatrix, float[] mProjectionMatrix) {
Matrix.multiplyMM(mViewProjectionMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
GLES20.glUseProgram(iProgId);
lineBuffer.position(0);
GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, 0, lineBuffer);
GLES20.glEnableVertexAttribArray(iPosition);
colorBuffer.position(0);
GLES20.glVertexAttribPointer(iColor, 3, GLES20.GL_FLOAT, false, 0, colorBuffer);
GLES20.glEnableVertexAttribArray(iColor);
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.rotateM(mModelMatrix, 0, rotX, 1, 0, 0);
Matrix.rotateM(mModelMatrix, 0, -rotY, 0, 1, 0);
Matrix.setIdentityM(mViewProjectionMatrix, 0);
Matrix.multiplyMM(mViewProjectionMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
//GLES20.glUniformMatrix4fv(iVPMatrix, 1, false, mMVPMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewProjectionMatrix, 0);
GLES20.glUniformMatrix4fv(iVPMatrix, 1, false, mMVPMatrix, 0);
//GLES20.glDrawElements(GLES20.GL_LINES, mVertices.length/2, GLES20.GL_UNSIGNED_SHORT, indexBuffer);
GLES20.glDrawArrays(GLES20.GL_LINES, 0, mVertices.length / 2);
}
look at function takes 3 vertices, eye position, target position and up vector. Basically it generates a matrix that moves scene around to render scene like you are looking from eye position to target position. In your example your is at 0,0,0 and looks at 5, 0, 0 (so you are looking at +x direction and up is defined as 0, 1, 0 (higher y value means object will be at top of window.)
Instead of using those constants, first define a camera position.
float cameraX, cameraY, cameraY;
it is harder to work with target vectors, so instead use an angle that defines which direction you are looking at
float angle;
and to calculate targetVector use this angle.
float targetX = cameraX + cos(angle);
float targetY = cameraY;
float targetZ = cameraZ + sin(angle);
Now to move camera around, you have to modify cameraX-Y-Z. If you want to move forward you should move your camera towards to target vector. For example to move 10 unit forward.
targetX += cos(angle)*10;
targetY += sin(angle)*10;
You also need to recalculate target vector since target position also should move.
If you want to move backwards, use -= operator instead. If you want to move sides then you have to add or remove angle PI/2 in those calculations.
To rotate camera around just increase/decrease angle and recalculate target vector.
This is a very basic camera and you won't be able to look up or down. You have to use pitch/yaw camera to be able to look up and down.
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.
I'm trying to create a SurfaceView that contains a GLView showing 9 planes.
I'm trying to get planes oriented in a diamond shape around the origin. Essentially it will have the top layer all point in towards the origin at a 120 degree angle separated in a circular shape by 120 degrees. The middle layer will also be separated by 120 degrees but be perpendicular to the x axis and parallel to the y. The bottom layer will be an inverse of the top layer.
So far I have tried loops (didn't end well, the planes were scattered across creation) and going by plane by plane to make sure that the yaw and pitch were properly set. Neither have worked.
If you have any ideas please tell me or point me in the direction of a decent tutorial.
Thanks
~Aedon
Here is my line by line code snippet:
dyaw & dpitch: 120 degrees
w & h: width(2) and height(3) accordingly
spacing: .5f
// Top Layer
mGL.glRotatef(dyaw, 0, 1f, 0);
mGL.glRotatef(dpitch, 0, 0, 1f);
mGL.glTranslatef(0, h + spacing, 0);
mPanels[0].drawColorful(mGL);
mGL.glRotatef(dyaw, 0, 1f, 0);
mPanels[1].drawColorful(mGL);
mGL.glRotatef(dyaw, 0, 1f, 0);
mPanels[2].drawColorful(mGL);
// Middle Layer
mGL.glRotatef(dyaw, 0, 1f, 0);
mGL.glRotatef(-dpitch, 0, 0, 1f);
mGL.glTranslatef(0, -(h + spacing), 0);
mPanels[3].drawColorful(mGL);
mGL.glRotatef(dyaw, 0, 1f, 0);
mPanels[4].drawColorful(mGL);
mGL.glRotatef(dyaw, 0, 1f, 0);
mPanels[5].drawColorful(mGL);
// Bottom Layer
mGL.glRotatef(dyaw, 0, 1f, 0);
mGL.glRotatef(-dpitch, 0, 0, 1f);
mGL.glTranslatef(0, -(h + spacing), 0);
mPanels[6].drawColorful(mGL);
mGL.glRotatef(dyaw, 0, 1f, 0);
mPanels[7].drawColorful(mGL);
mGL.glRotatef(dyaw, 0, 1f, 0);
mPanels[8].drawColorful(mGL);
Never mind, found a much better tutorial from INsanity. If anyone has any OpenGL question for android take a stab with this guys tutorials, they are fantastic.
~Aedon
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)
{
...