
Pendahuluan
OpenGL, yang merupakan backend untuk OpenSceneGraph, menggunakan primitif geometris (seperti titik, garis, segitiga, dan wajah poligonal) untuk membangun semua objek di dunia tiga dimensi.
Primitif ini ditentukan oleh data tentang simpulnya, yang mencakup koordinat simpul, komponen normal, data warna, dan koordinat tekstur. Data ini disimpan dalam array khusus. Primitif dapat dibentuk, misalnya, dengan menentukan objek yang menggambarkan daftar indeks verteks. Metode ini disebut metode array vertex, menghilangkan penyimpanan simpul redundan dalam memori dan memiliki kinerja yang baik.
Selain itu, OpenGL dapat menggunakan mekanisme yang disebut
daftar tampilan , ketika primitif yang disiapkan dalam memori video dapat digunakan kembali, yang secara signifikan mempercepat tampilan objek statis.
Secara default, OSG menggunakan metode array vertex dan metode daftar tampilan untuk membuat geometri. Namun, strategi rendering dapat diubah, tergantung pada bagaimana data geometri disajikan. Pada artikel ini, kita akan membahas teknik dasar untuk bekerja dengan geometri di OSG.
1. Kelas Geode dan Drawable
Kelas osg :: Geode adalah terminal, yang disebut "daun" simpul pohon adegan. Itu tidak dapat memiliki node anak, tetapi berisi semua informasi yang diperlukan untuk rendering geometri. Namanya, Geode, adalah kependekan dari simpul geometri.
Data geometris yang akan diproses oleh mesin disimpan dalam sekumpulan objek dari kelas osg :: Drawable, dikelola oleh kelas osg :: Geode. The osg :: Drawable class adalah murni kelas virtual. Sejumlah subclass diwarisi darinya, yang merupakan model tiga dimensi, gambar dan teks yang diproses oleh pipa OpenGL. OSG mengacu pada drawable karena semua elemen yang dapat ditarik oleh mesin.
Kelas osg :: Geode menyediakan sejumlah metode untuk melampirkan dan melepaskan drawable:
- Metode publik addDrawable () - meneruskan sebuah pointer ke elemen yang dapat digambar dalam instance dari kelas osg :: Geode. Semua elemen ini dikendalikan oleh osg :: ref_ptr <> smart pointer.
- Metode publik removeDrawable () dan removeDrawables () menghapus objek dari osg :: Geode dan mengurangi jumlah referensi untuk itu. Metode removeDrawable () mengambil sebagai parameter tunggal penunjuk ke elemen yang diminati, dan metode removeDrawables () mengambil dua parameter: indeks awal dan jumlah elemen yang akan dihapus dari array objek osg :: Geode.
- Metode getDrawable () mengembalikan pointer ke elemen pada indeks yang diteruskan sebagai parameter.
- Metode getNumDrawables () mengembalikan jumlah total elemen yang dilampirkan ke osg :: Geode. Misalnya, untuk menghapus semua elemen dari osg :: Geode, Anda dapat menggunakan kode tersebut
geode->removeDrawables(0, geode->getNumDrawables());
2. Menggambar bentuk sederhana
OSG menyediakan kelas osg :: ShapeDrawable, yang merupakan turunan dari kelas osg :: Drawable dan dirancang untuk membuat primitif tiga dimensi sederhana. Kelas ini mencakup objek osg :: Shape yang menyimpan informasi tentang geometri tertentu dan parameter lainnya. Primitif dihasilkan menggunakan metode setShape (), misalnya
shapeDrawable->setShape(new osg::Box(osg::Vec3(1.0f, 0.0f, 0.0f), 10.0f, 10.0f, 5.0f));
menciptakan kotak persegi panjang dengan pusat geometris di titik (1,0, 0,0, 0,0) dengan lebar dan tinggi 10 dan kedalaman 5 unit. Kelas osg :: Vec3 mendefinisikan vektor dalam ruang tiga dimensi (selain itu, kelas osg :: Vec2 dan osg :: Vec4 yang menggambarkan vektor dari dimensi yang sesuai juga disajikan).
Primitif paling populer diwakili dalam OSG oleh kelas osg :: Box, osg :: Capsule, osg :: Cone, osg :: Cylinder dan osg :: Sphere.
Perhatikan contoh penerapan mekanisme ini.
main.h #ifndef MAIN_H #define MAIN_H #include <osg/ShapeDrawable> #include <osg/Geode> #include <osgViewer/Viewer> #endif // MAIN_H
main.cpp #include "main.h" int main(int argc, char *argv[]) { (void) argc; (void) argv; osg::ref_ptr<osg::ShapeDrawable> shape1 = new osg::ShapeDrawable; shape1->setShape(new osg::Box(osg::Vec3(-3.0f, 0.0f, 0.0f), 2.0f, 2.0f, 1.0f)); osg::ref_ptr<osg::ShapeDrawable> shape2 = new osg::ShapeDrawable; shape2->setShape(new osg::Cone(osg::Vec3(0.0f, 0.0f, 0.0f), 1.0f, 1.0f)); shape2->setColor(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); osg::ref_ptr<osg::ShapeDrawable> shape3 = new osg::ShapeDrawable; shape3->setShape(new osg::Sphere(osg::Vec3(3.0f, 0.0f, 0.0f), 1.0f)); shape3->setColor(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f)); osg::ref_ptr<osg::Geode> root = new osg::Geode; root->addDrawable(shape1.get()); root->addDrawable(shape2.get()); root->addDrawable(shape3.get()); osgViewer::Viewer viewer; viewer.setSceneData(root.get()); return viewer.run(); }
Contoh ini terutama tidak memerlukan komentar: dalam program tiga bentuk sederhana dibuat, setelah kompilasi dan peluncuran kita akan melihat hasil seperti itu

