Hari ini saya akan menunjukkan cara membuka jendela dan membuat konteks OpenGL. Ini adalah tugas yang sangat sulit, OpenGL masih tidak memiliki alat lintas platform resmi untuk membuat konteks, jadi kami akan bergantung pada perpustakaan pihak ketiga (dalam hal ini GLFW dan senang). Sudah ada banyak dunia halo serupa di Internet, tetapi saya tidak suka semua yang saya lihat: entah itu sangat canggih, atau gambar dalam contoh sangat primitif (
atau keduanya !). Terima kasih banyak kepada semua penulis, tetapi saya akan mengunduh tutorial lain :)
Hari ini kita akan menggambar ini:

Model ini digambar oleh seniman
Samuel Sharit (arshlevon) , terima kasih banyak karena telah mengizinkan saya untuk menggunakannya sebagai bagian dari kursus kuliah saya tentang grafik komputer!
Tahap 0: membaca tinyrenderer
Secara umum, yang terbaik (meskipun tidak perlu) untuk memberikan kuliah ini setelah membaca seluruh kursus kecil saya. Bagi mereka yang tidak berbicara bahasa Inggris, kuliah ini tersedia
di hub , meskipun saya tidak lagi mendukung versi Rusia. Sebagai bagian dari kursus kuliah ini, saya menunjukkan bagaimana Anda dapat menggambar hanya gambar ini hanya dalam lima ratus baris kode, dan bahkan dengan larangan penuh pada perpustakaan pihak ketiga:

Anehnya, banyak siswa saya tidak mengerti bahwa rasterizer perangkat lunak ini bukan hanya mainan, tetapi pengantar nyata bagaimana OpenGL bekerja. Oleh karena itu, hari ini saya akan menunjukkan cara membuat diabetes dengan akselerasi perangkat keras, dan dalam banyak hal saya akan menggunakan kode dari repositori rasterizer perangkat lunak.
Perhatian, saya tidak mengatur sendiri tugas untuk menjelaskan setiap baris kode, karena saya mengandalkan fakta bahwa membaca dokumentasi adalah cara terbaik untuk memahami segalanya. Kode saya hanya diperlukan untuk mengetahui apa yang sebenarnya ada dalam dokumentasi untuk dibaca, dan dalam urutan apa. Selain itu, saya tidak akan menjelaskan apa itu shader , dan saya tidak akan menjelaskan cara membaca peta normal . Saya menghabiskan banyak waktu di tinyrenderer, di mana semuanya beres.Tahap satu, yang paling sulit: membuat jendela
Seluruh repositori tinggal di
sini ; membuat satu komit untuk setiap langkah tutorial, karena github memberikan penampil yang sangat nyaman dari semua perubahan yang dilakukan. Kami mulai di
sini , tujuan kami adalah mendapatkan jendela ini:

Kode ini dikompilasi menggunakan CMake; Saya memeriksa di Linux (g ++) dan Windows (Visual Studio 2017). Di Linux, versi terbaru dari kode mengkompilasi seperti ini:
git clone --recurse-submodules https://github.com/ssloy/hellOGL.git cd hellOGL mkdir build cd build cmake .. make
Gunakan `git checkout` jika Anda ingin mengkompilasi komit terpisah, bukan versi terbaru. Kode ini memuat GLFW dan senang, menciptakan jendela dengan keyboard callback yang diperlukan, dan memuat vertex kosong dan pixel shaders dari disk.
Tahap dua: memuat model 3D
Perubahan dalam proyek yang dibuat pada tahap ini,
lihat di sini . Pada tahap ini, tujuan kami adalah mem-parsing file model 3D, dan menggambar segitiga pertama tanpa khawatir tentang pencahayaan saat ini:

