EC5130 – Grafika Komputer dan
Pemrograman GPU
Suplemen Diktat Kuliah
OpenGL Tutorial dengan GLUT:
Fixed Pipeline
Ary Setijadi Prihatmanto
Sekolah Teknik Elektro & Informatika
Institut Teknologi Bandung
Table of Content
Table of Content ... 1
Tutorial 01. “Hello World” dengan GLUT ... 2
Tutorial 02. OpenGL Primitives ... 5
Tutorial 03. 3D Vertex ... 10
Tutorial 04. Callback Reshape ... 11
Tutorial 04. Modeling & Transformasi Proyeksi ... 13
Transformasi Proyeksi ... 15
Transformasi Viewing ... 17
Transformasi Modeling ... 17
Tutorial 05. Urutan Transformasi ... 20
Tutorial 06. Texture Mapping & Blending ... 23
Tutorial 07. Transparency ... 32
Tutorial 08. Fog ... 35
Tutorial 09. Obyek Kompleks ... 41
Tutorial 10. Particle System ... 62
Tutorial 11. Lighting ... 69
Tutorial 01. “Hello World” dengan GLUT
Tujuan dari bagian ini adalah untuk membuat OpenGL-based window. Ada banyak cara
untuk membuat dan memperlihatkan suatu window dalam berbagai sistem window. Salah
satunya adalah dengan menggunakan OpenGL Utility Toolkit. OpenGL UtilityToolkit
(GLUT) menyediakan banyak fungsi yang dapat membuat window dengan cara yang
independen terhadap sistem operasinya. Hal ini berarti program yang dibuat dengan
GLUT dapat beroperasi pada sistem windowing yang berbeda tanpa merubah code secara
manual.
GLUT adalah API (Application Programming Interface) dengan binding ANSI C untuk
penulisan Sistem Windows program OpenGL. GLUT adalah buatan Mark J. Killgard
ketika bekerja di Silicon Graphics Inc. Walaupun dirancang untuk digunakan
bersama-sama dengan kode OpenGL, GLUT dapat digunakan dengan atau tanpa OpenGL. Toolkit
ini mendukung fungsionalitas sebagai berikut:
• Multiplewindows untuk rendering OpenGL.
• Callback driven event processing.
• Sophisticated input devices.
• An “idle” routine and timers.
• A simple, cascading pop-up menu facility.
• Utility routines to generate various solid and wire frame objects.
• Support for bitmap and stroke fonts.
• Miscellaneous window management functions, including managing overlays.
Walaupun secara fungsional mungkin jauh tertinggal dari multiplatform window system
yang lain seperti Qt, namun kesederhanaan penggunaan serta hubungannya dengan API
grafika komputer OpenGL membuat glut masih banyak digunakan terutama sebagai alat
bantu pendidikan Grafika Komputer.
GLUT library dapat didownload dari
http://www.glut.org
. Setelah library GLUT diinstall,
GLUT dapat digunakan dengan mengacu ke header file glut.h. File tersebut selain
mendefinisikan beberapa hal-hal yang terkait dengan GLUT, mengacu pada opengl.h dan
glu.h juga memberikan arahan kepada compiler untuk me-link secara automatis dengan
library-library yang dibutuhkan contohnya opengl.lib(opengl32.lib), glu.lib(glu32.lib)
dan glut.lib(glut32.lib). Selain itu, untuk aplikasi di atas sistem operasi windows
memerlukan glut32.dll dapat terlihat oleh aplikasi.
Struktur dari aplikasi berbasis GLUT akan terdiri atas beberapa langkah berikut, yaitu:
• Menetapkan konfigurasi windows, dan membuka windows
• Inisialisasi status OpenGL
• Registrasi callback functions (jika dibutuhkan)
o Render
o Resize
o Input
o Timer
o Idle
• Enter event processing loop. Gambar 1 mengilustrasikan loop tersebut.
Gambar 1. GLUT Event Processing Loop yang disederhanakan
Fraksi kode berikut adalah contoh bagian main() dari suatu program GLUT:
void main( int argc, char** argv )
{
// Konfigurasi dan Menampilkan Window
int mode = GLUT_RGB|GLUT_DOUBLE;
glutInitDisplayMode( mode );
glutCreateWindow( argv[0] );
// Fungsi untuk melakukan initialisasi
init();
// Registrasi Callback Function
glutDisplayFunc( display );
glutReshapeFunc( resize );
glutKeyboardFunc( key );
glutIdleFunc( idle );
// Event Processing Loop
glutMainLoop();
}
Pada kode diatas, status OpenGL diinisialisasi di fungsi init(), sedangkan kode-kode
yang mengandung fungsi-fungsi rendering OpenGL biasanya merupakan bagian dari
fungsi callback display.
Program 01. GLUT “Hello World” & Gambar Segiempat
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <GL/glut.h> void mydisplay(){
glClear(GL_COLOR_BUFFER_BIT); // Menghapus layar glBegin(GL_POLYGON); glVertex2f(-0.5, -0.5); glVertex2f(-0.5, 0.5); glVertex2f(0.5, 0.5); glVertex2f(0.5, -0.5); glEnd(); glFlush(); }
int main(int argc, char** argv) {
printf(“Hello World… this is 2D Rectangle”); glutCreateWindow("simple");
glutDisplayFunc(mydisplay); glutMainLoop();
}
mydisplay() diregistrasi oleh glutDisplayFunc() sebagai fungsi yang dilaksanakan saat
window digambar, yang biasanya adalah isi dari gambarnya.. Hasilnya akan tampak
seperti gambar berikut:
Coba periksa dimensi window seperti koordinat titik tengah, titik kiri atas, titik kiri
bawah, titik kanan atas dan titik kanan bawah dengan merubah-rubah parameter fungsi
glVertex2f().
Diperoleh Koordinat:
- Titik Tengah ( ___, ___)
- Titik Kiri Atas ( ___, ___), Titik Kiri Bawah ( ___, ___)
- Titik Kanan Atas ( ___, ___), Titik Kanan Bawah ( ___, ___)
Tutorial 02. OpenGL Primitives
Pada tutorial 01 telah diberikan contoh program untuk merepresentasikan model obyek
segiempat 2D. OpenGL memiliki beberapa komponen dasar untuk merepresentasikan
suatu obyek. Komponen dasar tersebut disebut OpenGL Geometric primitives. Gambar
2 menggambarkan semua OpenGL Geometric primitives yang mungkin.
Gambar 2. OpenGL Geometric Primitives
Setiap obyek harus dimodelkan sebagai kombinasi dari komponen-komponen dasar
tersebut. Sebagai contoh, obyek segiempat pada tutorial 01 tersebut dimodelkan dengan
menggunakan komponen dasar GL_POLYGON. Obyek tersebut dapat pula dimodelkan
dengan komponen dasar GL_TRIANGLES atau pun GL_QUAD.
Hingga saat ini kita belum menerangkan secara detil masing-masing fungsi OpenGL.
Secara umum perintah-perintah dalam OpenGL memenuhi aturan sebagai berikut:
G
GL
L_
_Q
QU
UA
AD
D_
_S
ST
TR
RI
IP
P
G
GL
L_
_P
PO
OL
LY
YG
GO
ON
N
G
GL
L_
_T
TR
RI
IA
AN
NG
GL
LE
E_
_S
ST
TR
RI
IP
P
G
GL
L_
_T
TR
RI
IA
AN
NG
GL
LE
E_
_F
FA
AN
N
G
GL
L_
_P
PO
OI
IN
NT
TS
S
G
GL
L_
_L
LI
IN
NE
ES
S
G
GL
L_
_L
LI
IN
NE
E_
_L
LO
OO
OP
P
G
GL
L_
_L
LI
IN
NE
E_
_S
ST
TR
RI
IP
P
G
GL
L_
_T
TR
RI
IA
AN
NG
GL
LE
ES
S
G
GL
L_
_Q
QU
UA
AD
DS
S
Dalam OpenGL, menggambar geometric primitives selalu dilakukan di antara fungsi
glBegin(PRIMITIVES)
//
Fungsi
Menggambar Primitives di sini
glEnd()
Setiap OpenGL geometric primitive dispesifikasi oleh urutan vertex-vertex-nya dalam
bentuk urutan koordinat homogenous. Koordinat homogenous adalah koordinat dalam
bentuk ( x, y, z, w ). Setiap primitive memiliki standar tentang bagaimana vertex-vertex
diorganisasikan. Program 02 dan Program 03 memberikan contoh bagaimana
memodelkan primitive segitiga dan segidelapan.
Program 02. Segitiga
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <GL/glut.h> void mydisplay(){ glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_TRIANGLES); glVertex2f(-0.5, -0.5); glVertex2f(-0.5, 0.5); glVertex2f(0.5, 0.5); glEnd(); glFlush(); }int main(int argc, char** argv){
glutCreateWindow("simple"); glutDisplayFunc(mydisplay); glutMainLoop();
g
g
l
l
V
V
e
e
r
r
t
t
e
e
x
x
3
3
f
f
v
v
(
(
v
v
)
)
N Nuummbbeerr ooff c coommppoonneennttss 2 2 -- ((xx,,yy)) 3 3 -- ((xx,,yy,,zz)) 4 4 -- ((xx,,yy,,zz,,ww)) D Daattaa TTyyppee b b -- bbyyttee u ubb -- uunnssiiggnneedd bbyyttee s s -- sshhoorrtt u uss -- uunnssiiggnneedd sshhoorrtt i i -- iinntt u uii -- uunnssiiggnneedd iinntt f f -- ffllooaatt d d -- ddoouubbllee V Veeccttoorro
om
mi
it
t
“
“v
v”
”
f
fo
or
r
s
sc
ca
al
la
ar
r
f
fo
or
rm
m
g
gl
lV
Ve
er
rt
te
ex
x2
2f
f(
(
x
x,
,
y
y
)
)
}
Program 03. Polygon Segi Delapan
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <GL/glut.h> void mydisplay(){ glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_POLYGON); glColor3f(0, 1, 0); glVertex2f(-0.5, -0.5); glVertex2f(-0.75, 0); glVertex2f(-0.5, 0.5); glVertex2f(0, 0.75); glVertex2f(0.5, 0.5); glVertex2f(0.75, 0); glVertex2f(0.5, -0.5); glVertex2f(0,-0.75); glEnd(); glFlush(); }
int main(int argc, char** argv){
glutCreateWindow("simple"); glutDisplayFunc(mydisplay); glutMainLoop();
}
Perhatikan urutan dari vertex untuk setiap jenis OpenGL Geometric Primitive.
Tugas: Buat Program untuk menggambar jenis OpenGL Geometric Primitive yang
lain.
Bonus:
glColor3f()adalah fungsi untuk menentukan warna yang berlaku hingga fungsi
berikutnya. Program 03 berikut adalah program yang sama dengan Program 02 hanya di
sini setiap vertex diberi warna yang berbeda.
Program 04. Polygon Segi Delapan dengan warna
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <GL/glut.h> void mydisplay(){ glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_POLYGON); glColor3f(0, 1, 0); glVertex2f(-0.5, -0.5); glColor3f(0, 0, 1); glVertex2f(-0.75, 0); glColor3f(1, 0, 0); glVertex2f(-0.5, 0.5); glColor3f(0, 1, 0); glVertex2f(0, 0.75); glColor3f(0, 0, 1); glVertex2f(0.5, 0.5); glColor3f(1, 0, 0); glVertex2f(0.75, 0); glColor3f(0, 1, 0); glVertex2f(0.5, -0.5); glColor3f(0, 0, 1); glVertex2f(0,-0.75); glEnd(); glFlush(); }int main(int argc, char** argv){
glutCreateWindow("simple"); glutDisplayFunc(mydisplay); glutMainLoop();
}
Tutorial 03. 3D Vertex
Semua vertex dari obyek yang dimodelkan di atas masih berada pada satu bidang z=0,
atau obyek yang dimodelkan masih berupa model 2D karena kita hanya memberikan
vertex properti koordinat x dan y dengan menggunakan fungsi glVertex2f().
Untuk memodelkan obyek dalam 3D kita perlu memberi properti koordinat z dengan
menggunakan fungsi glVertex3f(). Program 05 memberikan ilustrasi penggunaan fungsi
tersebut.
Program 05. 3 Dimensional Vertex
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <GL/glut.h> void mydisplay(){ glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_POLYGON); glColor3f(0, 1, 0); glVertex3f(-0.5, -0.5, 1); glColor3f(0, 0, 1); glVertex3f(-0.75, 0, 1); glColor3f(1, 0, 0); glVertex3f(-0.5, 0.5, 1); glColor3f(0, 1, 0); glVertex3f(0, 0.75, 1); glColor3f(0, 0, 1); glVertex3f(0.5, 0.5, -1); glColor3f(1, 0, 0); glVertex3f(0.75, 0, -1); glColor3f(0, 1, 0); glVertex3f(0.5, -0.5, -1); glColor3f(0, 0, 1); glVertex3f(0,-0.75, -1); glEnd(); glFlush(); }
int main(int argc, char** argv){
glutCreateWindow("simple"); glutDisplayFunc(mydisplay); glutMainLoop();
Tutorial 04. Callback Reshape
Ambil Program 01 yang menggambar bujur sangkat sebagai dasar. Jika kita drag ujung
windows sehingga window tidak lagi berupa bujursangkar, bujursangkar-nya juga
berubah bentuk. Gambar berikut mengilustrasikan situasinya.
Agar gambar tetap berada pada proporsi yang tepat, maka perlu digunakan callback
reshape yang dipanggil setiap kali window berubah ukuran. Untuk itu perlu lakukan dua
langkah berikut:
- membuat fungsi yang akan dipanggil saat rehape, di sini fungsinya adalah
void reshape(int width, int height)
- melakukan registrasi callback reshape dengan fungsi glutReshapeFunc(.)
Program 06. ReShape Callback Function
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <GL/glut.h> void mydisplay(){
glClear(GL_COLOR_BUFFER_BIT); // Menghapus layar glBegin(GL_POLYGON); glVertex2f(-0.5, -0.5); glVertex2f(-0.5, 0.5); glVertex2f(0.5, 0.5); glVertex2f(0.5, -0.5); glEnd(); glFlush(); }
void resize( int w, int h ) {
if (w >= h)
glViewport(0, 0, (GLsizei)h, (GLsizei)h) ; else
glViewport(0, 0, (GLsizei)w, (GLsizei)w) ; }
int main(int argc, char** argv) {
glutCreateWindow("simple"); glutDisplayFunc(mydisplay); glutReshapeFunc(reshape);
glutMainLoop(); }
Hasilnya diilustrasikan pada gambar berikut:
glViewport(x_left, x_top, x_right, y_right) bertanggung jawab untuk melakukan
setting viewport dari suatu window, yaitu bagian dari window yang digunakan untuk
menggambar.
Selain setting glViewport() biasanya Reshape callback function juga digunakan untuk
mengatur Transformasi Proyeksi. Tutorial berikut akan memberi gambaran
Tutorial 04. Modeling & Transformasi Proyeksi
Secara substansi, Grafika Komputer adalah proses transformasi dari model 3D obyek
berupa informasi geometri bentuk, informasi pose, warna, texture, dan pencahayaan
menjadi citra 2D (cf. Gambar 3).
Gambar 3. Grafika Komputer: Transformasi dari Model 3D Obyek menjadi Citra
Jika dilihat secara analogi, hal di atas mirip dengan cara kerja kamera dalam mengambil
foto dalam bidang fotografi (cf. Gambar 4). Model ini disebut model sintesis kamera.
Gambar 4. Analogi Pengambilan Gambar oleh Kamera
Model 3D Obyek
-
Bentuk
-
Pose (Posisi & Orientasi)
-
Warna
-
Texture
-
Pencahayaan
Citra 2D Obyek
T
camera
tripod
model
viewing
volume
Untuk menghasilkan gambar dari obyek dengan skenario tertentu kita harus melakukan
beberapa proses, yaitu:
- melakukan pengesetan kamera dalam bentuk setting lensa kamera
(Transformasi Proyeksi),
- mengarah kamera dengan mengatur letak tripod (Transformasi Viewing),
- mengatur letak obyek (Transformasi Modeling), dan
- mengatur skala dan layout dari foto (Transformasi Viewport)
Kita telah mempelajari Transformasi Viewport pada tutorial sebelumnya dengan
menggunakan perintah glViewport(). Pada tutorial ini, kita akan mempelajari
transformasi-transformasi lainnya.
Transformasi Proyeksi
Lensa kamera dan mata manusia memiliki daerah penglihatan (viewing volume) yang
berbentuk kerucut, namun karena bentuk display yang biasanya berbentuk segiempat
membuat OpenGL (dan hampir semua API grafika komputer lain) lebih efisien
memodelkan daerah penglihatan sebagai volume berbentuk piramida.
Tipe transformasi proyeksi ada dua macam, bergantung pada parameter dan bentuk
piramidanya. Dua tipe transformasi tersebut adalah Transformasi Ortogonal/Paralel
(Orthogonal Transformation) dan Transformasi Perspektif(Perspective Transformation)
(cf. Gambar 5).
Gambar 5. Transformasi Ortogonal dan Transformasi Proyektif.
Transformasi Ortogonal/Paralel
Transformasi Perspektif
Pada tutorial sebelumnya digunakan transformasi orthogonal dengan parameter default.
Transformasi ini membuat jarak benda relatif terhadap kamera tidak berpengaruh pada
citra benda tersebut. Biasanya transformasi ini digunakan pada aplikasi-aplikasi teknik
seperti gambar teknik (cf. Gambar 6). Untuk merubah parameter transformasi ortogonal
dapat menggunakan perintah glOrtho() dengan didahului proses merubah status OpenGL
ke mode proyeksi dengan perintah glMatrixMode(GL_PROJECTION).
Gambar 6. Contoh Transformasi Ortogonal/Paralel
Pada tutorial ini dan selanjutnya, kita akan memfokuskan diri pada transformasi yang
banyak digunakan yaitu transformasi perspektif. Pada transformasi jenis ini jarak benda
akan mempengaruhi gambar yang di buat. Parameter transformasi jenis ini dapat dirubah
dengan menggunakan gluPerspective()/glFrustum() , juga dengan didahului proses
merubah status OpenGL ke mode proyeksi dengan perintah
glMatrixMode(GL_PROJECTION).
glMatrixMode(GL_PROJECTION);
glLoadIdentity( );
gluPerspective(fovy, aspect, near, far);
A
Section AA
Front elevation view
fovy adalah sudut antara bidang bottom dan up.
Transformasi Viewing
Untuk menghasilkan gambar, kamera perlu diletakkan pada posisi yang tepat didepan
pemandangan yang diinginkan. Secara default, dalam OpenGL kemera akan berada pada
posisi (0,0,0) dengan menghadap ke arah z = -1 dengan sumbu y mengarah ke atas
kamera. Hal ini dapat dilakukan dengan menggunakan perintah gluLookAt() dengan
didahului proses merubah status OpenGL ke mode proyeksi dengan perintah
glMatrixMode(GL_MODELVIEW).
Transformasi Modeling
Selain posisi dan orientasi kamera yang dapat dirubah-rubah, secara natural obyek juga
dapat berpindah posisi dan orientasi relatif terhadap yang lain.Transformasi obyek dapat
direpresentasikan dengan dua cara, yaitu:
- menggunakan matriks transformasi (glLoadMatrix)
- menggunakan operasi transformasi (glRotate, glTranslate)
dengan didahului proses merubah status OpenGL ke mode proyeksi dengan perintah
glMatrixMode(GL_MODELVIEW).
Program dibawah memberi ilustrasi tentang bagaimana transformasi di atas
diimplementasikan. Sebagai tambahan juga diberikan tentang callback keyboard untuk
menangani input keyboard. Obyek ditranslasikan pada sumbu z dengan menggunakan
tombol keyboard “,” dan “.”.Callback timer digunakan untuk timer yang di sini
digunakan untuk animasi berputar.
Program 07. Proyeksi Perspektif
// - Viewing Volume of Perspective Projection // - Try the keyboard callback
// - Reshape callback // - Timer
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <GL/glut.h> float z_pos=0.0f; float rot=0.0f; void mydisplay(){ glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0,0.0f,z_pos); glRotatef(rot, 0, 0, 1); glBegin(GL_POLYGON); glColor3f(0, 1, 0); glVertex3f(-0.5, -0.5, -5); glColor3f(0, 0, 1); glVertex3f(-0.75, 0, -5); glColor3f(1, 0, 0); glVertex3f(-0.5, 0.5, -5); glColor3f(0, 1, 0); glVertex3f(0, 0.75, -5); glColor3f(0, 0, 1); glVertex3f(0.5, 0.5, -5); glColor3f(1, 0, 0); glVertex3f(0.75, 0, -5); glColor3f(0, 1, 0); glVertex3f(0.5, -0.5, -5); glColor3f(0, 0, 1); glVertex3f(0,-0.75, -5); glEnd(); glFlush(); glutSwapBuffers(); }
void init( void ) {
glClearColor( 1.0, 0.0, 0.0, 1.0 ); // A Background Clear Color
glMatrixMode(GL_PROJECTION); glLoadIdentity();
gluPerspective(45, (GLdouble)500.0/(GLdouble)500.0, 0, 100); glMatrixMode(GL_MODELVIEW);
}
void resize( int w, int h ) {
glViewport( 0, 0, (GLsizei) w, (GLsizei) h ); glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective(45, (GLdouble)w/(GLdouble)h, 0, 100); glMatrixMode( GL_MODELVIEW );
}
{
// called if timer event
// ...advance the state of animation incrementally...
rot+=10;
glutPostRedisplay(); // request redisplay
glutTimerFunc(100, myTimeOut, 0); // request next timer event
}
void myKeyboard(unsigned char key,int x, int y) {
if((key=='<')||(key==',')) z_pos-=0.1f;
if((key=='>')||(key=='.')) z_pos+=0.1f; }
int main(int argc, char** argv) { glutInit(&argc,argv); //glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("simple"); // callbacks glutDisplayFunc(mydisplay); glutKeyboardFunc(myKeyboard); glutTimerFunc(100, myTimeOut, 0); glutReshapeFunc(resize); init(); glutMainLoop(); }
Tambahan:
Konsep Double Buffer. Pada program di atas mode display menggunakan tipe
GLUT_DOUBLE yang diikuti oleh glutSwapBuffers(). Hal ini merupakan teknik yang
disebut Double Buffer untuk menghindari flicker. Untuk mengetahui apa itu flicker,
ubah mode display menjadi GLUT_SINGLE dan hapus/commented perintah
Tutorial 05. Urutan Transformasi
Transformasi dapat dilakukan pada level vertex, level surface, maupun level obyek
bergantung dimana transformasi diletakkan dalam program. Operasi transformasi
merupakan operasi yang tidak bersifat komutatif, artinya, urutan transformasi juga
sangat berpengaruh pada hasilnya. Gambar 7 memberi ilustrasi akibat urutan transformasi
yang berbeda, yaitu hasil operasi “rotasi kemudian di translasi” berbeda dengan operasi
“translasi baru dirotasi”.
Gambar 7. Pengaruh urutan transformasi
Program 08 di bawah ini mirip dengan Program 07, hanya sekarang obyeknya sudah
berupa obyek 3D berupa kubus. Perhatikan bagaimana kubus dibentuk dari vertex dan
surface. Selain dengan mendefinisikan obyeknya sendiri, GLUT telah menyediakan
beberapa fungsi untuk menggambar standard obyek, yaitu kubus, bola, dan poci teh.
Perhatikan apa yang terjadi bila glTranslate() dan glRotate() di fungsi mydisplay()
ditukar posisinya atau diletakkan didalam salah satu glBegin()..glEnd()
// OpenGL
// - Complex Object // - Notice:
// 1. There are surfaces that are not correctly rendered in order. // uncommented the GL_DEPTH
// 2. Flicker can be eliminated by using GL_DOUBLE //
// Rubah rendering algoritma dengan menggunakan data struktur // #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <GL/glut.h> float z_pos=-10.0f; float rot=0.0f;
void resize(int width, int height) {
glMatrixMode(GL_PROJECTION); glLoadIdentity();
gluPerspective(45.0, (float)width/(float)height, 1.0, 300.0); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); }
void myTimeOut(int id) {
// called if timer event
// ...advance the state of animation incrementally...
rot+=10;
glutPostRedisplay(); // request redisplay
glutTimerFunc(100, myTimeOut, 0); // request next timer event
}
void myKeyboard(unsigned char key,int x, int y) {
if((key=='<')||(key==',')) z_pos-=0.1f;
if((key=='>')||(key=='.')) z_pos+=0.1f; }
void mydisplay(void) { glClear(GL_COLOR_BUFFER_BIT ); //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0,0.0f,z_pos); glRotatef(rot, 0, 1, 0); glBegin(GL_QUADS);
// Front Face, red
glColor3f(1.0,0.0,0.0); glVertex3f(-1.0f, -1.0f, 1.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
// Back Face, green
glColor3f(0.0,1.0,0.0); glVertex3f( 1.0f, -1.0f, -1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
// Top Face, blue
glColor3f(0.0,0.0,1.0); glVertex3f(-1.0f, 1.0f, -1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
// Bottom Face, yellow
glColor3f(1.0,1.0,0.0); glVertex3f(-1.0f, -1.0f, -1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
// Right face, cyan
glColor3f(0.0,1.0,1.0); glVertex3f( 1.0f, -1.0f, -1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
// Left Face, magenta glColor3f(1.0,0.0,1.0); glVertex3f(-1.0f, -1.0f, -1.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glEnd(); glFlush(); glutSwapBuffers(); } void init() { glEnable(GL_DEPTH_TEST);
glClearColor( 0.0, 0.0, 0.0, 1.0 ); // A Background Clear Color
glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45, (GLdouble)500.0/(GLdouble)500.0, 0, 100); glMatrixMode(GL_MODELVIEW); return; }
int main(int argc, char** argv) {
glutInit(&argc,argv);
//glutInitDisplayMode( GLUT_DOUBLE /*| GLUT_DEPTH*/ );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH ); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("simple"); // callbacks glutDisplayFunc(mydisplay); glutKeyboardFunc(myKeyboard); glutTimerFunc(100, myTimeOut, 0); glutReshapeFunc(resize); init(); glutMainLoop(); return 0; }
Tambahan:
Konsep Depth Buffer. Mode display pada program di atas diberi tambahan mode
GLUT_DEPTH dan perintah glEnable(GL_DEPTH_TEST). Hal ini untuk memastikan
bahwa surface digambar sesuai dengan urutan penampakkan yang logis. Teknik ini
merupakan salah satu algoritma HIDDEN SURFACE REMOVAL. Untuk melihat apa
yang terjadi bila teknik ini tidak dilakukan, hapus/commented moda GLUT_DEPTH dan
glEnable(GL_DEPTH_TEST).
Tutorial 06. Texture Mapping & Blending
Hingga tahap ini, geometric primitive digambar dengan warna solid atau warna hasil
interpolasi warna-warna vertex-nya. Texture mapping memungkinkan untuk menaruh
gambar pada geometric primitive tersebut dan sekaligus mengikuti transformasi yang
diterapkan kepada polygon tersebut (cf. Gambar 8).
Gambar 8. Konsep Texture Mapping
Texture merupakan data segi-empat sederhana yang berada pada bidang texture. Bidang
texture diwakili oleh dua sumbu koordinat yaitu sumbu s dan sumbu t. Setiap texture
akan memenuhi bidang koordinat (0.0,0.0) sd. (1.0,1.0). Nilai individual dari array
texture biasanya dikenal dengan istilah texels (texture pixels).
Yang membuat texture mapping sedikit rumit adalah bagaimana proses pemetaan antara
bentuk segi-empat texture ke polygon menginngat secara umum bentuk poligon biasanya
non-rectangular.
Beberapa contoh penggunaan texture mapping antara lain:
• mensimulasikan aspek visual dari material seperti tampakan kayu, batu bata, atau
granit
• mengurangi kompleksitas (jumlah polygon yang dibutuhkan) dari suatu obyek
geometri.
• teknik pemrosesan citra seperti image warping dan rectification, rotation dan
scaling
s
t
x
y
z
image
geometry
screen
(0.0,1.0)
(1.0,0.0)
(0.0,0.0)
• mensimulasikan berbagai efek permukaan seperti efek reflektif seperti cermin
atau lantai yang telah digosok mengkilat, efek tonjolan dll.
Salah satu keuntungan dari texture mapping adalah bahwa detail visual itu berada di citra
bukan di geometri. Dan sekompleks apapun citra, selama tidak merubah ukuran citra,
tidak berpengaruh pada kinerja keseluruhan, yaitu kompleksitas cari citra tidak
berpengaruh kepada pipeline geometric (transformasi, clipping) dari OpenGL.
Texture ditambahkan saat rasterisasi ketika geometric pipeline dan pixel pipeline bertemu
seperti diilustrasikan pada Gambar berikut.
Secara konseptual ada tiga langkah dalam melakukan texture mapping, yaitu:
- Penentuan texture
o Baca image dari file
o Generate texture id untuk image tersebut glGenTextures(3, &texture[0])
- Pemberian koordinat texture ke vertex
- Penentuan parameter texture (wrapping / filtering)
Program 09 memberi ilustrasi tentang proses di atas. Perhatikan:
- baris T
extureImage[0]=LoadBMP("Crate.bmp").Ubah sesuai file citra bmp
yang anda punya.
- prosedur int LoadGLTexture(). Perhatikan bagaimana menggunakan citra bmp
yang telah diload ke memory dalam bentuk struktur data
AUX_RGBImageRec* menjadi tiga buah texture dalam OpenGL dg metoda filterpembesaran texture yang berbeda. Metoda itu adalah yaitu metoda Nearest Filtered Texture, metoda Linear Interpolation Texture dan metoda Mipmapped Texture. Perhatikan bedanya dengan merubah-rubah filternya menggunakan tombol keyboard “f”.
Filter pembesaran texture berpengaruh pada bagaimana OpenGL melakukan proses
rasterisasi texture saat texture ditampilkan pada jumlah pixel yang lebih besar atau lebih
kecil dari ukuran sebenarnya. Pada Nearest Filtered Texture, texture yang ditampilkan
merupakan hasil pemilihan nilai pixel pada posisi terdekat. Sedangkan dengan Linear
Interpolation Texture (LPT), texture yang ditampilkan merupakan hasil interpolasi
linear antara pixel-pixel disekitarnya. Pada Mipmapped Texture(MPT), interpolasi
linear dilakukan pada awal secara offline sehingga dihasilkan banyak texture dengan
ukuran dari yang kecil hingga yang besar. LPT dan MPT akan menghasilkan kira-kira
geometry pipeline
vertices
pixel pipeline
image
hasil yang sama dengan LPT akan sedikit lebih lambat dari MPT walaupun memori yang
digunakan jauh lebih kecil.
Program 09
Bmp.h
#include <GL/glaux.h>
AUX_RGBImageRec *LoadBMP(char *Filename);
Bmp.cpp
#include <windows.h>
#include <stdio.h> // Header File For Standard Input/Output
#include <gl\gl.h> // Header File For The OpenGL32 Library
#include <gl\glu.h> // Header File For The GLu32 Library
#include <gl\glaux.h> // Header File For The Glaux Library
#include "bmp.h"
AUX_RGBImageRec *LoadBMP(char *Filename) // Loads A Bitmap Image
{
FILE *File=NULL; //
File Handle
if (!Filename)
// Make Sure A Filename Was Given {
return NULL;
// If Not Return NULL }
File=fopen(Filename,"r"); //
Check To See If The File Exists
if (File)
// Does The File Exist? {
fclose(File);
// Close The Handle
return auxDIBImageLoad(Filename); // Load The Bitmap And Return A Pointer
}
return NULL;
// If Load Failed Return NULL }
Program.cpp
// OpenGL// - Texture Mapping Magnification Filter // filter=0 --> Nearest Filtered Texture // filter=1 --> Linear Interpolation Texture // filter=2 --> Mipmapped Texture
#include <windows.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <GL/glut.h> #include "bmp.h" float z_pos=-5.0f; float rot=0.0f; GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f }; GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f }; /* array to hold texture handles */
GLuint filter; // Which Filter To Use
GLuint texture[3]; // Storage For 3 Textures
int LoadGLTextures() //
Load Bitmaps And Convert To Textures {
int Status=FALSE; //
Status Indicator
AUX_RGBImageRec *TextureImage[1]; // Create
Storage Space For The Texture
memset(TextureImage,0,sizeof(void *)*1); // Set The Pointer To NULL
// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
if (TextureImage[0]=LoadBMP("Crate.bmp")) {
Status=TRUE; // Set The Status To TRUE
glGenTextures(3, &texture[0]); //
Create Three Textures
// Create Nearest Filtered Texture
glBindTexture(GL_TEXTURE_2D, texture[0]);
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, 3, TextureImage[0]->sizeX, >sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, >sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
// Create MipMapped Texture
glBindTexture(GL_TEXTURE_2D, texture[2]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_
NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); }
if (TextureImage[0]) //
If Texture Exists {
if (TextureImage[0]->data) //
If Texture Image Exists {
free(TextureImage[0]->data); // Free
The Texture Image Memory }
free(TextureImage[0]); //
Free The Image Structure }
return Status;
// Return The Status }
void resize(int width, int height) {
glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (float)width/(float)height, 1.0, 300.0);
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
}
void myTimeOut(int id) {
// called if timer event
// ...advance the state of animation incrementally... rot+=10;
glutPostRedisplay(); // request redisplay
glutTimerFunc(100, myTimeOut, 0); // request next timer event }
{
if((key=='<')||(key==',')) z_pos-=0.1f;
else if((key=='>')||(key=='.')) z_pos+=0.1f;
else if((key=='F')||(key='f')) { filter+=1; if (filter>2) { filter=0; } printf("filter: %i",filter); } }
void mydisplay(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glLoadIdentity(); glTranslatef(0.0,0.0f,z_pos); glRotatef(rot, 0, 1, 0); glBindTexture(GL_TEXTURE_2D, texture[filter]); glBegin(GL_QUADS); // Front Face glColor3f(1.0,0.0,0.0); glNormal3f( 0.0f, 0.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Back Face glNormal3f( 0.0f, 0.0f,-1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Top Face glNormal3f( 0.0f, 1.0f, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Bottom Face glNormal3f( 0.0f,-1.0f, 0.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Right face glNormal3f( 1.0f, 0.0f, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Left Face glNormal3f(-1.0f, 0.0f, 0.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glEnd(); glFlush(); glutSwapBuffers(); } void init() { if (!LoadGLTextures()) //
Jump To Texture Loading Routine {
return; //
If Texture Didn't Load Return FALSE }
glEnable(GL_TEXTURE_2D); //
Enable Texture Mapping
glShadeModel(GL_SMOOTH); //
Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black
Background
glClearDepth(1.0f);
// Depth Buffer Setup
glEnable(GL_DEPTH_TEST); //
Enables Depth Testing
glDepthFunc(GL_LEQUAL); //
The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light
glEnable(GL_LIGHT1);
return; }
int main(int argc, char** argv) {
glutInit(&argc,argv);
glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH ); glutInitWindowSize(500,500);
glutCreateWindow("simple"); // callbacks glutDisplayFunc(mydisplay); glutKeyboardFunc(myKeyboard); glutTimerFunc(100, myTimeOut, 0); glutReshapeFunc(resize); init(); glutMainLoop(); return 0; }
Seringkali, efek yang diinginkan dapat diperoleh dengan mencampur lebih dari satu
texture. Proses pencampuran lebih dari satu texture disebut dengan istilah blending.
Salah satu efek blending yang paling sederhana adalah dengan memblending texture
dengan warna.
Fragment program 10 di bawah memperlihatkan perubahan yang terjadi pada void
mydisplay() jika kita ingin melakukan pencampuran antara texture dan warna.
Perhatikan fungsi glEnable(GL_BLEND). Di sini texture di blend dengan warna merah.
TUGAS: coba rubah codenya agar warna blending berbeda-beda pada setiap surface dari
box-nya.
Program 10.
void mydisplay(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glLoadIdentity(); glTranslatef(0.0,0.0f,z_pos); glRotatef(rot, 0, 1, 0);
glEnable(GL_BLEND); // Turn Blending On glColor3f(1.0,0.0,0.0); // Blending Color glBindTexture(GL_TEXTURE_2D, texture[filter]); glBegin(GL_QUADS); // Front Face glNormal3f( 0.0f, 0.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Back Face
glNormal3f( 0.0f, 0.0f,-1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Top Face glNormal3f( 0.0f, 1.0f, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Bottom Face glNormal3f( 0.0f,-1.0f, 0.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Right face glNormal3f( 1.0f, 0.0f, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Left Face glNormal3f(-1.0f, 0.0f, 0.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glEnd(); glFlush(); glutSwapBuffers(); }
Tutorial 07. Transparency
Salah satu efek yang dapat ditampilkan dari blending adalah transparency, yaitu
bagaimana membuat suatu permukaan tampak transparant. Hal ini dicapai dengan
menggunakan warna blending putih (full-brightness) dengan transparansi satu dengan
fungsi:
glColor4f(1.0f, 1.0f, 1.0f, 0.5);// Full Brightness. 50% Alpha glBlendFunc(GL_SRC_ALPHA,GL_ONE);
Program 11 menampilkan perubahan yang terjadi pada void init() dan void mydisplay()
pada Program 10 untuk menghasilkan suatu box tranparan. Coba untuk merubah
texturenya dengan citra yang lebih sesuai agar didapat nuansa boks dengan material kaca
dari pada boks “hantu”, seperti pada Gambar berikut:
Program 11
void mydisplay(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glLoadIdentity(); glTranslatef(0.0,0.0f,z_pos); glRotatef(rot, 0, 1, 0); glBindTexture(GL_TEXTURE_2D, texture[filter]);
glEnable(GL_BLEND); // Turn Blending On
glDisable(GL_DEPTH_TEST); // Turn Depth Testing Off
glBegin(GL_QUADS); // Front Face glNormal3f( 0.0f, 0.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Back Face glNormal3f( 0.0f, 0.0f,-1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Top Face glNormal3f( 0.0f, 1.0f, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Bottom Face glNormal3f( 0.0f,-1.0f, 0.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Right face glNormal3f( 1.0f, 0.0f, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Left Face glNormal3f(-1.0f, 0.0f, 0.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glEnd(); glFlush(); glutSwapBuffers(); } void init() { if (!LoadGLTextures())
// Jump To Texture Loading Routine
{
return;
// If Texture Didn't Load Return FALSE
}
glEnable(GL_TEXTURE_2D); //
Enable Texture Mapping
glShadeModel(GL_SMOOTH); //
Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f);
// Depth Buffer Setup
glEnable(GL_DEPTH_TEST); //
Enables Depth Testing
glDepthFunc(GL_LEQUAL);
// The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light glEnable(GL_LIGHT1); glColor4f(1.0f, 1.0f, 1.0f, 0.5); // Full Brightness. 50% Alpha glBlendFunc(GL_SRC_ALPHA,GL_ONE); return; }
TUGAS: Pada Program 10 seluruh bagian dari boks bersifat transparan. Coba rubah agar
hanya satu bagian saja yang menjadi transparan dengan texture yang berbeda dari
Tutorial 08. Fog
Kabut/fog adalah salah satu fitur OpenGL lain yang sering digunakan pada banyak
kesempatan. Kabut digunakan dalam banyak kesempatan, antara lain:
- mensimulasikan efek kabut
- membatasi ruang pandang pengguna agar komputasi grafis yang diperlukan dapat
dibatasi. Hal ini terutama dilakukan pada era-era ketika algoritma grafis masih
dilakukan di CPU.
Program 12 memperlihatkan bagaimana menggunakan fungsi-fungsi OpenGL yang
terkait dengan fog.
Program 12.
// OpenGL// - Fog Filter
// fogfilter=0 --> Nearest Filtered Texture // fogfilter=1 --> Linear Interpolation Texture // fogfilter=2 --> Mipmapped Texture
#include <windows.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <GL/glut.h> #include "bmp.h" float z_pos=-5.0f; float rot=0.0f; GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f }; GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f }; /* array to hold texture handles */
GLuint filter; // Which Filter To Use
GLuint texture[3]; // Storage For 3 Textures // Fog
bool gp;
GLuint fogfilter;
GLuint fogMode[]={GL_EXP, GL_EXP2, GL_LINEAR}; GLfloat fogColor[4]={0.5f, 0.5f, 0.5f, 1.0f};
int LoadGLTextures() //
Load Bitmaps And Convert To Textures {
int Status=FALSE; //
AUX_RGBImageRec *TextureImage[1]; // Create Storage Space For The Texture
memset(TextureImage,0,sizeof(void *)*1); // Set The Pointer To NULL
// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
if (TextureImage[0]=LoadBMP("glass.bmp")) {
Status=TRUE; // Set The Status To TRUE
glGenTextures(3, &texture[0]); //
Create Three Textures
// Create Nearest Filtered Texture
glBindTexture(GL_TEXTURE_2D, texture[0]);
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, 3, TextureImage[0]->sizeX, >sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
// Create Linear Filtered Texture
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, >sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
// Create MipMapped Texture
glBindTexture(GL_TEXTURE_2D, texture[2]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_
NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); }
if (TextureImage[0]) //
If Texture Exists {
if (TextureImage[0]->data) //
If Texture Image Exists {
free(TextureImage[0]->data); // Free
The Texture Image Memory }
free(TextureImage[0]); //
Free The Image Structure }
return Status; // Return The Status
}
void resize(int width, int height) {
glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (float)width/(float)height, 1.0, 300.0);
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
}
void myTimeOut(int id) {
// called if timer event
// ...advance the state of animation incrementally... rot+=1;
glutPostRedisplay(); // request redisplay
glutTimerFunc(100, myTimeOut, 0); // request next timer event }
void myKeyboard(unsigned char key,int x, int y) {
if((key=='<')||(key==',')) z_pos-=0.1f;
else if((key=='>')||(key=='.')) z_pos+=0.1f;
else if((key=='F')||(key='f')) { filter+=1; if (filter>2) { filter=0; } printf("filter: %i \n",filter); }
else if( (key=='G') || (key=='g')) {
if(gp==FALSE) {
gp=TRUE; fogfilter+=1;
if (fogfilter>2) // Is fogfilter Greater Than 2? {
fogfilter=0; // If So, Set fogfilter To Zero }
glFogi (GL_FOG_MODE, fogMode[fogfilter]); // Fog Mode } else { gp=FALSE; } printf("filter: %i \n",fogfilter); } }
void mydisplay(void) { glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glLoadIdentity(); glTranslatef(0.0,0.0f,z_pos); glRotatef(rot, 0, 1, 0); glBindTexture(GL_TEXTURE_2D, texture[filter]); glBegin(GL_QUADS); // Front Face glNormal3f( 0.0f, 0.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Back Face glNormal3f( 0.0f, 0.0f,-1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Top Face glNormal3f( 0.0f, 1.0f, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Bottom Face glNormal3f( 0.0f,-1.0f, 0.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Right face glNormal3f( 1.0f, 0.0f, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Left Face glNormal3f(-1.0f, 0.0f, 0.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glEnd(); glFlush(); glutSwapBuffers(); }
void init() {
if (!LoadGLTextures()) //
Jump To Texture Loading Routine {
return; //
If Texture Didn't Load Return FALSE }
glEnable(GL_TEXTURE_2D); //
Enable Texture Mapping
glShadeModel(GL_SMOOTH); //
Enable Smooth Shading // FOG
glClearColor(0.5f,0.5f,0.5f,1.0f); // We'll Clear To The Color Of The Fog
glFogi(GL_FOG_MODE, fogMode[fogfilter]); // Fog Mode glFogfv(GL_FOG_COLOR, fogColor); // Set Fog Color
glFogf(GL_FOG_DENSITY, 0.35f); // How Dense Will The Fog Be glHint(GL_FOG_HINT, GL_DONT_CARE); // Fog Hint Value
glFogf(GL_FOG_START, 100.0f); // Fog Start Depth glFogf(GL_FOG_END, 1000.0f); // Fog End Depth glEnable(GL_FOG);
glClearDepth(1.0f);
// Depth Buffer Setup
glEnable(GL_DEPTH_TEST); //
Enables Depth Testing
glDepthFunc(GL_LEQUAL); //
The Type Of Depth Testing To Do
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light
glEnable(GL_LIGHT1);
return; }
int main(int argc, char** argv) {
glutInit(&argc,argv);
glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH ); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("simple"); // callbacks glutDisplayFunc(mydisplay); glutKeyboardFunc(myKeyboard); glutTimerFunc(100, myTimeOut, 0);
glutReshapeFunc(resize); init();
glutMainLoop();
return 0; }
Variabel global dibuat agar kita bisa mencoba-coba tiga macam mode fog. Pada void
init() terdapat beberapa baris kode baru, yaitu:
- glEnable(GL_FOG) yang melakukan inisialisasi fog
- glFogi(GL_FOG_MODE, fogMode[fogfilter]); menentukan mode fog dengan
variabel array fogMode. Variabel fogMode diinisialisasi dengan tiga nilai, yaitu
GL_EXP, GL_EXP2, dan GL_LINEAR.:
o GL_EXP – fog standar yang dirender pada keseluruhan screen. Efek fognya
tidak terlalu terlihat namun jenis yang paling cepat dirender.
o GL_EXP2 – fog jenis ini juga mirip dengan GL_EXP, hanya akan memberikan
kesan dalam pada scene.
o GL_LINEAR – pada fog jenis ini, efek fog diinterpolasi secara linier
bergantung jarak dengan kamera sehingga didapat efek yang lebih baik.
- glFogfv(GL_FOG_COLOR, fogcolor); menentukan warna dari fog.
- glFogf(GL_FOG_DENSITY, 0.35f); menentukan seberapa padat kabutnya. Semakin
tinggi nilainy, semakin pekat kabut yang dihasilkan.
- The line glHint (GL_FOG_HINT, GL_DONT_CARE); memberikan informasi
kepada OpenGL tentang bagaimana proses rendering ingin dilakukan.
o gl_dont_care – terserah openGL
o gl_nicest – perhitungan fog dilakukan per-pixel.
o gl_fastest – perhitungan fog dilakukan per-vertex yang berarti lebih cepat tapi
lebih tidak akurat.
- glFogf(GL_FOG_START, 1.0f); menentukan jarak dari kamera ketika fog mulai.
- glFogf(GL_FOG_END, 5.0f); menentukan sejauh mana kabut masih berefek.
TUGAS: Rubah berbagai variabel di atas untuk memlihat apa pengaruhnya.
Tutorial 09. Obyek Kompleks
Hingga tahap ini obyek yang digunakan masih berangkat dari pemodelan manual
sehingga model yang dihasilkan masih sederhana. Kebutuhan untuk dapat menggunakan
model yang lebih kompleks sangat besar. Ada banyak aplikasi perangkat lunak yang
dapat digunakan untuk membuat model dengan lebih mudah. Contoh aplikasi untuk
pembuatan model 3D antara lain: 3DS Max, Blender, Maya, Milkshape dengan dibantu
aplikasi pemrosesan citra 2D seperti Photoshop, Corel dll. Format-format file standar
model 3D yang biasa digunakan antara lain .3ds, .obj, dll.
Persoalannya adalah bagaimana kita dapat menggunakan hasil dari aplikasi perangkat
lunak tersebut dalam program kita. Untuk itu kita membutuhkan kode untuk membaca
file tersebut dalam dan merepresentasikannya ke dalam program kita.
Tutorial 09 memberikan ilustrasi tentang bagaimana kita membaca file model 3D dan
menggunakannya dalam program berbasis openGL dan GLUT. Pertama file dalam
format .txt yang kita buat sendiri dan kemudian dengan format file .3ds. Model dengan
format 3DS sendiri awalnya merupakan file format pada versi-versi awal aplikasi 3D
Studio dari Autodesk Animation Ltd. sebelum berubah menjadi format file yang lebih
kompleks dengan aplikasinya menjadi 3D Studio Max. Format ini merupakan salah satu
format yang paling banyak dikenal.
Suatu set model 3D yang direpresentasikan oleh file .3ds biasanya ditemani oleh
beberapa file citra untuk texture dari model tersebut. Format file-nya disusun dengan
organisasi sebagai berikut:
Pada Program 13 kita membuat file model 3D dengan format kita sendiri. File format kita
adalah file .txt yang formatnya akan berupa aturan sebagai berikut:
- Kita dapat memasukkan baris kosong semau kita agar file lebih mudah dibaca
- Kita dapat memasukkan baris komentar dengan menambahkan “//” pada awal
baris
- Hanya terkait dengan satu file texture
- Primitif yang digunakan hanya GL_TRIANGLES
- Informasi awalnya akan berupa frasa NUMPOLLIES xx, dengan xx adalah
jumlah primitif
- Setelah itu kita harus memberi spesifikasi triangle-nya dengan menuliskan daftar
vertex perbaris dengan format baris sbb.
X
Y
Z S T
dengan X,Y, Z adalah posisi vertex sedangkan S, T adalah pixel texture yang
bersesuaian.
Contoh datanya juga diberikan pada bagian bawah dari Program 13.
Program 13
#include <windows.h>
#include <math.h> // Math Library Header File
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <GL/glut.h>
#include <GL/glaux.h>
const float piover180 = 0.0174532925f;
float heading;
float xpos;
float zpos;
GLfloat yrot; // Y Rotation GLfloat walkbias = 0;
GLfloat walkbiasangle = 0; GLfloat lookupdown = 0.0f;
GLfloat z=0.0f; // Depth Into The Screen
GLuint filter; // Which Filter To Use
GLuint texture[3]; // Storage For 3 Textures
typedef struct tagVERTEX {
float x, y, z;
float u, v; } VERTEX;
typedef struct tagTRIANGLE {
VERTEX vertex[3];
} TRIANGLE;
typedef struct tagSECTOR {
int numtriangles;
TRIANGLE* triangle; } SECTOR;
SECTOR sector1; // Our Model Goes Here:
void readstr(FILE *f,char *string) {
do
{
fgets(string, 255, f);
} while ((string[0] == '/') || (string[0] == '\n'));
return; } void SetupWorld() { float x, y, z, u, v; int numtriangles; FILE *filein; char oneline[255];
filein = fopen("data/world.txt", "rt"); // File To Load World Data From
sscanf(oneline, "NUMPOLLIES %d\n", &numtriangles); sector1.triangle = new TRIANGLE[numtriangles]; sector1.numtriangles = numtriangles;
for (int loop = 0; loop < numtriangles; loop++) {
for (int vert = 0; vert < 3; vert++) {
readstr(filein,oneline);
sscanf(oneline, "%f %f %f %f %f", &x, &y, &z, &u, &v); sector1.triangle[loop].vertex[vert].x = x; sector1.triangle[loop].vertex[vert].y = y; sector1.triangle[loop].vertex[vert].z = z; sector1.triangle[loop].vertex[vert].u = u; sector1.triangle[loop].vertex[vert].v = v; } } fclose(filein); return; }
AUX_RGBImageRec *LoadBMP(char *Filename) // Loads A Bitmap Image
{
FILE *File=NULL; // File Handle
if (!Filename) // Make Sure A Filename Was Given
{
return NULL; // If Not Return NULL }
File=fopen(Filename,"r"); // Check To See If The File Exists
if (File) // Does The File Exist?
{
fclose(File); // Close The Handle
return auxDIBImageLoad(Filename); // Load The Bitmap And Return A Pointer
}
return NULL; // If Load Failed Return NULL
}
int LoadGLTextures() // Load Bitmaps And Convert To Textures
{
int Status=FALSE; // Status Indicator
AUX_RGBImageRec *TextureImage[1]; // Create Storage Space For The Texture
memset(TextureImage,0,sizeof(void *)*1); // Set The Pointer To NULL
// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
if (TextureImage[0]=LoadBMP("Data/Mud.bmp")) {
Status=TRUE; // Set The Status To TRUE
glGenTextures(3, &texture[0]); // Create Three Textures
// Create Nearest Filtered Texture
glBindTexture(GL_TEXTURE_2D, texture[0]);
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, 3, TextureImage[0]->sizeX, >sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
// Create Linear Filtered Texture
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, >sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
// Create MipMapped Texture
glBindTexture(GL_TEXTURE_2D, texture[2]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_
NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); }
if (TextureImage[0]) // If Texture Exists {
if (TextureImage[0]->data) // If Texture Image Exists
{
free(TextureImage[0]->data); // Free The Texture Image Memory
}
free(TextureImage[0]); // Free The Image Structure
}
return Status; // Return The Status }
void resize(int width, int height) // Resize And Initialize The GL Window
{
if (height==0)
{
height=1;
// Making Height Equal One }
glViewport(0,0,width,height); // Reset
The Current Viewport
glMatrixMode(GL_PROJECTION); // Select
The Projection Matrix
glLoadIdentity(); //
Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); //
Select The Modelview Matrix
glLoadIdentity(); //
Reset The Modelview Matrix }
void init() // All
Setup For OpenGL Goes Here {
if (!LoadGLTextures()) //
Jump To Texture Loading Routine {
return; //
If Texture Didn't Load Return FALSE }
glEnable(GL_TEXTURE_2D); //
Enable Texture Mapping
glBlendFunc(GL_SRC_ALPHA,GL_ONE); // Set
The Blending Function For Translucency
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This
Will Clear The Background Color To Black
glClearDepth(1.0); // Enables Clearing Of The Depth Buffer
glDepthFunc(GL_LESS); //
The Type Of Depth Test To Do
glEnable(GL_DEPTH_TEST); //
Enables Depth Testing
glShadeModel(GL_SMOOTH); //
Enables Smooth Color Shading
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
SetupWorld();
return; //
Initialization Went OK }
{
// called if timer event
// ...advance the state of animation incrementally... //rot+=1;
glutPostRedisplay(); // request redisplay
glutTimerFunc(100, myTimeOut, 0); // request next timer event }
void myKeyboard(unsigned char key,int x, int y) {
}
void mySpecialKeyboard(int key,int x, int y) {
if(key==GLUT_KEY_UP) {
xpos -= (float)sin(heading*piover180) * 0.05f; zpos -= (float)cos(heading*piover180) * 0.05f;
if (walkbiasangle >= 359.0f) { walkbiasangle = 0.0f; } else { walkbiasangle+= 10; }
walkbias = (float)sin(walkbiasangle * piover180)/20.0f;
}
else if(key==GLUT_KEY_DOWN) {
xpos += (float)sin(heading*piover180) * 0.05f; zpos += (float)cos(heading*piover180) * 0.05f;
if (walkbiasangle <= 1.0f) { walkbiasangle = 359.0f; } else { walkbiasangle-= 10; }
walkbias = (float)sin(walkbiasangle * piover180)/20.0f;
} else if(key==GLUT_KEY_RIGHT) { heading -= 1.0f; yrot = heading; } else if(key==GLUT_KEY_LEFT) { heading += 1.0f; yrot = heading; } else if(key==GLUT_KEY_PAGE_UP) {