Mekanisme yang ditunjukkan dalam contoh ini sederhana dan mudah, tetapi itu bukan cara paling efektif untuk membuat geometri dan dapat digunakan secara eksklusif untuk pengujian. Kelas osg :: Geometry digunakan untuk membuat geometri dalam aplikasi berbasis OSG kinerja tinggi.
3. Penyimpanan data geometri: kelas osg :: Array dan osg :: Geometri
Kelas osg :: Array adalah kelas abstrak dasar, yang darinya beberapa keturunan diwarisi, dirancang untuk menyimpan data yang diteruskan ke fungsi OpenGL. Bekerja dengan kelas ini mirip dengan bekerja dengan std :: vector dari pustaka standar C ++. Kode berikut menggambarkan menambahkan vektor ke array vertex menggunakan metode push_back ()
vertices->push_back(osg::Vec3(1.0f, 0.0f, 0.0f));
Array OSG dialokasikan pada heap dan dikelola oleh smart pointer. Namun, ini tidak berlaku untuk elemen array, seperti osg :: Vec3 atau osg :: Vec2, yang juga dapat dibuat di stack.
Kelas osg :: Geometry adalah pembungkus fungsi OpenGL yang bekerja dengan array vertex. Ini diturunkan dari kelas osg :: Drawable dan dapat dengan mudah ditambahkan ke daftar objek osg :: Geode. Kelas ini mengambil array yang dijelaskan di atas sebagai input dan menggunakannya untuk menghasilkan geometri menggunakan OpenGL.
4. Verteks dan atributnya
Vertex adalah satuan atom primitif geometri. Ini memiliki sejumlah atribut yang menggambarkan suatu titik dalam ruang dua atau tiga dimensi. Atribut meliputi: posisi, warna, vektor normal, koordinat tekstur, koordinat kabut, dan sebagainya. Bagian atas harus selalu memiliki posisi dalam ruang, seperti untuk atribut lainnya, mereka dapat hadir secara opsional. OpenGL mendukung 16 atribut simpul dasar dan dapat menggunakan berbagai array untuk menyimpannya. Semua array atribut didukung oleh osg :: Geometry class dan dapat diatur menggunakan metode dari form set * Array ().
Atribut Vertex dalam OpenSceneGraphAtribut | Tipe data | Osg :: Metode Geometri | Panggilan OpenGL Setara |
---|
Posisi | 3-vektor | setVertexArray () | glVertexPointer () |
Normal | 3-vektor | setNormalArray () | glNormalPointer () |
Warna | 4-vektor | setColorArray () | glColorPointer () |
Warna sekunder | 4-vektor | setSecondaryColorArray () | glSecondaryColorPointerEXT () |
Koordinat Kabut | mengapung | setFogCoordArray () | glFogCoordPointerEXT () |
Koordinat tekstur | 2- atau 3-vektor | setTexCoordArray () | glTexCoordPointer () |
Atribut lainnya | Ditentukan Pengguna | setVertexArribArray () | glVertexAttribPointerARB () |
Pada prinsipnya, perlu untuk mengatur atribut Anda sendiri untuk masing-masing simpul, yang mengarah pada pembentukan beberapa array atribut dengan ukuran yang sama - jika tidak, ketidaksesuaian dalam ukuran array dapat menyebabkan perilaku mesin yang tidak ditentukan. OSG mendukung berbagai metode untuk menghubungkan atribut vertex, misalnya
geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
berarti bahwa setiap titik dan setiap warna titik saling berkorelasi satu sama lain. Namun, jika Anda melihat kode tersebut
geom->setColorBinding(osg::Geometry::BIND_OVERALL);
lalu dia menerapkan satu warna ke seluruh geometri. Demikian pula, hubungan antara atribut lain dapat dikonfigurasi dengan memanggil metode setNormalBinding (), setSecondaryColorBinding (), setFogCoordBinding (), dan setVertexAttribBinding ().
5. Set primitif geometri
Langkah selanjutnya setelah mendefinisikan array atribut vertex adalah untuk menggambarkan bagaimana data vertex akan diberikan. Virtual osg :: PrimitiveSet class digunakan untuk mengontrol primitif geometri yang dihasilkan oleh renderer dari sekumpulan simpul. The osg :: Kelas Geometri menyediakan beberapa metode untuk bekerja dengan set primitif geometri:
- addPrimitiveSet () - meneruskan pointer ke sekumpulan primitif di objek osg :: Geometry.
- removePrimitiveSet () - menghapus satu set primitif. Sebagai parameter, dibutuhkan indeks awal set dan jumlah set yang akan dihapus.
- getPrimitiveSet () - mengembalikan seperangkat primitif pada indeks yang diteruskan sebagai parameter.
- getNumPrimitiveSets () - mengembalikan jumlah total set primitif yang terkait dengan geometri ini.
Kelas osg :: PrimitiveSet adalah abstrak dan tidak dapat dipakai, tetapi beberapa kelas turunan yang merangkum set primitif yang beroperasi dengan OpenGL, seperti osg :: DrawArrays dan osg :: DrawElementsUInt, mewarisi darinya.
Kelas osg :: DrawArrays menggunakan beberapa elemen berturut-turut dari sebuah array vertex untuk membangun sebuah geometri primitif. Itu dapat dibuat dan dilampirkan ke geometri dengan memanggil metode.
geom->addPrimitiveSet(new osg::DrawArrays(mode, first, count));
Mode parameter pertama menetapkan tipe primitif ke tipe primitif OpenGL yang sesuai: GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, GL_QUAD_STRIP, GL_QUADS dan GL_POL.
Parameter pertama dan kedua menentukan indeks pertama dalam array verteks dan jumlah simpul dari mana geometri harus dihasilkan.
Selain itu, OSG tidak memeriksa apakah jumlah simpul yang ditentukan cukup untuk membangun geometri yang ditentukan oleh mode, yang dapat menyebabkan aplikasi crash!6. Contoh - menggambar kotak dicat
Kami menerapkan semua hal di atas sebagai contoh sederhana
Kode sumber lengkap untuk contoh quadmain.h #ifndef MAIN_H #define MAIN_H #include <osg/Geometry> #include <osg/Geode> #include <osgViewer/Viewer> #endif // MAIN_H
main.cpp #include "main.h" int main(int argc, char *argv[]) { osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; vertices->push_back(osg::Vec3(0.0f, 0.0f, 0.0f)); vertices->push_back(osg::Vec3(1.0f, 0.0f, 0.0f)); vertices->push_back(osg::Vec3(1.0f, 0.0f, 1.0f)); vertices->push_back(osg::Vec3(0.0f, 0.0f, 1.0f)); osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f)); osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array; colors->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); colors->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); colors->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f)); colors->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); osg::ref_ptr<osg::Geometry> quad = new osg::Geometry; quad->setVertexArray(vertices.get()); quad->setNormalArray(normals.get()); quad->setNormalBinding(osg::Geometry::BIND_OVERALL); quad->setColorArray(colors.get()); quad->setColorBinding(osg::Geometry::BIND_PER_VERTEX); quad->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4)); osg::ref_ptr<osg::Geode> root = new osg::Geode; root->addDrawable(quad.get()); osgViewer::Viewer viewer; viewer.setSceneData(root.get()); return viewer.run(); }
Setelah kompilasi dan eksekusi, kami mendapatkan hasil yang mirip dengan ini

