ActionScriptでPoint Sprite


Point Sprite Particle | Si+ (wonderfl.net)

わりとマジメに Stage3D で Point Sprite を実装してみました。
Point Sprite というは、平たく言えば、どんなに回転しても常に自分の方向を向いている四角形を作成してテクスチャを張ったものです。大昔はビルボードとも呼ばれ、そこそこ面倒くさい技術でしたが、最近はGPUにPoint Spriteを書いてと命令するだけで勝手に処理してくれるようになりました。
しかし残念ながら、劣化 OpenGL こと FlashPlayer11 の Stage3D では、この PointSprite 命令は今のところ実装されていません(drawLines と drawPoints 位はあっても良いと思うんですが。将来的には実装される気もします)。そこで今回はこの Point Sprite を作ってみました。Point Sprite は非常に汎用性の高い技術なので、今回はいつものようにやっつけではなく、あとあと使いやすいように慎重に簡潔に実装しました(使用例として3Dパーティクルシステムも実装してみましたが、こっちはやっつけです)。
最もトラディショナルなビルボードの実装では、カメラ行列を取り出して回転成分だけ抜き取って、その逆行列で四角形を回転させることで実現します。この方法は非常にシンプルで判りやすいのですが、逆行列の扱いに注意が必要な点と負荷が高い点が難点になります。
またもう少しモダンな方法では、中心点座標をモデルビュー行列で変換してカメラ座標系にして、そこからx/y方向に四角形を広げるように4頂点を計算することで実現します。この方法は逆行列計算を必要としないため、一般的に前述の方法より負荷が低くなります。しかし本来シェーダが計算するモデルビュー行列変換を自前で計算するという点に難がありました。
これらの方法は、固定シェーダの時代にはGPUで行ったプロジェクション行列の計算結果を扱えなかったためのいわば苦肉の策でした。しかし、プログラマブルシェーダの登場により、プロジェクション変換後の計算結果も(シェーダプログラム内で)扱うことができるようになりました。そこで今回はプロジェクション変換後に頂点を動かす形で実装しています。基本的な方法は、

  • 予め表示させたい最大スプライト数の四角平面を含む立体を作る(この時点で頂点情報は設定されてない)
  • VertexBuffer, IndexBuffer を最大スプライトの分だけ確保,IndexBufferは不変なのでuploadする
  • 毎フレームはじめにclearSprites(line:603)で登録スプライト情報をクリアする(実際は描画スプライト数を0に設定するだけ)
  • createSprite(line:604)でそのフレームで描画したいスプライト情報をVertexBufferに書きこむ
  • 全スプライトを設定したら、マトリックス等必要情報を更新してdrawTriangleで登録したスプライト数だけ描画する(line:130-134)

PointSpriteの描画についてはマニアックになるので詳細は省略しますが、今回の実装ではソフトウェア上でスケール・回転、フラグメントシェーダでカラートランスフォームを行なっています。実装は586行目からです。