Shreyas V Kashyap - Amusement Park
Shreyas V Kashyap - Amusement Park
Shreyas V Kashyap - Amusement Park
I take this opportunity to whole-heartedly express my gratitude to each and every one who
has guided and helped me to complete my project successfully and in time.
I would also like to express my heartfelt gratitude to Dr. Sahana D. Gowda, HOD, Computer
Science and Engineering whose guidance and support was truly invaluable.
I would also indebted to my Parents and Friends for their continued moral and material
support throughout the course of project and helping me in finalize the presentation.
My heartfelt thanks to all those have contributed bits, bytes and words to accomplish this
project.
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.
CONTENTS
INTRODUCTION
1.1 Overview
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 Sky-Box for a realistic sky effect. The system also features first person movement,
where the viewer can move around anywhere in the scene.
The project is mainly devised to display the scene of an Amusement Park. The project
problem was taken and was implemented to show 3D realistic view of the Amusement Park,
thereby giving first person view.
1.3 Objectives
The objective of the program is to show how the 3D modeling and SKY-BOX feature works
in OpenGL, and also the perspective viewing of the scene as a first person where a user can
view the scene as if he/she is roaming inside the Amusement Park.
1.4 Motivation
I got motivation through the concepts of lab programs. The subject "Computer graphics with
OpenGL" that is studied as a part of the course and the laboratory helped to know the power
of computer graphics in real life and motivated to implement the idea which we see in the
real life application. I was first amazed by how the perspective view works in OpenGL, I
was even fascinated by knowing the features like movements of 3D objects. And I always
wanted to create a scene of Disney World using all those modules. Hence, this led to
implementation of "Amusement Park" using OpenGL libraries as my project.
LITERATURE SURVEY
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.
Computer Graphics finds its applications in a variety of fields. The applications of computer
graphics can be divided into four major areas:
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
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().
OpenGL is a state machine. It can be put into various states (or modes) that then remain in
effect until it is changed. As it is already seen, the current color is a state variable. The user
can set the current color to white, red, or any other color, and thereafter every object is drawn
with that color until the current set color to something else. The current color is only one of
many state variables that OpenGL maintains. Others control such things as the current
viewing and projection transformations; line and polygon stipple patterns, polygon drawing
modes, pixel-packing conventions, positions and characteristics of lights, and material
properties of the objects being drawn. Many state variables refer to modes that are enabled or
disabled with the command glEnable () or glDisable (). Each state variable or mode has a
default value, and at any point the user can query the system for each variable's current value.
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:
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:
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 ant aliasing 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.
SYSTEM REQUIREMENTS
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 3.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 3.2 outlines the minimum software requirements.
SYSTEM DESIGN
4.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
4.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
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.
5.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.
5.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_DIFFU
SE, 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_Skybox(float x, float y, float z, float width, float height, float length){
glMatrixMode(GL_PROJECTION
); glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
x = x - width / 2; y =
y - height / 2; z = z -
length / 2;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,skybox[SKY_UP])
; glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(x+width, y+height, z);
glTexCoord2f(1.0f, 0.0f); glVertex3f(x+width, y+height, z+length);
glTexCoord2f(1.0f, 1.0f); glVertex3f(x, y+height, z+length);
glTexCoord2f(0.0f, 1.0f); glVertex3f(x, y+height, z);
glEnd();
glBindTexture(GL_TEXTURE_2D,skybox[SKY_FRONT]);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(x+width, y, z);
glTexCoord2f(1.0f, 0.0f); glVertex3f(x+width, y, z+length);
glTexCoord2f(1.0f, 1.0f); glVertex3f(x+width, y+height, z+length);
glTexCoord2f(0.0f, 1.0f); glVertex3f(x+width, y+height, z);
glEnd();
glBindTexture(GL_TEXTURE_2D,skybox[SKY_BACK]);
glBegin(GL_QUADS);
glTexCoord2f(1.0f, 1.0f); glVertex3f(x, y+height, z);
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_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)
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_BUTTO
N);
}
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;
}
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.
References:
[1] Edward Angel, Interactive Computer Graphics A Top-Down Approach with
OpenGL, 5th Edition, Pearson Education, 2004.
nd
[2] F.S. Hill Junior, Computer Graphics using OpenGL, 2 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/