Contoh ini perlu klarifikasi. Jadi, pertama-tama, kita membuat array simpul dari persegi, di mana koordinatnya disimpan
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; vertices->push_back(osg::Vec3(0.0f, 0.0f, 0.0f)); vertices->push_back(osg::Vec3(1.0f, 0.0f, 0.0f)); vertices->push_back(osg::Vec3(1.0f, 0.0f, 1.0f)); vertices->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));
Selanjutnya kita atur array normals. Dalam kasus sederhana kami, kami tidak perlu membuat yang normal untuk setiap titik - cukup jelaskan satu unit vektor yang diarahkan tegak lurus ke bidang persegi
osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));
Atur warna untuk setiap titik
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array; colors->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); colors->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); colors->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f)); colors->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
Sekarang buat objek geometri tempat deskripsi kuadrat kita akan disimpan, yang akan diproses oleh render. Kami melewati array simpul ke geometri ini
osg::ref_ptr<osg::Geometry> quad = new osg::Geometry; quad->setVertexArray(vertices.get());
Melewati array normals, kami memberi tahu mesin bahwa satu normal tunggal akan digunakan untuk semua simpul, dengan menentukan metode penjilidan ("binding") dari normals BIND_OVAERALL
quad->setNormalArray(normals.get()); quad->setNormalBinding(osg::Geometry::BIND_OVERALL);
Melewati warna simpul, sebaliknya, kami menunjukkan bahwa setiap simpul akan memiliki warna sendiri
quad->setColorArray(colors.get()); quad->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
Sekarang buat satu set primitif untuk geometri. Kami menunjukkan bahwa wajah kuadrat (GL_QUADS) harus dihasilkan dari array vertex, mengambil verteks dengan indeks 0 sebagai verteks pertama, dan jumlah total simpul akan menjadi 4
quad->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));
Yah, saya pikir itu tidak layak menjelaskan transfer geometri dan peluncuran render
osg::ref_ptr<osg::Geode> root = new osg::Geode; root->addDrawable(quad.get()); osgViewer::Viewer viewer; viewer.setSceneData(root.get()); return viewer.run();
Kode di atas setara dengan desain berikut di OpenGL murni
static const GLfloat vertices[][3] = { … }; glEnableClientState( GL_VERTEX_ARRAY ); glVertexPointer( 4, GL_FLOAT, 0, vertices ); glDrawArrays( GL_QUADS, 0, 4 );
7. Mengindeks simpul dalam primitif
Kelas osg :: DrawArrays berfungsi dengan baik saat membaca data titik langsung dari array, tanpa celah. Namun, ini tidak begitu efektif ketika simpul yang sama dapat dimiliki oleh beberapa wajah dari suatu objek. Mari kita lihat sebuah contoh.

Kubus memiliki delapan simpul. Namun, seperti yang dapat dilihat dari gambar (kita melihat pembukaan kubus di pesawat) beberapa simpul milik lebih dari satu wajah. Jika Anda membuat kubus dengan 12 wajah segitiga, maka simpul-simpul ini akan diulang, dan alih-alih array 8 simpul, kita mendapatkan array yang terdiri dari 36 simpul, yang sebagian besar sebenarnya adalah simpul yang sama!
Kelas OSG osg :: DrawElementsUInt, osg :: DrawElementsUByte dan osg :: DrawElementsUShort, yang menggunakan array indeks titik sebagai data, dirancang untuk menyelesaikan masalah yang dijelaskan. Susunan indeks menyimpan indeks simpul primitif yang menggambarkan wajah dan elemen geometri lainnya. Ketika menerapkan kelas-kelas ini untuk sebuah kubus, itu cukup untuk menyimpan array delapan simpul yang terkait dengan wajah melalui array indeks.
Kelas tipe osg :: DrawElements * dibangun dengan cara yang sama dengan kelas standar std :: vector. Kode semacam itu dapat digunakan untuk menambahkan indeks.
osg::ref_ptr<osg::DrawElementsUInt> de = new osg::DrawElementsUInt(GL_TRIANGLES); de->push_back(0); de->push_back(1); de->push_back(2); de->push_back(3); de->push_back(0); de->push_back(2);
Kode ini mendefinisikan muka depan kubus yang ditunjukkan pada gambar.
Mari kita pertimbangkan satu contoh ilustratif lagi - octahedron

