QtQML / panel korelasi cepat

Halo semuanya! Saya adalah pemimpin tim untuk pengembangan aplikasi desktop di perusahaan Rogia Europe. Kami mengembangkan solusi perangkat lunak untuk industri minyak dan gas.


Kebetulan produk unggulan kami StarSteer tidak memiliki panel korelasi - alat klasik untuk panduan yang baik. Tugas itu ditunda untuk waktu yang lama karena tugas lain yang lebih prioritas, tetapi musim gugur yang lalu kami akhirnya bisa memulainya.


Memotong pertanyaan dari basis kode warisan - saya akan menyebutkannya di artikel - ada satu pertanyaan mendasar - teknologi apa yang harus saya gunakan? Kami benar-benar membutuhkan OpenGL - yang sudah digunakan dalam tampilan MapView dan 3d berdasarkan OpenSceneGraph - tetapi jelas bahwa itu tidak terbuka, dan dengan elemen antarmuka grafis. OSG jatuh = (. Sebuah teknologi yang memenuhi dua persyaratan - grafik adegan dan GUI pada OpenGL - Saya hanya tahu satu - Qt QML / Cepat. Tentang apa yang kami dapatkan dan apa yang harus kami bagikan - di dalam.


Entri


Kami mulai mengembangkan produk pada musim gugur 2013. Kumpulan perpustakaan apa yang digunakan untuk saya, sebagai penggemar Qt, bahkan bukan pertanyaan. Pada saat itu, mungkin muncul pertanyaan: gunakan versi Qt ke-4 atau ke-5 (masih terbilang baru). Kami telah memilih penerbangan kelima dan dari ketinggian penerbangan kami, saya hanya bisa mengatakan: terima kasih Tuhan!


Seluruh tampilan dikembangkan di QtGui / Widget. Semua adegan di mana grafik ditampilkan (gamma, porositas, resistensi, dll.) Dibuat di QGraphicsScene / View. Saran saya - jangan gunakan bundel ini untuk hal-hal serius! Argumen: gulir Bar dan tidak terputus dari luar (itu di luar tanpa edit Qt sendiri ) logika untuk memusatkan adegan ( qgraphicsview.cpp +458 dan di atas dalam metode yang sama untuk horizontal; qgraphicsview.cpp +3816 - apa kontrol atas matriks). Jika ini tidak mengganggu Anda, maka gunakan - banyak potongan nyaman dari kotak.


Apa lagi yang tidak boleh digunakan? NSIS.


Semuanya sempurna, produk berkembang, tugas sedang dikerjakan, jumlah pelanggan bertambah. Refactoring ... Secara umum, setelah beberapa waktu, QGraphicsScene mulai mengganggu kami - kami tidak terburu-buru untuk mengoptimalkan gambar grafik 40.000 poin, ketika garis tebal dihidupkan - semua hal ini pada CPU sangat lambat.


Sepanjang jalan, kami bosan mengembangkan GUY pada widget. Baik dengan tangan Anda sepenuhnya dalam kode, atau sedikit di perancang (dari Creator, .ui + .cpp). Saya menginginkan barang-barang modern, seperti deskripsi deklaratif dari antarmuka grafis.


Membuat daftar teknologi yang akan kami lakukan:


  • cara kuno di QGraphicsView / Scene;
  • untuk setiap lagu gunakan QOpenGLWidget kosong yang terpisah;
  • mengimplementasikan seluruh jendela pada QOpenGLWidget, tetapi GUI sendiri (atau menemukan sesuatu);
  • dua poin sebelumnya + OSG masing-masing;
  • Qt QML / Cepat,

hanya enam poin; dibahas. Karisma saya melebihi dan memutuskan untuk mencoba melihat bagaimana prototipe di QML berperilaku.


Prototipe


Saya membuka contoh scenegraph \ graph. Terlihat dan ditutup =). Saya bermain selama beberapa hari, melihat contoh-contoh lain, tetapi tidak ada yang mendekati tujuan saya.


Dan apa yang dibutuhkan saat itu? Seperti apa panel korelasinya:



Struktur yang cukup sederhana adalah daftar trek yang baik, di dalamnya trek untuk kurva, skala; Ya, hal-hal kecil. Banyak teks, di masa depan, beberapa kontrol - tombol, daftar drop-down, bidang input, dan banyak lagi.


Saya melihat sgengine, belajar cara membuat dua grafik adegan dan menggambarnya di viewport yang ditunjuk. Kemudian saya menyadari bahwa dengan opsi ini, QML / Quick tidak akan, lalu mengapa saya membutuhkan semua ini?


Sebenarnya, saya tidak ingat obat apa, tetapi karena alasan tertentu saya memutuskan untuk beralih ke dasar-dasar grafik komputer. Jadi pada tahap terakhir rasterisasi, semua koordinat adegan ditransfer ke NKU (Koordinat Perangkat Normalisasi; lebih dikenal sebagai NDC = Koordinat Perangkat Normalisasi). Ya, saya mendengar bahwa output dari vertex shader sebenarnya adalah ruang klip dan setelah itu masih ada distorsi affine, tetapi semua ini adalah untuk representasi tiga dimensi, dan dalam 2D ​​selalu ada w = 1 dan oleh karena itu kita dapat mengasumsikan bahwa output segera ke NDC.


