Thursday 21 June 2012

Rotating an image in opengl


In this part we will take a look on how to rotate an image in its local coordinates.

To rate an image opengl provides us with a function
glRotatef(angle,x,y,z);

angle indicates the rotation angle in degrees.
x,y,z indicates along which axis the image should rotate.

For example,
glRotatef(30,1,0,0)  would rotate an image in 30 degrees angle along x-axis.
glRotatef(90,0,1,0)  would rotate an image in 90 degrees angle along y-axis.
glRotatef(180,0,0,1)  would rotate an image in 180 degrees angle along z-axis.

But, it’s not sufficient to rotate an image just by passing the angle and specifying the coordinate axis. We have certain steps to be followed.


Steps to be followed:


The fact is that the image rotates w.r.t screen coordinates if we only use the above function, but the actual rotation we want is w.r.t image local coordinates.

Example of screen co-ordinates and local co-ordinates are shown below:


Now, how do we do that? Here it is

Step 1: Translate the image to screen coordinates
Step 2: Rotate the image to the desired angle and specify the axis.
Step 3: Finally, translate the image back to its original coordinates.

Let’s consider an example. Assume we have an image at rendered 10 , 10 (x, y coordinates)and you want to rotate the image in 30 degrees along z- axis.

Our normal image without rotation would something look like figure below :


Firstly ,Calculate the centerx and centery of the image
centerx = 10 + imagewidth/2;
centery = 10 + imageheight/2

Step 1:
Translate the image to screen coordinates

                                     glTranslatef(-centerx,-centery,0.0f);


Step 2:
Rotate the image to 30 degrees along z- axis



                                     glRotatef(30, 0.0f, 0.0f, 1.0f);


Step 3:
Translate back to its local coordinates

                                    


                                      glTranslatef(centerx, centery, 0.0f);

That’s it your done.

NOTE: The opengl takes the commands in the reverse way so while applying this in code it should be like this
glTranslatef(centerx,centery,0.0f);//final step
glRotatef(30, 0.0f, 0.0f, 1.0f);// 2nd step
glTranslatef(-centerx,centery,0.0f); //first step


You can download the complete source code here


Wednesday 20 June 2012

Rendering an image using opengl - Android


In the last part we have just seen the basic setup of the opengl view, Now we will work on how to create/load the textures in opengl and render them on the screen at given x and y of screen coordinates.

Let’s start with the initial commands required to render an image.

Add these opengl statements once the surface is initialized

Clear the color. The color value is red
glClearColor(1, 0, 0, 1);

Clear the depth buffer
glClearDepthf(1.0f);

disable depth buffer for objects not to occlude
glDisable(GL10.GL_DEPTH_TEST);

Enable blending for transparency
glEnable(GL10.GL_BLEND);  
glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);

Add these statements in onDrawFrame

Clear the buffers
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

Load the projection Matrix since we are more into 2d we set projection matrix to be 2d view
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluOrtho2D(gl, 0.0f,surfacewidth,surfaceheight,0.0f);

Avoid the back potion of the image to be visible.
glDisable(GL10.GL_CULL_FACE);

NOTE: Since onDrawFrame is called every frame we need to perform the above operation on every frame.

Loading a Texture:

A Texture is nothing but an image data.
All we need to do is get a  texture ID first.(A texture ID is a unique id for a texture to be loaded provided by following opengl function which can be later used to render).  Texture Id generally starts with 1.
                                   glGenTextures(1, array, 0);
1  Indicates number of texture ids to be created
array  is the array we pass to save the texture Id in it.
0 – is the offset of the texture.

Now, the above function reads the texture Id in the array passed. Here,  the size of the array is 1 since we have only one texture to load at once.

Next, Create a bitmap by passing an input stream which holds the image to be loaded.
                        bmp = BitmapFactory.decodeStream(inputStream, null, opts);

you got the bitmap and now you need to describe the pixel format of the image, this can be done as follows.
                        texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);

texImage2D provides us to define the internal format of texture, As we are working with 2d textures we pass the first parameter as 2D texture, and also pass the bitmap bmp created earlier,
The second and last parameters are pixel level and offset of the texture respectively which we don’t have to bother for now, hence passing zero.

The next step would be to create the filters for the texture. Texture filters provides us the flexibility of how the pixels of the texture (called as texels) should match with the pixels on the screen.
Opengl provides with the two different kinds of texture filters Minifying texture filters and Magnifying texture filters.

The texture minifying function is used whenever the pixel being textured maps to an area greater than one texture element. There are six defined minifying functions.
The texture magnification function is used when the pixel being textured maps to an area less than or equal to one texture element.

For example, Consider we are using filter “GL_NEAREST” as minifying filter. Now,  If one texel of the image is smaller than one pixel of the screen then the remaining part of the pixel is covered with the nearest pixel color.

Minifying filter
glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_NEAREST).

Magnifying filter
glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_LINEAR).

Till now, we have just loaded a texture. Here comes the core part of rendering a texture.
In opengl the render actual takes in steps, one is getting the vertex data and placing it in appropriate screen coordinates, the other thing is texturing the vertex data respectively.

Steps to be followed:
- To draw an image on the screen we actually need to divide the image into two triangles (as any image would be in the form of rectangular or square shape including alpha).
- Create a vertex data/buffer for each of the triangle.
- Create a texture data/buffer for each of the triangle.

Creating a vertex data/buffer:
Assume that the size of the image is 100x100(width x height), and you want to draw the image at 10,10 (where x-coordinate is 10 and y-coordinate is also 10).