Ini menarik karena hanya berisi enam simpul, tetapi setiap simpul masuk sebanyak empat wajah segitiga! Kita dapat membuat array 24 simpul untuk menampilkan kedelapan wajah menggunakan osg :: DrawArrays. Namun, kita akan melakukan sebaliknya - kita akan menyimpan simpul dalam array enam elemen, dan kita menghasilkan wajah menggunakan kelas osg :: DrawElementsUInt.
Sumber lengkap untuk contoh segi delapanmain.h #ifndef MAIN_H #define MAIN_H #include <osg/Geometry> #include <osg/Geode> #include <osgUtil/SmoothingVisitor> #include <osgViewer/Viewer> #endif
main.cpp #include "main.h" int main(int argc, char *argv[]) { osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array(6); (*vertices)[0].set( 0.0f, 0.0f, 1.0f); (*vertices)[1].set(-0.5f, -0.5f, 0.0f); (*vertices)[2].set( 0.5f, -0.5f, 0.0f); (*vertices)[3].set( 0.5f, 0.5f, 0.0f); (*vertices)[4].set(-0.5f, 0.5f, 0.0f); (*vertices)[5].set( 0.0f, 0.0f, -1.0f); osg::ref_ptr<osg::DrawElementsUInt> indices = new osg::DrawElementsUInt(GL_TRIANGLES, 24); (*indices)[ 0] = 0; (*indices)[ 1] = 1; (*indices)[ 2] = 2; (*indices)[ 3] = 0; (*indices)[ 4] = 4; (*indices)[ 5] = 1; (*indices)[ 6] = 4; (*indices)[ 7] = 5; (*indices)[ 8] = 1; (*indices)[ 9] = 4; (*indices)[10] = 3; (*indices)[11] = 5; (*indices)[12] = 3; (*indices)[13] = 2; (*indices)[14] = 5; (*indices)[15] = 1; (*indices)[16] = 5; (*indices)[17] = 2; (*indices)[18] = 3; (*indices)[19] = 0; (*indices)[20] = 2; (*indices)[21] = 0; (*indices)[22] = 3; (*indices)[23] = 4; osg::ref_ptr<osg::Geometry> geom = new osg::Geometry; geom->setVertexArray(vertices.get()); geom->addPrimitiveSet(indices.get()); osgUtil::SmoothingVisitor::smooth(*geom); osg::ref_ptr<osg::Geode> root = new osg::Geode; root->addDrawable(geom.get()); osgViewer::Viewer viewer; viewer.setSceneData(root.get()); return viewer.run(); }
Mari kita menganalisis kode ini lebih terinci. Tentu saja, hal pertama yang kita lakukan adalah membuat array enam simpul
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array(6); (*vertices)[0].set( 0.0f, 0.0f, 1.0f); (*vertices)[1].set(-0.5f, -0.5f, 0.0f); (*vertices)[2].set( 0.5f, -0.5f, 0.0f); (*vertices)[3].set( 0.5f, 0.5f, 0.0f); (*vertices)[4].set(-0.5f, 0.5f, 0.0f); (*vertices)[5].set( 0.0f, 0.0f, -1.0f);
Kami menginisialisasi setiap titik secara langsung dengan mengakses vektor koordinatnya menggunakan operasi penunjuk titik dari operator penunjuk dan operator [] (kami ingat bahwa osg :: Array serupa di perangkatnya dengan std :: vector).
Sekarang buat wajah sebagai daftar indeks titik
osg::ref_ptr<osg::DrawElementsUInt> indices = new osg::DrawElementsUInt(GL_TRIANGLES, 24); (*indices)[ 0] = 0; (*indices)[ 1] = 1; (*indices)[ 2] = 2;
Wajah akan berbentuk segitiga, akan ada 8, yang berarti daftar indeks harus berisi 24 elemen. Indeks wajah berjalan berurutan dalam larik ini: misalnya, wajah 0 dibentuk oleh simpul 0, 1, dan 2; wajah 1 - simpul 0, 4 dan 1; wajah 2 - simpul 4, 5 dan 1 dan seterusnya. Verteks terdaftar dalam urutan berlawanan jika Anda melihat wajah wajah (lihat gambar di atas).
Langkah-langkah lebih lanjut untuk membuat geometri yang kami lakukan dalam contoh sebelumnya. Satu-satunya hal yang tidak kami lakukan adalah pembuatan otomatis normals yang dihaluskan (rata-rata), yang kami lakukan dalam contoh ini dengan memanggil
osgUtil::SmoothingVisitor::smooth(*geom);
Memang, jika simpul dari sebuah wajah diberikan, maka mudah untuk menghitung normalnya. Pada titik-titik di mana beberapa wajah bertemu, normal rata-rata tertentu dihitung - normal dari wajah yang bertemu ditambahkan dan jumlah yang dihasilkan dinormalisasi lagi. Operasi-operasi ini (dan juga banyak lagi!) Dapat dilakukan oleh mesin itu sendiri menggunakan kelas-kelas dari perpustakaan osgUtil. Oleh karena itu, dalam contoh kami, kami akan menambahkan instruksi ke linker untuk membangun program kami dengan perpustakaan ini di file * .pro
octahedron.pro CONFIG(debug, debug|release) { TARGET = $$join(TARGET,,,_d) . . . LIBS += -L$$OSG_LIB_DIRECTORY -losgUtild } else { . . . LIBS += -L$$OSG_LIB_DIRECTORY -losgUtil }
Hasilnya, kami mendapatkan hasil berikut

