スポンサーサイト

--年--月--日 --:--

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

動的にシェーダー定数をプログラム

2006年10月20日 16:12

ってことで、上記タイトルの機能を あるけ が趣味で作ってるシェーダー編集エディターに追加しました。

既存のシェーダーの開発ツールとしては nVidia の FX Composer や ATI の RenderMonkey があります。
どっちのツールも定数レジスタを設定することは出来るけどプログラムすることは出来ませんでした。
射影行列を作ったり、ライトの位置を簡単な円運動させたり、そういうことは出来なかったわけです。

もちろん、定数を設定するだけなら出来ます。
たとえば、HDRの閾値を入力したり。

しかし、実際にゲームで使う場合、定数レジスタに設定する値は複雑な演算を行ったり、
計算で求めたベクトル同士の内積の値を突っ込んだりします。
そういう細かな定数レジスタの設定は、出来ませんでした。

あるけ はプログラマなので、別にスライダーなどで定数レジスタが弄れなくても、簡易的なプログラムが書け、それで定数レジスタを制御できる方がうれしいです。


・・・ってことで、Closure の機能をバリバリ使ってタイトルの機能を追加しました。
アプリケーションの中でプログラムを入力すると、構文解析を行い、エラーが無ければプログラムを構築します。

どんなことが出来るか?というと、、、


char pProgram[] = "\
 VEC vTest  = init(1,0,0); \
 MAT mtTest  = rotY( rad(cnt()) ); \
  \
 return vTest * mtTest;\
"
;



こんな感じのプログラムがあるとします。
cnt() っていうのは1フレームに1ずつ増えるカウンタを返す関数、rad() は与えられたパラメーターを Degree から Radian にする関数、init() はベクトルの初期化関数、rotY() はY軸回転の行列を返す関数です。

このテキストをほいさーって感じに Closure のジェネレーターに突っ込んでやると、これを評価する Closure が返ってきます。
後は、値が欲しい時に Closure を評価してやれば、この Closure が計算し、「Y軸周りに回転するベクトル」を取得することが出来るわけです。


Closure を使ってるので、他のプログラムの中でこのプログラムを呼び出すことも可能です。
スクリプトに見えますが、インタプリタで動いてるわけでなく、式を保存しているので Closure を評価するだけで式の実行を行います。

関数型プログラムの悪い欠点で、あまり長いプログラムはスタック食いつぶすだろうから書けないけどねw
シェーダー開発ツールはこの機能を入れてもうちょっと機能を追加したら、公開しようかな?って思ってます。


ためしに作ったようなものだけど、他のゲーム会社とかでも使われたら最高だね~w


blog_rank
スポンサーサイト

C++言語で関数型プログラミング 第1章

2006年08月25日 18:07

前回、どこまで書いたっけかなw

・・・・・前回の解説じゃちょっと飛んでるところも多いね、こりゃ。

まず、用語説明から。
 ・TCClosure  クロージャー(Closure)を実現するために あるけ が作ったテンプレートクラス
 ・Lambda   無名関数を扱えるようにした BOOST に入ってるトリッキーなテンプレートクラス
こんなもんかな。

他にはカリー化とかも知っておいた方がいいんだろうけど、あるけ 自体実は良くわかってないので省きますw



さて、前回は式のオブジェクト化を行えば Closure が出来そうなこととか、Lambda がどうやって動いてるのか?を簡単に説明しました。

Lambda 自体はすごく綺麗に動的に関数の生成を行えるように作られています。
しかし、実際問題として、Lambda を有機的に使うことはすごく難しいです。
なぜなら、この前の説明で作った ((_1 * 100 + _2 + 10)(1,2)) の左辺値を変数に格納しようとしたら、

boost::lambda::lambda_functor_base::sig::type boost::lambda::lambda_functor::operator ()(A &,B &) const'
 with
  Act=boost::lambda::arithmetic_action,
  Args=boost::tuples::tuple    arithmetic_action,boost::tuples::tuple    lambda_functor,
    boost::tuples::tuple>,
    const boost::lambda::detail::parameter_traits_    IF::RET>::type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::
    null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,
    boost::tuples::null_type>>>,boost::lambda::lambda_functor>,boost::tuples::null_type,
    boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,
    boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>>>,const boost::lambda::detail::
    parameter_traits_::RET>::type,boost::
    tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::
    null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>,
  SigArgs=boost::tuples::tuple    null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,
    boost::tuples::null_type>,
  T=boost::lambda::lambda_functor_base,boost::
    tuples::tuple    lambda_functor,
    boost::tuples::tuple    arithmetic_action,boost::tuples::tuple    lambda::placeholder<1>>,const boost::lambda::detail::parameter_traits_    IF::RET>::type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::
    null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,
    boost::tuples::null_type>>>,boost::lambda::lambda_functor>,boost::tuples::null_type,
    boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::
    tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>>>,const boost::lambda::detail::
    parameter_traits_::RET>::type,boost::
    tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::
    null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>>,
  A=int,
  B=int

まぁ、こんな冗談みたいな長さのテンプレートを宣言しないと格納できないわけです(;´Д`)'`ァ'`ァ

これが Lambda を使用する場合のもっともとっつきにくい部分でしょう。
使える場面が少ないのと、使う場合は必ずテンプレート関数にしないといけないからです。
暗黙のテンプレート引数として使えば、別にどんな型だろうが使う側は知らなくてもOKですからね。


次は、Lambda がどうやって動いてるのかを説明しようと思います。
今日は忙しいのでさわりの部分だけw


blog_rank



最近の記事


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。