Sunday, October 26, 2014

How to implement basic transformations on objects


I have taught CGV under Visvesvaraya Technological University more than six times and you may ask did I not get bored? Yes I did. Three times in the 1998/2002 scheme and three times in the 2006/2010 scheme. There is a vast difference between the syllabus of the earlier scheme and that of the 2006 scheme and onwards. Earlier scheme relied on textbook by James D Foley and others. The 2006 scheme follows Edward Angel and has introduced OpenGL to computer science students.
Students of yesteryears including me learn’t the now obsolete graphics.h library. I still remember those says when I had purchased a computer and was hunting for the EGAVGA.BGI file from my computer assembler. Coming to the topic It might strike you late but the importance of mathematics in Computer Graphics and Visualization is as Breath is to Life.
I will take you on a journey into a bit of transformations and how to realize them. “Your geometry lessons in schools will help you learn to write Graphics Programs”. Yes you heard it right.

Translation

One of the first things that a student of computer graphics learns is to move an object from one place to another. Actually, We draw an object at a particular place. So all we need to do to move it is to erase the object from that place and draw it at a new place (position). Place/position is measured with respect to a co-ordinate system. It may be 2-D or 3D coordinate system with x,y and z axis. A point may have three values like this:
int p1x,p1y,p1z; // non object oriented way
or
class point // object oriented way
{
int x,y,z;
};
point p1;
Now comes the most interesting part…. In OpenGL, transformations are implemented as functions. So if you want to apply any transformation on an object calling the transformation function before drawing the object will be sufficient to apply that transformation on that object.
So we have a function called glTranslatef to translate an object from one place to another. This function changes the position where objects are drawn.
Look at this code:
glTranslatef(4.0,3.0,0);
drawtriangle();
It draws a triangle at current raster position. That position is moved by glTranslatef() function to 4 units right(x axis) and three units up(y axis).

Rotation

All students of CSE/MCA would want to implement rotation in their projects but would not know how to rotate a particular object in the scene. Suppose I have drawn a line on the screen like this:
glBegin(GL_LINES);
glVertex2f(p1x,p1y);
glVertex2f(p2x,p2y);
glEnd();
This piece of code is present somewhere in the display function or any other function which is called from within display.

I want to rotate this line with respect to its centre. How to I do that?

You would have studied in your course about glPushMatrix(); and glPopMatrix(); functions. There is something called as the current transformation matrix (CTM). All objects going through the pipeline undergo these transformations. So if you want to apply a transformation to only the object you selected you just need to save the current transformation matrix somewhere so that it can be retrieved later. No better place than the stack to save it. PushMatrix saves the CTM on the stack and PopMatrix pops it from the stack and makes it the CTM.

To rotate this line we need to write the following code:
glPushMatrix();
glTranslatef((p1x+p2x)/2,(p1y+p2y)/2)); // go to a position at the center of the line 
glRotatef(10,0,1,0); // Rotate by 10 degrees the line wrt y-axis(0,1,0)
glTranslatef(-(p1x+p2x)/2,-(p1y+p2y)/2)); // go to a position at the center of the line
glBegin(GL_LINES);
glVertex2f(p1x,p1y);
glVertex2f(p2x,p2y);
glEnd();
glPopMatrix();

This code will draw the line in a rotated position. If you want continuous rotation you will need to increment this angle ‘10’ continuously by substituting a variable in its place. Here is the entire program to draw a rotating line while another object(teapot) nearby is stationary.
This snapshot represents the output:

Scaling:

Similar to rotation you would want objects to become big and small. Scaling an object involves calling the function glScalef();
So it it’s a 3D object like a teapot then glutSolidTeapot() is used to draw a teapot. To draw a teapot of different size we would
….. // here you would move the raster position to where
….. // you want to draw the teapot
glPushMatrix();
glScalef(2,2,2);
glutSolidTeapot();
glPopMatrix();

Here is a program where there is a rotating line and a teapot drawn with varying sizes and another nearby object(line) is not scaled but slowly rotating.
 Snapshot:

I hope your problem of applying transformations to selected objects is solved now. Happy Coding.

Wednesday, September 24, 2014

Tetra Turns into a Sphere and Viceversa

You may be aware of how a tetrahedron looks like. It is a polyhedra made up of four equilateral triangles.
 In this program all the equilateral triangles have a sierpinski gasket on them. Sierpinski gasket is a fractal drawn recursively by dividing the edges of the triangle and then inscribing a triangle with vertices at the center of each edge. Except the inscribed triangle all other triangles are repeatedly subdivided. Here is how a Sierpinski gasket looks like...
In my program that is the first one where the tetra turns into a sphere....i have colored the triangles inside the tetrahedron using Red, Green, Blue and Black Colors.
I will show a snippet of code which is doing this magic.
Here is the source.
 In the function normalize i have added the following code:(See comments)
void normalize(GLfloat *p)
{ double d=0.0;
int i;
for(i=0;i<3;i++) d+=p[i]*p[i]; //find the length of the vector
d=sqrt(d); // starting from origin to face of tetra
d=d+(1-d)*sf; // sf(scaling factor) has abs of sine wave 
                           // which is set in idle function
 if(max<d) max=d; // this statement i guess is not needed
if(d>0.0)
for(i=0;i<3;i++) p[i]/=d;//divide the vector components by the
}                                            // newly required length in d
Here is the idle function
void idle()
{ sf=fabs(sin(angle)); // as mentioned abs of sine wave
angle+=0.0004; // increment angle
if(angle>=360) angle=0; // if angle overflows
glutPostRedisplay(); // call display every possible moment
}
Happy Coding!
Small modification now the up and down arrow increases or decreases the angle and hence the scaling factor which decides the difference between the tetra and the sphere. Here is the modified code.

Tuesday, September 23, 2014

Another modification to the tetra program