Untuk memahami cara kerjanya, pertimbangkan pipa OpenGL

Mekanisme array vertex mengurangi jumlah panggilan OpenGL. Ini menyimpan data titik dalam memori aplikasi, yang digunakan pada sisi klien. Pipa OpenGL pada sisi server mendapat akses ke berbagai array vertex. Seperti yang ditunjukkan dalam diagram, OpenGL menerima data dari buffer vertex di sisi klien dan, secara teratur, melakukan perakitan primitif. Ini adalah bagaimana data diproses menggunakan metode set * Array () dari kelas osg :: Geometry. Kelas osg :: DrawArrays melewati array ini secara langsung dan menampilkannya.
Saat menggunakan osg :: DrawElements *, dimensi array verteks berkurang dan jumlah simpul yang ditransfer ke pipa berkurang. Array indeks memungkinkan Anda membuat cache vertex di sisi server. OpenGL membaca data vertex dari cache, alih-alih membaca dari buffer vertex di sisi klien. Ini secara signifikan meningkatkan kinerja rendering keseluruhan.
8. Teknik pengolahan mesh poligon
OpenSceneGraph mendukung berbagai teknik untuk memproses mesh poligon objek geometri pemandangan. Metode preprocessing ini, seperti pengurangan poligon dan tessellation, sering digunakan untuk membuat dan mengoptimalkan model poligon. Mereka memiliki antarmuka yang sederhana, tetapi dalam prosesnya mereka melakukan banyak perhitungan yang rumit dan tidak terlalu cocok untuk eksekusi on-the-fly.
Teknik yang dijelaskan meliputi:
- osgUtil :: Simplifier - mengurangi jumlah segitiga dalam geometri. Metode publik simplify () digunakan untuk menyederhanakan geometri model.
- osgUtil :: SmootingVisitor - penghitungan normals. Metode smooth () dapat digunakan untuk menghasilkan normals yang dihaluskan untuk model, alih-alih secara independen menghitungnya dan secara eksplisit mengaturnya melalui array normals.
- osgUtil :: TangentSpaceGenerator - generasi vektor basis garis singgung untuk simpul model. Ini diluncurkan dengan memanggil metode generate () dan menyimpan hasilnya dikembalikan oleh getTangentArray (), getNormalArray (), dan getBinormalArray () method. Hasil ini dapat digunakan untuk berbagai atribut simpul saat menulis shader di GLSL.
- osgUtil :: Tesselator - melakukan tessellation poligon - membagi primitif kompleks menjadi urutan yang sederhana (metode retesselatePolygons ())
- osgUtil :: TriStripVisitor - mengubah permukaan geometris menjadi set strip wajah segitiga, yang memungkinkan rendering dengan konsumsi memori yang efisien. Metode stripify () mengubah satu set primitif model menjadi geometri berdasarkan pada set GL_TRIANGLE_STRIP.
Semua metode menerima geometri objek sebagai parameter yang dilewatkan oleh osg :: Geometri & tautan, misalnya seperti ini
osgUtil::TriStripVisitor tsv; tsv.stripify(*geom);
di mana geom mengacu pada contoh geometri yang dijelaskan oleh penunjuk pintar.
Kelas osg :: Simplifier, osg :: SmoothingVisitor dan osg :: TriStripVisitor dapat bekerja secara langsung dengan node dalam grafik adegan, misalnya
osgUtil::TriStripVisitor tsv; node->accept(tsv);
Metode accept () memproses semua node anak hingga operasi yang ditentukan diterapkan ke semua node terminal dari bagian pohon adegan yang disimpan dalam node tipe osg :: Geode.
Mari kita coba teknik tessellation dalam praktek.
Kode contoh tesselator penuhmain.h #ifndef MAIN_H #define MAIN_H #include <osg/Geometry> #include <osg/Geode> #include <osgUtil/Tessellator> #include <osgViewer/Viewer> #endif
main.cpp #include "main.h" int main(int argc, char *argv[]) { osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; vertices->push_back( osg::Vec3(0.0f, 0.0f, 0.0f) ); // 0 vertices->push_back( osg::Vec3(2.0f, 0.0f, 0.0f) ); // 1 vertices->push_back( osg::Vec3(2.0f, 0.0f, 1.0f) ); // 2 vertices->push_back( osg::Vec3(1.0f, 0.0f, 1.0f) ); // 3 vertices->push_back( osg::Vec3(1.0f, 0.0f, 2.0f) ); // 4 vertices->push_back( osg::Vec3(2.0f, 0.0f, 2.0f) ); // 5 vertices->push_back( osg::Vec3(2.0f, 0.0f, 3.0f) ); // 6 vertices->push_back( osg::Vec3(0.0f, 0.0f, 3.0f) ); // 7 osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array; normals->push_back( osg::Vec3(0.0f, -1.0f, 0.0f) ); osg::ref_ptr<osg::Geometry> geom = new osg::Geometry; geom->setVertexArray(vertices.get()); geom->setNormalArray(normals.get()); geom->setNormalBinding(osg::Geometry::BIND_OVERALL); geom->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 8)); osg::ref_ptr<osg::Geode> root = new osg::Geode; root->addDrawable(geom.get()); osgViewer::Viewer viewer; viewer.setSceneData(root.get()); return viewer.run(); }
Berdasarkan posisi spasial dari simpul dalam contoh ini, jelas bahwa kami mencoba membuat poligon non-cembung dari delapan simpul, menggunakan generasi satu wajah dari tipe GL_POLYGON. Perakitan dan pelaksanaan contoh ini menunjukkan bahwa hasil yang kami harapkan tidak berfungsi - contohnya ditampilkan secara tidak benar

