Showing posts with label opengl es 2.0 tutorial. Show all posts
Showing posts with label opengl es 2.0 tutorial. Show all posts

Monday, July 4, 2011

3D shapes and Rotation in Opengl ES 2.0

It will be helpful to go through Previous tutorial before reading this one. LINK

Now, we will change the structure of Vertex a little. Position array is now of size 3 to handle x, y as well as z.


struct Vertex {
    float Position[3];
    float Color[4];
};



Our rotation matrix
void ApplyRotationX(float degrees)
{
    float radians = degrees * 3.14159f / 180.0f;
    float s = std::sin(radians);
    float c = std::cos(radians);
    float zRotation[16] = {
        1, 0, 0, 0,
        0, c, s, 0,
        0, -s, c, 0,
        0, 0, 0, 1
    };
    
    GLint modelviewUniform = glGetUniformLocation(buildProgram, "Modelview");
    glUniformMatrix4fv(modelviewUniform, 1, 0, &zRotation[0]);
}

void ApplyRotationY(float degrees)
{
    float radians = degrees * 3.14159f / 180.0f;
    float s = std::sin(radians);
    float c = std::cos(radians);
    float zRotation[16] = {
        s, 0, c, 0,
        0, 1, 0, 0,
        c, 0, -s, 0,
        0, 0, 0, 1
    };
    
    GLint modelviewUniform = glGetUniformLocation(buildProgram, "Modelview");
    glUniformMatrix4fv(modelviewUniform, 1, 0, &zRotation[0]);
}

void ApplyRotationXY(float degrees)
{
    float radians = degrees * 3.14159f / 180.0f;
    float s = std::sin(radians);
    float c = std::cos(radians);
    float zRotation[16] = {
        s, 0, c, 0,
        s*c, c, -s* s, 0,
        c*c, -s, -c * s, 0,
        0, 0, 0, 1
    };
    
    GLint modelviewUniform = glGetUniformLocation(buildProgram, "Modelview");
    glUniformMatrix4fv(modelviewUniform, 1, 0, &zRotation[0]);
}




Arrays of vertex and indices

// Define the positions and colors(R,G,B,A) of 8 vertices of square.
const Vertex Vertices[] = {
    {{0, 0, 0}, {1, 0, 0, 1}},
    {{0, 0.5, 0},  {0, 1, 0, 1}},
    {{0.5, 0.5, 0},  {1, 1, 0, 1}},
    {{0.5, 0, 0}, {1, 0, 1, 1}},
    {{0, 0, 0.5}, {0, 1, 1, 1}},
    {{0, 0.5, 0.5},  {0, 0.5, 0, 1}},
    {{0.5, 0.5, 0.5},  {0.5, 0.5, 0, 1}},
    {{0.5, 0, 0.5}, {0.5, 0, 0.5, 1}},
  
};

//Define the order of vertices for 12 triangles/
//0,1,2 forms first triangle
//2,3,0 form second triangle.
const GLubyte Indices[] = {
    0, 1, 2,
    2, 3, 0,
    4,5,6,
    6,7,4,
    0,1,4,
    1,4,5,
    1,2,6,
    1,5,6,
    2,3,6,
    3,6,7,
    0,3,4,
    3,4,7,
    
};


And finally drawing

       // Drawing code
    glClearColor(1.0f, 1.0f, 1.0f, 1);
    glClear(GL_COLOR_BUFFER_BIT);
    
    switch (rotateAlong) {
        case 1:
            ApplyRotationX(degreesX);
            break;
        case 2:ApplyRotationY(degreesY);
            break;
        default:ApplyRotation(degreesZ);
            break;
    }
    
    
    
    
    glEnableVertexAttribArray(_positionSlot);
    glEnableVertexAttribArray(_colorSlot);
    
    
    //Lets give these functions pointer to head of vertex array.
    GLsizei stride = sizeof(Vertex);
    const GLvoid* pCoords = &Vertices[0].Position[0];
    const GLvoid* pColors = &Vertices[0].Color[0];
    
   //Attribute changed from 2 (when we had drawn square) to 3 (dealing with cube x,y and z)
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, stride, pCoords);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, stride, pColors);
    
    //Draw the 12 triangles and (12*3=)36 indices.
    const GLvoid* bodyIndices = &Indices[0];
    glDrawElements(GL_TRIANGLES,12* 3, GL_UNSIGNED_BYTE, bodyIndices);
    
    glDisableVertexAttribArray(_positionSlot);
    glDisableVertexAttribArray(_colorSlot);    
    
    [mimContext presentRenderbuffer:GL_RENDERBUFFER];


