20190WebAssemblyで3Dを描画してみたかったので、WebGLの学習も兼ねてMDNのWebGLチュートリアルをRust+WebAssemblyで写経してみました。ちなみに、MDNのWebGLチュートリアルはGitHubのコード例があるのですが、コード例だけがリファクタされてしまったためにサイト上のコードと大きく食い違っています。今回はGitHubのコードを参考にしました。実際のコードや動作は以下です。コード動作サンプル写経しながらハマった点などを簡単に説明します。従ってプロジェクトを作成しました。RustのプロジェクトのサブディレクトリにWebアプリを作り、そこからWebAssemblyを読み込んで実行する構成になっています。wasm-packを使ってコンパイルした生成物をimport文で指定すると、webpackがいい感じに繋ぎ込んでくれます。エコシステムが整備されてかなり簡単になりました。JavaScriptのブラウザAPIはどうやって呼ぶ?wasm-bindgenを使います(上のサンプルにはデフォルトで入っています)。wasm-bindgenはJavaScriptのブラウザAPIとRustを繋ぎこむライブラリです。これを用いることで、ブラウザAPIをJavaScriptライクにRustから呼び出すことができます。.unwrap();wasm-bindgenとブラウザAPIのインターフェース非常に似ていますが、やはり言語による違いがあるのでいくつか紹介していきたいと思います。関数名の違い基本的にはキャメルケース→スネークケースでいけますが、引数の型ごとに別のメソッド名になっている場合もあります。参照渡しJavaScriptでオブジェクトを受け取る関数は、基本的に構造体を参照を受け取る形になっています。例)context.link_program(&shader_program)Option型JavaScriptでnullの可能性がある場合はOption型になっています。これらを全てハンドリングする必要があります。.get_element_by_id(id)キャストDOMを取得する関数の戻り値はElement型なので、特定のDOMの型にキャストする必要があります。.unwrap();ビルトイン配列の型Float32Arrayなどのビルトインされた配列型は、プリミティブ型ではなくjs-sysの型にする必要があります。WebGlRenderingContext::STATIC_DRAW);定数WebGlRenderingContextに同じ名前で定義されています。例)WebGlRenderingContext::COMPILE_STATUS行列計算ライブラリチュートリアルでは座標変換の行列計算をするためにgl-matrixというライブラリを使っています。JavaScriptのライブラリをそのまま使うわけにはいかないので、今回はnalgebra-glmというライブラリを使いました。図形をアニメーションで動かすために、requestAnimationFrameを再帰的に呼び出す必要があります。wasm-bindgenのサンプルを参考にして実装しました。FnMut()>));request_animation_frame(g.borrow().as_ref().unwrap());上記の書き方はアニメーションを途中停止させるケースを考慮しており、仮に停止させた場合にはクロージャが破棄されます。これを考慮しない場合はもうちょっとだけ簡単に書けますが、この記事では扱いません。まとめ非同期処理の実装でRustのライフタイムを考慮するのに苦労しましたが、wasm-packに含まれるwasm-bindgenがブラウザのAPIをしっかりサポートしているおかげで無事に写経できました。wasm-bindgen便利です。