I need a little help with this:
android developers, Tutorials: OpenGLES10.
a link
It all works fine for the first Triangle, until I put in the code for Projection & Camera View. This should rezise OpenGLES Square view to match Phone's screen, so object stay in propotions.
As a Newbie watching, the code looks fine and i have cheked with referencefiles, that there's not missing a parameter or something like that. But now i'm lost..! Can't see what's wrong.
If Projection and Camera code are applied, there is no triangle, but the app. is runing and the View with backgroundcolor are shown.
Here is my code:
package notme.helloopengles10;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
public class HelloOpenGLES10Renderer implements GLSurfaceView.Renderer {
// Set the background frame color
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
// initialize the triangle vertex array
initShapes();
//enable use of vertex arrays
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
}
public void onDrawFrame(GL10 gl) {
// Redraw background color
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
/* // set GL_MODELVIEW transformation mode (If outline from here to after GLU.gluLookAt() - it works when also outlines further down i code!
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity(); // reset Matrix to its default state
// when using GL_MODELVIEW, you must set the view point
GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f); */
//Draw Triangel
gl.glColor4f(0.63671875f, 0.76953125f, 0.22265625f, 0.0f);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, triangleVB);
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
}
// Redraw on orientation changes // adjust for screen size ratio
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
// Make adjustments for screen ratio
/*(If outline from here to after gl.Frumstumf() - it works!
float ratio = (float) width / height;
gl.glMatrixMode(GL10.GL_PROJECTION); // set matrix to projection mode
gl.glLoadIdentity(); // reset the matrix to its default state
gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7); // apply the projection */
}
/*
* Draw a shape, a triangle. first add new member variable to contain
* the vertices of a triangle
*/
private FloatBuffer triangleVB;
//Create a method, initShaoe(), which populate the members variable
private void initShapes(){
//create a array
float triangleCoords[] = {
// X, Y, Z
-0.5f, -0.25f, 0,
0.5f, -0.25f, 0,
0.0f, 0,559016994f, 0
};
// initialize vertex Buffer for triangle
ByteBuffer vbb= ByteBuffer.allocateDirect(
//(# of coordinates values * 4 bytes per float)
triangleCoords.length * 4 );
vbb.order(ByteOrder.nativeOrder()); // use device hardware's native byte order
triangleVB = vbb.asFloatBuffer(); //create floating point buffer from the ByteBuffer
triangleVB.put(triangleCoords); // add coordinates to the FloatBuffer
triangleVB.position(0); // set the buffer to read the first coordinate
}
} // end
I hope some one can tell me, where things go wrong?
DevTool: Eclipse.
I had the same problem with this tutorial and it got solved when I changed the order of multiplying in the vertex shader code in the Triangle class. So instead of having uMVPMatrix * vPosition, replace it with vPosition * uMVPMatrix. I guess the reason for this is because vPosition is a row vector.
The code looks resonable (if you uncomment the parts that are commented out at the moment). Your matrix modification code is quite correct and all transformations are applied to the correct matrices.
But at the moment you are looking from the point (0,0,-5) to the point (0,0,0) and therefore along the +z axis. But since the default OpenGL view looks along the -z axis, you actually rotate the view 180 degrees around the y-axis. Whereas this is absolutely no problem, you now see the back-side of the triangle. So can it be, that you have back-face culling enabled and this back-side is just optimized away? Just try disabling back-face culling by calling glDisable(GL_CULL_FACE) or change the -5 in the gluLookAt call to a 5, so that you look along the -z axis.
You can also try to use gluPerspective(45, ratio, 3, 7) instead of the glFrustum call, but your arguments to glFrustum look quite reasonable. Of course, keep in mind that both calls create a perspective view, with farther objects getting smaller, like in reality. If you actually want a parallel/orthographic view (where size on screen is independent on depth) you should replace the glFrustum with a glOrtho, though the parameters can stay the same.
Your call to gluLookAt trashes your modelview matrix. You should call this function with the projection matrix active.
http://www.opengl.org/sdk/docs/man/xhtml/gluLookAt.xml
This code shows the triangle for me:
public void onDrawFrame(GL10 gl) {
// Redraw background color
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
// when using GL_MODELVIEW, you must set the view point
GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// set GL_MODELVIEW transformation mode (If outline from here to after GLU.gluLookAt() - it works when also outlines further down i code!
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity(); // reset Matrix to its default state
//Draw Triangel
gl.glColor4f(0.63671875f, 0.76953125f, 0.22265625f, 0.0f);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, triangleVB);
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
}
Related
I'm trying to create a simple game in android. By road I meant games like Temple Run or Subway Surf but much simpler and abstract so I could do it only with the OpenGL ES without any other libraries.
So I've read a lot of basic tutorials that explains the 3D construction logic and used the basic sample of creating a 3D cube that rotates.
I am now trying to use that sample to create the game road. I made the square to look more like a rectangle and duplicate it to a 30x5 square road. I've tried many combinations and the internet to find a solution and yet I have this problems\questions:
How do I set all 30x5 squares to be one next to another? I'm always
getting the squares with some unwanted gap
I want to set the vieweye point (the "camera") 45 degrees to the
middle of the first row, so the player could see the road upon him
Next, I would want to move along the road. So Iv'e seen the rotate
and how it works. Is there a way to do the same to the viewpoint or
do I need to change the squares drawing Z's?
I see that onDrawFrame() is calling over and over many times. To
control the FPS, I've seen on the internet that people have used
there own FPS calculation with a sleep(). Isn't there a built one
already?
GLRenderer code:
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.util.Log;
class GLRenderer implements GLSurfaceView.Renderer {
private static final String TAG = "GLRenderer" ;
private final Context context;
private float mCubeRotation = 70.0f;
private Triangle triangle;
private Cube[][] cube;
GLRenderer(Context context) {
this.context = context;
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
gl.glClearDepthf(1.0f);
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glDepthFunc(GL10.GL_LEQUAL);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_NICEST);
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
Log.d("MyOpenGLRenderer", "Surface changed. Width=" + width
+ " Height=" + height);
System.out.println("arg");
//get map
cube = new Cube[30][5];
for(int i = 0; i < cube.length; i++)
for(int j = 0; j < cube[i].length; j++)
cube[i][j] = new Cube();
//draw triangle
triangle = new Triangle(0.5f, 1, 0, 0);
// Define the view frustum
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
float ratio = (float) width / height;
GLU.gluPerspective(gl, 45.0f, ratio, 0.1f, 100.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
}
public void onDrawFrame(GL10 gl) {
// Clear the screen to black
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
//translate(dx, dy, dz)
// Position model so we can see it
//gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glTranslatef(0.0f, 0.0f, -10.0f);
gl.glRotatef(mCubeRotation, 1.0f, 1.0f, 1.0f);
gl.glTranslatef(0.0f, 0.0f, -10.0f);
cube[0][0].draw(gl);
gl.glTranslatef(0.0f, 0.0f, -10.0f);
cube[0][1].draw(gl);
gl.glTranslatef(0.0f, 0.0f, -10.0f);
cube[0][2].draw(gl);
gl.glLoadIdentity();
//set rotation
mCubeRotation -= 0.15f;
System.out.println("mCubeRotation: "+mCubeRotation);
}
}
Cube code:
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
class Cube {
private FloatBuffer mVertexBuffer; //vertex
private FloatBuffer mColorBuffer; //color
private ByteBuffer mIndexBuffer; //face indices
float width = 1.0f;
float height = 0.5f;
float depth = 1.0f;
private float vertices[] = {
-width, -height, -depth, // 0
width, -height, -depth, // 1
width, height, -depth, // 2
-width, height, -depth, // 3
-width, -height, depth, // 4
width, -height, depth, // 5
width, height, depth, // 6
-width, height, depth, // 7
};
private float colors[] = {
0.0f, 1.0f, 0.0f,
1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 1.0f,
0.5f, 0.0f, 1.0f,
1.0f, 0.5f, 0.0f,
1.0f, 1.0f, 0.0f,
0.0f, 1.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f,
1.0f, 1.0f
};
private byte indices[] = {
0, 4, 5,
0, 5, 1,
1, 5, 6,
1, 6, 2,
2, 6, 7,
2, 7, 3,
3, 7, 4,
3, 4, 0,
4, 7, 6,
4, 6, 5,
3, 0, 1,
3, 1, 2
};
public Cube() {
ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);
byteBuf.order(ByteOrder.nativeOrder());
mVertexBuffer = byteBuf.asFloatBuffer();
mVertexBuffer.put(vertices);
mVertexBuffer.position(0);
byteBuf = ByteBuffer.allocateDirect(colors.length * 4);
byteBuf.order(ByteOrder.nativeOrder());
mColorBuffer = byteBuf.asFloatBuffer();
mColorBuffer.put(colors);
mColorBuffer.position(0);
mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
mIndexBuffer.put(indices);
mIndexBuffer.position(0);
}
public void draw(GL10 gl) {
gl.glFrontFace(GL10.GL_CW);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
gl.glColorPointer(4, GL10.GL_FLOAT, 0, mColorBuffer);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
gl.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE,
mIndexBuffer);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
}
}
Eventually I'll draw the square array using glDrawArrays() or glDrawElements() but for now I've used only 3 objects.
There's a lot of questions here. I can't cover everything in detail, but hopefully I can give you some pointers to steer you in the right direction.
To draw 150 squares, you have a number of options:
Create a vertex buffer with a single square, and draw it 150 times, with translations applied. This is probably the easiest to get you off the ground, so I would recommend getting it working first. It's a reasonable approach if all your squares look the same.
Create 150 vertex buffers, with different coordinates. I wouldn't recommend it because it's the least efficient, and doesn't have any benefits over other approaches.
Store the vertices for all 150 squares in a single vertex buffer. This will be the most efficient of the first 3 options, but only works well as long as the relative orientation of the squares remains the same. You may want to try this once you have the basics working.
Use instanced rendering. This is a more advanced feature, and only available in ES 3.0. Just mentioning it for future reference.
What you attempted is sort of a hybrid between option 1 and 2. If you want to go for option 1, you only need one instance of your Cube class. If you look at what you did, this makes sense. You created 150 objects that are all exactly the same, which is not very useful.
Now, on your questions:
To draw the squares without gaps between them, the amount of your translations needs to be the same as the size of each square. Your squares are 2 units wide, but you translate each one by 10 units. You also translate them in the z-direction, which I don't quite understand.
If you want to stick with the kind of functionality you have been using, check out GLU.gluLookAt(). It allows you to place your camera where you want it, and point it in any direction.
Same as 2. Call GLU.gluLookAt() every time you want to move the viewpoint.
Android caps the frame rate at 60 frames per second. That's normally what you should be shooting for anyway, IMHO. If you want to limit it to 30 fps later to save power, I think you can cross that bridge when you get there. Based on what I researched recently, there's no clean and portable way to do this on Android. The proposed solutions I have seen all look kind of hacky to me.
A couple more things on your code:
Your color definitions look odd. You specify colors in 4 components, and the size of the array is correct for that. But you write the array with 3 values per line, which makes it look like you want 3 component colors. Either one can be done, but you need to make sure that you're consistent. 3 components are enough, unless you need transparency.
You are using ES 1.0. That's valid, and might be easier to get started with. But you should be aware that many of its features are considered obsolete, and using ES 2.0 would let you learn more modern and current OpenGL features. The initial hurdle will be higher, so there's definitely a tradeoff here.
Here is my problem:
I have a GLSurfaceView with Renderer and stuff. Everything works just as I wanted, on older Android versions. But on newer versions (I guess > 4.X) it just shows a black screen without any Bitmaps. For example if I use gl.glClearColor(0.1f, 0.2f, 0.3f, 0.5f); in my onSurfaceCreated method, it changed from black to the color. So I think the problem must be the camera looking in the wrong direction or something, because the background-color is drawn.
Since I am pretty new to OpenGL, I wanted to ask if there are any connections between Android versions and the OpenGL-camera or something like that?
Many people say my Bitmap-Sizes have to be powers of 2, but it doesnt solve anything.
Here is my Renderer:
public class GlRenderer implements Renderer {
#Override
public void onDrawFrame(GL10 gl) {
// clear Screen Buffer
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// Reset the Modelview Matrix
gl.glLoadIdentity();
gl.glTranslatef(0.0f, 0.0f, -5.0f); // move 5 units INTO the screen
// is the same as moving the camera 5 units away
updateLogic(gl);
drawEverything(gl);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION); // or some matrix uniform if using shaders
gl.glLoadIdentity();
gl.glOrthof(0, width, height, 0, -1, 1); // this will allow to pass vertices in 'canvas pixel' coordinates
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glDisable(GL10.GL_DITHER);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
gl.glEnable(GL10.GL_TEXTURE_2D); //Enable Texture Mapping ( NEW )
gl.glShadeModel(GL10.GL_SMOOTH); //Enable Smooth Shading
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); //Set Background
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
}
}
Not sure if this is the issue you are having, but try changing the following line:
gl.Orthof(0, widht, height, 0, -1, 1);
to
gl.Orthof(0, widht, height, 0, 1, -1);
Notice that the near/far values are inverted. See this for a description of this maddness :)
As a beginner to android and openGL 2.0 es, I'm testing simple things and see how it goes.
I downloaded the sample at http://developer.android.com/training/graphics/opengl/touch.html .
I changed the code to check if I could animate a rotation of the camera around the (0,0,0) point, the center of the square.
So i did this:
public void onDrawFrame(GL10 unused) {
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// Set the camera position (View matrix)
long time = SystemClock.uptimeMillis() % 4000L;
float angle = ((float) (2*Math.PI)/ (float) 4000) * ((int) time);
Matrix.setLookAtM(mVMatrix, 0, (float) (3*Math.sin(angle)), 0, (float) (3.0f*Math.cos(angle)), 0 ,0, 0, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
// Draw square
mSquare.draw(mMVPMatrix);
}
I expected the camera to look always to the center of the square (the (0,0,0) point) but that's not what happens. The camera is indeed rotating around the square but the square does not stay in the center of the screen.. instead it is moving along the X axis...:
I also expected that if we gave the eyeX and eyeY the same values as centerX and centerY,like this:
Matrix.setLookAtM(mVMatrix, 0, 1, 1, -3, 1 ,1, 0, 0f, 1.0f, 0.0f);
the square would keep it's shape (I mean, your field of vision would be dragged but along a plane which would be paralel to the square), but that's also not what happens:
This is my projection matrix:
float ratio = (float) width / height;
// this projection matrix is applied to object coordinates
// in the onDrawFrame() method
Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 2, 7);
What is going on here?
Looking at the source code to the example you downloaded, I can see why you're having that problem, it has to do with the order of the matrix multiplication.
Typically in OpenGL source you see matrices set up such that
transformed vertex = projMatrix * viewMatrix * modelMatrix * input vertex
However in the source example program that you downloaded, their shader is setup like this:
" gl_Position = vPosition * uMVPMatrix;"
With the position on the other side of the matrix. You can work with OpenGL in this way, but it requires that you reverse the lhs/rhs of your matrix multiplications.
Long story short, in your case, you should change your shader to read:
" gl_Position = uMVPMatrix * vPosition;"
and then I believe you will get the expected behavior.
I've been beating my head against the desk trying to figure this out for days now, and after scouring Stack Overflow and the web, I haven't found any examples that have worked for me. I've finally got code that's seems close, so maybe you guys (and gals?) can help me figure this out.
My first problem is that I'm trying to implement a motion blur by taking a screen grab as a texture, then drawing the texture over the next frame with transparency -- or use more frames for more blur. (If anyone's interested, this is the guide I followed: http://www.codeproject.com/KB/openGL/MotionBlur.aspx)
I've got the screen saving as a texture working fine. The issue I'm having is drawing in Ortho mode on top of the screen. After much head banging, I finally got a basic square drawing, but my lack of OpenGL ES understanding and an easy to follow example are holding me back now. I need to take the texture I saved, and draw it into the square I drew. Nothing I've been doing seems to work.
Also, my second problem, is drawing more complex 3d models into Ortho mode. I can't seem to get any models to draw. I'm using the (slightly customized) min3d framework (http://code.google.com/p/min3d/), and I'm trying to draw Object3d's in Ortho mode just like I draw them in Perspective mode. As I understand it, they should draw the same, they should just not have depth. Yet I don't seem to see them at all.
Here's the code I'm working with. I've tried a ton of different things and this is the closest I've gotten (actually drawing something on the screen that can be seen). I still have no idea how to get a proper 3d model drawing in the ortho view. I'm sure I'm doing something horribly wrong and probably completely misunderstanding some basic aspects of OpenGL drawing. Let me know if there's any other code I need to post.
// Gets called once, before all drawing occurs
//
private void reset()
{
// Reset TextureManager
Shared.textureManager().reset();
// Do OpenGL settings which we are using as defaults, or which we will not be changing on-draw
// Explicit depth settings
_gl.glEnable(GL10.GL_DEPTH_TEST);
_gl.glClearDepthf(1.0f);
_gl.glDepthFunc(GL10.GL_LESS);
_gl.glDepthRangef(0,1f);
_gl.glDepthMask(true);
// Alpha enabled
_gl.glEnable(GL10.GL_BLEND);
_gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
// "Transparency is best implemented using glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
// with primitives sorted from farthest to nearest."
// Texture
_gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); // (OpenGL default is GL_NEAREST_MIPMAP)
_gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); // (is OpenGL default)
// CCW frontfaces only, by default
_gl.glFrontFace(GL10.GL_CCW);
_gl.glCullFace(GL10.GL_BACK);
_gl.glEnable(GL10.GL_CULL_FACE);
// Disable lights by default
for (int i = GL10.GL_LIGHT0; i < GL10.GL_LIGHT0 + NUM_GLLIGHTS; i++) {
_gl.glDisable(i);
}
//
// Scene object init only happens here, when we get GL for the first time
//
}
// Called every frame
//
protected void drawScene()
{
if(_scene.fogEnabled() == true) {
_gl.glFogf(GL10.GL_FOG_MODE, _scene.fogType().glValue());
_gl.glFogf(GL10.GL_FOG_START, _scene.fogNear());
_gl.glFogf(GL10.GL_FOG_END, _scene.fogFar());
_gl.glFogfv(GL10.GL_FOG_COLOR, _scene.fogColor().toFloatBuffer() );
_gl.glEnable(GL10.GL_FOG);
} else {
_gl.glDisable(GL10.GL_FOG);
}
// Sync all of the object drawing so that updates in the mover
// thread can be synced if necessary
synchronized(Renderer.SYNC)
{
for (int i = 0; i < _scene.children().size(); i++)
{
Object3d o = _scene.children().get(i);
if(o.animationEnabled())
{
((AnimationObject3d)o).update();
}
drawObject(o);
}
}
//
//
//
// Draw the blur
// Set Up An Ortho View
_switchToOrtho();
_drawMotionBlur();
// Switch back to the previous view
_switchToPerspective();
_saveScreenToTexture("blur", 512);
}
private void _switchToOrtho()
{
// Set Up An Ortho View
_gl.glDisable(GL10.GL_DEPTH_TEST);
_gl.glMatrixMode(GL10.GL_PROJECTION); // Select Projection
_gl.glPushMatrix(); // Push The Matrix
_gl.glLoadIdentity(); // Reset The Matrix
_gl.glOrthof(0f, 480f, 0f, 800f, -1f, 1f);
//_gl.glOrthof(0f, 480f, 0f, 800f, -100f, 100f);
_gl.glMatrixMode(GL10.GL_MODELVIEW); // Select Modelview Matrix
_gl.glPushMatrix(); // Push The Matrix
_gl.glLoadIdentity(); // Reset The Matrix
}
private void _switchToPerspective()
{
// Switch back to the previous view
_gl.glEnable(GL10.GL_DEPTH_TEST);
_gl.glMatrixMode(GL10.GL_PROJECTION);
_gl.glPopMatrix();
_gl.glMatrixMode(GL10.GL_MODELVIEW);
_gl.glPopMatrix(); // Pop The Matrix
}
private void _saveScreenToTexture(String $textureId, int $size)
{
// Save the screen as a texture
_gl.glViewport(0, 0, $size, $size);
_gl.glBindTexture(GL10.GL_TEXTURE_2D, _textureManager.getGlTextureId($textureId));
_gl.glCopyTexImage2D(GL10.GL_TEXTURE_2D,0,GL10.GL_RGB,0,0,512,512,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);
_gl.glViewport(0, 0, 480, 800);
}
private void _drawMotionBlur()
{
// Vertices
float squareVertices[] = {
-3f, 0f, // Bottom Left
475f, 0f, // Bottom Right
475f, 800f, // Top Right
-3f, 800f // Top Left
};
ByteBuffer vbb = ByteBuffer.allocateDirect(squareVertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
FloatBuffer vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(squareVertices);
vertexBuffer.position(0);
//
//
// Textures
FloatBuffer textureBuffer; // buffer holding the texture coordinates
float texture[] = {
// Mapping coordinates for the vertices
0.0f, 1.0f, // top left (V2)
0.0f, 0.0f, // bottom left (V1)
1.0f, 1.0f, // top right (V4)
1.0f, 0.0f // bottom right (V3)
};
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(squareVertices.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
byteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
textureBuffer = byteBuffer.asFloatBuffer();
textureBuffer.put(texture);
textureBuffer.position(0);
//
//
//
_gl.glLineWidth(3.0f);
_gl.glTranslatef(5.0f, 0.0f, 0.0f);
_gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertexBuffer);
_gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
_gl.glDrawArrays(GL10.GL_LINE_LOOP, 0, 4);
//_gl.glTranslatef(100.0f, 0.0f, 0.0f);
//_gl.glDrawArrays(GL10.GL_LINE_LOOP, 0, 4);
//_gl.glTranslatef(100.0f, 0.0f, 0.0f);
//_gl.glDrawArrays(GL10.GL_LINE_LOOP, 0, 4);
_gl.glEnable(GL10.GL_TEXTURE_2D);
_gl.glEnable(GL10.GL_BLEND);
_gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
_gl.glLoadIdentity();
//
//
//
_gl.glBindTexture(GL10.GL_TEXTURE_2D, _textureManager.getGlTextureId("blur"));
_gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
_gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
//
//
//
_gl.glDisable(GL10.GL_BLEND);
_gl.glDisable(GL10.GL_TEXTURE_2D);
_gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
EDIT: Here's a simpler example, it's all in the one function and doesn't include any of the saving the screen to a texture stuff. This is just drawing a 3d scene, switching to Ortho, drawing a square with a texture, then switching back to perspective.
// Called every frame
//
protected void drawScene()
{
// Draw the 3d models in perspective mode
// This part works (uses min3d) and draws a 3d scene
//
for (int i = 0; i < _scene.children().size(); i++)
{
Object3d o = _scene.children().get(i);
if(o.animationEnabled())
{
((AnimationObject3d)o).update();
}
drawObject(o);
}
// Set Up The Ortho View to draw a square with a texture
// over the 3d scene
//
_gl.glDisable(GL10.GL_DEPTH_TEST);
_gl.glMatrixMode(GL10.GL_PROJECTION); // Select Projection
_gl.glPushMatrix(); // Push The Matrix
_gl.glLoadIdentity(); // Reset The Matrix
_gl.glOrthof(0f, 480f, 0f, 800f, -1f, 1f);
_gl.glMatrixMode(GL10.GL_MODELVIEW); // Select Modelview Matrix
_gl.glPushMatrix(); // Push The Matrix
_gl.glLoadIdentity(); // Reset The Matrix
// Draw A Square With A Texture
// (Assume that the texture "blur" is already created properly --
// it is as I can use it when drawing my 3d scene if I apply it
// to one of the min3d objects)
//
float squareVertices[] = {
-3f, 0f, // Bottom Left
475f, 0f, // Bottom Right
475f, 800f, // Top Right
-3f, 800f // Top Left
};
ByteBuffer vbb = ByteBuffer.allocateDirect(squareVertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
FloatBuffer vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(squareVertices);
vertexBuffer.position(0);
FloatBuffer textureBuffer; // buffer holding the texture coordinates
float texture[] = {
// Mapping coordinates for the vertices
0.0f, 1.0f, // top left (V2)
0.0f, 0.0f, // bottom left (V1)
1.0f, 1.0f, // top right (V4)
1.0f, 0.0f // bottom right (V3)
};
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(squareVertices.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
byteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
textureBuffer = byteBuffer.asFloatBuffer();
textureBuffer.put(texture);
textureBuffer.position(0);
_gl.glLineWidth(3.0f);
_gl.glTranslatef(5.0f, 0.0f, 0.0f);
_gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertexBuffer);
_gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
_gl.glDrawArrays(GL10.GL_LINE_LOOP, 0, 4);
_gl.glEnable(GL10.GL_TEXTURE_2D);
_gl.glEnable(GL10.GL_BLEND);
_gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
_gl.glLoadIdentity();
_gl.glBindTexture(GL10.GL_TEXTURE_2D, _textureManager.getGlTextureId("blur"));
_gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
_gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
_gl.glDisable(GL10.GL_BLEND);
_gl.glDisable(GL10.GL_TEXTURE_2D);
_gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// Switch Back To The Perspective Mode
//
_gl.glEnable(GL10.GL_DEPTH_TEST);
_gl.glMatrixMode(GL10.GL_PROJECTION);
_gl.glPopMatrix();
_gl.glMatrixMode(GL10.GL_MODELVIEW);
_gl.glPopMatrix(); // Pop The Matrix
}
EDIT2: Thanks to Christian's answer, I removed the second glVertexPointer and _gl.glBlendFunc (GL10.GL_ONE, GL10.GL_ONE); (I deleted them from the sample code above as well so it wouldn't confuse the question). I now have a texture rendering, but only in one of the triangles that make up the square. So I'm seeing a triangle in the left portion of the screen that has the texture applied. Why is it not being applied to both halves of the square? I think it's because I have only one of these calls: gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); so I'm literally only drawing one triangle.
First, you set the blend function to (GL_ONE, GL_ONE), which will just add the blur texture to the framebuffer and make the whole scene overbright. You probalby want to use (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), but then you have to make sure your blur texture has the correct alpha, by configuring the texture environment to use a constant value for the alpha (instead of the texture's) or use GL_MODULATE with a (1,1,1,0.5) coloured square. Alternatively use a fragment shader.
Second, you specify a size 3 in the second call to glVertexPointer, but your data are 2d vectors (the first call is right).
glOrtho is not neccessarily 2D, its just a camera without perspective distortion (farther objects don't get smaller). The parameters to glOrtho specify your screen plane size in view coordinates. Thus if your scene covers the world in the unit cube, an ortho of 480x800 is just too large (this is no problem if you draw other objects than in perspective, as your square or UI elements, but when you want to draw your same 3d objects the scales have to match). Another thing is that in ortho the near and far distances still matter, everything that falls out is clipped away. So if your camera is at (0,0,0) and you view along -z with a glOrtho of (0,480,0,800,-1,1), you will only see those objects that intersect the (0,0,-1)-(480,800,1)-box.
So keep in mind, that glOrtho and glFrustum (or gluPerspective) all define a 3d viewing volume. In ortho its a box and in frustum its, guess a frustum (capped pyramid). consult some more introductory texts on transformations and viewing if this was not clear enough.
assuming that some opengl-veterans might facepalm now :-)
I am working on a tilebased game (2D only) on android with open gl es.
After days of introducing myself into the concepts of opengl basics, I still don't know how to keep the relation between object and screen size.
To be concrete: My mobile display has 480x800 pixels. When I specify the simple square with its following dimensions, it fills the whole screen (?):
object-vertices:
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
};
short[] indices = { 0, 1, 2, 2, 3, 0 };
onSurfaceCreated:
public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glShadeModel(GL10.GL_FLAT);
gl.glEnable(GL10.GL_TEXTURE_2D);
GLU.gluOrtho2D(gl, 0, Shared.dm.widthPixels, Shared.dm.heightPixels, 0);
onDrawFrame:
#Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Replace the current matrix with the identity matrix
gl.glLoadIdentity();
//Move this only
gl.glPushMatrix();
Log.d(Shared.LOGTAG, "X: " + offset.x + "Y: " + offset.y);
gl.glTranslatef(offset.x, offset.y, 0);
root.draw(gl);
gl.glPopMatrix();
}
Can anyone give me a hint into the right direction? I assume it has something to do with the matrices?
It looks like this is happening because your projection matrix is getting reset. I see in onSurfaceCreated, you call gluOrtho2D. That's fine, but it doesn't look like you're switching back with glMatrixModel(GL_MODELVIEW). So when glLoadIdentity gets called in onDrawFrame, it will reset your projection matrix.
When the project matrix is identity, coordinates just get passed through. -1 and +1 on the X axis correspond to the left and right sides of the window (respectively). On the Y axis, they are the bottom and top of the window. On the Z axis they are the far and near clipping planes.
Typical, misconception done by OpenGL newbies: They think there is some kind of "one time projection initialization".
You normally setup the whole requires OpenGL state anew everytime you start drawing things. This also catches mishaps like accidently overwriting projection matrices.
onSurfaceCreated:
public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
// Just upload textures and shaders here.
onDrawFrame:
#Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// set everything just right before you need it
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluOrtho2D(gl, 0, Shared.dm.widthPixels, Shared.dm.heightPixels, 0);
// order in which different matrices are set is not important,
// but order in which each matrix is manipulated is!
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
// enable and configure blending on a as-needed base
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glShadeModel(GL10.GL_FLAT);
gl.glEnable(GL10.GL_TEXTURE_2D);
//Move this only
// make sure this is operating really on the modelview matrix
// redundant in this rather simple example, but in large codebases
// inevitable.
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glPushMatrix();
Log.d(Shared.LOGTAG, "X: " + offset.x + "Y: " + offset.y);
gl.glTranslatef(offset.x, offset.y, 0);
root.draw(gl);
gl.glPopMatrix();
}