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 :
0 komentar: