Kamis, 24 November 2016

Penerapan Model Ray Tracing Pada OpenGL
Pada praktikum 7 mempelajari tentang ray tracing dan menerapkan metode ray tracing tersebut dengan OpenGL.

Metode Ray Tracing me-render obyek dengan melakukan penelusuran sinar dari mata ke arah obyek dengan memperhitungkan semua efek pencahayaan yang mengenai obyek tersebut seperti titik sinar, jumlah sinar dan lain sebagainya. Sehingga konsep dasar metode ini yaitu merunut pada proses yang dialami oleh sebuah cahaya dalam perjalanananya dari sumber cahaya hingga layer dan memperkirakan warna seperti apa yang akan ditampilkan pada pixel tempat jatuhnya cahaya. Kemudian proses tersebut akan terus diulang hingga seluruh pixel yang dibutuhkan telah terpenuhi.


Perbedaan kelebhan rasterisasi dengan ray tracing yaitu rasterisasi sulit mendapatkan tampilan yang cukup bagus namun proses perhitungannya lebih lama. 

Contoh Program :

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <glut.h>
#include <GLAux.h>          
#include <vector>
#include "praktikum07.h"

// tentukan ukuran window OpenGL
#define screenWidth 480
#define screenHeight 480

// buat variable untuk menyimpan bola yang akan dibuat
std::vector<Sphere> spheres;

// lakukan ray tracing dengan obyek bola
Vec3f trace(
const Vec3f &rayorig,
const Vec3f &raydir,
const std::vector<Sphere> &spheres, const int &depth)
{
float tnear = INFINITY;
const Sphere* sphere = NULL;

// hitung perpotongan cahaya ini dengan bola yang ada dilayar
for (unsigned i = 0; i < spheres.size(); ++i)
{
float t0 = INFINITY, t1 = INFINITY;
if (spheres[i].intersect(rayorig, raydir, t0, t1))

{
if (t0 < 0) t0 = t1;
if (t0 < tnear)
{
tnear = t0;
sphere = &spheres[i];
}
}
}
// jika tidak ada perpotongan maka kembalikan warna hitam atau warna background
if (!sphere) return Vec3f(2);

Vec3f surfaceColor = 0; // warna permukaan obyek yang berpotongan dengan sinar
Vec3f phit = rayorig + raydir * tnear; // titik perpotongan
Vec3f nhit = phit - sphere->center; // normal di titik perpotongan 
nhit.normalize(); // menormalisasikan arah normal
// jika normal dan arah pandang tidak berlawanan satu sama lain
// balikkan arah normal yang berarti arah sekarang berada didalam bola
// membuat bagian dalam bola bernilai benar.
float bias = 1e-4; // tambahkan bias pada titik dimana akan di telusuri
bool inside = false;
if (raydir.dot(nhit) > 0)
nhit = -nhit, inside = true;
if ((sphere->transparency > 0 || sphere->reflection > 0)
&& depth < MAX_RAY_DEPTH)
{
float facingratio = -raydir.dot(nhit);
// ubah nilai mix untuk memberikan efek
float fresneleffect = mix(pow(1 - facingratio, 3), 1, 0.1);
// hitung arah refleksi sinar
// (tidak perlu dinormalisasi karena sudah ternormalisasi di awal) 
Vec3f refldir = raydir - nhit * 2 * raydir.dot(nhit); refldir.normalize();
Vec3f reflection = trace(phit + nhit * bias,
refldir, spheres, depth + 1); Vec3f refraction = 0;
// jika bola nya transparan maka hitung sinar tembusnya
if (sphere->transparency)
{
float ior = 1.1, eta = (inside) ? ior : 1 / ior;
float cosi = -nhit.dot(raydir);
float k = 1 - eta * eta * (1 - cosi * cosi);
Vec3f refrdir = raydir * eta + nhit * (eta * cosi - sqrt(k));
refrdir.normalize();
refraction = trace(phit - nhit * bias, 
  refrdir, spheres, depth + 1);
}



// hasilnya merupakan campuran dari pantulan dan tembusan cahaya
// (jika bolanya transparan)
surfaceColor = (reflection * fresneleffect + refraction
* (1 - fresneleffect) * sphere->transparency)
* sphere->surfaceColor;

}
else {

// bila obyek diffuse tidak perlu dilakukan ray tracing 
for (unsigned i = 0; i < spheres.size(); ++i)
{

if (spheres[i].emissionColor.x > 0)
{
// cahaya

Vec3f transmission = 1;
Vec3f lightDirection = spheres[i].center - phit;
lightDirection.normalize();
for (unsigned j = 0; j < spheres.size(); ++j)
{
if (i != j)
{
float t0, t1;
if (spheres[j].intersect(phit + nhit * bias, lightDirection, t0, t1))
{
transmission = 0;
break;
}
}
}
surfaceColor += sphere->surfaceColor * transmission
* max(float(0), nhit.dot(lightDirection))
* spheres[i].emissionColor;
}
}
}

return surfaceColor + sphere->emissionColor;
}