Another modification to the tetra program that i made my poor students do were to add a timer to the program. In the timer function the color of the four faces of the tetra are changed. Its a glittering program where the tetra changes color every second. Some may say i went crazy making the students do these modifications. They were begging me to explain the code and i could just mumble that you will not understand now. When i covered the topic on timers i guess they understood.

Here are the snapshots:



Here is the source.

Modification to house rotation program

This program asks for initial rotation angle and starting from that orientation keeps rotating the house about the pivot point. Meaning less modification you may say but this is what i taught the students in the lab.

Snapshots:




Here is the source.

Modifications made to Cylinder and Parallelepiped

Modifications made to Cylinder and Parallelepiped program. The scene has been made to rotate on mouse input.
Several modifications need to be made in code to achieve this.

Snapshots:






Here is the source.

Program to draw a teapot over a table and rotate the scene using mouse

Program to draw a teapot over a table and rotate the scene using mouse input. This is the same program as the teapot program. The only modifications done are color of the teapot and the walls are changed. The scene is rotated using mouse input(on dragging the mouse).

Here are the snapshots:








Here is the source.

Drawing a sphere using a tetrahedron in OpenGL

This is a program in the seventh unit of Computer Graphics & Visualization (14CS65) of 6th semester CSE branch in VTU. This program has been modified to rotate the scene using mouse input. It asks for number of divisions. Once that is entered it draws a sphere using the same program to draw a tetra. A brief explanation of the code will follow soon.

Here are the snapshots:







Here is the source. Have a look at an animation of the above transformation where the tetra turns into a sphere and vice-versa. In another modification I have created a tetra with colors of sides changing every second. Both the above modifications require us to use a timer and an idle function.

Sunday, July 27, 2014

Scenario Based Nature

A Satyendra and MB Vinay the credits go to them. The code given here is a compressed file. Uncompress it using some software into a folder. Copy that folder. Then in eclipse create a C++ project and paste this folder inside that project. Set the project properties and off you go.

You should get this snapshot:



Here is the source.

Egg Game

Project by Jyothi SV and Vaishnavi R. Good improvisation. Mouse position controls the location of the basket. Newton's apple was a similar project but i am still including this.

Snapshots:
This is the initial Screen:
 Here the egg does not fall into the basket.

Here the egg goes into the basket. Points need to be increased but that does not happen in this project. Only level is shown.

Here is the source. Instead of going on posting projects created by students if i take the effort in explaining how these were created in the first place i feel i would be doing a great service. That is actually what i will be doing. I hope i have sufficient time for that. I will be explaining Brainvita first so giving a link here for easy browsing.

Paper Fold and Unfold

This is a project on folding a paper sheet also called as Origami in japanese.

This is an art itself. Paper folded and cut at several places yields good design when opened. This can be done in a program.

In this project by Pankaj Datta and Aditya Raj the paper is folded and made into a paper rocket. The rotation of the sheet of paper can be toggled.

Snapshot:


Here is the code. Modifications to the code include using a different sized paper. or folds at other places.

Friday, June 27, 2014

Waves on a water surface

This project was sent to me by a student in belgaum via FB. It was his end sem project.
The crux of the code is in the function fnc()...
// variable stp is initialized to 1 hence the mesh is having 300 horizontal and vertical lines
// MAX is 300
// for every intersection of x , y
// rpl and nrm are two arrays with ripple values of the mesh and the normal to the wave

void fnc()
{
int i,j;
double x,y,z,w;

w=-MAX*stp/2.0;    // this works out to -150

for (i=0;i<MAX;i++)    // i varies from 0 to 299
{
y=w+(double)i*stp;       // this y varies from -150 to 150

for (j=0;j<MAX;j++)     // j varies from 0 to 299
{
x=w+(double)j*stp;       // this x varies from -150 to 150

z=2.0*sin((x*x+y*y-phase)/100.0);   // this is the sin wave which gives this mesh its wavey nature
                                         // for more refer=> Link
rpl[i][j][0]=x;
rpl[i][j][1]=y;
rpl[i][j][2]=z;       // z is the height field or the height of the wave
}
}
}

Here is the snapshot.

Here is the code.

I had modified the code and took this snapshot where the mesh is being drawn using line strip.

Modification Snapshot:

Hawk Eye

This project by ramachandra and rakshit is about animating motion of the ball going and hitting the wicket.

Here are the snapshots:




Here is the code. Remember this is a c++ project. It runs on Ubuntu platform with opengl libraries added.

Sinking Ship

Namratha and sweekruthi worked on this existing project. The modification done to the sinking ship project that has been done is the ice berg becomes two pieces... both the pieces move down and sink.

Here are the snaps:
Moving....
 Collison....

 Pieces of iceberg and ship sinking....


I just want to add something to explain how this pieces of ice cube and their rotation was achieved.

Here is the code which does the trick.
/* TO DRAW ICEBERG */
void ice()
{
    glPushMatrix();
    glTranslated(450,50,0.0);
    glScaled(10,10,0);
    glColor3f(0.0,1.0,1.0);
    if(c>0)                          // This flag is used to indicate if ice berg is
    {glPushMatrix();          // intact or split into two after collision
    glTranslated(0,x,0);      //move the ice bergs down all the while rotating them.
    glPushMatrix();
    glTranslated(7,2,0.0);
    glRotated(-x,0,0,1);      // clockwise for the right piece.
    glTranslated(-7,-2,0.0);
    glBegin(GL_POLYGON);
        glVertex2f(7,2);
        glVertex2f(8,3);
        glVertex2f(11,18);
        glVertex2f(12,19);
        glVertex2f(12,3);
        glEnd();
        glPopMatrix();
        glPushMatrix();

        glTranslated(12,3,0.0);
        glRotated(x,0,0,1);           // anti clock wise for the left piece.
        glTranslated(-12,-3,0.0);
        glBegin(GL_POLYGON);
        glVertex2f(12,3);
        glVertex2f(12,19);
        glVertex2f(17,18);
        glVertex2f(18,3);
        glVertex2f(19,3);
        glEnd();
        glPopMatrix();
        glPopMatrix();
    }
    else                                 // if ice berg is intact draw one piece
    {                                     // without any transformations
        glBegin(GL_POLYGON);
            glVertex2f(7,2);
            glVertex2f(8,3);
            glVertex2f(11,18);
            glVertex2f(12,19);
            glVertex2f(12,3);
            glEnd();
            glBegin(GL_POLYGON);
            glVertex2f(12,3);
            glVertex2f(12,19);
            glVertex2f(17,18);
            glVertex2f(18,3);
            glVertex2f(19,3);
            glEnd();
    }
    glPopMatrix();
}
The variable c is global and it is set in the display function
like this...
    if(b>250)
    {

        c+=10;
        display3();

    }
