OpenSceneGraph: Dasar-dasar Tekstur

gambar

Pendahuluan


Kami telah memeriksa contoh di mana mereka melukis sebuah persegi dengan semua warna pelangi. Namun demikian, ada teknologi lain, yaitu aplikasi untuk geometri tiga dimensi dari apa yang disebut peta tekstur atau hanya tekstur - gambar raster dua dimensi. Dalam hal ini, efeknya bukan pada simpul geometri, tetapi data dari semua piksel yang diperoleh saat adegan diraster diubah. Teknik ini secara signifikan dapat meningkatkan realisme dan detail gambar akhir.

OSG mendukung beberapa atribut tekstur dan mode tekstur. Tetapi, sebelum berbicara tentang tekstur, mari kita bicara tentang bagaimana OSG menangani gambar bitmap. Untuk bekerja dengan gambar raster, kelas khusus disediakan - osg :: Image, yang menyimpan data gambar di dalamnya, dimaksudkan, pada akhirnya, untuk texturing objek.

1. Penyajian data gambar raster. Kelas Osg :: Gambar


Cara terbaik untuk memuat gambar dari disk adalah dengan menggunakan panggilan osgDB :: readImageFile (). Ini sangat mirip dengan panggilan osg :: readNodeFile (), yang sudah membuat kita bosan. Jika kita memiliki bitmap bernama picture.bmp, maka memuatnya akan terlihat seperti ini

osg::ref_ptr<osg::Image> image = osgDB::readImageFile("picture.bmp"); 

Jika gambar dimuat dengan benar, maka pointer akan valid, jika tidak fungsi akan mengembalikan NULL. Setelah mengunduh, kami dapat memperoleh informasi gambar menggunakan metode publik berikut

  1. t (), s () dan r () - mengembalikan lebar, tinggi, dan kedalaman gambar.
  2. data () - mengembalikan pointer dari tipe unsigned char * ke data gambar "raw". Melalui pointer ini, pengembang dapat langsung bertindak pada data gambar. Anda bisa mendapatkan gagasan tentang format data gambar menggunakan metode getPixalFormat () dan getDataType (). Nilai yang dikembalikan oleh mereka setara dengan parameter format dan jenis fungsi OpenGL glTexImage * (). Misalnya, jika gambar memiliki format piksel GL_RGB dan jenisnya adalah GL_UNSIGNED_BYTE, maka tiga elemen independen (byte tanpa tanda) digunakan untuk mewakili komponen warna RGB



Anda dapat membuat objek gambar baru dan mengalokasikan memori untuk itu.

 osg::ref_ptr<osg::Image> image = new osg::Image; image->allocateImage(s, t, r, GL_RGB, GL_UNSIGNED_BYTE); unsigned char *ptr = image->data(); //         

Ini s, t, r adalah ukuran gambar; GL_RGB menetapkan format piksel, dan GL_UNSIGNED_BYTE menetapkan tipe data untuk menggambarkan komponen warna tunggal. Buffer data internal ukuran yang diperlukan dialokasikan dalam memori dan secara otomatis dihancurkan jika tidak ada tautan tunggal ke gambar ini.

Sistem plug-in OSG mendukung pengunduhan hampir semua format gambar populer: * .jpg, * .bmp, * .png, * .tif, dan sebagainya. Daftar ini mudah diperluas dengan menulis plugin Anda sendiri, tetapi ini adalah topik untuk diskusi lain.

2. Dasar-dasar tekstur


Untuk menerapkan tekstur ke model tiga dimensi, Anda perlu melakukan sejumlah langkah:

  1. Tentukan koordinat tekstur simpul untuk objek geometris (di lingkungan desainer 3D, ini disebut pemindaian UV).
  2. Buat objek atribut tekstur untuk 1D, 2D, 3D, atau tekstur kubik.
  3. Tetapkan satu atau lebih gambar untuk atribut tekstur.
  4. Lampirkan atribut dan mode tekstur ke set status yang diterapkan pada objek yang sedang digambar.

OSG mendefinisikan osg :: Texture class, yang merangkum semua jenis tekstur. Subkelas osg :: Texture1D, osg :: Texture2D, osg :: Texture3D dan osg :: TextureCubeMap diwarisi darinya, yang mewakili berbagai teknik tekstur yang diadopsi dalam OpenGL.

Osg yang paling umum: Metode kelas tekstur adalah setImage (), yang menetapkan gambar yang digunakan dalam tekstur, misalnya

 osg::ref_ptr<osg::Image> image = osgDB::readImageFile("picture.bmp"); osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D; texture->setImage(image.get()); 

atau, Anda dapat mengirimkan objek gambar langsung ke konstruktor kelas tekstur

 osg::ref_ptr<osg::Image> image = osgDB::readImageFile("picture.bmp"); osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D(image.get()); 

Gambar dapat diambil dari objek tekstur dengan memanggil metode getImage ().

Poin penting lainnya adalah mengatur koordinat tekstur untuk setiap titik di objek osg :: Geometry. Transfer koordinat ini terjadi melalui array osg :: Vec2Array dan osg :: Vec3Array dengan memanggil metode setTexCoordArray ().

Setelah mengatur koordinat tekstur, kita perlu mengatur nomor slot tekstur (unit), karena OSG mendukung superimposing banyak tekstur pada geometri yang sama. Saat menggunakan tekstur tunggal, angka satuan selalu 0. Sebagai contoh, kode berikut menggambarkan pengaturan koordinat tekstur untuk unit 0 dari geometri

 osf::ref_ptr<osg::Vec2Array> texcoord = new osg::Vec2Array; texcoord->push_back( osg::Vec2(...) ); ... geom->setTexCoordArray(0, texcoord.get()); 

Setelah itu, kita dapat menambahkan atribut tekstur ke set status, secara otomatis menyalakan mode tekstur yang sesuai (dalam contoh kita GL_TEXTURE_2D) dan menerapkan atribut ke geometri atau simpul yang berisi geometri ini

 geom->getOrCreateStateSet()->setTextureAttributeAndModes(texture.get()); 

Harap dicatat bahwa OpenGL mengelola data gambar dalam memori grafis kartu video, tetapi objek osg :: Image bersama dengan data yang sama terletak di memori sistem. Akibatnya, kita akan menghadapi kenyataan bahwa kita telah menyimpan dua salinan dari data yang sama, menempati memori proses. Jika gambar ini tidak dibagi oleh beberapa atribut tekstur, gambar dapat dihapus dari memori sistem segera setelah OpenGL mentransfernya ke memori adaptor video. Kelas osg :: Texture menyediakan metode yang sesuai untuk mengaktifkan fungsi ini.

 texture->setUnRefImageDataAfterApply( true ); 

3. Muat dan terapkan tekstur 2D


Teknik yang paling umum digunakan adalah texturing 2D - overlay gambar dua dimensi (atau gambar) di tepi permukaan tiga dimensi. Pertimbangkan contoh paling sederhana untuk menerapkan tekstur tunggal ke poligon segi empat

Contoh tekstur
main.h

 #ifndef MAIN_H #define MAIN_H #include <osg/Texture2D> #include <osg/Geometry> #include <osgDB/ReadFile> #include <osgViewer/Viewer> #endif 

main.cpp

 #include "main.h" int main(int argc, char *argv[]) { (void) argc; (void) argv; osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; vertices->push_back( osg::Vec3(-0.5f, 0.0f, -0.5f) ); vertices->push_back( osg::Vec3( 0.5f, 0.0f, -0.5f) ); vertices->push_back( osg::Vec3( 0.5f, 0.0f, 0.5f) ); vertices->push_back( osg::Vec3(-0.5f, 0.0f, 0.5f) ); osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array; normals->push_back( osg::Vec3(0.0f, -1.0f, 0.0f) ); osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array; texcoords->push_back( osg::Vec2(0.0f, 0.0f) ); texcoords->push_back( osg::Vec2(0.0f, 1.0f) ); texcoords->push_back( osg::Vec2(1.0f, 1.0f) ); texcoords->push_back( osg::Vec2(1.0f, 0.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->setTexCoordArray(0, texcoords.get()); quad->addPrimitiveSet( new osg::DrawArrays(GL_QUADS, 0, 4) ); osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D; osg::ref_ptr<osg::Image> image = osgDB::readImageFile("../data/Images/lz.rgb"); texture->setImage(image.get()); osg::ref_ptr<osg::Geode> root = new osg::Geode; root->addDrawable(quad.get()); root->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture.get()); osgViewer::Viewer viewer; viewer.setSceneData(root.get()); return viewer.run(); } 