// fungsi untuk menggambar obyek 
void drawObject()
{
float invWidth = 1 / float(screenWidth); 
float invHeight = 1 / float(screenHeight); 
float fov = 45;
float aspectratio = screenWidth / float(screenHeight);
float angle = tan(M_PI * 0.5 * fov / 180.);

// telusuri sinar
for (unsigned y = 0; y < screenHeight; ++y)
{
for (unsigned x = 0; x < screenWidth; ++x)
{
float xx = (2 * ((x + 0.5) * invWidth) - 1) * angle * aspectratio;
float yy = (1 - 2 * ((y + 0.5) * invHeight)) * angle;
Vec3f raydir(xx, yy, -1);
raydir.normalize();
Vec3f pixel = trace(Vec3f(0), raydir, spheres, 0);
// tentukan warna setiap titik 
float r = min(float(1), pixel.x); float g = min(float(1), pixel.y); float b = min(float(1), pixel.z);
// gambar titik warna permukaan hasil ray tracing 
glColor3f(r, g, b);
glBegin(GL_POINTS);
glVertex2f(-1.0f + 2 * (float)x / screenWidth, 1.0f - 2
* (float)y / screenHeight);
glEnd();
}
}
}


// taruh semua obyek yang akan digambar di fungsi display()
void display()
{
    // bersihkan layar dan buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    // posisikan kamera pandang
    // dalam hal ini sumbu Y ada diatas dan posisi kamera pandang di (posX, posY, posZ)
 //   gluLookAt(posX, posY, posZ, posX + rotX, posY + rotY, posZ + rotZ, 0.0f, 1.0f, 0.0f);

    // panggil fungsi untuk menggambar obyek
    drawObject();
    
    // tampilkan obyek ke layar
    // gunakan glFlush() bila memakai single buffer
    // gunakan glutSwapBuffers() bila memakai double buffer
    glutSwapBuffers();
}

// inisialisasi variabel, pencahayaan, tekstur dan pengaturan kamera pandang di fungsi init()
void init(void)
{
// inisialisasi warna latar belakang layar dalam hal ini warna putih 
glClearColor(1.0, 1.0, 1.0, 0.0);
glEnable(GL_DEPTH_TEST); // mengaktifkan depth buffer
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, screenWidth, 0, screenHeight); // set proyeksi ke orthogonal

// posisi bola, radius bola, warna permukaan, tingkat pantulan,
// transparansi, warna emisi
// buat 3 bola biasa
spheres.push_back(Sphere(Vec3f(0.0, -10004, -20), 10000, Vec3f(0.20, 0.20, 0.20), 0, 0.0));
spheres.push_back(Sphere(Vec3f(0.0, 0, -30), 4,
Vec3f(1.00, 0.32, 0.36), 1, 0.5));
spheres.push_back(Sphere(Vec3f(5.0, -1, -25), 2, Vec3f(0.90, 0.89, 0.12), 1, 0.0));
// buat 1 bola cahaya 
spheres.push_back(Sphere(Vec3f(0.0, 20, -40), 3,
Vec3f(0.00, 0.00, 0.00), 0, 0.0, Vec3f(3)));
                    
}