In order to know about rotation matrix, read this LINK
It tells you about matrix used for rotation around x, y and z axis. For rotation around X as well Y (mixed rotation) we just multiply rotation matrix of X and Y axis.

There are 3 sliders with which  you can rotate the cube along X, Y and Z axis.

     //Solo Rotation along either of X,Y or Z.
    switch (rotateAlong) {
        case 1:
            ApplyRotationX(degreesX);
            break;
        case 2:ApplyRotationY(degreesY);
            break;
        default:ApplyRotation(degreesZ);
            break;
    }


    //Comment above lines in switch in code
    //Uncomment following lines to see mixed rotation.
    //Mixed Rotation along X and Y
    ApplyRotationXY(40);
    

Check out screenshot:
















You can download the code HERE

Sunday, July 3, 2011

First Polygon in Opengl ES 2.0

Ok. After reading this tutorial , you officially enter the Opengl ES 2.0 club.

We gotta define structures we will be using for creating our shapes. If you ever played that game in childhood where you connect the dots to create a shape. Opengl is same way. A Dot is called a vertex(plural: vertices) and A line created by drawing 2 Dots is called Index(plural: Indices).
Now every shape can be created by joining loads of triangle. If you don't believe me. Lets begin with square: It can made up of 2 triangles.
Imagine this: We have 4 vertex of square as 0,1,2,3 then a square can be made by 2 triangles with vertices 0,1,2 and 3,1,2. Lets stick with square in this tutorial we will move onto 3D shapes in next tutorial.

So in our code there are 2 properties sticked with each vertex- position and color. So we define our structure in code for 2D shapes for now as (for 3D we will have position[3] for x,y and z , as we will see in next tutorial)


struct Vertex {
    float Position[2];
    float Color[4];
};




Lets define now a little about shaders. There are 2 kinds of shaders: Vertex Shader and Fragment Shader.
In short, Vertex Shaders is called per vertex  for defining its color . And Fragment Shader is called per pixel of the scene to define color of that pixel.

We will have 2 shader files, one for each. We will just create an empty new file and name it as MIMFrag.glsl , you can name them whatever you want. Copy following files into it.


const char* FragmentShader = STRINGIFY(

varying lowp vec4 DestinationColor;

void main(void)
{
    gl_FragColor = DestinationColor;
}
);

You will later see all data of file MIMFrag.glsl will be transferred into const char var called FragmentShader. Got it from Philip Rideout book.

Another empty file, name it as MIMVert.glsl and copy following:

const char* VertexShader = STRINGIFY(

attribute vec4 Position;
attribute vec4 SourceColor;
varying vec4 DestinationColor;
uniform mat4 Projection;
uniform mat4 Modelview;

void main(void)
{
    DestinationColor = SourceColor;
    gl_Position = Projection * Modelview * Position;
}
);


Lets forget about Projection, Modelview for now. We will need them more specifically later on for more complicated jobs.

There you go ! Now you have defined how vertex shader and fragment shader will work. Now lets include them in our OpenglView.m file.

#define STRINGIFY(A)  #A
#include "MIMFrag.glsl"
#include "MIMVert.glsl"


We will define our vertex position and corresponding colors , remember the structure we defined for the our vertices above as
struct Vertex {



    float Position[2];
    float Color[4];
};.
We also define the indices array which tells us with what vertices our triangles will be formed.


// Define the positions and colors(R,G,B,A) of two triangles.
const Vertex Vertices[] = {
    {{-0.5, 0}, {1, 0, 0, 1}},
    {{0, 0.5},  {0, 1, 0, 1}},
    {{0.5, 0},  {1, 1, 0, 1}},
    {{0, -0.5}, {1, 0, 1, 1}},
  
};

