2013年9月26日木曜日

やっぱり3Dは避けて通れなかった

映像的な面でのモチベーションとして,色々なデザインモチーフやVFX的効果を取り入れて動きを出し,画面いっぱいを使って楽しさを演出したいというイメージをもって進めています.

プログラマブルシェーダ使いたさ故にイキナリOpenGL ES 2.0で作り始めてるのは,そんな自分の中のイメージを楽に具現化できる機能というか可能性を感じるからで,全くGPUプログラミングの経験がない自分でも楽に試作を重ねられるGLSL Sandboxは大いに活用させてもらってます.




さて,音と映像との同期について考えるときに誰でもすぐに思いつきそうなパターンの1つとしては,ビートに合わせて背景が変化する系の映像効果があります.

例えば『躍動的に動く網』なんて典型的ですよね.

OpenGLを使ってる以上,X,Yの2次元で組んでいるプリミティブ(点やら面やら線やら)でもZ軸の値を持っているから,Z軸の値を適当に増やしたり減らしたりすれば簡単に3次元画像になるはずだよね!

とか思い,とりあえず斜めから見てこんな形に盛り上がった状態のメッシュを作りました.


これをメッシュの正面から見れば,こちら側に向かって飛び出てきそうな感じのグラフィックになるだろうと期待してカメラを正面に置いてみたんですよ.するとですね…







…正直すまんかったorz
平行投影法だと奥行き成分が現れないんだから,正面から撮っても膨らみを表現できないのは当然じゃないかw 一点透視法とか勉強しただろ昔ww

とかなんとか混乱を解消しながら進めてると,座標系と行列と写像とシェーダ,各々の役割と計算の流れはとりあえず理解できた.さらに,カメラの投影行列を求める関数なんぞきょうびどこにでも出揃ってるんですねえ.




そういった透視投影のカメラ行列を求める関数の引数としてよくあるのは,
(視野角, near, far)
みたいな3つの要素.GLUTもlibGDXもここは共通でした.

視野角については、このメッシュ面の大きさ(幅とか)と,それを置く位置を決めればarctanで自然に決まる.nearとfarもこれらの要素と相関があるのかと思って混乱したけど,どうやら独立した係数らしい.floatの演算精度と関わってくる部分があるらしいけど,とりあえずは手前と奥の視界が切れる距離だという認識でいれば現状はよさそう.


さて,一般的にバーテックスシェーダには頂点に色情報を持たせて渡しますが,1つのポリゴンの頂点にそれぞれ違う色を与えると,ポリゴン内部の画素の色はグラデーション的に補間されて出てきます.

というかそもそも頂点の情報を与えるとポリゴン内部の値を計算してくれるのこそがバーテックスシェーダの基本機能なわけで,それは座標だけでなく色とて同じ事というわけですな.
例えばさっきの四角形を、こんな感じで斜めに折り曲げてみます.

完全にパキっと曲がってますが,これに色を塗ると…
なにげにあんまり角ばった感じがしないんですよね.
頂点色の補間機能というのは端的には,ポリゴンを滑らかに見せるために必要な機能の一つということでシェーダに標準搭載されているのだと考えて良いのではないでしょうか.

フラットシェーディング

ストリップや縮退ポリゴンなど高速にポリゴンを描くテクニックが色々とありますが,いわゆるフラットシェーディング(初代バーチャファイタ―みたいなアレ)的に1つのポリゴン内を任意の色で塗りつぶしたいという場合,上記の補間がかかってしまうため頂点を共有することはできません.
隣のポリゴンを描くときも,同じ場所に点と色を打ち直さないといけないんですね.

OpenGL 1.0にあったフラットシェーディング固定機能 glShadeMode(GL_FLAT) は2.0では削除されたようで,プログラマブルシェーダにおける同等の機能は,OpenGL 3.0(GLSL 1.3以降)で入ったflat機能を待ちます.OpenGL ESの3.0は昨年リリースされたばかりなのでさすがに使えません.
何かできないんかなあと調べたところ…
Replacement for glShadeModel on OpenGL ES 2.0
「ぜんぶ頂点打ちなおすのがジ・オンリーウェイ」
あそうですか…



というか,一口に「フラットシェーディング」って言ってしまうと、面ごとに違う色を割り当てること(バーテックスシェーダ側の処理)と,面ごとに陰影をつけること(フラグメントシェーダの処理)がごっちゃになってしまうんですが,後者に関しては面の法線ベクトルを求めるとかで対応はできそうです.
しかし面の法線ベクトルをマジメに求めようとすると偏微分が必要になるわけで…
Emulating glShadeModel( GL_FLAT )?
khronos.org: OES_standard_derivatives.txt
自分としてはリアルな表現とかには全く拘っておらず,面白く見栄えればそれでよいので,もう少し高速に概算できる方法を探してみようかと思います.

つうか,なんでCG黎明期の原始的なレンダリングを実現するために,GPUが本気出して全ピクセルの偏微分なんぞ計算する羽目になっちゃったりしてんですかね…
ってまぁ,ジオメトリ演算をGPUの3次元世界にもちこまずにCPU側でやってたからってことですかね.



シェーダでエフェクトを作っていると精度が変になったりと,なにかと詰まることが多くなってきたので一冊本を買っとこうということで,OpenGL ES 2.0をメインで扱っているこいつを取り寄せました.
Open GL ES 2.0 プログラミングガイド Aaftab Munshi
英語の電子版であれば安く手に入ったんですが,英語の本を読むのはlibpdで既にイッパイイッパイなので,ちょっとヒヨって日本語訳版を.

解説は詳細だがかなり専門的で難しいという前評判にちょっとビビりながら読み始めましたが,さすがに暗中模索とはいえプログラマブルシェーダありき(2.0志向)でコーディングしてきてるので,思ったよりはスムーズに理解できるところまで来てるみたいでちょっとだけ安堵.


0 件のコメント :

コメントを投稿