Buat array simpul dan normals ke wajah

 osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; vertices->push_back( osg::Vec3(-0.5f, 0.0f, -0.5f) ); vertices->push_back( osg::Vec3( 0.5f, 0.0f, -0.5f) ); vertices->push_back( osg::Vec3( 0.5f, 0.0f, 0.5f) ); vertices->push_back( osg::Vec3(-0.5f, 0.0f, 0.5f) ); osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array; normals->push_back( osg::Vec3(0.0f, -1.0f, 0.0f) ); 

Buat array koordinat tekstur

 osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array; texcoords->push_back( osg::Vec2(0.0f, 0.0f) ); texcoords->push_back( osg::Vec2(0.0f, 1.0f) ); texcoords->push_back( osg::Vec2(1.0f, 1.0f) ); texcoords->push_back( osg::Vec2(1.0f, 0.0f) ); 

Intinya adalah bahwa setiap simpul dari model tiga dimensi sesuai dengan titik pada tekstur dua dimensi, dan koordinat titik pada tekstur relatif - mereka dinormalisasi dengan lebar aktual dan tinggi gambar. Kami ingin meregangkan seluruh gambar yang dimuat ke kotak, masing-masing, sudut kotak akan sesuai dengan titik tekstur (0, 0), (0, 1), (1, 1) dan (1, 0). Urutan simpul dalam array vertex harus sesuai dengan urutan simpul tekstur.

Selanjutnya, buat kotak, menugaskan geometri array simpul dan array normals

 osg::ref_ptr<osg::Geometry> quad = new osg::Geometry; quad->setVertexArray(vertices.get()); quad->setNormalArray(normals.get()); quad->setNormalBinding(osg::Geometry::BIND_OVERALL); quad->setTexCoordArray(0, texcoords.get()); quad->addPrimitiveSet( new osg::DrawArrays(GL_QUADS, 0, 4) ); 

Buat objek tekstur dan muat gambar yang digunakan untuk itu.

 osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D; osg::ref_ptr<osg::Image> image = osgDB::readImageFile("../data/Images/lz.rgb"); texture->setImage(image.get()); 

Buat simpul akar adegan dan letakkan geometri yang kami buat di sana

 osg::ref_ptr<osg::Geode> root = new osg::Geode; root->addDrawable(quad.get()); 

dan akhirnya menerapkan atribut tekstur ke simpul di mana geometri ditempatkan

 root->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture.get()); 



Kelas osg :: Texture2D menentukan apakah ukuran gambar tekstur merupakan kelipatan dari kekuatan dua (misalnya, 64x64 atau 256x512), secara otomatis skala gambar yang tidak sesuai untuk ukuran, sebenarnya menggunakan fungsi OpenGL gluScaleImage (). Ada metode setResizeNonPowerOfTwoHint () yang menentukan apakah akan mengubah ukuran gambar atau tidak. Beberapa kartu video memerlukan kelipatan ukuran gambar dengan kekuatan dua, sedangkan kelas osg :: Texture2D mendukung bekerja dengan ukuran tekstur yang sewenang-wenang.

Sesuatu Tentang Pencampuran Tekstur


Seperti yang telah kami katakan, koordinat tekstur dinormalisasi dari 0 hingga 1. Titik (0, 0) sesuai dengan sudut kiri atas gambar, dan titik (1, 1) sesuai dengan kanan bawah. Apa yang terjadi jika Anda menetapkan koordinat tekstur lebih dari satu?

Secara default, di OpenGL, seperti pada OSG, tekstur akan berulang dalam arah sumbu, nilai koordinat tekstur akan melebihi satu. Teknik ini sering digunakan, misalnya, untuk membuat model dinding bata yang panjang, saya menggunakan tekstur kecil, mengulangi superposisi berkali-kali baik lebar dan tinggi.

Perilaku ini dapat dikontrol melalui metode setWrap () dari kelas osg :: Texture. Sebagai parameter pertama, metode ini mengambil pengidentifikasi sumbu yang menerapkan mode campuran, diteruskan sebagai parameter kedua, misalnya

 //     s texture->setWrap( osg::Texture::WRAP_S, osg::Texture::REPEAT ); //     r texture->setWrap( osg::Texture::WRAP_R, osg::Texture::REPEAT ); 

Kode ini secara eksplisit memberi tahu mesin untuk mengulangi tekstur sepanjang sumbu s dan r jika nilai koordinat tekstur melebihi 1. Daftar lengkap mode pemetaan tekstur:

  1. REPEAT - ulangi tekstur.
  2. CERMIN - ulangi tekstur, mirroring itu.
  3. CLAMP_TO_EDGE - koordinat yang melampaui 0 hingga 1 diambil ke tepi tekstur yang sesuai.
  4. CLAMP_TO_BORDER - koordinat yang melampaui 0 hingga 1 akan memberikan warna batas yang ditetapkan oleh pengguna.

