Related
I am trying to understand how camera works on OpenGL ES, so I am tryng to look at the same point with the two differents types, Matrix.frustumM and Matrix.orthoM
I will like to know what exactly I am doing when use Matrix.frustumM or orthoM, I know that I apply them to the ProjectionMatrix but I dont understand what defines the parameters(left,right,bottom,top,near,far of what? it is supposed to be the screen of the phone? ) same with orthoM
I want to draw a square on the screen on 0,0,0 with 1f of height and weight(like 2D just to test the cameras)
but if I do onSurfaceCreated
final float eyeX = 2f;
final float eyeY = 5f;
final float eyeZ = 8f;
final float lookX = 2f;
final float lookY = 5f;
final float lookZ = 0.0f;
final float upX = 0.0f;
final float upY = 1.0f;
final float upZ = 0.0f;
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
onSurfaceChanged
GLES20.glViewport(0, 0, width, height);
// Create a new perspective projection matrix. The height will stay the
// same
// while the width will vary as per aspect ratio.
final float ratio = (float) width / height;
final float left = -ratio;
final float right = ratio;
final float bottom = -1.0f;
final float top = 1.0f;
final float near = 1.0f;
final float far = 25.0f;
Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
That is what i saw onn phone
Draw function:
public void dibujarBackground()
{
// Draw a plane
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBackgroundDataHandle);
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, 0.0f,2.0f, 0.0f);
drawBackground();
}
private void drawBackground()
{
coordinate.drawBackground(mPositionHandle, mNormalHandle, mTextureCoordinateHandle);
// This multiplies the view matrix by the model matrix, and stores the
// result in the MVP matrix
// (which currently contains model * view).
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glUniform3f(mLightPosHandle,Light.mLightPosInEyeSpace[0], Light.mLightPosInEyeSpace[1], Light.mLightPosInEyeSpace[2]);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
}
Coords of the square:
final float[] backgroundPositionData = {
// In OpenGL counter-clockwise winding is default.
0f, 1f, 0.0f,
0f, 0f, 0.0f,
1f, 1f, 0.0f,
0f, 0f, 0.0f,
1f, 0f, 0.0f,
1f, 1f, 0.0f,
};
final float[] backgroundNormalData = {
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, };
final float[] backgroundTextureCoordinateData = {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f, };
Overall what you get in the end is a single matrix which is used to multiply the positions so that the visible fragments are in range [-1,1] in all 3 dimensions. That means if you use no matrix or use the identity the coordinates will need to be in this range to be visible. So the 3 matrix computations you are using are actually only conveniences to help you achieve a correct transformation:
Ortho is an orthographical transformation. This means the visual representation of x and y screen coordinates are not effected by the z coordinate at all. Visually that means the object does not appear smaller when it is further. The values you insert into this convenience method are border values (left, right, top, bottom) which means a rectangle with same coordinates will take exactly the full screen. These values are mostly used to be the same as your view coordinate system (left = 0, right = screenWidth, top = 0, bottom = screenHeight). Also there are near and far parameters which represent the clipping planes so that positions smaller then near or further then far are not visible. This projection is mostly used for 2D drawing.
Frustum matrix is designed so that the x and y coordinates are reduced with increasing z. This means an object will appear smaller when further. The border parameters are connected to the near parameter so that the rectangle with border coordinates having z at near will appear as full screen. The near must be larger then zero in this case or the result is unpredictable. The far promoter is just a clipping plane but same as with ortho the pixels are clipped if z value is smaller then near or larger then far. The border parameters are best computed with the field of view (angle) and screen aspect ratio. You use the tang function to compute border parameters to get the desired effect. This method is mostly used for 3D drawing.
LookAt is a convenience which is used to transform all the objects to such positions and orientations that they appear to be effected by the camera position. Though this method is defined with vectors you may imagine it having a vector position and rotations. What this does it creates a matrix that will rotate all the objects by -rotations and translate them by -position.
Overall the usage then is pretty simple. Each position should first be multiplied by the model matrix which is the matrix representing the model position in your scene. Then multiplied by the matrix received with lookAt to simulate the camera. Then multiplied by the projection matrix which in most cases is either the ortho or the frustum. The optimization then is to multiply the matrices first on the CPU and then have the positions multiplied by them on the GPU. Some variations then persist where you split the matrix to the "model view matrix" and the "projection matrix". This is used to compute things like lighting effect where the position must not be effected by the projection matrix.
I've gotten the texture to load, but it seemingly displays a single color of the texture. I've targeted the texture coordinates first, and can't seem to get the texture to display right. the intended texture is below:
256x256
The texture is being displayed, but seemingly in a solid color. Maybe zoomed in to one pixel of the texture, or a warp of bad texture coordinates.:
Geometry:
static float squareCoords[] = {
-0.1f, 0.1f, 0.0f,
-0.1f, -0.1f, 0.0f,
0.1f, -0.1f, 0.0f,
0.1f, 0.1f, 0.0f };
Texture coordinates:
final float TextureCoordinates[] =
{
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
};
The texturing process is encapsulated inside the Entity class and I could include more code if it isn't immediately obvious to a second pair of eyes.
On an unforeseeable note, GLES20.glEnableVertexAttribArray(mTextureUniformHandle); was not set.
I want to draw a line in my Android NDK app using OpenGL|ES.
I am using the following code to draw the line on the screen.
GLfloat line[] = {
0,0,0,
100,100,0
};
GLfloat colors[] = {
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glShadeModel(GL_SMOOTH);
glVertexPointer(3, GL_FLOAT, 0, line);
glColorPointer(4, GL_FLOAT, 0, colors);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_LINES, 0, 2);
glFlush();
The above code will paint a Line on the Screen, but the issue I am facing is that if I change the coordinates in the array line e.g.
GLfloat line[] = {
0,0,0,
5,5,0
};
then also same line will be drawn on the screen i.e. there will be no change in the length of the line. Output attched:
what is the reason for this abnormal behavior ?
Without modifying matrices the default OpenGL coordinates are normalized (mapped 0-1). (0,0) is the center of the screen, (1,0) is the center right side, (0, -1) is the bottom of the screen, etc.
In your example (5,5) and (100,100) are in exactly the same direction relative to the center and offscreen so that is why you see the same line in both.
I'd like to create some kind of simple tetris clone with OpenGL ES 2.0 for education purposes. So far I managed to draw a simple rectangle made of two triangles on the screen.
I'd like to use those primitive rectangles as my tetris blocks.
Now, my problem is how to move those rectangles as they should fall down like tetris blocks.
This is how I define my rectangle:
...
public Rectangle()
{
_vertices = new float[]
{
// x, y, z
// R, G, B, A
-1.0f, 1.0f, 0.0f,
1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 0.0f,
1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
InitBuffer();
}
...
This is the code that draws the rectangle:
private void drawRectangle(final FloatBuffer aRectangleBuffer)
{
aRectangleBuffer.position(mPositionOffset);
GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false,
mStrideBytes, aRectangleBuffer);
GLES20.glEnableVertexAttribArray(mPositionHandle);
aRectangleBuffer.position(mColorOffset);
GLES20.glVertexAttribPointer(mColorHandle, mColorDataSize, GLES20.GL_FLOAT, false,
mStrideBytes, aRectangleBuffer);
GLES20.glEnableVertexAttribArray(mColorHandle);
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
}
The code is basically copied from this tutorial:Learn OpenGL ES - Android Lesson One: Getting Started
The only way to move the rectangle I can think of is to change the vertices in my _vertices-array. But that would mean to create a new array, a new VertexBuffer etc. on every draw and I don't think that this is the way to go.
Perhaps this is a dump question but although I'm starting to understand how OpenGL ES works, this one I have not figured out yet.
Any help is really appreciated.
There are a number of ways to handle this. Which way is best depends on your goals. Since the game you're writing is relatively undemanding GPU-wise, it makes sense to start with something simple.
In the example you cited, every vertex is being multiplied by u_MVPMatrix. If you update the matrix with the position before each draw call, you can use the same set of vertices to draw the shape anywhere on the screen (and change its scale, and rotate it, and all the other fancy stuff matrices let you do). This is the approach used by Android Breakout and parts of Grafika (see e.g. the "Hardware scaler exerciser").
If you get to the point where this approach isn't efficient enough, it's probably time to look into game engines (perhaps cocos2d-x?) rather than reinventing the texture-mapped wheel.
I wrote opengl android code to show a bitmap on a square. But bitmap was drawn in reverse. When i change texture array combination to the commented code it is drawn correctly. But i insist my texture array must be as below . Am i thinking wrong ?
/** The initial vertex definition */
private float vertices[] = {
-1.0f, 1.0f, 0.0f, //Top Left
-1.0f, -1.0f, 0.0f, //Bottom Left
1.0f, -1.0f, 0.0f, //Bottom Right
1.0f, 1.0f, 0.0f //Top Right
};
/** Our texture pointer */
private int[] textures = new int[1];
/** The initial texture coordinates (u, v) */
private float texture[] = {
//Mapping coordinates for the vertices
// 1.0f, 0.0f,
// 1.0f, 1.0f,
// 0.0f, 1.0f,
// 0.0f, 0.0f,
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
};
/** The initial indices definition */
private byte indices[] = {
//2 triangles
0,1,2, 2,3,0,
};
Whereas Android uses the top-left corner as being 0,0 of the coordinate system, OpenGL uses the bottom-left corner being 0,0 which is why your texture gets flipped.
A common solution to this is to flip your texture at load time,
Matrix flip = new Matrix();
flip.postScale(1f, -1f);
Bitmap bmp = Bitmap.createBitmap(resource, 0, 0, resource.getWidth(), resource.getHeight(), flip, true);
Actually, I think Will Kru's solution should have flipped the background around both axes
flip.postScale(-1f, -1f);
That solution worked for me!
This worked for me. (no need to create another bitmap and scale)
private float vertices[] = {
1.0f, -1.0f, 0.0f, //Bottom Right
1.0f, 1.0f, 0.0f, //Top Right
-1.0f, 1.0f, 0.0f, //Top Left
-1.0f, -1.0f, 0.0f, //Bottom Left
};