// fungsi ini digunakan bila layar akan diresize (default)
void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
    glMatrixMode(GL_MODELVIEW);
}



// timer untuk animasi (gunakan bila perlu)
void timer(int value)
{
    glutPostRedisplay();
    glutTimerFunc(55, timer, 0);
}

// program utama
int main(int argc, char** argv)
{
srand48(13);

// inisialisasi jendela OpenGL
// GLUT_SINGLE berarti memakai single buffer
// GLUT_DOUBLE berarti memakai double buffer
// GLUT_RGB berarti mode tampilan yang dipakai RGB
// GLUT_RGBA berarti mode tampilang yang dipakai RGBA
// GLUT_DEPTH berarti memakai depth buffer
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);

// set ukuran jendela tampilan 
glutInitWindowSize(screenWidth, screenHeight);

glutInitWindowPosition(100, 100);
// judul jendela (wajib diubah dengan informasi NAMA / NIM - JUDUL PRAKTIKUM)
glutCreateWindow("Imam Muamar Kharisma/ 1502318006- PRAKTIKUM 07 : RAY TRACING");
  //  glutCreateWindow("PRAKTIKUM 04 - IMAM MUAMAR KHARISMA - 1501318006");
printf("PRAKTIKUM 07\n "); 
printf("Imam Muamar Kharisma\n "); 
printf("\n "); 
printf("\n "); 
printf("\n "); 
printf("\n ");
// panggil fungsi init untuk inisialisasi awal
init();

// event handler untuk display
glutDisplayFunc(display); // display

// looping 
glutMainLoop();

return 0;
}

Screecshoot :



Tekstur Prosedural OpenGL
Pada praktikum 5 menpelajari tentang tekstur proseduran serta perbedaannya dengan tekstur 2D. Kemudian menerapkan tekstur procedural tersebut pada objek dengan OpenGL. Tekstur procedural yaitu sebuah fungsi yang menghitung koordinat tekstur dan tekstur tersebut dapat dibuat menggunakan fungsi procedural, misal seperti tekstur pola kayu, marble dan lan-lain. Itu dapat menggunakan fungsi sinus harmonic yang diberi noise, tekstur langit, tekstur pola kayu dan lain sebagainya.

Tekstur prosedural juga mempuyai berbagai keuntungan seperti menghindari perhitungan trasformasi tekstur dari koordinat citra 2D ke permukaan objek. Keuntungan tersebut salah satunya yaitu trasformasi tekstur tersebut hanya membutuhkan ruang penyimpanan yang kecil dan dapat divariasikan sesuai dengan kebutuhan.


Source Code :

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <glut.h>
#include <GLAux.h>          

#include "praktikum05_addon.h"

// inisialisasi variabel untuk transformasi seperti translasi, rotasi atau scaling
// gunakan bila perlu
float angle = 0.0f; 
float posX = 0.0f, rotX =  0.0f;
float posY = 0.0f, rotY =  0.0f;
float posZ = 5.0f, rotZ = -1.0f;

float objectAngle = 0.0f;
float objectPosX = 0.0f;
float objectPosY = 0.0f;
float objectPosZ = 0.0f;

// penyimpanan tekstur
// dalam hal ini satu tekstur saja
GLuint texture[1];
const int texWidth = 512; // panjang ukuran tekstur 
const int texHeight = 512; // lebar ukuran tekstur
char texData[texWidth][texHeight][3]; // alokasi memori untuk tekstur 3D
double noiseData[texWidth][texHeight]; // alokasi memori untuk noise 2D

// fungsi untuk membangkitkan noise 
void genNoise()
{
for (int i = 0; i < texHeight; i++)
{
for (int j = 0; j < texWidth; j++)
noiseData[i][j] = (rand() % 32768) / 32768.0;
}
}