4. Rendering ke tekstur


Teknik rendering tekstur memungkinkan pengembang untuk membuat tekstur berdasarkan beberapa sub-adegan tiga dimensi atau model dan menerapkannya pada permukaan di adegan utama. Teknologi serupa sering disebut tekstur "memanggang".

Untuk memanggang tekstur secara dinamis, Anda harus menyelesaikan tiga langkah:

  1. Buat objek tekstur untuk dirender ke dalamnya.
  2. Jadikan adegan menjadi tekstur.
  3. Gunakan tekstur yang dihasilkan sebagaimana dimaksud.

Kita harus membuat objek tekstur kosong. OSG memungkinkan Anda membuat tekstur kosong dengan ukuran tertentu. Metode setTextureSize () memungkinkan Anda untuk mengatur lebar dan tinggi tekstur, serta kedalaman sebagai parameter tambahan (untuk tekstur 3D).

Untuk merender tekstur, Anda harus melampirkannya ke objek kamera dengan memanggil metode attach (), yang menggunakan objek tekstur sebagai argumen. Selain itu, metode ini menerima argumen yang menunjukkan bagian mana dari frame buffer yang harus diterjemahkan ke dalam tekstur ini. Misalnya, untuk mentransfer buffer warna ke tekstur, Anda harus menjalankan kode berikut

 camera->attach( osg::Camera::COLOR_BUFFER, texture.get() ); 

Bagian lain dari buffer bingkai yang tersedia untuk rendering termasuk buffer kedalaman DEPTH_BUFFER, buffer stensil STENCIL_BUFFER, dan buffer warna tambahan dari COLOR_BUFFER0 hingga COLOR_BUFFER15. Kehadiran buffer warna tambahan dan jumlahnya ditentukan oleh model kartu video.

Selain itu, untuk kamera yang merender menjadi tekstur, Anda harus mengatur parameter matriks proyeksi dan viewport, yang ukurannya sesuai dengan ukuran tekstur. Tekstur akan diperbarui saat setiap frame digambar. Perlu diingat bahwa kamera utama tidak boleh digunakan untuk rendering menjadi tekstur, karena memberikan rendering adegan utama dan Anda hanya mendapatkan layar hitam. Persyaratan ini mungkin tidak terpenuhi hanya ketika Anda melakukan rendering di luar layar.

5. Contoh implementasi rendering ke tekstur


Untuk mendemonstrasikan teknik rendering dalam tekstur, kami menerapkan tugas berikut: membuat kotak, menggambar tekstur kotak di atasnya, dan membuat adegan animasi ke dalam tekstur, tentu saja dengan cessna yang kita cintai. Program yang mengimplementasikan contoh ini cukup banyak. Namun, saya akan memberikan kode sumber lengkapnya.

Contoh Texrender
main.h

 #ifndef MAIN_H #define MAIN_H #include <osg/Camera> #include <osg/Texture2D> #include <osg/MatrixTransform> #include <osgDB/ReadFile> #include <osgGA/TrackballManipulator> #include <osgViewer/Viewer> #endif 

