Professional Documents
Culture Documents
CGV Complete
CGV Complete
An Amusement Park
Submitted by
Karthik A (1BI10CS040)
Certificate
This is to certify that the Project work entitled “An Amusement Park” has been
successfully completed by the student Karthik A (1BI10CS040) of VI semester B.E. for the
partial fulfillment of the requirements for the Computer Graphics and Visualization in Computer
Science & Engineering of the VISVESVARAYA TECHNOLOGICAL UNIVERSITY during
the academic year 2012-2013.
Internal Guides:
1. Prof. Nagamani D. R, Dr. Nandagopalan S,
Assistant Professor Professor and Head,
2. Prof. Girija J, Department of CSE,
Associate Professor Bangalore Institute of Technology,
Department of CSE, K.R. Road, V.V. Puram,
Bangalore Institute of Technology, Bangalore - 560004
K.R. Road, V.V. Puram,
Bangalore – 560004
Examiners:
1.
2.
Chapter - 1
INTRODUCTION
Computer graphics is the creation and manipulation of picture with the aid of
computers. It is concerned with all aspects of producing pictures or images using a computer.
Computer graphics enables us to display the information in the form of graphical objects such
as pictures, charts, graphs and diagrams instead of simple text. The pictures or graphical objects
may vary from engineering drawings, business graphs and architectural structures to animated
movies. All the functionalities required for the development and presentation of such an
environment or interface to the user is provided by the graphics package.
1. Display of information
2. Design
4. User interface
Display of information:
Computer graphics has enabled architects, researchers and designers to pictorially
interpret the vast quantity of data. Cartographers have developed maps to display the celestial
and geographical information. Medical imaging technologies like Computerized Tomography
(CT), Magnetic Resonance Imaging (MRI), Ultrasound, Positron Emission Tomography (PET)
and many others make use of computer graphics.
Design:
Professions such as engineering and architecture are concerned with design. They start
with a set of specification; seek cost-effective solutions that satisfy the specification. Designing
is an iterative process. Designer generates a possible design, tests it and then uses the results
as the basis for exploring other solutions. The use of interactive graphical tools in Computer
Aided Design (CAD) pervades the fields including architecture, mechanical engineering, the
design of very-large-scale integrated (VLSI) circuits and creation of characters for animation.
User interfaces:
Computer graphics has led to the creation of graphical user interfaces (GUI) using which
even naive users are able to interact with a computer. Interaction with the computer has been
dominated by a visual paradigm that includes windows, icons, menus and a pointing device
such as mouse. Millions of people are internet users; they access the internet through the
graphical network browsers such as Microsoft internet explorer and Mozilla Firefox
1.2 OpenGL
OpenGL is a standard specification defining a cross-language API for writing applications that
produce 2D and 3D computer graphics. The interface consists of over 250 different function
calls which can be used to draw complex three-dimensional scenes from simple primitives.
OpenGL was developed by Silicon Graphics Inc. (SGI) in 1992 and is widely used in
CAD, virtual reality, scientific visualization, information visualization, and flight simulation.
It is also used in video games, where it competes with Direct3D on Microsoft Windows
platforms. OpenGL is managed by the non-profit technology consortium, the Khronos Group.
OpenGL's basic operation is to accept primitives such as points, lines and polygons,
and convert them into pixels. This is done by a graphics pipeline known as the OpenGL state
machine. Most OpenGL commands either issue primitives to the graphics pipeline, or
configure how the pipeline processes these primitives.
OpenGL is a low-level, procedural API, requiring the programmer to dictate the exact
steps required to render a scene. These contrasts with descriptive APIs, where a programmer
only needs to describe a scene and can let the library manage the details of rendering it.
OpenGL's low-level design requires programmers to have a good knowledge of the graphics
pipeline, but also gives a certain amount of freedom to implement novel rendering algorithms.
OpenGL has historically been influential on the development of 3D accelerators, promoting a
base level of functionality that is now common in consumer-level hardware.
GL library contains the main functions for windows implementation. GLU library uses only
GL functions, but contains code for creating common objects and simplifying viewing. GLUT
is the OpenGL Utility Toolkit, a window system independent toolkit for writing OpenGL
programs. It implements a simple windowing application programming interface (API) for
OpenGL. GLUT makes it considerably easier to learn about and explore OpenGL
Programming.
The OpenGL Extension to the X Window System (GLX) provides a means of creating
an OpenGL context and associating it with an X Window System window.
To be hardware independent, OpenGL provides its own data types. They all begin with
"GL". For example GLfloat, GLint and so on. All symbolic constants begin with "GL_", like
GL_POINTS, GL_POLYGON. The commands have the prefix "gl" like glBegin().
For temporary state changes, the user should use these commands rather than any of the
query commands, since they're likely to be more efficient.
OpenGL uses graphics pipeline architecture to convert high level specifications into low level
implementations. In graphics pipeline architecture, commands enter from the left and proceed
through what can be thought of as a graphics processing pipeline. Some commands specify
geometric objects to be drawn, and others control how the objects are handled during the
various processing stages. The graphics pipeline is built in stages. Every stage is specialized in
precisely one element of the rendering process. Once we are familiar with these tasks, we will
be able to recognize them in the designs of the GPU. Figure 1.2 gives an abstract, high-level
block diagram of how OpenGL processes data.
Display Lists:
All data, whether it describes geometry or pixels, can be saved in a display list for
current or later use. (The alternative to retaining data in a display list is processing the data
immediately - also known as immediate mode.) When a display list is executed, the retained
data is sent from the display list just as if it were sent by the application in immediate mode.
Evaluators:
The evaluator stage of processing provides an efficient means for approximating curve
and surface geometry by evaluating polynomial commands of input values. During the next
stage, per-vertex operations and primitive assembly, OpenGL processes geometric primitives
like points, line segments, and polygons, all of which are described by vertices. Vertices are
transformed and lit, and primitives are clipped to the viewport in preparation for the next stage
OpenGL performs to render an image on the screen.
Per-Vertex Operations:
For vertex data, next is the "per-vertex operations" stage, which converts the vertices
into primitives. Some vertex data are transformed by 4 x 4 floating-point matrices. Spatial
coordinates are projected from a position in the 3D world to a position on the screen. If
advanced features are enabled, this stage is even busier. If texturing is used, texture coordinates
may be generated and transformed here. If lighting is enabled, the lighting calculations are
performed using the transformed vertex, surface normal, light source position, material
properties, and other lighting information to produce a colour value.
Primitive Assembly:
Clipping, a major part of primitive assembly, is the elimination of portions of
geometry which fall outside a half-space, defined by a plane. Point clipping simply passes or
rejects vertices; line or polygon clipping can add additional vertices depending upon how the
line or polygon is clipped. Depending upon the polygon mode, a polygon may be drawn as
points or lines. The results of this stage are complete geometric primitives, which are the
transformed and clipped vertices with related colour, depth, and sometimes texture-coordinate
values and guidelines for the rasterization step.
Pixel Operations:
While geometric data takes one path through the OpenGL rendering pipeline, pixel data
takes a different route. Pixels from an array in system memory are first unpacked from one of
a variety of formats into the proper number of components. Next the data is scaled, biased, and
processed by a pixel map. The results are clamped and then either written into texture memory
or sent to the rasterization step. If pixel data is read from the frame buffer, pixel-transfer
operations are performed. Then these results are packed into an appropriate format and returned
to an array in system memory. There are special pixel copy operations to copy data in the frame
buffer to other parts of the frame buffer or to the texture memory. A single pass is made through
the pixel transfer operations before the data is written to the texture memory or back to the
frame buffer.
Texture Assembly:
An OpenGL application may wish to apply texture images onto geometric objects
to make them look more realistic. If several texture images are used, it's wise to put them into
texture objects so that it can be easily switched among them. Some OpenGL implementations
may have special resources to accelerate texture performance. There may be specialized, high-
performance texture memory. If this memory is available, the texture objects may be prioritized
to control the use of this limited and valuable resource.
Rasterization:
Rasterization is the conversion of both geometric and pixel data into fragments. Each
fragment square corresponds to a pixel in the frame buffer. Line and polygon stipples, line
width, point size, shading model, and coverage calculations to support antialiasing are taken
into consideration as vertices are connected into lines or the interior pixels are calculated for a
filled polygon. Colour and depth values are assigned for each fragment square.
Fragment Operations:
Before values are actually stored into the frame buffer, a series of operations are
performed that may alter or even throw out fragments. All these operations can be enabled or
disabled. The first operation which may be encountered is texturing, where a Texel is generated
from texture memory for each fragment and applied to the fragment. Then fog calculations may
be applied, followed by the scissor test, the alpha test, the stencil test, and the depth-buffer test.
Failing an enabled test may end the continued processing of a fragment's square. Then,
blending, dithering, logical operation, and masking by a bitmask may be performed. Finally,
the thoroughly processed fragment is drawn into the appropriate buffer.
To be used efficiently, all computer software needs certain hardware components or other
software components to be present on a computer. These prerequisites are known as software
requirements. Though our graphics software does not demand strict specifications, certain basic
hardware and software requirements must be met.
Table 2.1 specifies the minimum hardware requirements that must be met in order to run the
graphics software.
System Memory 1 GB
Graphics Memory 64 MB
Secondary Memory 20 GB
Since GLUT is a cross platform library, the graphics software can be run on any platform that
GLUT supports. In our implementation, we have used a windows distribution of GLUT and
hence we expect the target machine to have windows distribution of GLUT library installed.
Table 2.2 outlines the minimum software requirements.
DESIGN
3.1 Flowchart
A flowchart is a common type of chart that represents an algorithm or process showing the steps
as boxes of various kinds, and their order by connecting these with arrows. Flowcharts are used in
analyzing, designing, documenting or managing a process or program in various fields. Figure 3.1
shows the interactions between various components of the graphics software system as a flowchart.
Change colour
Main
Start/Stop movement
Flag set?
Navigation
Display
Yes
Change camera
Update Angle position
or Rotation and Draw Skybox
Roller Coaster
progress
Update state variables and
Draw Giant
movement flags
Wheel,
Columbus and
Roller Coaster
Quit
Stop
3.2 Algorithm
The design process of each component can be explained using algorithms. An algorithm is a step-
by-step finite list of well-defined instructions. Algorithms provide only high level descriptions,
but sometimes they can also provide implementation level details. The following sections describe
algorithms for each component created in this graphics software system.
Spin trolley
about its center
Figure 3.2: Second trolley formed by Figure 3.3: Second trolley made
rotating original trolley. upright by spinning about its center.
1. Initialize theta=0.
2. Scale the z axis about thrice its original scale and draw a sphere. Use a clipping plane to
cut it horizontally exactly about its center to form the Columbus ship body.
3. Stand of Columbus is visualized using cylinders.
4. Rotate the Columbus ship body about the center of the stand with an offset_angle where
the offset_angle is the product of a fixed offset and sine of the angle theta, where theta
varies from 0 to 360 degrees continuously.
5. Since sine of theta varies from +1 to -1, rotation angle of Columbus ship varies from
+offset_angle to -offset_angle. This gives a swinging effect to the Columbus ship body.
6. Increase the value of theta and go to step 2.
1. Create a cube. Use the six skybox images to texture map them on the six faces from the
inner side of the cube.
2. If the viewer moves horizontally or vertically in the scene, translate the center of the skybox
along with him so that he does not goes beyond the face of the skybox after moving
continuously.
3. If viewer rotates, rotate the skybox in opposite direction to give appropriate effect.
4. The ground is created using textured squares repeated like tiles of a floor.
Implementation is a stage where the planned activities are put into action. It is the realization
of a technical specification or an algorithm as a program or software component.
4.1 Modules
The module implementation of the graphics software system can be described in two stages:
glutInitWindowSize() Specifies the initial height and width of the window in pixels.
Sets the present RGBA clear colour used when clearing the
glClearColor()
colour buffer.
Sets the reshape callback for the current window. The reshape
callback is triggered when a window is reshaped. A reshape
glutReshapeFunc() callback is also triggered immediately before a window's first
display callback after a window is created or whenever an
overlay for the window is established.
4.2 Code
#include<stdlib.h>
#include<GL/glut.h>
#include<GL/gl.h>
#include<stdio.h>
#include<math.h>
#include<windows.h>
const int SKY_FRONT=0, SKY_RIGHT=1, SKY_LEFT=2, SKY_BACK=3, SKY_UP=4, SKY_DOWN=5,
COLUMBUS=1, COLUMBUS_STAND=2, GWHEEL_RING=3, GWHEEL_TROLLEY=4, GWHEEL_TOP=5,
ROLLER_BODY=6, ROLLER_FRAME=7;
void set_material(int m)
{ if(m==0)
{
float materialGrey[]={0.8,0.8,0.8},materialWhite[]={0.2,0.2,0.2};
glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,materialGrey);
glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,materialWhite);
}
if(m==COLUMBUS)
glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,
materialColours[columbus_color]);
glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,materialLightBr);
{
FILE *file;
unsigned char header[54],*data;
unsigned int dataPos,size,width, height;
file = fopen(fileName, "rb");
fread(header, 1, 54, file);
dataPos = *(int*)&(header[0x0A]);
size = *(int*)&(header[0x22]);
width = *(int*)&(header[0x12]);
height = *(int*)&(header[0x16]);
if (size == NULL)
size = width * height * 3;
if (dataPos == NULL)
dataPos = 54;
data = new unsigned char[size];
fread(data, 1, size, file);
fclose(file);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR_EXT,
GL_UNSIGNED_BYTE, data);
return texture;
}
void initSky()
{
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
skybox[SKY_DOWN] = LoadBMP("BMP11/down.bmp");
skybox[SKY_FRONT] = LoadBMP("BMP11/front.bmp");
skybox[SKY_BACK] = LoadBMP("BMP11/back.bmp");
skybox[SKY_RIGHT] = LoadBMP("BMP11/right.bmp");
skybox[SKY_LEFT] = LoadBMP("BMP11/left.bmp");
skybox[SKY_UP] = LoadBMP("BMP11/up.bmp");
grass=LoadBMP("BMP11/grass_1.bmp");
}
void initLights()
{
GLfloat whiteSpecularMaterial[] =
{1.0,1.0,1.0},light_post0[]={0.0,0.0,10.0,1.0},whiteSpecularLight[] = {1.0,
1.0, 1.0},blackAmbientLight[] = {0.3, 0.3, 0.3},whiteDiffuseLight[] = {1.0,
1.0, 1.0},mShininess[] = {50},twoModel[]={GL_TRUE};
glEnable (GL_DEPTH_TEST);
glEnable (GL_LIGHTING);
glEnable (GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_SPECULAR, whiteSpecularLight);
glLightfv(GL_LIGHT0, GL_AMBIENT, blackAmbientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, whiteDiffuseLight);
glLightfv(GL_LIGHT0, GL_POSITION, light_post0);
glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, twoModel);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, whiteSpecularMaterial);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mShininess);
}
void draw_ground()
{ glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,grass);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(5000,-10,5000);
glTexCoord2f(800.0f, 0.0f); glVertex3f(5000,-10,-5000);
glTexCoord2f(800.0f, 800.0f); glVertex3f(-5000,-10,-5000);
glTexCoord2f(0.0f, 800.0f); glVertex3f(-5000,-10,5000);
glEnd();
glDisable(GL_TEXTURE_2D);
glLineWidth(5.0);
glTranslatef(0.0, -2, 0.0);
draw_bezier();
glTranslatef(0.0, 2, 0.0);
}
void draw_gwheel()
{
int num=12;
GLUquadricObj *quadric=gluNewQuadric();
gluQuadricNormals(quadric, GLU_SMOOTH);
glPushMatrix();
initLightsforGW();
GLfloat twoModel[]={GL_FALSE};
glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, twoModel);
set_material(GWHEEL_RING);
glTranslatef(0.0,0.0, gw_width);
glRotatef(-gw_spin,0,0,1);
draw_cyl(0,0,0,0,-55,20,1.5,8);
glTranslatef(0.0,0.0, -gw_width*2);
draw_cyl(0,0,0,0,-55,-20,1.5,8);
glTranslatef(0.0,0.0, gw_width*2);
glRotatef(gw_spin,0,0,1);
glutSolidTorus(1.0, 35.0, 16, 64);
gluDisk(quadric,0.0, 10.0, 10.0, 1);
glTranslatef(0.0,0.0, -gw_width*2);
glutSolidTorus(1.0, 35.0, 16, 64);
gluDisk(quadric,0.0, 10.0, 10.0, 1);
glTranslatef(0.0,0.0, gw_width);
for(int i=0; i<num; i++)
{ glEnable(GL_LIGHTING);
glPushMatrix();
glRotatef(360*i/num, 0.0, 0.0, 1.0);
glEnable(GL_DEPTH_TEST);
glTranslatef(0.0,0.0, gw_width);
draw_cyl(0.0, 45.0, 0.0, 0.0, 45.0, -5.0, 1.0, 12);
draw_cyl(0.0, 45.0, 0.0, 0.0, 2.0, 0.0, 1.0, 12);
glTranslatef(0.0,0.0, -gw_width*2);
draw_cyl(0.0, 45.0, 0.0, 0.0, 2.0, 0.0, 1.0, 12);
draw_cyl(0.0, 45.0, 0.0, 0.0, 45.0, 5.0, 1.0, 12);
glTranslatef(0.0,0.0, gw_width);
glDisable(GL_LIGHTING);
glTranslatef(0.0, -45.0, 0.0);
glRotatef(-gw_spin-(360*i/num)-sin(gw_spin/10)*10, 0, 0, 1.0);
set_material(GWHEEL_TROLLEY);
draw_wagon();
set_material(GWHEEL_RING);
glTranslatef(0.0, 45.0, 0.0);
glPopMatrix();
}
set_material(0);
twoModel[0]=GL_TRUE;
glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, twoModel);
glPopMatrix();
glDisable(GL_LIGHT1);
}
void draw_columbus()
{
double eqn[]={0.0, -1.0, 0.0, 0.5};
glPushMatrix();
glEnable(GL_LIGHTING);
GLfloat twoModel[]={GL_FALSE};
glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, twoModel);
set_material(COLUMBUS_STAND);
draw_cyl(0.0, 105.0,30.0,0.0,105.0,-30.0 ,1.0,10);
draw_cyl(0.0, 105.0,30.0,30.0,-10.0,30.0 ,1.0,10);
draw_cyl(0.0, 105.0,30.0,-30.0,-10.0,30.0 ,1.0,10);
draw_cyl(0.0, 105.0,-30.0,30.0,-10.0,-30.0 ,1.0,10);
draw_cyl(0.0, 105.0,-30.0,-30.0,-10.0,-30.0 ,1.0,10);
glTranslatef(0.0, 105.0, 0.0);
glRotatef(cos(c_angle*3.14/180.0)*50.0, 0.0, 0.0, 1.0);
draw_cyl(0.0, -70.0,-15.0,0.0,-2.0,-1.0 ,0.3,10);
draw_cyl(0.0, -70.0,15.0,0.0,-2.0,1.0 ,0.3,10);
glutSolidTorus(1.0, 3.0, 5, 8);
twoModel[0]=GL_TRUE;
glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, twoModel);
glTranslatef(0.0, -70.0, 0.0);
glEnable(GL_DEPTH_TEST);
glClipPlane(GL_CLIP_PLANE0, eqn);
glEnable(GL_CLIP_PLANE0);
glScalef(3.0,1.0, 1.0);
set_material(COLUMBUS);
glutSolidSphere(15.0, 64.0, 64.0);
set_material(0);
glScalef( 1/3.0,1.0, 1.0);
glDisable(GL_CLIP_PLANE0);
glRotatef(-90.0, 1.0, 0.0, 0.0);
glScalef(3.0, 5.0, 3.0);
glTranslatef(11.5,0.0,0.0);
for(int c=0;c<6;c++)
{
glTranslatef(-3.2, 0.0, 0.0);
draw_seat();
}
glPopMatrix();
void draw_wagon()
{
GLdouble wagon_size=5.0;
double eqn[]={0.0, -1.0, 0.0, -3.5};
glPushMatrix();
glTranslatef(0.0, -5.0, 0.0);
glEnable(GL_CLIP_PLANE0);
glClipPlane(GL_CLIP_PLANE0, eqn);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glDisable(GL_CLIP_PLANE0);
for(int c=0;c<4;c++)
{
glRotatef((90/4.0), 0.0, 1.0, 0.0);
glNormal3f(1.0,0.0,0.0);
glutWireCube(wagon_size*2.0);
}
glPopMatrix();
}
void idle()
{
double bez_offset=0.000;
if(cswing)
{ c_angle++;
if(camw==2)
{ movcord[0]=-co_x-cos(c_angle*3.14/180.0)*50.0;
movcord[1]=-co_y-35-fabs(cos(c_angle*3.14/180.0))*35;
movcord[2]=co_z;
}
}
if(roll)
{ if(ni==bezno-2)
{ roll=0;
bez_prog=0.0;
ni=0.0;
viewer[0]=1.0;
viewer[1]=viewer[2]=camera[0]=camera[1]=camera[2]=x_r=0.0;
return;
}
if(bez_prog>=1.0)
{ ni++;
bez_prog=0.0;
}
bez_prog+=roller_speed;
moveToBezier(bez_prog+bez_offset);
}
if(gw)
{ gw_spin+=0.25;
if(camw==1)
{
movcord[0]=-gw_x+(gw_radius*sin(gw_spin*3.14/180))+ sin(gw_spin/10);
movcord[2]=gw_z;
movcord[1]=-gw_y-(gw_radius*cos(gw_spin*3.14/180.0))+6;
}
}
glutPostRedisplay();
}
void draw_seat()
{ glPushMatrix();
glEnable(GL_LIGHTING);
glTranslatef(1.0, 0.0, -1.0);
glRotatef(90.0, 0.0, 0.0, 1.0);
glTranslatef(0.0, 0.5, 0.0);
draw_cyl(-2.5,0.0,0.0,2.5,0.0,0.0,0.05,6);
glTranslatef(0.0,-0.5,0.0);
glNormal3f(0.0,1.0,0.0);
glScalef(4.0, 0.1, 1.0);
glutSolidCube(1.0);
glScalef(1/4.0, 1/0.1, 1.0);
glTranslatef(0.0, 0.5, -1.0);
glRotatef(80.0, 1.0, 0.0, 0.0);
glScalef(4.0, 0.1, 1.0);
glNormal3f(0.0,1.0,0.0);
glutSolidCube(1.0);
glScalef(1/4.0, 1/0.1, 1.0);
glPopMatrix();
}
void draw_wheels()
{
int i=0;
glPushMatrix();
glRotatef(90.0,1.0,0.0,0.0);
for(i=0;i<4;i++)
{ glutSolidTorus(0.2,0.3,4,16);
glTranslatef(0.0,2.0,0.0);
}
glPopMatrix();
void draw_loco()
{
int i;
double eqn[]={1.0, 0.0, 0.0, -0.5};
double eqnt[]={-1.0, 0.0, 0.0, 1.6};
glPushMatrix();
set_material(ROLLER_BODY);
glEnable (GL_LIGHTING);
glEnable(GL_CLIP_PLANE0);
glClipPlane(GL_CLIP_PLANE0, eqn);
glScalef(1.3, 2.0, 1.5);
glutSolidCube(3.0);
glScalef(1/1.3, 1/2.0, 1/1.5);
glDisable(GL_CLIP_PLANE0);
glRotatef(90.0, 1.0, 0.0, 0.0);
glEnable(GL_CLIP_PLANE1);
glClipPlane(GL_CLIP_PLANE1, eqnt);
glTranslatef(0.0, 0.0, 3.0);
glutSolidTorus(0.2, 3.0, 10, 10);
draw_seat();
glTranslatef(0.0, 0.0, -1.5);
glutSolidTorus(0.2, 3.0, 10, 10);
glTranslatef(0.0, 0.0, -1.5);
glutSolidTorus(0.2, 3.0, 10, 10);
draw_seat();
glTranslatef(0.0, 0.0, -1.5);
glutSolidTorus(0.2, 3.0, 10, 10);
glTranslatef(0.0, 0.0, -1.5);
glutSolidTorus(0.2, 3.0, 10, 10);
glDisable(GL_CLIP_PLANE1);
set_material(0);
glTranslatef(2.5,1.0,0);
draw_wheels();
glTranslatef(-2.5,-1.0,0);
glTranslatef(2.5,-1.0,0);
draw_wheels();
for(i=0;i<4;i++)
{
draw_cyl(0,2.1,0,0,-0.1,0,0.1,12);
glTranslatef(0.0,0.0,2.0);
}
glPopMatrix();
}
void display()
{ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor4f(1.0,1.0,1.0,1.0);
glLoadIdentity();
gluLookAt(viewer[0], viewer[1], viewer[2],camera[0], camera[1],
camera[2],0, 1, 0);
getCurveAt(&tx,&ty,&tz,ni,bez_prog+0.058);
getCurveAt(&nx,&ny,&nz,ni,bez_prog+0.070);
gy=ny;
float
bz1=bezier(bez[0+ni][2],bez[1+ni][2],bez[2+ni][2],bez[3+ni][2],bez_prog+0.02)-
1*fabs(cos(angle*3.14/180.0));
float
bx1=bezier(bez[0+ni][0],bez[1+ni][0],bez[2+ni][0],bez[3+ni][0],bez_prog+0.02)-
1*fabs(sin(angle*3.14/180.0));
float
bz2=bezier(bez[0+ni][2],bez[1+ni][2],bez[2+ni][2],bez[3+ni][2],bez_prog+0.02)+1*fa
bs(cos(angle*3.14/180.0));
float
bx2=bezier(bez[0+ni][0],bez[1+ni][0],bez[2+ni][0],bez[3+ni][0],bez_prog+0.02)+1*fa
bs(sin(angle*3.14/180.0));
double degreer = atan2(1,bx2-bx1)*fabs(sin(angle*3.14/180.0))* 180 /
3.14+fabs(cos(angle*3.14/180.0))*atan2(1,bz2-bz1)* 180 / 3.14;
double angler = degreer ;
double degree= atan2(nz-tz, nx-tx);
angle = degree * 180 / 3.14;
double degreey= atan2(ny-ty,1);
double angley = degreey * 180 / 3.14;
glPushMatrix();
glTranslatef(-nx,-ny,-nz);
glRotatef(-angle, 0.0, 1.0, 0.0);
glRotatef(angley-90, 0, 0, 1.0);
glRotatef(angler-45, 0.0, 1.0, 0.0);
if(camw==0) angle=90.0;
glTranslatef(-2.5, 3.0, 0.0);
draw_loco();
glPopMatrix();
glPushMatrix();
glTranslatef(co_x, co_y, -co_z);
draw_columbus();
glPopMatrix();
glPushMatrix();
glTranslatef(gw_x, gw_y, -gw_z);
glRotatef(gw_spin, 0.0, 0.0, 1.0);
draw_gwheel();
glPopMatrix();
glutSwapBuffers();
}
void displayReshape(int width,int height)
{
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(65,(GLfloat)width/(GLfloat)height,0.01f,1000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
double bezier(double x0, double x1, double x2, double x3, double t)
{
return 0.5f*((2.0f*x1)+(-x0+x2)*t+(2.0f*x0-5.0f*x1+4*x2-x3)*t*t+(-
x0+3.0f*x1-3.0f*x2+x3)*t*t*t);
}
void moveToBezier( double t)
{ int n=0.0;
viewer[0]=1.0;
viewer[1]= viewer[2]=0.0;
if(camw==3)
{ getCurveAt(&movcord[0],&movcord[1], &movcord[2], ni, t);
movcord[0]+=1.0;
movcord[1]-=3.5;
camera[0]=bezier(bez[0+ni][0],bez[1+ni][0],bez[2+ni][0],bez[3+ni][0],t+0.1)
-bezier(bez[0+ni][0],bez[1+ni][0],bez[2+ni][0],bez[3+ni][0],t);
camera[1]=bezier(bez[0+ni][1],bez[1+ni][1],bez[2+ni][1],bez[3+ni][1],t+0.1)-
bezier(bez[0+ni][1],bez[1+ni][1],bez[2+ni][1],bez[3+ni][1],t);
camera[2]=bezier(bez[0+ni][2],bez[1+ni][2],bez[2+ni][2],bez[3+ni][2],t+0.1)-
bezier(bez[0+ni][2],bez[1+ni][2],bez[2+ni][2],bez[3+ni][2],t);
if(gy<movcord[1]+2.5)
movcord[1]=gy-2.5;
glutPostRedisplay();
}
}
void renderCylinder(float x1, float y1, float z1, float x2,float y2, float z2,
float radius,int subdivisions,GLUquadricObj *quadric)
{ float vx = x2-x1,vy = y2-y1,vz = z2-z1;
if(vz == 0) vz = .0001;
float v = sqrt( vx*vx + vy*vy + vz*vz );
float ax = 57.2957795*acos( vz/v );
if ( vz < 0.0 )
ax = -ax;
float rx = -vy*vz;
float ry = vx*vz;
glPushMatrix();
glTranslatef( x1,y1,z1 );
glRotatef(ax, rx, ry, 0.0);
gluQuadricOrientation(quadric,GLU_OUTSIDE);
gluCylinder(quadric, radius, radius, v, subdivisions, 1);
gluQuadricOrientation(quadric,GLU_INSIDE);
gluDisk( quadric, 0.0, radius, subdivisions, 1);
glTranslatef( 0,0,v );
gluQuadricOrientation(quadric,GLU_OUTSIDE);
gluDisk( quadric, 0.0, radius, subdivisions, 1);
glPopMatrix();
}
void draw_cyl(float x1, float y1, float z1, float x2,float y2, float z2, float
radius,int subdivisions)
{
GLUquadricObj *quadric=gluNewQuadric();
gluQuadricNormals(quadric, GLU_SMOOTH);
renderCylinder(x1,y1,z1,x2,y2,z2,radius,subdivisions,quadric);
gluDeleteQuadric(quadric);
}
void draw_bezier()
{ GLfloat bx,by,bz,bx1,by1,bz1,bx2,by2,bz2,i=0.0;
int n=0;
glColor3f(1.0,1.0,0.0);
glDisable(GL_LIGHTING);
glPushMatrix();
for(n=0; n<bezno-2; n++)
{
for(i=0.0;i<=1.0;i+=0.015)
{
glBegin(GL_LINES);
bx1=bezier(bez[0+n][0],bez[1+n][0],bez[2+n][0],bez[3+n][0],i)-
1.3*fabs(sin(angle*3.14/180.0));
by1=bezier(bez[0+n][1],bez[1+n][1],bez[2+n][1],bez[3+n][1],i);
bz1=bezier(bez[0+n][2],bez[1+n][2],bez[2+n][2],bez[3+n][2],i)-
1.3*fabs(cos(angle*3.14/180.0));
glVertex3f(bx1,by1,bz1);
bx2=bezier(bez[0+n][0],bez[1+n][0],bez[2+n][0],bez[3+n][0],i)+1.3*fabs(sin(
angle*3.14/180.0));
by2=bezier(bez[0+n][1],bez[1+n][1],bez[2+n][1],bez[3+n][1],i);
bz2=bezier(bez[0+n][2],bez[1+n][2],bez[2+n][2],bez[3+n][2],i)+1.3*fabs(cos(
angle*3.14/180.0));
glVertex3f(bx2,by2,bz2);
glEnd();
}
glBegin(GL_LINE_STRIP);
for(i=0.0;i<=1.00;i+=0.02)
{
bz1=bezier(bez[0+n][2],bez[1+n][2],bez[2+n][2],bez[3+n][2],i+0.02)-
1.0*fabs(cos(angle*3.14/180.0));
bx1=bezier(bez[0+n][0],bez[1+n][0],bez[2+n][0],bez[3+n][0],i+0.02)-
1.0*fabs(sin(angle*3.14/180.0));
by1=bezier(bez[0+n][1],bez[1+n][1],bez[2+n][1],bez[3+n][1],i+0.02);
glVertex3f(bx1,by1,bz1);
}
glEnd();
glBegin(GL_LINE_STRIP);
for(i=0.0;i<=1.0;i+=0.02)
{
bz1=bezier(bez[0+n][2],bez[1+n][2],bez[2+n][2],bez[3+n][2],i+0.02)+1.0*fabs
(cos(angle*3.14/180.0));
bx1=bezier(bez[0+n][0],bez[1+n][0],bez[2+n][0],bez[3+n][0],i+0.02)+1.0*fabs
(sin(angle*3.14/180.0));
by1=bezier(bez[0+n][1],bez[1+n][1],bez[2+n][1],bez[3+n][1],i+0.02);
glVertex3f(bx1,by1,bz1);
}
glEnd();
glLineWidth(2.0);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
for(i=0.0;i<=1.0;i+=1.00)
{
bx=bezier(bez[0+n][0],bez[1+n][0],bez[2+n][0],bez[3+n][0],i);
by=bezier(bez[0+n][1],bez[1+n][1],bez[2+n][1],bez[3+n][1],i);
bz=bezier(bez[0+n][2],bez[1+n][2],bez[2+n][2],bez[3+n][2],i);
draw_cyl(bx,by-0.5,bz,bx,-10.0,bz,0.5,12);
}
glDisable(GL_LIGHTING);
glLineWidth(2.0);
}
glFlush();
glPopMatrix();
}
void windowSpecial(int key,int x,int y)
{
if(key==GLUT_KEY_UP)
{ movcord[0]+=5*cos(-2.0*x_r*3.14/180.0);
movcord[2]+=5*sin(2.0*x_r*3.14/180.0);
}
if(key== GLUT_KEY_DOWN)
{ movcord[0]-=5*cos(-2.0*x_r*3.14/180.0);
movcord[2]-=5*sin(2.0*x_r*3.14/180.0);
}
if(key==GLUT_KEY_RIGHT) x_r+=3;
if(key==GLUT_KEY_LEFT) x_r-=3;
display();
}
void kb(unsigned char key, int x, int y)
{ if(key=='+') movcord[1]--;
if(key=='-') movcord[1]++;
glutPostRedisplay();
}
void handleMouse(int x,int y)
{ if((x-prevx)>=0) x_r+=1;
else x_r-=1;
prevx=x;
}
viewer[1]=viewer[2]=camera[0]=camera[1]=camera[2]=x_r=0.0;
}
}
glutAddMenuEntry("Pale red",2);
glutAddMenuEntry("Brown",3);
glutAddMenuEntry("Grey",4);
submenu22 = glutCreateMenu(handle_gwheel_trolley);
glutAddMenuEntry("Blue",0);
glutAddMenuEntry("Yellow",1);
glutAddMenuEntry("Grey",2);
glutAddMenuEntry("Pale red",3);
glutAddMenuEntry("Brown",4);
submenu2 = glutCreateMenu(handle_gwheel);
glutAddMenuEntry("Stop/Start Giant Wheel",0);
glutAddSubMenu("Giant Wheel frame colour",submenu21);
glutAddSubMenu("Giant Wheel trolley colour",submenu22);
submenu31 = glutCreateMenu(handle_columbus_body);
glutAddMenuEntry("Light Brown",0);
glutAddMenuEntry("Black",1);
glutAddMenuEntry("Grey",2);
glutAddMenuEntry("Dark Brown",3);
glutAddMenuEntry("Purple",4);
submenu32 = glutCreateMenu(handle_columbus_stand);
glutAddMenuEntry("Light Grey",0);
glutAddMenuEntry("White",1);
glutAddMenuEntry("Dark Grey",2);
glutAddMenuEntry("Brown",3);
glutAddMenuEntry("Dark Blue",4);
submenu3 = glutCreateMenu(handle_columbus);
glutAddMenuEntry("Stop/Start Columbus ship",0);
glutAddSubMenu("Columbus body colour",submenu31);
glutAddSubMenu("Columbus stand colour",submenu32);
submenu41 = glutCreateMenu(handle_roller_color);
glutAddMenuEntry("Silver",0);
glutAddMenuEntry("Gold",1);
glutAddMenuEntry("Dark Grey",2);
glutAddMenuEntry("Brown",3);
glutAddMenuEntry("Purple",4);
submenu4 = glutCreateMenu(handle_roller);
glutAddMenuEntry("Stop/Start Roller Coaster",0);
glutAddSubMenu("Roller Coaster colour",submenu41);
glutCreateMenu(menu);
glutAddSubMenu("Camera Position",submenu1);
glutAddSubMenu("Giant Wheel",submenu2);
glutAddSubMenu("Columbus ship",submenu3);
glutAddSubMenu("Roller Coaster",submenu4);
glutAddMenuEntry("Change Background",0);
glutAddMenuEntry("Quit",1);
glutAttachMenu(GLUT_RIGHT_BUTTON);
}
int main(int argc, char** argv)
{
bezno=(sizeof(bez)/24)-2;
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
glutInitWindowSize(800,600);
glutCreateWindow("Amusement Park");
initLights();
initSky();
glutDisplayFunc(display);
glutReshapeFunc(displayReshape);
glutKeyboardFunc(kb);
glutMotionFunc(handleMouse);
glutPassiveMotionFunc(passiveMouse);
glutIdleFunc(idle);
glutSpecialFunc(windowSpecial);
addMenu();
glutMainLoop();
return 0;
}
Conclusion
An Amusement Park simulator is developed in OpenGL using the library functions defined in
it. The graphics software system not only draws objects like Giant Wheel, Columbus and Roller
Coaster, but also adds rotation and motion effects to them. The Entire scene is placed in a
SkyBox for a realistic sky effect. The system also features first person movement, where the
viewer can move around anywhere in the scene.
The curves of Roller Coaster track is drawn using Bezier functions. Lighting effect is
also employed for a better 3D appearance. The graphics software system is found to be
successful in displaying an Amusement Park.
Further enhancements
References:
[1] Edward Angel, “Interactive Computer Graphics A Top-Down Approach with
OpenGL”, 5th Edition, Pearson Education, 2004.
[2] F.S. Hill Junior, “Computer Graphics using OpenGL”, 2nd Edition, Pearson Education,
2001.
[3] http://www.opengl.org/resources/code/samples/redbook/
[4] http://stackoverflow.com/questions/4288367/how-to-rotate-and-then-move-on-that-
direction/
[5] http://stackoverflow.com/questions/6243693/move-object-along-a-bezier-path-in-3d-
rotation-problem
[6] http://nehe.gamedev.net/