![見出し画像](https://assets.st-note.com/production/uploads/images/7800192/rectangle_large_type_2_e1441c961f22b3ac33d0fc4a22dee0be.jpg?width=1200)
RustでシンプルOpenGLアプリ作成
はじめに
WebGLでcubemapテクスチャーを使用する際にcubemapテクスチャーを立方体の見取り図のまま(下画像の左部分)として使用できず、テクチャーを6枚にスライス(下画像の右部分)して使用しないといけません。(しなくてもできるのかなと思いつつ。それぽいデモやwebglのapiもなかったので断念)
Lysというソフトウェアを使ってHDRからcubemapのテクチャーの書き出しをします。見取り図のようなCubemapを書き出してくれますが、スライスした画像を書き出してくれません。。
GIMPというフリーの画像編集ソフトでcubemapをスライスしてくれるプラグインを発見して使おうと思いましたが、動かず。。4年前のリリースだししょうがないです。
photoshopで手動かスクリプでスライスしてよかったんですが、なんか面倒なので、断念。
OpenGLかWebGLで簡易なデスクトップ・アプリを作成しようと決めました(将来的に楽しようとした結果、意外と時間かかるいつものパターンですw)。
候補としては2つありました。
- RustでOpenGLアプリ
- Electron+WebGLアプリ
Electron+WebGLアプリはできそうなので、やったことないRustでOpenGLで簡単アプリ作成に挑戦しました。
なぜRustをやるのか
WebAssemblyでRust押されているからが一番の理由です。
WebAssemblyの記事やライブラリの多くがRustで書かれていて、Rustで開発元のMozillaも激推ししています。
C/C++の速度の速さとメモリ管理を簡易化しているという記事を読み興味を持ちました。
RustでHello, World!
Rustのメインサイトから言語をインストールして終了しました。
Cargo(jsでいうnpm)というpackage managerでアプリ管理できるのがわかり、早速お決まりのHello, World!を作成してみます。Hello Worldがエラーなく初めて出るまで緊張します。。
>cargo new --bin hello-world
hello-worldというプロジェクトが作成されます。
main.rsというファイルも自動的に作成されるので、開いてみると、
fn main() {
println!("Hello, world!");
}
最初からHello, World!作成されてる。。
>cd hello-world
>cargo run
Hello Worldがターミナルに表示されました。
これで新しいコンピュータ言語の学習が50%ぐらい出来た感じがします。
後はオフィシャル・ドキュメントかオライリー本の最初の1, 2章読みます。自分で簡単なプロジェクトを始めて、わからなくなったらわかるまで調べるスタイルで挑みます。
RustでOpenGL動かしてみる
Rust + OpenGL + tutorialで検索すると、良さげなチュートリアルを発見。
三角形を作成するというGLお決まりのHello World!を詳しく解説してくれてます。
ここのリポは多くのサンプルがあるので、こちらを参考にしながら作成しました。
わからないところはRust glのオフィシャル・ドキュメントを読むことにしました。
OpenGLアプリの作成
アプリの仕様としては以下のようにしました。
1. 下のようにcubemapの名前を入力するとresouces/texturesに置いてあるcubemapを読み込み、存在しない場合は存在しないと警告してアプリを終了する。
cargo run cubemap_name // cubemapの名前
2.Cubemapを表示させる。
3. Sボタンを押すと6つにスライスして自動的に保存する。
Rustはクロスプラットフォームなので、macもwindowsも簡単に実行できます。Cargoはnpm並ぶぐらい便利ですねー
Rustについて気づいたこと
Rust独特な書き方があり、型判定が独特でjavascriptで適当にやるとエラーが出てビルドできないので、そのあたりは手探りでやりました。
glからReadPixelsでpixelsの引数として渡すのですが、*mut c_voidの型として渡さないといけず、c_voidの型と悩ましかったです。
let mut imgbuf: image::RgbImage = ImageBuffer::new(img_size as u32, img_size as u32);
let imgbuf_ptr = imgbuf.as_mut_ptr();
gl::ReadPixels(x as GLint, y as GLint, img_size as GLint, img_size as GLint, gl::RGB, gl::UNSIGNED_BYTE, imgbuf_ptr as *mut c_void );
ImageBufferを作成し、ImageBufferのポインター取得、最後にImageBufferのポインターを*mut c_voidとして引数に渡すことで実装できました。
動いたからよかったんですが、なぜimageBufferをポインターとして取得しないといけないか答えが出ませんでした。
文字列の連結や可変長配列の扱い方がもっと良く出来たんじゃないかとそのあたりを本とドキュメントで確認していきたいです。
ちょくちょくRustは書いて、慣れていきたいです!