// fungsi untuk menghaluskan noise 
double smoothNoise(double x, double y)
{
// hitung nilai selisih fraksi dari x dan y 
double fractX = x - int(x);
double fractY = y - int(y);

// hitung jumlah langkah
int x1 = (int(x) + texWidth) % texWidth;
int y1 = (int(y) + texHeight) % texHeight;

// hitung nilai ketetanggaan
int x2 = (x1 + texWidth - 1) % texWidth;
int y2 = (y1 + texHeight - 1) % texHeight;

// haluskan noise 
double value = 0.0;
value += fractX * fractY * noiseData[y1][x1];
value += (1 - fractX) * fractY * noiseData[y1][x2];
value += fractX * (1 - fractY) * noiseData[y2][x1];
value += (1 - fractX) * (1 - fractY) * noiseData[y2][x2];

return value;
}

// fungsi untuk memberi turbulensi pada noise
double turbNoise(double x, double y, double size)
{
double value = 0.0, initialSize = size;

while (size >= 1)
{
value += smoothNoise(x / size, y / size) * size;
size /= 2.0;
}
return(128.0 * value / initialSize);
}


// fungsi untuk melakukaan pemetaan tekstur 
int setTextures()
{
int status = FALSE;
// buat alokasi untuk teksturnya
glGenTextures(1, texture);

// buat tekstur dengan fungsi perlin 
float perlinData;
for (int i = 0; i < texHeight; i++)
{

for (int j = 0; j < texWidth; j++)
{
// tekstur rumput dengan perlin noise


perlinData = perlinNoise2D(i, j, 0.1f, 0.9f, 8.0f); 
texData[i][j][0] = (char)perlinData / 64; 
texData[i][j][1] = (char)perlinData; 
texData[i][j][2] = (char)perlinData / 64;
}
}

status = TRUE;
// bind tekstur dari fungsi perlin tadi 
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexImage2D(GL_TEXTURE_2D, 0, 3, texWidth, texHeight, 0, GL_RGB,
GL_UNSIGNED_BYTE, texData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

return status;
}



// fungsi untuk menggambar obyek 
void drawObject()
{
// obyek bisa dimasukkan diantara glPushMatrix() dan glPopMatrix()
// fungsinya agar obyek tidak terpengaruh atau mempengaruhi obyek lain
// saat diwarnai, ditransformasi dan sebagainya
glPushMatrix();

// operasi transformasi rotasi ke arah sumbu X (gunakan bila perlu)
glRotatef(objectAngle, objectPosX, objectPosY, objectPosZ);

// menggambar obyek diawali glBegin(tipe obyek) dan diakhiri dengan glEnd()
// kecuali menggunakan fungsi yang sudah ada di GLUT-OpenGL

// sisi depan kotak
glBindTexture(GL_TEXTURE_2D, texture[0]); // bind tekstur dari tekstur pertama
glBegin(GL_QUADS);
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();
//sisi belakang kotak
glBindTexture(GL_TEXTURE_2D, texture[0]); // bind tekstur dari tekstur pertama
glBegin(GL_QUADS);
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();
// sisi samping kanan kotak
glBindTexture(GL_TEXTURE_2D, texture[0]); // bind tekstur dari tekstur pertama
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); 
glVertex3f(1.0f, -1.0f, 1.0f); 
glTexCoord2f(0.0f, 1.0f); 
glVertex3f(1.0f, 1.0f, 1.0f); 
glTexCoord2f(1.0f, 1.0f); 
glVertex3f(1.0f, 1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); 
glVertex3f(1.0f, -1.0f, -1.0f); 
glEnd();
// sisi samping kiri kotak
glBindTexture(GL_TEXTURE_2D, texture[0]); // bind tekstur dari tekstur pertama 
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glEnd();
// sisi bawah kotak
glBindTexture(GL_TEXTURE_2D, texture[0]); // bind tekstur dari tekstur pertama 
glBegin(GL_QUADS);
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();

glPopMatrix();
}