As I told you that image is a combination of triangles, we have two triangles in our example which are described as follows.
                                                                       
  
                     

NOTE: A, B, C, D, E and F are the vertices of the triangle, Each vertex has x and y coordinates respectively. Totally we have 6 vertices for two triangles.
The value of x-coordinate in our example is 10 and the value y-coordinate is 10.
So, x =10 and y = 10; width = 100, height = 100;

Now, the vertex A is drawn at x, y  of the screen coordinates(which is 10,10 respectively).
Vertex B is drawn at x , y +height  (10, 10 +100)
Vertex C is drawn at x + width , y +height  (10+100, 10+100)
Vertex D is drawn at x + width , y  (10+100, 10)
Vertex E is drawn at x , y  (10,10)
Vertex F is drawn at x + width , y + height (10+100, 10+100);

The final image when we combine these two triangles would be as follows



Observe that vertex A, E are similar and vertex C, F are similar because though we are combining these vertices two form an image a vertex should be individual for both the triangles.


NOTE: The order of the vertices must be followed (order is A,B,C,D,E,F).

Till now we are only done with the vertex data/buffer, now we see how to place the texture coordinates for the respective vertex coordinates.

Texture coordinates represents the image data  used to map the vertices on the screen coordinates.
They usually known as U,V values with respect to image. Both these values start from top left corner of the image. U along x-axis(horizontal) and V along y-axis(vertical).The values  range from 0 to 1.
Now, we will match these texture coordinates with the above shown vertices. Each vertex has its own texture coordinates (U, V). The mapping would be as follows

Vertex A will have texture coordinates as U = 0 and V = 0;
Vertex B will have texture coordinates as U = 0 and V = 1;
Vertex C will have texture coordinates as U = 1 and V = 1;
Vertex D will have texture coordinates as U = 1 and V = 0;
Vertex E will have texture coordinates as U = 0 and V = 0;
Vertex F will have texture coordinates as U = 1 and V = 1;

 Observe that U, V values are similar for  A, E vertices and C, F vertices as seen in the example above creating vertex buffer.

NOTE: The order of the texture coordinates must be followed. The minimum value of U is 0 and the maximum value of U is 1, similarly for V.

We are done with creating vertex buffer and texture buffers, now we need to pass these buffers to the respective functions of opengl to render an image.

Before that, we have few steps to be followed for every frame to render

Enable the texture2d as we are dealing with 2D stuff
glEnable(GL10.GL_TEXTURE_2D);

Activate the texture.
glActiveTexture(GL10.GL_TEXTURE0);

Bind the texture using the texture ID which we have generated in the very first stage
glBindTexture(GL10.GL_TEXTURE_2D,  textureID);

enable the vertex coordinate array
glEnableClientState(GL10.GL_VERTEX_ARRAY);

enable the texture coordinate array
glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

here comes the vertex data usage, pass the vertex buffer
glVertexPointer(2, GL10.GL_FLOAT, 0, vertexBuffer);

pass the texure buffer
glTexCoordPointer (2, GL10.GL_FLOAT, 0, textureBuffer);

And the final step which we were waiting for is here which draws the image with specified vertex data/buffer and texture data/buffer passed in the previous steps.
glDrawArrays(GL10.GL_TRIANGLES, 0, 6);

GL_TRIANGLES  is the mode to be specified to draw, we are using triangles for our example.
0 represents the first index of the buffer, and 6 indicates the number of vertices we are drawing. We have two triangles, each triangles has 3 vertices and so total 3 * 2 = 6 vertices.


you can download the complete code here

Thursday 24 May 2012

OpenGL Android

Let's start with basic opengl application which displays a view with specified color.




Create an Activity class and override onCreate method.
inside onCreate initialize  GLSurfaceView class, (GLSurfaceView is a class managed to render opengl graphics).

GLSurfaceView myView =  new GLSurfaceView(getApplicationContext());



Now, set a renderer for the view which is used for actual rendering stuff.

myView.setRenderer(new MyGLRenderer(getApplicationContext(),myView));

MyGLRenderer is a class implementing Renderer interface to render the graphics

MyGLRenderer class goes this way:


This class implements Renderer interface which in turn overrides three methods
1.onSurfaceCreated
2 onSurfaceChanged
3 onDrawFrame

Now, what has to be done inside these methods?

1. onSurfaceCreated: This method is called for the first time and only once when  this class is been initialized, All the initialization stuff should be taken care here. For now we will have only once line of code in this method

Clear the color of the view with the color values, basically its a background color.I have choose red color to display,you can try replacing with any other color values.
                                     
                                         R      G     B     A

                glClearColor(1.0f, 0.0f, 0.0f, 1.0f);


2. onSurfaceChanged: This method is called when their are changes in the screen sizes for example screen orientation.For now all we need to do is set the viewport. viewport is the viewing area for the user this can be using

                glViewport(0, 0, width, height);


3. onDrawFrame: This is yet another method where all the regular drawing content should be taken care.
This method is looper method meaning it is called continuously for every frame. It goes this way

The first statement should be to clear the depth and color buffer. For every frame you render clear both the color and depth buffers(clearing the surface) for the next frame to be rendered.this could be acheived using following function provided by opengl

               glClear(GL10.GL_DEPTH_BUFFER_BIT | GL10.GL_COLOR_BUFFER_BIT);


Finally, set this view as content view in the activity class,this will display the view with red color

                setContentView(myView)




You can download the complete code here.