//Define the order of vertices
//0,1,2 forms first triangle
//2,3,0 form second triangle.
const GLubyte Indices[] = {
    0, 1, 2,
    2, 3, 0
};

 Next important thing to discuss will be to draw
       //Lets give these functions pointer to head of vertex array.
    GLsizei stride = sizeof(Vertex);
    const GLvoid* pCoords = &Vertices[0].Position[0];
    const GLvoid* pColors = &Vertices[0].Color[0];
    
    glVertexAttribPointer(_positionSlot, 2, GL_FLOAT, GL_FALSE, stride, pCoords);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, stride, pColors);
    
    //Draw the 2 triangles of the square.
    const GLvoid* bodyIndices = &Indices[0];
    glDrawElements(GL_TRIANGLES,2* 3, GL_UNSIGNED_BYTE, bodyIndices);


So we set the VertexAttributes with Colors and Positions of the VertexArray. Thats just pure programming bullshit incase it looks very complicated to beginners . Dont worry.
const GLvoid* pCoords is the pointer pointing to the header of the Vertices array(accessing the position property).

We will be using glDrawElements to draw triangles, there is glDrawArrays too but lets just stick to one thing till we are comfortable in one. Also  there GL_TRIANGLES_STRIP , GL_TRIANGLES_FAN but we will just use GL_TRIANGLES for now. Oh and 2 * 3 in glDrawElements is the number of lines(indices) we will be drawing. There will be 6 lines((0,1) , (1,2), (2,0) ,(2,3),(3,0),(0,2)).


Finally we see the triangle like following:


Setting up Opengl ES 2.0 window in XCode.


This tutorial covers only Opengl ES 2.0 for iOS. You don't need to install any Opengl ES package from anywhere… its already there.
So we will start from a very generic template for iOS and open a Window-based application. We should add Opengl ES framework and QuartzCore framework.
LINK (How to add frameworks in project in XCode 4).

Ok. So we will just load a clean screen in this tutorial where we will doing drawing in our further tutorials.

Now I am going to make sure that I can compile the combination of Objective-C and C++ as we will be dealing with lots of C++ here as well, hence we will have to make some changes in the project setting regarding our GCC-Language as described in this article. LINK
In this tutorial its not useful but will be later on.

For this tutorial I am going to do everything in single file for beginners not get confused with so many files, classes etc… but later on we will move to get it more standard with classes and templates etc once we are past the beginners step.

Ok. Lets add a UIView and name it OpenglView.
Lets import gl.h
#import "OpenglView.h"





We need to add following to convert the layer of this view to CAEAGLLayer format so that we can do our OpenGL drawing on it.

+ (Class) layerClass
{
    return [CAEAGLLayer class];
}




We extract our CAEAGLLayer from the current layer. Remember it was easy to extract CALayer from current layer by just doing self.layer for a UIView but now we are downcasting CALayer to CAEAGLLayer for OpenGL specific drawings.
CAEAGLLayer* eaglLayer = (CAEAGLLayer*) super.layer;








This will tell Quartz to stop handling transparency as Opengl will do it all now.
eaglLayer.opaque = YES;


If you have done any Quartz Drawing then you must remember we used to have CGContext prepared in order to be able to draw anything. It acted like a canvas.
        mimContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
        BOOL setContext=[EAGLContext setCurrentContext:mimContext];
        if (!mimContext || !setContext) 
        {
            [self release];
            return nil;
        }
     

Then we set up the render buffer and frame buffer and viewport


            
        
        //Lets init and bind render buffer with current context
        glGenRenderbuffers(1, &renderbuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); 
        [mimContext renderbufferStorage:GL_RENDERBUFFER fromDrawable: eaglLayer];
        
        //Frame buffer- which is a collection of render buffers and other kind of buffers like depth etc.
        glGenFramebuffers(1, &framebuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);        

        //Setting the dimensions of your view area.
        glViewport(0, 0, CGRectGetWidth(frame), CGRectGetHeight(frame));





And then simply draw ! Here we are just clearing up the screen to white for the drawing in further articles. This will make your screen complete white.

       glClearColor(1.0f, 1.0f, 1.0f, 1);
    glClear(GL_COLOR_BUFFER_BIT);
    [mimContext presentRenderbuffer:GL_RENDERBUFFER];


CODE available to download HERE
Next tutorial available : HERE (wait for sometime :) )