// taruh semua obyek yang akan digambar di fungsi display()
void display()
{
    // bersihkan layar dan buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    // posisikan kamera pandang
    // dalam hal ini sumbu Y ada diatas dan posisi kamera pandang di (posX, posY, posZ)
    gluLookAt(posX, posY, posZ, posX + rotX, posY + rotY, posZ + rotZ, 0.0f, 1.0f, 0.0f);

    // panggil fungsi untuk menggambar obyek
    drawObject();
    
    // tampilkan obyek ke layar
    // gunakan glFlush() bila memakai single buffer
    // gunakan glutSwapBuffers() bila memakai double buffer
    glutSwapBuffers();
}

// inisialisasi variabel, pencahayaan, tekstur dan pengaturan kamera pandang di fungsi init()
void init(void)
{
    // inisialisasi warna background layar
    glClearColor(1.0, 1.0, 1.0, 0.0);
    glEnable(GL_DEPTH_TEST);                // mengaktifkan depth buffer
    glMatrixMode(GL_PROJECTION);        
    glLoadIdentity();
    gluPerspective(45.0, 1.0, 1.0, 100.0);    // set proyeksi ke perspektif
    glMatrixMode(GL_MODELVIEW);                
    glLoadIdentity();                        
    // set kamera pandang awal
    gluLookAt(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    // aktifkan tekstur
    glEnable(GL_TEXTURE_2D);                    
}

// fungsi ini digunakan bila layar akan diresize (default)
void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
    glMatrixMode(GL_MODELVIEW);
}

// fungsi untuk mengatur masukan dari keyboard untuk arah kiri, kanan, atas, dan bawah
void keyboard(int key, int x, int y)
{
    float fraction = 0.1f;

    switch (key) 
    {
    case GLUT_KEY_LEFT:
        // masukkan perintah disini bila tombol kiri ditekan 
        // dalam hal ini perintah rotasi obyek ke kiri sebanyak 1 derajat 
        objectAngle -= 1.0f;
        objectPosX = 0.0f;
        objectPosY = 1.0f;
        objectPosZ = 0.0f;
        glutPostRedisplay();    // update obyek
        break;
    case GLUT_KEY_RIGHT:
        // masukkan perintah disini bila tombol kanan ditekan
        // dalam hal ini perintah rotasi obyek ke kanan sebanyak 1 derajat 
        objectAngle += 1.0f;
        objectPosX = 0.0f;
        objectPosY = 1.0f;
        objectPosZ = 0.0f;
        glutPostRedisplay();    // update obyek
        break;
    case GLUT_KEY_UP:
        // masukkan perintah disini bila tombol atas ditekan
        // dalam hal ini perintah rotasi obyek ke atas sebanyak 1 derajat 
        objectAngle -= 1.0f;
        objectPosX = 1.0f;
        objectPosY = 0.0f;
        objectPosZ = 0.0f;
        glutPostRedisplay();    // update obyek
        break;
    case GLUT_KEY_DOWN:
        // masukkan perintah disini bila tombol bawah ditekan
        // dalam hal ini perintah rotasi obyek ke bawah sebanyak 1 derajat 
        objectAngle += 1.0f;
        objectPosX = 1.0f;
        objectPosY = 0.0f;
        objectPosZ = 0.0f;
        glutPostRedisplay();    // update obyek
        break;
    // zoom in
    case GLUT_KEY_PAGE_UP:
        // masukkan perintah disini bila tombol PgUp ditekan
        posX += rotX * fraction;        
        posZ += rotZ * fraction;
        glutPostRedisplay();    // update obyek
        break;
    // zoom out
    case GLUT_KEY_PAGE_DOWN:
        // masukkan perintah disini bila tombol PgDn ditekan
        posX -= rotX * fraction;
        posZ -= rotZ * fraction;
        glutPostRedisplay();    // update obyek
        break;
    }
}

// timer untuk animasi (gunakan bila perlu)
void timer(int value)
{
    glutPostRedisplay();
    glutTimerFunc(55, timer, 0);
}