Here is the complete code.

Simulation of Train

Kudos to Kusuma V(1CE11CS025)... This is her original creation. I have been trying to get adsense work on this blog but they have issues with plagiarized content. So am trying to post original projects of our students.

There are three trains which move on a track. The wheels rotate and they all move one after the other out of view.

Here are a few snapshots.



Here is the link to the code.

Thursday, June 26, 2014

A few Project Ideas - Computer Graphics and Visualization - VTU

Its June,2014 and past the peak traffic to my blog. I'm just writing a post to list a few project ideas that may strike me in the next few minutes. I have one already in mind so will start the list of ideas right away...

1) Furniture Arrangement App:
I have moved to a new home and having quite a few choices to make. I have to arrange furniture in the limited space of about a couple of hundred square feet. Knowing the dimensions of the various items like the sofa, dining set, wardrobe, cot and tables i just am unable to think all possibilities in which i could arrange them. If an interactive app using which a user could move around the objects like furniture to see how much space is occupied or remaining un-utilized would really be helpful.
Also you may make a project for measuring how many buses may enter and leave a bus station like magestic. For that you need to create a top view of the magestic bus stand and represent buses as rectangular boxes something similar to furniture and then implement translation of the boxes along with certain rules to avoid collision, governing their speed and taking care of exigencies like pedestrians walking past. Similar software can be made for airports too.
There is a beautiful theory of NP problems behind this simple app. The technique to enumerate all permutations of furniture in a room may yield an optimum solution. It is not possible to arrive at this solution in any other way(other than exhaustive search).
Read more: https://www.quora.com/What-is-the-most-interesting-math-problem-you-have-seen-recently?ch=10&share=da9a9076&srid=Cmht

2) Animating a Simulation:
After having handled the subject of system simulation and modeling twice and knowing the fact that animation and simulation can be great tools to design systems, I suggest these kind of projects to sixth semester students of VTU. I feel sorry to have suggested something that such students will study in eighth semester. Here is a sub-list of all the simulation/animation projects that one may possibly implement.
a) Single channel queue of either packets in a network or customers arriving at a server/bank teller. Some inputs such as IAT distribution or service time distribution may be input.
Here is a sample image of how the output might look(taken from google images)
b) Multiple channel queue of

customers such as in able/baker problem. Again the distributions may be input.
c) Simulation of a Simple Linear Digital Circuit: Updation of voltages and currents across a circuit such as a counter may be tried.
d) Simulation of an Inventory System such as refrigerator or newspaper. The inventory may be shown as a collection of items or a stack of newspapers.

3) Realization of Widgets:
Several widgets such as button, slide, knob or drop down list may be implemented by the students himself. The output may have all of these in a single screen.

4) Polymesh editor:
A rudimentary polymesh editor which is explained in the text book by edward angel may be improved to edit positions of individual points.

5) Animating Vodafone Zoozoos:
This is a project on my wish list. I know how they made the ZooZoos and if a program generates the animations they will look robotic.


I hope to keep adding to this list of ideas and it may grow to a large size. A good student may be able to implement these on his own.

Saturday, May 17, 2014

Western Michigan - CS5270 - Lab Assignment #2

Here is the second assignment @ Link.
The output looks like this:


I lazily kept postponing working on this assignment and somewhat slogged in the last few days. The professor kept postponing the last date for submitting the assignment so that helped. My purpose of posting the solutions is not to help future students but with an intension of forcing changes in assignments and updation of questions.
I don't know if the gimbal lock problem is there in this solution or not. I thought using quaternions solves the problem. If you think there is a problem still plz contact me.

I didn't solve this assignment completely. Anyone with basic programming skills can modify the code and make it work according to the expectations of the professor.

Here it is:
/*
 * ellipsoid.c
 *
 *  Created on: Oct 27, 2013
 *      Author: kamath
 */
