Hari kemarin Team Whitecyber diminta untuk membuat Project Pembuatan Gambar namun menggunakan C++ Programming.
Tentu! Mari kita buat program C++ menggunakan OpenGL dan GLUT untuk menggambar setengah topeng ini, lalu memirorkannya untuk membentuk topeng utuh. Kita juga akan menambahkan fitur scaling, rotasi, dan translasi.
Gambaran Umum Solusi
Kita akan menggambar topeng ini sebagai serangkaian poligon. Karena gambar ini simetris, kita hanya perlu menggambar satu sisi (misalnya, sisi kanan atau kiri) dan kemudian menggunakan matriks transformasi untuk memirorkannya dan menggabungkan kedua sisi.
Berikut adalah langkah-langkah pengembangan yang akan kita lakukan:
- Inisialisasi OpenGL dan GLUT: Mengatur jendela dan konteks rendering.
- Mendefinisikan Vertices untuk Setengah Topeng: Kita akan memecah gambar topeng menjadi bentuk-bentuk dasar (seperti oval, segitiga, atau bentuk bebas) dan mendefinisikan titik-titik (vertices) untuk setengah dari topeng tersebut.
- Menggambar Setengah Topeng: Menggunakan
glBegin(GL_POLYGON)
atauGL_TRIANGLE_FAN
untuk menggambar setiap bagian. - Memirorkan dan Menggambar Sisi Lain: Menggunakan
glScalef(-1.0, 1.0, 1.0)
untuk membalikkan koordinat x dan menggambar kembali bagian yang sama. - Menambahkan Interaktivitas (Scaling, Rotasi, Translasi): Menggunakan variabel global untuk menyimpan nilai transformasi dan memperbarui tampilan saat tombol keyboard ditekan.
Asumsi dan Batasan:
- Kita akan menyederhanakan bentuk topeng menjadi poligon-poligon untuk kemudahan implementasi. Detail kecil mungkin tidak 100% akurat dengan gambar asli, tetapi bentuk dasarnya akan serupa.
- Warna akan didefinisikan secara manual.
- Interaksi akan menggunakan tombol keyboard.
Kode dan Instruksi Implementasi
Berikut adalah kode C++ lengkapnya:
C++
#include <GL/glut.h>
#include <GL/gl.h>
#include <iostream>
// Global variables for transformations
float translateX = 0.0f;
float translateY = 0.0f;
float scaleX = 1.0f;
float scaleY = 1.0f;
float rotateAngle = 0.0f;
// Function to draw one half of the mask
void drawHalfMask() {
// --- Outer Mask Shape (simplified) ---
glColor3f(0.5f, 0.3f, 0.1f); // Dark Brown
glBegin(GL_POLYGON);
glVertex2f(0.0f, 0.5f);
glVertex2f(0.2f, 0.4f);
glVertex2f(0.25f, 0.0f);
glVertex2f(0.15f, -0.5f);
glVertex2f(0.0f, -0.6f);
glEnd();
// --- Eye Area (Orange and Red concentric circles/ovals) ---
// Outer Orange Eye
glColor3f(1.0f, 0.6f, 0.0f); // Orange
glBegin(GL_TRIANGLE_FAN);
glVertex2f(0.0f, 0.2f); // Center for eye
for (int i = 0; i <= 360; i += 10) {
float angle = i * 3.14159265f / 180.0f;
glVertex2f(0.0f + 0.15f * cos(angle) * 0.7f, 0.2f + 0.1f * sin(angle));
}
glEnd();
// Inner Red Eye
glColor3f(0.8f, 0.0f, 0.0f); // Red
glBegin(GL_TRIANGLE_FAN);
glVertex2f(0.0f, 0.2f); // Center for eye
for (int i = 0; i <= 360; i += 10) {
float angle = i * 3.14159265f / 180.0f;
glVertex2f(0.0f + 0.1f * cos(angle) * 0.7f, 0.2f + 0.07f * sin(angle));
}
glEnd();
// Eye shape around the circles (darker brown/black)
glColor3f(0.2f, 0.1f, 0.0f); // Very Dark Brown
glBegin(GL_POLYGON);
glVertex2f(0.0f, 0.3f);
glVertex2f(0.15f, 0.25f);
glVertex2f(0.12f, 0.15f);
glVertex2f(0.0f, 0.1f);
glEnd();
// --- Nose/Central Line (simplified) ---
glColor3f(0.5f, 0.3f, 0.1f); // Dark Brown
glBegin(GL_POLYGON);
glVertex2f(0.0f, 0.1f);
glVertex2f(0.05f, 0.0f);
glVertex2f(0.05f, -0.1f);
glVertex2f(0.0f, -0.15f);
glEnd();
// --- Cheek/Mouth Area (concentric arcs/shapes) ---
// Outer Red arc/shape
glColor3f(0.8f, 0.0f, 0.0f); // Red
glBegin(GL_POLYGON);
glVertex2f(0.0f, -0.15f);
glVertex2f(0.1f, -0.2f);
glVertex2f(0.1f, -0.3f);
glVertex2f(0.0f, -0.35f);
glEnd();
// Inner Yellow arc/shape
glColor3f(0.9f, 0.7f, 0.0f); // Yellow
glBegin(GL_POLYGON);
glVertex2f(0.0f, -0.2f);
glVertex2f(0.07f, -0.25f);
glVertex2f(0.07f, -0.3f);
glVertex2f(0.0f, -0.32f);
glEnd();
// Mouth (Red lips)
glColor3f(0.8f, 0.0f, 0.0f); // Red
glBegin(GL_POLYGON);
glVertex2f(0.0f, -0.4f);
glVertex2f(0.1f, -0.45f);
glVertex2f(0.1f, -0.5f);
glVertex2f(0.0f, -0.52f);
glEnd();
}
void display() {
glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer
glLoadIdentity(); // Reset transformations
// Apply global transformations (translation, rotation, scaling)
glTranslatef(translateX, translateY, 0.0f);
glRotatef(rotateAngle, 0.0f, 0.0f, 1.0f);
glScalef(scaleX, scaleY, 1.0f);
// --- Draw the first half of the mask ---
glPushMatrix(); // Save the current matrix state
// No specific transformation needed for the first half, it's drawn as defined
drawHalfMask();
glPopMatrix(); // Restore the matrix state
// --- Draw the mirrored half of the mask ---
glPushMatrix(); // Save the current matrix state
glScalef(-1.0f, 1.0f, 1.0f); // Mirror across the Y-axis
drawHalfMask();
glPopMatrix(); // Restore the matrix state
glutSwapBuffers(); // Swap the front and back buffers
}
void keyboard(unsigned char key, int x, int y) {
switch (key) {
// Translation
case 'w': translateY += 0.05f; break; // Move up
case 's': translateY -= 0.05f; break; // Move down
case 'a': translateX -= 0.05f; break; // Move left
case 'd': translateX += 0.05f; break; // Move right
// Scaling
case 'q': scaleX += 0.1f; scaleY += 0.1f; break; // Scale up
case 'e': scaleX -= 0.1f; scaleY -= 0.1f; break; // Scale down
// Rotation
case 'z': rotateAngle += 5.0f; break; // Rotate clockwise
case 'x': rotateAngle -= 5.0f; break; // Rotate counter-clockwise
case 27: // ESC key to exit
exit(0);
}
glutPostRedisplay(); // Request a redraw
}
void init() {
glClearColor(0.7f, 0.7f, 0.7f, 1.0f); // Set background color (light gray)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); // Set up a 2D orthographic projection
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); // Enable double buffering and RGB color
glutInitWindowSize(600, 800); // Set window size
glutCreateWindow("Topeng Etnik dengan OpenGL"); // Create window with title
init(); // Initialize OpenGL settings
glutDisplayFunc(display); // Register display callback function
glutKeyboardFunc(keyboard); // Register keyboard callback function
std::cout << "Gunakan tombol berikut untuk transformasi:\n";
std::cout << "Translasi: W (atas), S (bawah), A (kiri), D (kanan)\n";
std::cout << "Scaling: Q (perbesar), E (perkecil)\n";
std::cout << "Rotasi: Z (putar CW), X (putar CCW)\n";
std::cout << "ESC untuk keluar.\n";
glutMainLoop(); // Enter the GLUT event processing loop
return 0;
}
Penjelasan Kode dan Cara Mengimplementasikan
1. Struktur Kode
#include <GL/glut.h>
dan#include <GL/gl.h>
: Header ini menyediakan fungsi-fungsi OpenGL dan GLUT yang diperlukan.#include <iostream>
: Digunakan untuk output ke konsol.#include <cmath>
: Digunakan untuk fungsicos
dansin
saat menggambar lingkaran/oval.- Variabel Global Transformasi:
translateX
,translateY
: Mengatur posisi topeng pada sumbu X dan Y.scaleX
,scaleY
: Mengatur skala topeng pada sumbu X dan Y.rotateAngle
: Mengatur sudut rotasi topeng.
drawHalfMask()
: Fungsi ini bertanggung jawab untuk menggambar setengah dari topeng. Ini adalah bagian inti yang perlu Anda sesuaikan jika ingin mengubah bentuk topeng.display()
: Fungsi callback yang dipanggil setiap kali jendela perlu digambar ulang. Di sinilah kita menerapkan transformasi global dan kemudian memanggildrawHalfMask()
dua kali, satu kali normal dan satu kali lagi dengan mirroring.keyboard()
: Fungsi callback yang dipanggil saat tombol keyboard ditekan. Ini memperbarui variabel transformasi berdasarkan input pengguna.init()
: Fungsi untuk inisialisasi pengaturan OpenGL dasar seperti warna latar belakang dan proyeksi.main()
: Fungsi utama yang menginisialisasi GLUT, membuat jendela, mendaftarkan fungsi callback, dan memulai loop utama GLUT.
2. Fungsi drawHalfMask()
Ini adalah bagian paling penting dan memerlukan sedikit “seni” dalam coding:
glColor3f(R, G, B)
: Mengatur warna untuk objek yang akan digambar berikutnya. Nilai R, G, B berkisar dari 0.0 hingga 1.0.glBegin(GL_POLYGON)
: Memberi tahu OpenGL bahwa kita akan mulai mendefinisikan sebuah poligon. Poligon akan diisi dengan warna saat ini.glBegin(GL_TRIANGLE_FAN)
: Digunakan untuk menggambar bentuk melingkar atau oval. Parameter pertama adalah titik pusat, diikuti oleh titik-titik di sekeliling lingkaran.glVertex2f(x, y)
: Mendefinisikan titik (vertex) dengan koordinat X dan Y.glEnd()
: Menandai akhir definisi primitif.
Penting: Untuk menggambar topeng ini, saya telah menyederhanakan bentuknya menjadi beberapa poligon dasar. Anda mungkin perlu menyesuaikan koordinat glVertex2f
agar lebih mirip dengan gambar topeng yang Anda berikan. Saya telah mencoba meniru bentuk umum dan proporsi.
3. Fungsi display()
glClear(GL_COLOR_BUFFER_BIT)
: Menghapus isi buffer warna, mengisi jendela dengan warna latar belakang yang ditentukan diinit()
.glLoadIdentity()
: Mengatur ulang matriks modelview ke matriks identitas. Ini penting agar transformasi sebelumnya tidak menumpuk.glTranslatef(translateX, translateY, 0.0f)
: Menerapkan translasi (pergeseran) ke topeng.glRotatef(rotateAngle, 0.0f, 0.0f, 1.0f)
: Menerapkan rotasi di sekitar sumbu Z (sumbu yang keluar dari layar).glScalef(scaleX, scaleY, 1.0f)
: Menerapkan scaling (perubahan ukuran) pada topeng.glPushMatrix()
danglPopMatrix()
: Ini sangat penting!glPushMatrix()
: Menyimpan kondisi matriks transformasi saat ini ke tumpukan.glPopMatrix()
: Mengambil kondisi matriks yang disimpan dari tumpukan dan mengembalikannya ke matriks saat ini. Kita menggunakannya untuk:- Menggambar bagian pertama topeng (tanpa mirroring tambahan).
- Menyimpan matriks, menerapkan
glScalef(-1.0f, 1.0f, 1.0f)
untuk mirroring, menggambar bagian kedua, lalu mengembalikan matriks ke kondisi sebelumnya agar transformasi mirroring tidak mempengaruhi gambar selanjutnya.
glutSwapBuffers()
: Saat menggunakan double buffering (disarankan untuk animasi), ini menukar buffer depan (yang terlihat) dengan buffer belakang (yang sedang digambar), menghindari flicker.
4. Fungsi keyboard()
- Fungsi ini membaca tombol yang ditekan (
key
). - Berdasarkan tombol yang ditekan, nilai
translateX
,translateY
,scaleX
,scaleY
, ataurotateAngle
diubah. glutPostRedisplay()
: Memberi tahu GLUT bahwa jendela perlu digambar ulang. Ini akan memicu panggilan ke fungsidisplay()
.
5. Fungsi init()
glClearColor(0.7f, 0.7f, 0.7f, 1.0f)
: Mengatur warna latar belakang jendela menjadi abu-abu terang.glMatrixMode(GL_PROJECTION)
: Mengatur mode matriks ke proyeksi.glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0)
: Mengatur proyeksi ortografis 2D. Ini berarti objek akan terlihat sama ukurannya tanpa mempertimbangkan kedalaman. Rentang koordinat X dan Y yang terlihat adalah dari -1.0 hingga 1.0.glMatrixMode(GL_MODELVIEW)
: Mengatur mode matriks kembali ke modelview. Matriks ini digunakan untuk transformasi objek (translasi, rotasi, skala).
6. Fungsi main()
glutInit(&argc, argv)
: Menginisialisasi GLUT.glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB)
: Mengatur mode tampilan:GLUT_DOUBLE
untuk double buffering (mengurangi flicker) danGLUT_RGB
untuk mode warna RGB.glutInitWindowSize(600, 800)
: Mengatur ukuran jendela dalam piksel.glutCreateWindow("Topeng Etnik dengan OpenGL")
: Membuat jendela dengan judul yang diberikan.glutDisplayFunc(display)
: Mendaftarkan fungsidisplay
sebagai fungsi yang akan dipanggil untuk menggambar konten jendela.glutKeyboardFunc(keyboard)
: Mendaftarkan fungsikeyboard
sebagai fungsi yang akan dipanggil saat tombol keyboard ditekan.glutMainLoop()
: Memulai loop pemrosesan event GLUT. Program akan terus berjalan di sini, menunggu event (seperti input keyboard atau kebutuhan untuk menggambar ulang) hingga ditutup.
Cara Mengkompilasi dan Menjalankan
Untuk mengkompilasi kode ini, Anda memerlukan pustaka GLUT yang terinstal di sistem Anda.
Di Linux (Ubuntu/Debian):
- Instal GLUT:
Bash
sudo apt-get update sudo apt-get install freeglut3-dev
- Simpan kode di atas sebagai
topeng.cpp
. - Kompilasi menggunakan g++:
Bash
g++ topeng.cpp -o topeng -lglut -lGL -lGLU -lm
- Jalankan:
Bash
./topeng
Di Windows (menggunakan MinGW dan MSYS2):
- Pastikan Anda telah menginstal MinGW dan MSYS2.
- Instal GLUT melalui MSYS2:
Bash
pacman -S mingw-w64-x86_64-freeglut pacman -S mingw-w64-x86_64-glew # Mungkin juga butuh ini
- Simpan kode di atas sebagai
topeng.cpp
. - Buka terminal MinGW (MSYS2 MinGW 64-bit).
- Kompilasi:
Bash
g++ topeng.cpp -o topeng -lfreeglut -lopengl32 -lglu32 -lm
- Jalankan:
Bash
./topeng.exe
Di macOS:
- Instal Homebrew jika belum:
Bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
- Instal GLUT:
Bash
brew install freeglut
- Simpan kode di atas sebagai
topeng.cpp
. - Kompilasi:
Bash
g++ topeng.cpp -o topeng -framework OpenGL -framework GLUT -lm
- Jalankan:
Bash
./topeng
Setelah menjalankan program, akan muncul jendela dengan topeng yang digambar. Anda bisa menggunakan tombol keyboard yang telah dijelaskan di konsol untuk melakukan translasi, scaling, dan rotasi.
Selamat mencoba! Jika ada bagian yang kurang jelas atau ingin penyesuaian lebih lanjut, jangan ragu untuk bertanya.
Hasilnya :