// program utama
int main(int argc, char** argv)
{
    // inisialisasi jendela OpenGL
    // GLUT_SINGLE berarti memakai single buffer
    // GLUT_DOUBLE berarti memakai double buffer
    // GLUT_RGB berarti mode tampilan yang dipakai RGB
    // GLUT_RGBA berarti mode tampilang yang dipakai RGBA
    // GLUT_DEPTH berarti memakai depth buffer
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

    // set ukuran jendela tampilan
    glutInitWindowSize(480, 480);        // besarnya jendela dalam piksel dalam hal ini 300x300
    glutInitWindowPosition(100, 100);    // posisi jendela dilayar komputer dalam piksel
    // judul jendela (wajib diubah dengan informasi NAMA / NIM - JUDUL PRAKTIKUM masing-masing)
    glutCreateWindow("PRAKTIKUM 05 - Imam Muamar Kharisma - 1502318006");
printf("PRAKTIKUM 05\n "); 
printf("Imam Muamar Kharisma \n "); 
printf("\n "); 
printf("\n "); 
printf("\n "); 
printf("\n ");
    
    // panggil fungsi init untuk inisialisasi awal
    init();

    // event handler untuk display, reshape dan keyboard
    glutDisplayFunc(display);   // display
    glutReshapeFunc(reshape);   // reshape
    glutSpecialFunc(keyboard);  // keyboard
    //glutTimerFunc(0, timer, 0); // aktifkan timer bila perlu

    // set tekstur dengan citra yang sudah disediakan
    int status = setTextures();

    // looping
    glutMainLoop();

    return 0;
}

Screenshot 

Kamis, 17 November 2016

Pemetaan Tekstur
Pada kesempatan kali ini. Saya akan share praktikum 04 mata kuliah Grafika Lanjut. 
Pada praktikum 04 Grafika Lanjut mahasiswa dituntut agar mampu menjelaskan tentang pemetaan tekstur 2D dengan citra tekstur serta mamp memetakan tekstur 2D pada obyek dengan OpenGL


Tekstur sendiri merupakan bentuk yang terstruktur dari storage yang dapat diakses dibaca atau ditulis oleh shader. Biasanya tekstur digunakan untuk menyimpan data citra tekstur 2D. 
Ada beberapa cara untuk memetakan tekstur diantaranya :

1. Menentukan koordinat 2D (s, t) yang merupakan koordinat pada citra
2. Normalisasi ke rentang (0,1) yang kemudian disebut koordinat tekstur
3. Memetakan koordinat tekstur ke setiap vertex di permukaan. 

4. Memetakan tekstur parametric dengan mengubah nilai pikselnya sesuai yang diinginkan. 

Contoh program pemetaan tekstur :

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <glut.h>
#include <GLAux.h>            

// inisialisasi variabel untuk transformasi seperti translasi, rotasi atau scaling
// gunakan bila perlu
float angle = 0.0f; 
float posX = 0.0f, rotX =  0.0f;
float posY = 0.0f, rotY =  0.0f;
float posZ = 5.0f, rotZ = -1.0f;

float objectAngle = 0.0f;
float objectPosX = 0.0f;
float objectPosY = 0.0f;
float objectPosZ = 0.0f;

// penyimpanan tekstur
// dalam hal ini satu tekstur saja
GLuint    texture[1];

// fungsi untuk membuka citra
AUX_RGBImageRec *loadBMP(char *filename)
{
    FILE *File = NULL;                                        
    // cek apakah file tersedia
    fopen_s(&File, filename, "r");                            
    // bila tersedia lakukan prosedur membaca citra
    if (File)                                            
    {
        fclose(File);        
        size_t outSize;
        wchar_t wtext[256];
        mbstowcs_s(&outSize, wtext, filename, strlen(filename) + 1);
        LPWSTR filenamePtr = wtext;
        return auxDIBImageLoad(filenamePtr);                
    }
    // jika gagal kembalikan NULL
    return NULL;                                        
}