#include<GL/glut.h>
#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include "quater.h"
#define Pi 3.141
static  GLdouble  viewer[]={80,80,50};
float phi=0,timestamp,alpha1,beta1,gamma1;
FILE *fp;
void DrawEllipsoid(unsigned int uiStacks, unsigned int uiSlices, float fA, float fB, float fC)
{
    float s,t,tStep = (Pi) / (float)uiSlices;
    float sStep = (Pi) / (float)uiStacks;

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    for(t = -Pi/2; t <= (Pi/2)+.0001; t += tStep)
    {
        glBegin(GL_TRIANGLE_STRIP);
        for(s = -Pi; s <= Pi+.0001; s += sStep)
        {
            glVertex3f(fA * cos(t) * cos(s), fB * cos(t) * sin(s), fC * sin(t));
            glVertex3f(fA * cos(t+tStep) * cos(s), fB * cos(t+tStep) * sin(s), fC * sin(t+tStep));
        }
        glEnd();
    }
}
void display()
{float m2[4][4],m3[4][4],m4[4][4],m21[16],m31[16],m41[16];
float a1[3]={0,0,1.0},a2[3]={0,1.0,0},q[4],k[4],j[4];

int i;

alpha1=alpha1*3.141/180;    //convert degrees into radians
beta1=beta1*3.141/180;
gamma1=gamma1*3.141/180;
axis_to_quat(a1,alpha1,q);    //convert euler angles into quaternions
axis_to_quat(a2,beta1,k);
axis_to_quat(a1,gamma1,j);
//add_quats(q,k,dest)
build_rotmatrix(m2,q);        //convert quaternions into matrices
build_rotmatrix(m3,k);
build_rotmatrix(m4,j);
for(i=0;i<16;i++) //convert matrix into column major order
{
    m21[i]=m2[i%4][(int)floor(i/4)];
}
for(i=0;i<16;i++)
{
    m31[i]=m3[i%4][(int)floor(i/4)];
}
for(i=0;i<16;i++)
{
    m41[i]=m4[i%4][(int)floor(i/4)];
}

usleep(1000);
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glColor3f(1,0,0);
    glLoadIdentity();
    gluLookAt(viewer[0],viewer[1],viewer[2],0,0,0,0,1,0);
    glLoadIdentity();
    glPushMatrix();
    glRotatef(45,1,1,1);
    glBegin(GL_LINES);
    glVertex3f(0,0,-10);
    glVertex3f(0,0,10);
    glVertex3f(10,0,0);
    glVertex3f(-10,0,0);
    glVertex3f(0,10,0);
        glVertex3f(0,-10,0);
        glEnd();
        glColor3f(0.8,0.8,0.4);
        glTranslatef(30,30,0);
    glMultMatrixf(m41);//rotate wrt Z
    glMultMatrixf(m31);//rotate wrt x
    glMultMatrixf(m21);//rotate wrt z
    DrawEllipsoid(10, 10, 12,6,24);
    glFlush();
    glPopMatrix();
    glutSwapBuffers();

}
void init()
{
    glClearColor(1.0,1.0,1.0,0.0);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(-80,80,-80,80,-80,80);
        glMatrixMode(GL_MODELVIEW);
}
void idle()
{// read file and get angles
    if(fscanf (fp,"%f %f %f %f\n",&timestamp,&alpha1,&beta1,&gamma1)==EOF)
    {
        fclose(fp);
        printf("end of input");
        exit(0);
    }

    glutPostRedisplay();
}
int main(int argc,char *argv[])
{
    fp = fopen ("el1_sh.txt", "r");
     if (fp == NULL)
            {
                printf ("Error opening file");
                exit(1);
            }
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
    glutInitWindowSize(500,500);
    glutInitWindowPosition(200,0);
    glutCreateWindow("ellipsoid");
    glutDisplayFunc(display);
    init();
    glEnable(GL_DEPTH_TEST);
    glutIdleFunc(idle);
    glutMainLoop();

    return 0;
}



This is a .h file you need to include: (Contains code to work with quaternions)
#include <math.h>
//#include "trackball.h"

/*
 * This size should really be based on the distance from the center of
 * rotation to the point on the object underneath the mouse.  That
 * point would then track the mouse as closely as possible.  This is a
 * simple example, though, so that is left as an Exercise for the
 * Programmer.
 */
#define TRACKBALLSIZE  (0.8)

/*
 * Local function prototypes (not defined in trackball.h)
 */
static float tb_project_to_sphere(float, float, float);
static void normalize_quat(float [4]);

void
vzero(float *v)
{
    v[0] = 0.0;
    v[1] = 0.0;
    v[2] = 0.0;
}

void
vset(float *v, float x, float y, float z)
{
    v[0] = x;
    v[1] = y;
    v[2] = z;
}

void
vsub(const float *src1, const float *src2, float *dst)
{
    dst[0] = src1[0] - src2[0];
    dst[1] = src1[1] - src2[1];
    dst[2] = src1[2] - src2[2];
}

void
vcopy(const float *v1, float *v2)
{
    register int i;
    for (i = 0 ; i < 3 ; i++)
        v2[i] = v1[i];
}

void
vcross(const float *v1, const float *v2, float *cross)
{
    float temp[3];

    temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
    temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
    temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
    vcopy(temp, cross);
}

float
vlength(const float *v)
{
    return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
}

void
vscale(float *v, float div)
{
    v[0] *= div;
    v[1] *= div;
    v[2] *= div;
}

void
vnormal(float *v)
{
    vscale(v,1.0/vlength(v));
}

float
vdot(const float *v1, const float *v2)
{
    return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}

void
vadd(const float *src1, const float *src2, float *dst)
{
    dst[0] = src1[0] + src2[0];
    dst[1] = src1[1] + src2[1];
    dst[2] = src1[2] + src2[2];
}
/*
 *  Given an axis and angle, compute quaternion.
 */
void
axis_to_quat(float a[3], float phi, float q[4])
{
    vnormal(a);
    vcopy(a,q);
    vscale(q,sin(phi/2.0));
    q[3] = cos(phi/2.0);
}
/*
 * Ok, simulate a track-ball.  Project the points onto the virtual
 * trackball, then figure out the axis of rotation, which is the cross
 * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
 * Note:  This is a deformed trackball-- is a trackball in the center,
 * but is deformed into a hyperbolic sheet of rotation away from the
 * center.  This particular function was chosen after trying out
 * several variations.
 *
 * It is assumed that the arguments to this routine are in the range
 * (-1.0 ... 1.0)
 */
void
trackball(float q[4], float p1x, float p1y, float p2x, float p2y)
{
    float a[3]; /* Axis of rotation */
    float phi;  /* how much to rotate about axis */
    float p1[3], p2[3], d[3];
    float t;

    if (p1x == p2x && p1y == p2y) {
        /* Zero rotation */
        vzero(q);
        q[3] = 1.0;
        return;
    }

    /*
     * First, figure out z-coordinates for projection of P1 and P2 to
     * deformed sphere
     */
    vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y));
    vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y));

    /*
     *  Now, we want the cross product of P1 and P2
     */
    vcross(p2,p1,a);

    /*
     *  Figure out how much to rotate around that axis.
     */
    vsub(p1,p2,d);
    t = vlength(d) / (2.0*TRACKBALLSIZE);

    /*
     * Avoid problems with out-of-control values...
     */
    if (t > 1.0) t = 1.0;
    if (t < -1.0) t = -1.0;
    phi = 2.0 * asin(t);

    axis_to_quat(a,phi,q);
}



/*
 * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
 * if we are away from the center of the sphere.
 */
static float
tb_project_to_sphere(float r, float x, float y)
{
    float d, t, z;

    d = sqrt(x*x + y*y);
    if (d < r * 0.70710678118654752440) {    /* Inside sphere */
        z = sqrt(r*r - d*d);
    } else {           /* On hyperbola */
        t = r / 1.41421356237309504880;
        z = t*t / d;
    }
    return z;
}

/*
 * Given two rotations, e1 and e2, expressed as quaternion rotations,
 * figure out the equivalent single rotation and stuff it into dest.
 *
 * This routine also normalizes the result every RENORMCOUNT times it is
 * called, to keep error from creeping in.
 *
 * NOTE: This routine is written so that q1 or q2 may be the same
 * as dest (or each other).
 */

#define RENORMCOUNT 97

void
add_quats(float q1[4], float q2[4], float dest[4])
{
    static int count=0;
    float t1[4], t2[4], t3[4];
    float tf[4];

    vcopy(q1,t1);
    vscale(t1,q2[3]);

    vcopy(q2,t2);
    vscale(t2,q1[3]);

    vcross(q2,q1,t3);
    vadd(t1,t2,tf);
    vadd(t3,tf,tf);
    tf[3] = q1[3] * q2[3] - vdot(q1,q2);

    dest[0] = tf[0];
    dest[1] = tf[1];
    dest[2] = tf[2];
    dest[3] = tf[3];

    if (++count > RENORMCOUNT) {
        count = 0;
        normalize_quat(dest);
    }
}

/*
 * Quaternions always obey:  a^2 + b^2 + c^2 + d^2 = 1.0
 * If they don't add up to 1.0, dividing by their magnitued will
 * renormalize them.
 *
 * Note: See the following for more information on quaternions:
 *
 * - Shoemake, K., Animating rotation with quaternion curves, Computer
 *   Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
 * - Pletinckx, D., Quaternion calculus as a basic tool in computer
 *   graphics, The Visual Computer 5, 2-13, 1989.
 */
static void
normalize_quat(float q[4])
{
    int i;
    float mag;

    mag = (q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
    for (i = 0; i < 4; i++) q[i] /= mag;
}

/*
 * Build a rotation matrix, given a quaternion rotation.
 *
 */
void
build_rotmatrix(float m[4][4], float q[4])
{
    m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
    m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
    m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
    m[0][3] = 0.0;

    m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
    m[1][1]= 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
    m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
    m[1][3] = 0.0;

    m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
    m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
    m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
    m[2][3] = 0.0;

    m[3][0] = 0.0;
    m[3][1] = 0.0;
    m[3][2] = 0.0;
    m[3][3] = 1.0;
}


This is a text file el1_sh.txt that is the input to the rotation functions, so u need to put it inside the project folder. I will soon update the post to include a few more comments to explain the program.

Western Michigan - CS5270 - Lab Assignment #1

One of my students happened to take admission in a US varsity and sought my help in a lab assignment. I wanted to learn something new so happily volunteered for help.

This was the first assignment @ Link.

I solved it within a couple of days and here is the solution for the first task. The code runs in ubuntu. Please search some good site which will help you install glew.

This program uses glew and runs as well as the glaux function using program.

/**************************************************
   solar.c

   Program to demonstrate how to use a local
   coordinate method to position parts of a
   model in relation to other model parts.

   Pressing the "a" key toggles the animation
   Pressing the up and down arrow keys will
   increase/decrease the animation rate

**************************************************/

//#include "glos.h" // MS specifc stuff
#include<GL/glew.h>
#include <GL/gl.h> // system OpenGL includes
#include <GL/glu.h>
//#include <GL/glaux.h>
#include<GL/glut.h>

static GLenum spinMode = GL_TRUE;

void OpenGLInit(void);

static void Animate(void );
/*static void Key_a(void );
static void Key_up(void );
static void Key_down(void );*/
static void ResizeWindow(GLsizei w, GLsizei h);
static int HourOfDay = 0, DayOfYear = 0;
static int AnimateIncrement = 24; // in hours

/*static void Key_a(void)
{
    spinMode = !spinMode;
}

static void Key_up(void)
{
    AnimateIncrement *= 2;
    if ( 0 == AnimateIncrement )
        AnimateIncrement = 1;
}

static void Key_down(void)
{
    AnimateIncrement /= 2;

}*/
static void special1(int key,int x,int y)
{
    switch(key)
    {
    case GLUT_KEY_UP:
        AnimateIncrement *= 2;
            if ( 0 == AnimateIncrement )
                AnimateIncrement = 1;break;
    case GLUT_KEY_DOWN:AnimateIncrement /= 2;break;
    }

}
void mykeys(unsigned char key,int x,int y)
{
    if(key=='a' || key=='A')
        spinMode = !spinMode;
}

static void Animate(void)
{
    // clear the redering window
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if (spinMode)
        {
        // calc animation parameters
        HourOfDay += AnimateIncrement;
        DayOfYear += HourOfDay/24;

        HourOfDay = HourOfDay%24;
        DayOfYear = DayOfYear%365;
        }

    // clear current matrix (Modelview)
    glLoadIdentity();
    // back off six units
    glTranslatef ( 0.0f, 0.0f, -5.0f );
    // rotate the plane of the elliptic
    // (rotate the model's plane about the
    // x axis by five degrees)
    glRotatef( 5.0f, 1.0f, 0.0f, 0.0f );

    // draw the sun
    glColor3f( 1.0, 1.0, 1.0 );
    glutWireSphere( 1.0,100,100 );

    // draw the Earth
    glRotatef( (GLfloat)(360.0*DayOfYear/365.0),
        0.0, 1.0, 0.0 );
    glTranslatef( 4.0, 0.0, 0.0 );
    glPushMatrix(); // save matrix state
    glRotatef( (GLfloat)(360.0*HourOfDay/24.0), 0.0, 1.0, 0.0 );
    glColor3f( 0.2, 0.2, 1.0 );
    glutWireSphere( 0.2,100,100 );
    glPopMatrix(); // restore matrix state

       glRotatef( (GLfloat)(360.0*12.5*DayOfYear/365.0),
        0.0, 1.0, 0.0 );
    glTranslatef( 0.5, 0.0, 0.0 );
    glColor3f( 0.3, 0.3, 0.3 );
    glutWireSphere( 0.05 ,100,100);

    // flush the pipeline, swap the buffers
    glFlush();
    glutSwapBuffers();

}

// initialize OpenGL
void OpenGLInit(void)
{
    glShadeModel( GL_FLAT );
    glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
    glClearDepth( 1.0f );
    glDepthFunc( GL_LEQUAL );
    glEnable( GL_DEPTH_TEST );
}

// called when the window is resized
static void ResizeWindow(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    w = (w == 0) ? 1 : w;
    glViewport( 0, 0, w, h );
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    gluPerspective( 45.0, (GLfloat)w/(GLfloat)h, 1.0f, 20.0f );
    // select the Modelview matrix
    glMatrixMode( GL_MODELVIEW );
}

// main routine
// set up OpenGL, hook up callbacks
// and start the main loop
int main( int argc, char** argv )
{
    // we're going to animate it, so double buffer
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB|GLUT_DEPTH );
    glutInitWindowPosition( 0, 0);
    glutInitWindowSize(620, 160 );
    glutCreateWindow( "Solar System Example" );

    // Initialize OpenGL as we like it..
    OpenGLInit();

    // set up callback functions
/*    auxKeyFunc( AUX_UP, Key_up ); // faster
    auxKeyFunc( AUX_DOWN, Key_down ); // slower
    auxKeyFunc( AUX_a, Key_a ); //animate*/
    glutReshapeFunc( ResizeWindow );
    glutSpecialFunc(special1);
    glutKeyboardFunc(mykeys);
    glEnable(GL_DEPTH_TEST);
    // call this when idle
    glutIdleFunc( Animate );
    // call this in main loop
//    auxMainLoop( Animate );
    glutMainLoop();

    return(0);
}