Harap dicatat bahwa model itu sendiri dan perpustakaan untuk bekerja dengan vektor, dan saya mengambil parser model sepenuhnya dari tinyrenderer. Mungkin renderer perangkat lunak tidak begitu berguna?
Ide dasar dalam OpenGL modern sangat sederhana. Kami pertama kali mengunggah model 3D, dan kemudian saya membuat array simpul ukuran 3 * 3 * (jumlah segitiga). Setiap segitiga memiliki tiga simpul, bukan? Setiap dhuwur dijelaskan oleh tiga angka (x, y, z). Secara total, 3 * 3 * model.nfaces () cukup bagi kita untuk menggambarkan seluruh model:
std::vector<GLfloat> vertices(3*3*model.nfaces(), 0); for (int i=0; i<model.nfaces(); i++) { for (int j=0; j<3; j++) { for (int k=0; k<3; k++) vertices[(i*3+j)*3 + k] = model.point(model.vert(i, j))[k]; } }
Dan kemudian kami memberi tahu OpenGL bahwa ini adalah array, draw, asli!
while (!glfwWindowShouldClose(window)) { [...]  glDrawArrays(GL_TRIANGLES, 0, vertices.size()); [...] }
Vertex shader tidak melakukan hal yang menarik, ia hanya meneruskan data ke fragmen shader karena:
#version 330 core
Nah,
fragmen shader juga bersahaja. Ini hanya menarik acar saat ini menjadi merah:
#version 330 core
Hal tersulit dilakukan, sekarang soal teknologi!
Tahap Tiga: Pencahayaan Diffuse
Perubahan dalam proyek yang dibuat pada tahap ini,
lihat di sini . Kita harus mendapatkan gambar ini:

Pencahayaan difus dalam model Phong, seperti yang Anda tahu, adalah produk skalar sederhana di antaranya
vektor normal dan vektor pencahayaan. Oleh karena itu, selain array simpul, saya menambahkan array normals lain. Tanpa melihat kode, beri tahu saya ukurannya apa?
Hal paling menarik terjadi di fragmen shader, di file .cpp utama, hanya data yang dimuat:
#version 330 core
Tahap Empat: Matriks Transformasi
Perubahan dalam proyek yang dibuat pada tahap ini,
lihat di sini . Pada titik ini, saya memberi kode pada matriks Model, Tampilan, dan Proyeksi. Pada awalnya, mereka hanya tunggal, tetapi jika Anda menekan bilah spasi, model akan mulai berputar: setiap kali saya menggambar, saya memutar matriks Model di sekitar sumbu z dengan 0,01 radian:
{
Di sini fungsi rot_z () mengembalikan matriks rotasi di sekitar sumbu z dengan sudut tertentu. Karena OpenGL tidak tahu apa-apa tentang kelas matriks saya, saya harus menambahkan matriks ekspor void export_row_major () ke pointer sederhana ke float.

Langkah Lima: Peta Normal
Perubahan dalam proyek yang dibuat pada tahap ini,
lihat di sini . Pada tahap ini kita akan belajar cara melapisi tekstur. Karena tekstur difus yang biasa membosankan, saya akan segera menerapkan peta normal, dan bahkan di ruang singgung. Peta normal terlihat seperti ini:

Perhitungan yang sesuai, secara sederhana, tidak jelas, jadi sekali lagi,
baca penjelasannya di tinyrenderer . Dalam hal data, Anda perlu menambahkan beberapa buffer: koordinat uv, dan array vektor tangen dan bi-tangen.

Tahap Lima: Tekstur Diffuse
Nah, jika kita sudah tahu bagaimana cara menghitung peta normal, maka menerapkan tekstur difus normal itu hanya sepele. Perubahan dalam proyek yang dibuat pada tahap ini,
lihat di sini .

Tahap Enam: Silau
Perubahan dalam proyek yang dibuat pada tahap ini,
lihat di sini . Tahap terakhir, tambahkan tekstur lain yang memungkinkan kita mensimulasikan cahaya pencahayaan dari permukaan mengkilap:

Kesimpulan
Ada banyak hal yang dapat diperbaiki dalam kode ini, dan efek visualnya dapat diputar tanpa henti. Tapi ini bukan tujuan saya, tujuan saya adalah untuk menunjukkan bahwa benar-benar semua teknik yang saya sentuh dalam rendering perangkat lunak berlaku dalam konteks OpenGL saat ini. Dan secara pribadi, saya masih berpikir bahwa Anda harus mulai berkenalan dengan grafik 3D dengan menggambar gambar tanpa menggunakan keajaiban perpustakaan grafis.
Sebagai ekstensi, coba, misalnya,
menambahkan bayangan , atau menghitung
pencahayaan global , atau, akhirnya, membuat peta bercahaya: setelah semua, mata dan kristal di dahi Diablo harus bersinar!