main.cpp

 #include "main.h" //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ osg::Geometry *createQuad(const osg::Vec3 &pos, float w, float h) { osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; vertices->push_back( pos + osg::Vec3( w / 2, 0.0f, -h / 2) ); vertices->push_back( pos + osg::Vec3( w / 2, 0.0f, h / 2) ); vertices->push_back( pos + osg::Vec3(-w / 2, 0.0f, h / 2) ); vertices->push_back( pos + osg::Vec3(-w / 2, 0.0f, -h / 2) ); osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f)); osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array; texcoords->push_back( osg::Vec2(1.0f, 1.0f) ); texcoords->push_back( osg::Vec2(1.0f, 0.0f) ); texcoords->push_back( osg::Vec2(0.0f, 0.0f) ); texcoords->push_back( osg::Vec2(0.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->setTexCoordArray(0, texcoords.get()); quad->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4)); return quad.release(); } //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ int main(int argc, char *argv[]) { (void) argc; (void) argv; osg::ref_ptr<osg::Node> sub_model = osgDB::readNodeFile("../data/cessna.osg"); osg::ref_ptr<osg::MatrixTransform> transform1 = new osg::MatrixTransform; transform1->setMatrix(osg::Matrix::rotate(0.0, osg::Vec3(0.0f, 0.0f, 1.0f))); transform1->addChild(sub_model.get()); osg::ref_ptr<osg::Geode> model = new osg::Geode; model->addChild(createQuad(osg::Vec3(0.0f, 0.0f, 0.0f), 2.0f, 2.0f)); int tex_widht = 1024; int tex_height = 1024; osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D; texture->setTextureSize(tex_widht, tex_height); texture->setInternalFormat(GL_RGBA); texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR); texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR); model->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture.get()); osg::ref_ptr<osg::Camera> camera = new osg::Camera; camera->setViewport(0, 0, tex_widht, tex_height); camera->setClearColor(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->setRenderOrder(osg::Camera::PRE_RENDER); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); camera->attach(osg::Camera::COLOR_BUFFER, texture.get()); camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); camera->addChild(transform1.get()); osg::ref_ptr<osg::Group> root = new osg::Group; root->addChild(model.get()); root->addChild(camera.get()); osgViewer::Viewer viewer; viewer.setSceneData(root.get()); viewer.setCameraManipulator(new osgGA::TrackballManipulator); viewer.setUpViewOnSingleScreen(0); camera->setProjectionMatrixAsPerspective(30.0, static_cast<double>(tex_widht) / static_cast<double>(tex_height), 0.1, 1000.0); float dist = 100.0f; float alpha = 10.0f * 3.14f / 180.0f; osg::Vec3 eye(0.0f, -dist * cosf(alpha), dist * sinf(alpha)); osg::Vec3 center(0.0f, 0.0f, 0.0f); osg::Vec3 up(0.0f, 0.0f, -1.0f); camera->setViewMatrixAsLookAt(eye, center, up); float phi = 0.0f; float delta = -0.01f; while (!viewer.done()) { transform1->setMatrix(osg::Matrix::rotate(static_cast<double>(phi), osg::Vec3(0.0f, 0.0f, 1.0f))); viewer.frame(); phi += delta; } return 0; } 


Untuk membuat kotak, tulis fungsi bebas terpisah

 osg::Geometry *createQuad(const osg::Vec3 &pos, float w, float h) { osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; vertices->push_back( pos + osg::Vec3( w / 2, 0.0f, -h / 2) ); vertices->push_back( pos + osg::Vec3( w / 2, 0.0f, h / 2) ); vertices->push_back( pos + osg::Vec3(-w / 2, 0.0f, h / 2) ); vertices->push_back( pos + osg::Vec3(-w / 2, 0.0f, -h / 2) ); osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f)); osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array; texcoords->push_back( osg::Vec2(1.0f, 1.0f) ); texcoords->push_back( osg::Vec2(1.0f, 0.0f) ); texcoords->push_back( osg::Vec2(0.0f, 0.0f) ); texcoords->push_back( osg::Vec2(0.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->setTexCoordArray(0, texcoords.get()); quad->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4)); return quad.release(); } 

Fungsi menerima posisi pusat kuadrat dan dimensi geometrisnya sebagai input. Selanjutnya, array simpul, array normals dan koordinat tekstur dibuat, setelah itu geometri yang dibuat dikembalikan dari fungsi.

Dalam isi program utama, muat model cessna

 osg::ref_ptr<osg::Node> sub_model = osgDB::readNodeFile("../data/cessna.osg"); 

Untuk menghidupkan model ini, buat dan inisialisasi transformasi rotasi di sekitar sumbu Z

 osg::ref_ptr<osg::MatrixTransform> transform1 = new osg::MatrixTransform; transform1->setMatrix(osg::Matrix::rotate(0.0, osg::Vec3(0.0f, 0.0f, 1.0f))); transform1->addChild(sub_model.get()); 

Sekarang buat model untuk adegan utama - kotak yang akan kita render

 osg::ref_ptr<osg::Geode> model = new osg::Geode; model->addChild(createQuad(osg::Vec3(0.0f, 0.0f, 0.0f), 2.0f, 2.0f)); 

Buat tekstur kosong untuk persegi 1024x1024 piksel dengan format piksel RGBA (warna tiga komponen 32-bit dengan saluran alfa)

 int tex_widht = 1024; int tex_height = 1024; osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D; texture->setTextureSize(tex_widht, tex_height); texture->setInternalFormat(GL_RGBA); texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR); texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR); 

Terapkan tekstur ini ke model persegi.

 model->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture.get()); 