The second programming task uses shaders which i was not familiar with. I somehow solved the problem but still wondering how it works.

Here it is:
Solar2.cpp

/**************************************************
   solar.c

   Program to demonstrate how to use a local
   coordinate method to position parts of a
   model in relation to other model parts.

   Pressing the "a" key toggles the animation
   Pressing the up and down arrow keys will
   increase/decrease the animation rate

**************************************************/

//#include "glos.h" // MS specifc stuff
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>

#include<GL/glew.h>

#include <GL/gl.h> // system OpenGL includes
#include <GL/glu.h>
//#include <GL/glaux.h>
#include<GL/glut.h>



static GLenum spinMode = GL_TRUE;

void OpenGLInit(void);

static void Animate(void );
/*static void Key_a(void );
static void Key_up(void );
static void Key_down(void );*/
static void ResizeWindow(GLsizei w, GLsizei h);

static int HourOfDay = 0, DayOfYear = 0;
static int AnimateIncrement = 24; // in hours
using namespace std;

/*
   Global handles for the currently active program object, with its two shader objects
*/
GLuint programObject = 0;
GLuint vertexShaderObject = 0;
GLuint fragmentShaderObject = 0;
static GLint win = 0;

int readShaderSource(char *fileName, GLchar **shader )
{
    // Allocate memory to hold the source of our shaders.
    FILE *fp;
    int count, pos, shaderSize;

    fp = fopen( fileName, "r");
    if ( !fp )
        return 0;

    pos = (int) ftell ( fp );
    fseek ( fp, 0, SEEK_END );            //move to end
    shaderSize = ( int ) ftell ( fp ) - pos;    //calculates file size
    fseek ( fp, 0, SEEK_SET );             //rewind to beginning

    if ( shaderSize <= 0 ){
        printf("Shader %s empty\n", fileName);
        return 0;
    }

    *shader = (GLchar *) malloc( shaderSize + 1);

    // Read the source code

    count = (int) fread(*shader, 1, shaderSize, fp);
    (*shader)[count] = '\0';

    if (ferror(fp))
        count = 0;


    fclose(fp);

    return 1;
}