OKE, NDC, apa selanjutnya? Bahwa jika lebar jendela Anda adalah 800 piksel, maka koordinat NDC dari pusat piksel nol adalah -1; koordinat pusat dari 799 adalah 1. Singkatnya, ndcX = -1 + 2 * i / 799. Sekarang bayangkan bahwa ada persegi panjang dari 100 hingga 300 dan saya ingin menggambar seluruh adegan tidak ke dalam seluruh jendela, tetapi ke dalamnya. Menggunakan pengetahuan yang terpisah-pisah ini, saya akan menghitung ndcX100, ndcX300, kemudian membuangnya ke vertex shader dan di sana, setelah standar


gl_Position = matrix * position; 

linear "bungkus" gl_Position.x dalam [ndcX100; ndcX300]. Kami melakukan hal yang sama untuk komponen vertikal. Trik ini akan memungkinkan Anda untuk memunculkan adegan di setiap persegi panjang adegan yang dipilih. Dengan pengetahuan ini, contoh grafik mulai mengalami perubahan. Anda dapat melihat paroki di sini - grafik ; semua garam di shaders/line.vsh .


SceneItem / Adegan


Tiga bulan berikutnya adalah penulisan TK, ternyata 12 lembar A4 =). Secara paralel, kami mempertimbangkan arsitektur. Mereka mengambil MVC ... itu MVP ... itu Hierarchical MVC / MVP ... atau bahkan PAC - semua ini adalah konvensi, dekomposisi yang baik adalah penting.


Secara umum, kami telah menyiapkan contoh adegan. Sumber tersedia di sini - Contoh Scene . Ternyata kerangka kerja tertentu untuk membuat aplikasi dengan grafik di QtQML / Cepat. Tolong jangan lupa bahwa kode ini masih bertindak sebagai contoh. Ya, sudah setengah jadi dan terlihat kurang lebih rapi, tetapi belum siap.


Adegan adalah pemain utama. Kelas ini memonitor koordinat NDC-nya dan memperbarui matriks yang sesuai. SceneCamera berteman dekat dengannya. Entitas berikutnya yang layak disebutkan adalah SceneItem. Itu tidak berguna dalam dirinya sendiri, itu hanya mengandung beberapa logika dasar; mewarisinya - seperti LineStrip - dan terapkan apa yang Anda butuhkan. Pada saat yang sama, di updatePaintNode Anda harus menggunakan turunan dari SceneMaterial - FlatColorMaterial sebagai referensi. Entitas yang tersisa juga melakukan sesuatu =), semua jenis manipulator, alat. Banyak kelas tidak dilemparkan ke QML, dan Anda tidak dapat melakukannya tanpa C ++; Anda ingat apa yang belum siap?


Kesulitan kedua adalah bahwa jika kita ingin menggunakan kontrol di dalam adegan baru, kita tidak akan dapat melakukan ini. Kami berpikir, memutuskan bahwa kami tidak membutuhkannya, dan dengan tenang melanjutkan pengembangannya.


Keuntungan dari pendekatan:


  • semuanya digambar dalam satu kolom adegan;
  • kami tidak memperbaiki Qt - masih memungkinkan untuk menambahkan kontrol QML reguler ke Stage sehingga z-order antara mereka dan kurva (atau SceneItem lainnya) benar;
  • konsumsi memori lebih rendah dibandingkan dengan pendekatan lain.

Cons


  • urbermachine kompleks;
  • pengetahuan tentang OpenGL dan GLSL diperlukan;
  • solusi setengah jadi.

Tentu saja, kami mengalami beberapa kesulitan selama pengembangan. Salah satunya


Bug dengan z-order


Ketika kami pertama kali mencoba menampilkan adegan dengan kurva, kami melihat gambar-gambar tersebut:



Sekilas tidak jelas, "kami melakukan semuanya dengan benar!" Samar-samar diduga bahwa gl_Position.z entah bagaimana keliru, tapi mengapa sulit untuk memahami mengapa di malam hari. Kami tidak menyerah: kami melihat bahwa Qt mengoreksi shader dan menambahkan kode untuk mengubah gl_Position.z, kami pikir. Setelah beberapa saat, kami sadar: kami mengacaukan data matriks dengan perubahan z, dan Qt mentransfer nilainya kepada mereka! Dengan demikian, nilai item.z dari QML dipetakan ke z dari OpenGL ( SceneMaterial.cpp +20 ):



Bug dengan klip: true


Sekali dalam obrolan, tim bisnis mengirim layar di mana garis kiri kotak koordinat menghilang.



Tanya Jawab kami menyiksa program dan menemukan langkah-langkah untuk pemutaran yang stabil: kami mengatur penskalaan untuk monitor agar tidak kelipatan 100% dan garis-garis "berkedip". Artyom duduk, berpikir, dan menemukan bahwa ketika clip: true dan item berbentuk persegi panjang, glScissor digunakan, tetapi argumennya adalah koordinat pixel integer! Pada item QML mereka nyata dan ternyata rasterisasi garis jatuh ke piksel berikutnya / sebelumnya, dan gunting dipotong ke arus.


Kami memperbaiki adegan seperti ini: width: Math.round(metrics.width + leftPadding + 2 * rightPadding + 0.5) . Karenanya, item pemandangan harus selalu memiliki koordinat bilangan bulat untuk menghindari artefak tersebut.


Kesimpulannya, saya akan membawa KDPV



Terima kasih atas perhatian Anda!

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


All Articles