// fungsi untuk membuat tekstur dari citra tekstur
int setTextures()
{
    int status = FALSE;                        
    // buat alokasi memori untuk penyimpanan tekstur
    AUX_RGBImageRec *textureImage[1];            
    // buat alokasi untuk teksturnya
    glGenTextures(1, texture);
    memset(textureImage, 0, sizeof(void *) * 1); 

    // baca citra
    if (textureImage[0] = loadBMP("praktikum04.bmp"))
    {
        status = TRUE;                                                
        // buat tekstur dari citra yang sudah dibaca tadi
        // dalam hal ini baca tekstur pertama
        glBindTexture(GL_TEXTURE_2D, texture[0]);
        glTexImage2D(GL_TEXTURE_2D, 0, 3, textureImage[0]->sizeX, textureImage[0]->sizeY, 
            0, GL_RGB, GL_UNSIGNED_BYTE, textureImage[0]->data);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    }
    // jika tekstur sudah berhasil dibuat
    if (textureImage[0])                                    
    {
        // bersihkan alokasi memori
        if (textureImage[0]->data)                            
            free(textureImage[0]->data);                    
        free(textureImage[0]);                                
    }
    return status;
}

// fungsi untuk menggambar obyek
void drawObject()
{
    // obyek bisa dimasukkan diantara glPushMatrix() dan glPopMatrix() 
    // fungsinya agar obyek tidak terpengaruh atau mempengaruhi obyek lain
    // saat diwarnai, ditransformasi dan sebagainya
    glPushMatrix();

    // operasi transformasi rotasi ke arah sumbu X (gunakan bila perlu)
    glRotatef(objectAngle, objectPosX, objectPosY, objectPosZ);

    // set warna obyek ke warna hijau (0, 1, 0)
    //glColor3f(0.0f, 1.0f, 0.0f);

    // bila menggambar obyek harus diawali glBegin(tipe obyek) dan diakhiri dengan glEnd()
    // kecuali menggunakan fungsi yang sudah ada di GLUT-OpenGL
    
    // sisi depan kotak
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    glBegin(GL_QUADS);
    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();
    //sisi belakang kotak
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    glBegin(GL_QUADS);
    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();
    // sisi samping kanan kotak
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f,  1.0f);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f,  1.0f,  1.0f);
    glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f,  1.0f, -1.0f);
    glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, -1.0f, -1.0f);
    glEnd();
    // sisi samping kiri kotak
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
    glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
    glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
    glEnd();
    // sisi bawah kotak
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    glBegin(GL_QUADS);
    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();

    glPopMatrix();
}

// taruh semua obyek yang akan digambar di fungsi display()
void display()
{
    // bersihkan layar dan buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    // posisikan kamera pandang
    // dalam hal ini sumbu Y ada diatas dan posisi kamera pandang di (posX, posY, posZ)
    gluLookAt(posX, posY, posZ, posX + rotX, posY + rotY, posZ + rotZ, 0.0f, 1.0f, 0.0f);

    // panggil fungsi untuk menggambar obyek
    drawObject();
    
    // tampilkan obyek ke layar
    // gunakan glFlush() bila memakai single buffer
    // gunakan glutSwapBuffers() bila memakai double buffer
    glutSwapBuffers();
}

// inisialisasi variabel, pencahayaan, tekstur dan pengaturan kamera pandang di fungsi init()
void init(void)
{
    // inisialisasi warna background layar
    glClearColor(1.0, 1.0, 1.0, 0.0);
    glEnable(GL_DEPTH_TEST);                // mengaktifkan depth buffer
    glMatrixMode(GL_PROJECTION);        
    glLoadIdentity();
    gluPerspective(45.0, 1.0, 1.0, 100.0);    // set proyeksi ke perspektif
    glMatrixMode(GL_MODELVIEW);                
    glLoadIdentity();                        
    // set kamera pandang awal
    gluLookAt(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    // aktifkan tekstur
    glEnable(GL_TEXTURE_2D);                    
}

// fungsi ini digunakan bila layar akan diresize (default)
void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
    glMatrixMode(GL_MODELVIEW);
}