//  public
int installShaders(const GLchar *vertex, const GLchar *fragment)
{
    GLint  vertCompiled, fragCompiled;  // status values
    GLint  linked;

    // Create a vertex shader object and a fragment shader object

    vertexShaderObject = glCreateShader(GL_VERTEX_SHADER);
    fragmentShaderObject = glCreateShader(GL_FRAGMENT_SHADER);

    // Load source code strings into shaders, compile and link

    glShaderSource(vertexShaderObject, 1, &vertex, NULL);
    glShaderSource(fragmentShaderObject, 1, &fragment, NULL);

    glCompileShader(vertexShaderObject);
    glGetShaderiv(vertexShaderObject, GL_COMPILE_STATUS, &vertCompiled);

    glCompileShader( fragmentShaderObject );
    glGetShaderiv( fragmentShaderObject, GL_COMPILE_STATUS, &fragCompiled);

    if (!vertCompiled || !fragCompiled)
        return 0;

    // Create a program object and attach the two compiled shaders

    programObject = glCreateProgram();
    glAttachShader( programObject, vertexShaderObject);
    glAttachShader( programObject, fragmentShaderObject);

    // Link the program object

    glLinkProgram(programObject);
    glGetProgramiv(programObject, GL_LINK_STATUS, &linked);

    if (!linked)
        return 0;

    // Install program object as part of current state

    glUseProgram(programObject);

    return 1;
}

/*static void Key_a(void)
{
    spinMode = !spinMode;
}

static void Key_up(void)
{
    AnimateIncrement *= 2;
    if ( 0 == AnimateIncrement )
        AnimateIncrement = 1;
}

static void Key_down(void)
{
    AnimateIncrement /= 2;

}*/
static void special1(int key,int x,int y)
{
    switch(key)
    {
    case GLUT_KEY_UP:
        AnimateIncrement *= 2;
            if ( 0 == AnimateIncrement )
                AnimateIncrement = 1;break;
    case GLUT_KEY_DOWN:AnimateIncrement /= 2;break;
    }

}
void mykeys(unsigned char key,int x,int y)
{
    if(key=='a' || key=='A')
        spinMode = !spinMode;
}
void CleanUp(void)
{
   glDeleteShader(vertexShaderObject);
   glDeleteShader(fragmentShaderObject);
   glDeleteProgram(programObject);
   glutDestroyWindow(win);
}
void Animate(void)
{
     GLchar *VertexShaderSource, *FragmentShaderSource;
       int loadstatus = 0;
    // clear the redering window
       readShaderSource("tests.vert", &VertexShaderSource );
           readShaderSource("tests.frag", &FragmentShaderSource );
           loadstatus = installShaders(VertexShaderSource, FragmentShaderSource);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if (spinMode)
        {
        // calc animation parameters
        HourOfDay += AnimateIncrement;
        DayOfYear += HourOfDay/24;

        HourOfDay = HourOfDay%24;
        DayOfYear = DayOfYear%365;
        }

    // clear current matrix (Modelview)
    glLoadIdentity();
    // back off six units
    glTranslatef ( 0.0f, 0.0f, -5.0f );
    // rotate the plane of the elliptic
    // (rotate the model's plane about the
    // x axis by five degrees)
    glRotatef( 5.0f, 1.0f, 0.0f, 0.0f );

    // draw the sun
    glColor3f( 1.0, 1.0, 1.0 );
    glutWireSphere( 1.0,100,100 );

    readShaderSource("tests.vert", &VertexShaderSource );
               readShaderSource("tests1.frag", &FragmentShaderSource );
               loadstatus = installShaders(VertexShaderSource, FragmentShaderSource);
    // draw the Earth
    glRotatef( (GLfloat)(360.0*DayOfYear/365.0),
        0.0, 1.0, 0.0 );
    glTranslatef( 4.0, 0.0, 0.0 );
    glPushMatrix(); // save matrix state
    glRotatef( (GLfloat)(360.0*HourOfDay/24.0), 0.0, 1.0, 0.0 );
    glColor3f( 0.2, 0.2, 1.0 );
    glutWireSphere( 0.2,100,100 );
    glPopMatrix(); // restore matrix state

       glRotatef( (GLfloat)(360.0*12.5*DayOfYear/365.0),
        0.0, 1.0, 0.0 );
    glTranslatef( 0.5, 0.0, 0.0 );
    glColor3f( 0.3, 0.3, 0.3 );
    readShaderSource("tests.vert", &VertexShaderSource );
    readShaderSource("tests2.frag", &FragmentShaderSource );
    loadstatus = installShaders(VertexShaderSource, FragmentShaderSource);
    glutWireSphere( 0.05 ,100,100);

    // flush the pipeline, swap the buffers
    glFlush();
    glutSwapBuffers();

}
int init(void)
{

   const char *version;
   GLchar *VertexShaderSource, *FragmentShaderSource;
   int loadstatus = 0;

   version = (const char *) glGetString(GL_VERSION);
   if (version[0] != '2' || version[1] != '.') {
      printf("This program requires OpenGL 2.x, found %s\n", version);
      exit(1);
   }
   readShaderSource("tests.vert", &VertexShaderSource );
   readShaderSource("tests.frag", &FragmentShaderSource );
   loadstatus = installShaders(VertexShaderSource, FragmentShaderSource);

   return loadstatus;
}
// initialize OpenGL
void OpenGLInit(void)
{
    glShadeModel( GL_FLAT );
    glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
    glClearDepth( 1.0f );
    glDepthFunc( GL_LEQUAL );
    glEnable( GL_DEPTH_TEST );
}

// called when the window is resized
static void ResizeWindow(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    w = (w == 0) ? 1 : w;
    glViewport( 0, 0, w, h );
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    gluPerspective( 45.0, (GLfloat)w/(GLfloat)h, 1.0f, 20.0f );
    // select the Modelview matrix
    glMatrixMode( GL_MODELVIEW );
}

// main routine
// set up OpenGL, hook up callbacks
// and start the main loop
int main( int argc, char** argv )
{
    // we're going to animate it, so double buffer
    int success=0;
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB|GLUT_DEPTH );
    glutInitWindowPosition( 0, 0);
    glutInitWindowSize(620, 160 );
    glutCreateWindow( "Solar System Example" );

    // Initialize OpenGL as we like it..
    OpenGLInit();



    // set up callback functions