Untuk memperbaiki masalah ini, geometri yang dibangun harus di-tessellasikan sebelum meneruskannya ke pemirsa
osgUtil::Tessellator ts; ts.retessellatePolygons(*geom);
setelah itu kita mendapatkan hasil yang benar

Bagaimana cara kerjanya? Poligon non-cembung, tanpa menggunakan tessellation yang benar, tidak akan ditampilkan seperti yang kami harapkan, karena OpenGL, yang berupaya mengoptimalkan kinerja, akan menganggapnya sebagai poligon cembung sederhana atau mengabaikannya, yang dapat memberikan hasil yang benar-benar tak terduga.
Kelas osgUtil :: Tessellator menggunakan algoritma untuk mengubah poligon cembung menjadi serangkaian non-cembung - dalam kasus kami, ia mengubah geometri menjadi GL_TRIANGLE_STRIP.
Kelas ini dapat menangani poligon lubang dan poligon yang memotong sendiri. Menggunakan metode setWindingType () publik, Anda dapat menentukan berbagai aturan pemrosesan, seperti GLU_TESS_WINDING_ODD atau GLU_TESS_WINDING_NONZERO, yang menentukan wilayah bagian dalam dan luar dari poligon kompleks.Kesimpulan
Pada artikel ini, kami mendapat pemahaman dasar tentang bagaimana geometri objek tiga dimensi disimpan dan diproses dalam mesin OSG. Jangan berpikir bahwa contoh sederhana dan tidak terlalu mengesankan yang dipertimbangkan dalam artikel adalah batas kemampuan mesin. Hanya contoh-contoh ini yang dapat membantu pengembang memahami mekanisme OpenSceneGraph, dan tanpa pemahaman ini sulit membayangkan pekerjaan dari hal-hal yang lebih kompleks.Artikel ini didasarkan pada terjemahan dan pemrosesan teks dari bab-bab yang sesuai dari buku OpenSceneGraph 3.0. Panduan Pemula . Semua contoh diperiksa oleh saya secara pribadi, dan kode sumbernya tersedia di sini . Dilanjutkan ...