// fungsi untuk mengatur masukan dari keyboard untuk arah kiri, kanan, atas, dan bawah
void keyboard(int key, int x, int y)
{
    float fraction = 0.1f;

    switch (key) 
    {
    case GLUT_KEY_LEFT:
        // masukkan perintah disini bila tombol kiri ditekan 
        // dalam hal ini perintah rotasi obyek ke kiri sebanyak 1 derajat 
        objectAngle -= 1.0f;
        objectPosX = 0.0f;
        objectPosY = 1.0f;
        objectPosZ = 0.0f;
        glutPostRedisplay();    // update obyek
        break;
    case GLUT_KEY_RIGHT:
        // masukkan perintah disini bila tombol kanan ditekan
        // dalam hal ini perintah rotasi obyek ke kanan sebanyak 1 derajat 
        objectAngle += 1.0f;
        objectPosX = 0.0f;
        objectPosY = 1.0f;
        objectPosZ = 0.0f;
        glutPostRedisplay();    // update obyek
        break;
    case GLUT_KEY_UP:
        // masukkan perintah disini bila tombol atas ditekan
        // dalam hal ini perintah rotasi obyek ke atas sebanyak 1 derajat 
        objectAngle -= 1.0f;
        objectPosX = 1.0f;
        objectPosY = 0.0f;
        objectPosZ = 0.0f;
        glutPostRedisplay();    // update obyek
        break;
    case GLUT_KEY_DOWN:
        // masukkan perintah disini bila tombol bawah ditekan
        // dalam hal ini perintah rotasi obyek ke bawah sebanyak 1 derajat 
        objectAngle += 1.0f;
        objectPosX = 1.0f;
        objectPosY = 0.0f;
        objectPosZ = 0.0f;
        glutPostRedisplay();    // update obyek
        break;
    // zoom in
    case GLUT_KEY_PAGE_UP:
        // masukkan perintah disini bila tombol PgUp ditekan
        posX += rotX * fraction;        
        posZ += rotZ * fraction;
        glutPostRedisplay();    // update obyek
        break;
    // zoom out
    case GLUT_KEY_PAGE_DOWN:
        // masukkan perintah disini bila tombol PgDn ditekan
        posX -= rotX * fraction;
        posZ -= rotZ * fraction;
        glutPostRedisplay();    // update obyek
        break;
    }
}

// timer untuk animasi (gunakan bila perlu)
void timer(int value)
{
    glutPostRedisplay();
    glutTimerFunc(55, timer, 0);
}

// program utama
int main(int argc, char** argv)
{
    // inisialisasi jendela OpenGL
    // GLUT_SINGLE berarti memakai single buffer
    // GLUT_DOUBLE berarti memakai double buffer
    // GLUT_RGB berarti mode tampilan yang dipakai RGB
    // GLUT_RGBA berarti mode tampilang yang dipakai RGBA
    // GLUT_DEPTH berarti memakai depth buffer
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

    // set ukuran jendela tampilan
    glutInitWindowSize(480, 480);        // besarnya jendela dalam piksel dalam hal ini 300x300
    glutInitWindowPosition(100, 100);    // posisi jendela dilayar komputer dalam piksel
    // judul jendela (wajib diubah dengan informasi NAMA / NIM - JUDUL PRAKTIKUM masing-masing)
    glutCreateWindow("PRAKTIKUM 04 - IMAM MUAMAR KHARISMA - 1501318006");
printf("PRAKTIKUM 04\n "); 
printf("Imam Muamar Kharisma \n "); 
printf("\n "); 
printf("\n "); 
printf("\n "); 
printf("\n ");
    
    // panggil fungsi init untuk inisialisasi awal
    init();

    // event handler untuk display, reshape dan keyboard
    glutDisplayFunc(display);   // display
    glutReshapeFunc(reshape);   // reshape
    glutSpecialFunc(keyboard);  // keyboard
    //glutTimerFunc(0, timer, 0); // aktifkan timer bila perlu

    // set tekstur dengan citra yang sudah disediakan
    int status = setTextures();

    // looping
    glutMainLoop();

    return 0;
}

Hasil :