Kemudian buat kamera yang akan memanggang tekstur

 osg::ref_ptr<osg::Camera> camera = new osg::Camera; camera->setViewport(0, 0, tex_widht, tex_height); camera->setClearColor(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

Tampilan kamera memiliki ukuran yang sama dengan tekstur. Selain itu, jangan lupa untuk mengatur warna latar belakang saat membersihkan layar dan masker pembersih, yang mengindikasikan untuk menghapus buffer warna dan buffer kedalaman. Selanjutnya, konfigurasikan kamera untuk membuat tekstur

 camera->setRenderOrder(osg::Camera::PRE_RENDER); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); camera->attach(osg::Camera::COLOR_BUFFER, texture.get()); 

Urutan rendering PRE_RENDER menunjukkan bahwa kamera ini melakukan rendering sebelum rendering ke adegan utama. Tentukan FBO sebagai target rendering dan tempelkan tekstur kami ke kamera. Sekarang kami menyiapkan kamera untuk bekerja dalam sistem koordinat absolut, dan sebagai pemandangan kami mengatur subtree kami, yang ingin kami render menjadi tekstur: transformasi rotasi dengan model cessna yang melekat padanya

 camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); camera->addChild(transform1.get()); 

Buat simpul grup akar dengan menambahkan model utama (persegi) dan tekstur pemrosesan kamera ke dalamnya

 osg::ref_ptr<osg::Group> root = new osg::Group; root->addChild(model.get()); root->addChild(camera.get()); 

Buat dan sesuaikan pemirsa

 osgViewer::Viewer viewer; viewer.setSceneData(root.get()); viewer.setCameraManipulator(new osgGA::TrackballManipulator); viewer.setUpViewOnSingleScreen(0); 

Siapkan matriks proyeksi untuk kamera - proyeksi perspektif melalui parameter piramida kliping

 camera->setProjectionMatrixAsPerspective(30.0, static_cast<double>(tex_widht) / static_cast<double>(tex_height), 0.1, 1000.0); 

Kami mengatur matriks tampilan yang mengatur posisi kamera di ruang angkasa sehubungan dengan asal usul sub-cessna

 float dist = 100.0f; float alpha = 10.0f * 3.14f / 180.0f; osg::Vec3 eye(0.0f, -dist * cosf(alpha), dist * sinf(alpha)); osg::Vec3 center(0.0f, 0.0f, 0.0f); osg::Vec3 up(0.0f, 0.0f, -1.0f); camera->setViewMatrixAsLookAt(eye, center, up); 

Akhirnya, hidupkan dan tampilkan pemandangan, mengubah sudut rotasi pesawat di sekitar sumbu Z di setiap frame

 float phi = 0.0f; float delta = -0.01f; while (!viewer.done()) { transform1->setMatrix(osg::Matrix::rotate(static_cast<double>(phi), osg::Vec3(0.0f, 0.0f, 1.0f))); viewer.frame(); phi += delta; } 

Alhasil, kami mendapat gambaran yang agak menarik



Dalam contoh ini, kami menerapkan beberapa adegan animasi, tetapi ingat bahwa memperluas loop run () dan mengubah parameter rendering sebelum atau setelah rendering frame adalah aktivitas yang tidak aman dalam hal mengatur akses ke data dari aliran yang berbeda. Karena OSG menggunakan rendering multi-threaded, ada juga mekanisme reguler untuk menanamkan tindakan mereka sendiri dalam proses rendering, yang menyediakan akses thread-safe ke data.

6. Menyimpan hasil rendering ke file


OSG mendukung kemampuan untuk melampirkan objek osg :: Image ke kamera dan menyimpan konten buffer bingkai ke buffer data data. Setelah itu, dimungkinkan untuk menyimpan data ini ke disk menggunakan fungsi osg :: writeImageFile ()

 osg::ref_ptr<osg::Image> image = new osg::Image; image->allocateImage( width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE ); camera->attach( osg::Camera::COLOR_BUFFER, image.get() ); ... osgDB::writeImageFile( *image, "saved_image.bmp" ); 

Kesimpulan


Mungkin materi yang disajikan dalam artikel itu nampak sepele. Namun, ini menguraikan dasar-dasar bekerja dengan tekstur di OpenSceneGraph, di mana teknik yang lebih kompleks untuk bekerja dengan mesin ini didasarkan, yang pasti akan kita bicarakan di masa depan.

Dilanjutkan ...

Source: https://habr.com/ru/post/id437624/


All Articles