Menggambar Object Gambar Topeng dengan C++ Advance

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:

  1. Inisialisasi OpenGL dan GLUT: Mengatur jendela dan konteks rendering.
  2. 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.
  3. Menggambar Setengah Topeng: Menggunakan glBegin(GL_POLYGON) atau GL_TRIANGLE_FAN untuk menggambar setiap bagian.
  4. Memirorkan dan Menggambar Sisi Lain: Menggunakan glScalef(-1.0, 1.0, 1.0) untuk membalikkan koordinat x dan menggambar kembali bagian yang sama.
  5. 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 fungsi cos dan sin 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 memanggil drawHalfMask() 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 di init().
  • 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() dan glPopMatrix(): 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:
      1. Menggambar bagian pertama topeng (tanpa mirroring tambahan).
      2. 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, atau rotateAngle diubah.
  • glutPostRedisplay(): Memberi tahu GLUT bahwa jendela perlu digambar ulang. Ini akan memicu panggilan ke fungsi display().

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) dan GLUT_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 fungsi display sebagai fungsi yang akan dipanggil untuk menggambar konten jendela.
  • glutKeyboardFunc(keyboard): Mendaftarkan fungsi keyboard 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):

  1. Instal GLUT:

    Bash

     
    sudo apt-get update
    sudo apt-get install freeglut3-dev
    
  2. Simpan kode di atas sebagai topeng.cpp.
  3. Kompilasi menggunakan g++:

    Bash

     
    g++ topeng.cpp -o topeng -lglut -lGL -lGLU -lm
    
  4. Jalankan:

    Bash

     
    ./topeng
    

Di Windows (menggunakan MinGW dan MSYS2):

  1. Pastikan Anda telah menginstal MinGW dan MSYS2.
  2. Instal GLUT melalui MSYS2:

    Bash

     
    pacman -S mingw-w64-x86_64-freeglut
    pacman -S mingw-w64-x86_64-glew # Mungkin juga butuh ini
    
  3. Simpan kode di atas sebagai topeng.cpp.
  4. Buka terminal MinGW (MSYS2 MinGW 64-bit).
  5. Kompilasi:

    Bash

     
    g++ topeng.cpp -o topeng -lfreeglut -lopengl32 -lglu32 -lm
    
  6. Jalankan:

    Bash

     
    ./topeng.exe
    

Di macOS:

  1. Instal Homebrew jika belum:

    Bash

     
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    
  2. Instal GLUT:

    Bash

     
    brew install freeglut
    
  3. Simpan kode di atas sebagai topeng.cpp.
  4. Kompilasi:

    Bash

     
    g++ topeng.cpp -o topeng -framework OpenGL -framework GLUT -lm
    
  5. 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 :

Leave a Reply

Your email address will not be published. Required fields are marked *