/*    auxKeyFunc( AUX_UP, Key_up ); // faster
    auxKeyFunc( AUX_DOWN, Key_down ); // slower
    auxKeyFunc( AUX_a, Key_a ); //animate*/
    glutReshapeFunc( ResizeWindow );
    glutSpecialFunc(special1);
    glutKeyboardFunc(mykeys);
    glEnable(GL_DEPTH_TEST);
    // call this when idle
    glutIdleFunc( Animate );
    glewInit();
    // call this in main loop
//    auxMainLoop( Animate );
    success = init();
       if ( success )
         glutMainLoop();
       return 0;
}

tests.frag(this is a file you need to create and place inside your project folder)
//tests.frag
//a minimal fragment shader

void main(void)
{
  gl_FragColor = vec4( 1, 1, 1, 1);    //yellow color
}

tests.vert(this is a file you need to create and place inside your project folder)
//tests.vert
//a minimal vertex shader
void main(void)
{
  gl_Position     = ftransform();
  /*
    Same as:
      gl_Position = gl_ProjectionMatrix *  gl_ModelViewMatrix * gl_Vertex;
    or
      gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
  */
}

Hope to share many more things. I solved these assignments using google only. I could not mention the site from where i took the code to solve this.

Monday, April 21, 2014

Wind Energy - An animation

I presume this is the landing page of my blog. I am showcasing a project on wind energy. After that i have given links to a large set of projects with comments on each project and how it would be useful to you.
Wind mills have blades which rotate clockwise or anti-clockwise based on mouse input(menus). If you choose no wind the rotors stop turning. Electricity generated lights up the villages and homes can be seen glowing.
Snaps:




Here is the source for this project.

I have made an attempt to encourage bright students of CS branch of VTU to venture into a project solo. If you have not yet enrolled for CS branch but would do so in future or not yet into sixth semester where you will need to demonstrate your skills, consider yourself lucky to have visited this blog. Here you can learn a lot and I hope you have a lot of time for that. Bookmark this blog and I promise you will not return empty handed.
To repeat what I mentioned elsewhere, these student projects run in eclipse under Ubuntu platform. I am not sure that they will run in windows(may be a little tweaking here and there is needed). The files have been made public, so anyone on the net can find them and download. It is heartening to see the number of page views of this blog increasing tremendously. It gives me a lot of satisfaction to impact so many budding developers. My goal is to inspire the student community to take interest in their subjects and inspire confidence, they too can do projects on their own. Take some interest in having a look at the code of all these projects. I call it a cursory code inspection. I know you cannot understand all that you read. I know its an awful experience similar to reading greek and latin. But it gives you experience of going through other people's code and appreciating the work of art. With practical experience and after considerable coding yourself you will outgrow this blog I am sure.
Once you click and open in a new tab the source link of each project, you can have a look at the code. Don't postpone code inspection. If you download and keep for future reference you will never have the time to read. I am observing several sites have sprung up with a lot of projects and some language and sentences of mine. I cannot object to that but they cannot take out my passion towards the subject nor my ability to write on it.

Only 1-3% of these projects are my own. Several of them students own creation and many downloaded from elsewhere on the internet. Look at all the posts with a view to create something of your own.

You can borrow pieces of code from a project and use it in your own. I call it code transplantation. Most of these projects are non-object oriented and don't support code reuse. You need to be a surgeon(much higher difficulty than reuse of OO code). You need to know where to paste a particular piece of code(copy), what to modify and what to delete(cut). Only if you attain proficiency in understanding the code would you be able to do these things. The flowing fountain and the particles project have objects moving in a parabolic path. Shadow fun has a light source in simple harmonic motion(It is a sine wave) and has code which draws shadows. Robot movement has code which can be used to walk a human model. Many of the projects have code to use the mouse like the trackball to rotate the scene. Water ripples has code which draws waves on a water surface. Ray tracing has code which maps a scene image onto the sphere as a texture. Multi mirror has code to get mirror images of scenes. I have come across texture mapping in several of the projects. Fractals has breathtaking views of higher dimensional objects such as the mandelbrot set.

There are several projects on cars. You have the tata sumo type of car. The formula one racer type of car. An ambassador type of car. Only a top view(2D) type of car. You can use code from such projects. Believe me you, will get real advantage of reusing this code. In Jumping Dino there is code to update the orientation of the car or any object. It is simple trigonometry. There is code to draw trees in many projects esp the one on sea view. A realistic tree can be drawn using fractal techniques. I have written this JOGL program to use L-System for drawing a tree. Hope to make several changes to make it look realistic. There is code to draw a bus in one of the projects. The project on pac man has interesting code to move the devil which attacks the pac-man or runs away from it. The tic tac toe game played against the computer has code to make a move(best possible). I wanted something similar for the chess game. If someone could work out the code for making a move in the chess game it would be really great. Even some code to solve a given Rubik cube could be a really great achievement. You could get ready made code for such tasks and probably integrate into your project to draw the display.

Many of the techniques that are implemented in these projects are not that easy to understand.
Yes, Just like how complex mathematics is difficult to understand even programs making use of such mathematics are difficult to understand. To try and explain the water waves project has taken me to mathematics of wave equations.

So starting from my next post I would hopefully delve into specific programming techniques and insights that are shared by professional animators. Someday I wish I would write a game engine. Learning DirectX... Maya... and many more things are in the pipeline(dreaming). Its been a long time since I updated this page. My new goals are to learn to make use of existing game engines and not to reinvent the wheel. Also top on the wish list is learning to use Unity to make games. I have now got fair bit of exposure to Blender 3D.

I often advise students not to waste time playing video games. I appeal to the sadist(sic) in everyone and say them to write games that other people would waste their time on, so that you can steal a march. After all what happens when you play a game is just change in contents of bits in the memory. Nothing productive would ever come out of playing a video game. Read my personal experience of playing video games in the post if you have time (Indian audience would appreciate this more):- One rupee taught me a very big lesson.