テレワークならECナビ Yahoo 楽天 LINEがデータ消費ゼロで月額500円〜!
無料ホームページ 無料のクレジットカード 海外格安航空券 海外旅行保険が無料! 海外ホテル


log

2012.04.09 C++:ボクセルその2


前回はポイントレンダリングでボクセルを描画しましたが、今度はMineCraftと似たような
描画方法を実装してみました(個人的にはボックスレンダリングと名付けてます)。

実装方法について少し説明すると、ボクセルの各頂点を頂点バッファに用意するとバッファ
の再生成に時間がかかるだろうなと思ったので、ボックス1つ分の頂点バッファと各ボック
スごとのインスタンスデータの頂点バッファの2つを作成し、ハードウェアインスタンシング
で描画するようにしました。インスタンスデータの頂点バッファは空間番号のインデックス
とカラー情報を持っていて、インデックス番号に合わせてボックスの位置を移動させて描画
という感じです。動画ではLMBクリックで生成、RMBクリックで削除という操作方法ですが、
色の選択はまだ実装していないのでとりあえずランダムな色で描画してみました。

それにしても、始めはByte型のインデックスをHLSLでfloatに変換して使おうとしたので
すが、シェーダ4.0じゃないと整数演算は出来ないみたいですね。なのでシェーダ2.0でも
使えるようにやむなくインデックスをfloatで作成しましたが。やっぱりGPUに転送するサイ
ズが小さい方が早いだろうな。

2012.04.07 C++:ボクセルとか剣エフェクトとか


今までボクセルの描画部分はマーチンキューブ法で描画していましたが、最近気になる
Point-Based Renderingに触発されてポイントレンダリングで描画してみたいなと思い、
さっそく試してみることにしましたが。。1日も立たずにサクッと出来てしまいました笑。

まぁ、ボクセル情報を頂点としてポイントで描画するだけなので簡単に出来て当然です。
で、動画を作るためにボクセルでマリオを作ってマウスでボクセルを削除するものを作ろう
かと思ったのですが、、ボクセルとマウスカーソル位置のレイの衝突判定の方がややこし
いという始末…;まぁこれも2日で出来たので良かったでした。

ちなみに、動画のマリオの肌の血色が悪いのは色情報を24,32bitではなく8bitで保持
しているためです。ボクセルは恐ろしくメモリを消費するものなので、なるべくメモリ消費
を抑えようと圧縮しているのですが。それでも100MBもメモリを使っています、恐ろしや。

それと他には剣の軌跡のエフェクトも実装してみたり。これも1日2日で出来ました。
ということで今回はサクサクと新しい実装が出来たので嬉しい反面、次はものすごく苦戦
したりするんじゃないかなぁと不安な部分もあったりします苦笑;

2012.04.03 C++:会話イベント


ようやくですが、イベントシステムを導入して会話を行えるようにしてみました。動画を見ると
分かりやすいですが、会話動作は1つの関数で固定的な表現をするより、イベントシステムで
組んだ方がより汎用的な表現ができるようになります。

ちなみに、動画内では大まかに以下のようなイベントの流れで会話を表現しています。
・会話モデルをプレイヤーモデルに向かせるイベント
・会話に必要なスプライトの描画フラグを変更するイベント
・テキスト表示するイベント
・会話に必要なスプライトの描画フラグを戻すイベント

これらのイベントのパラメータを変えたり追加することで、状況に応じて会話を変更したり、
会話ごとに会話スピードを変更したり会話の枠を外したりといった演出をしている訳です。

しかしながら、イベントシステムというのは少なからず無駄がでてくるのでそこが厄介です。
万能ってそうそう無いもんだなぁ、、なんてことを思いました。

2012.02.25 C++:またですか、デバイスロストさん。。

ほんと、見えないときは全く姿を現さないですが。見えるときになってからがやっかいですね、
デバイスロストさん。というのも自身のプログラムをWindows7+オンボードGPUの環境で
プレイしてみたのですが、プレイ自体は何も問題ないものの、スリープモードから復帰した
ときにデバイスロストの復旧が正常に行えないという問題に直面したわけです。
以下、メモ書き風に話がグダグダと続きます。プログラム周りに興味のある方だけどうぞ苦笑;

さて、コードを見渡しても復旧前に開放し忘れたりとかは無い…(まぁ、XPで動作出来てる
のでこれは当たり前だろうなと思ってましたが)。しょうがないのでネット上にあるマルペケ
さんの所のデバイスロストのサンプルを実行してみるとこれも復旧できず、、「んっ?」て
思いました。コードを削っていくとどうやらD3Dデバイス作成時にD3DCREATE_SOFT
WARE_VERTEXPROCESSINGを指定するとデバイスロストから復旧できるということが
分かり、オンボだとHARDWAREで指定しちゃいかんのかなとも考えましたが、指定でき
ないのにデバイスの作成が通るというのもおかしいのでもう少しだけ考えることにしました。

そこで、サンプルコードから一旦自身のプログラムに戻って修正してみると、デカール描画
の部分だけデバイスロストから復旧時に不自然な描画の仕方をする現象を見つけました。
デカール描画の部分だけDrawIndexedPrimitive()ではなくDrawIndexedPrimitiveUP()
で描画していたので、これはすぐにピンと来たわけです。
つまり、「Windows7は内部でDirectX10.1を使っているし、DirectX10ではUP系の
描画を廃止してるんだからこれはうまくエミュレートできていないってことだろうな」と思った
訳です。で試しにデバイス作成部分を元に戻してDrawIndexedPrimitiveUP()部分を
コメントアウトしてみるとデバイスロストの復旧が無事出来ました!(要追伸)

ちなみにマルペケさんのサンプルがデバイスロストから復旧出来なかったのはソース
コードの短縮のためにD3DXSPRITEやD3DXFONTを使っていたのでこれが原因みたい
でした(おそらく内部でUP系の処理をしているのかな)。デバイスをSOFTWAREで作成した
時にうまくいったのも、予想の域を超えませんがオンボではなくCPU側で頂点処理をエミュ
レートしたのがうまく働いたのかな。

この問題はオンボGPUのサポートの不手際が悪いとも言えそうですが、結論から言えば
「UP系描画はこの先どう描画されるか分からないから使うな」という警告だなと思いました。
いっそオンボは無視するというのもアリですが。最近のオンボは結構早いですからね。
、、それにしても結論までに結構時間かかったなぁ;

追伸:
UP系命令が原因と書きましたが、デカール描画だけはボリュームテクスチャで描画して
いたので、こっちが原因かもしれないなと思いDrawIndexedPrimitiveUP()を消さずに
ボリュームテクスチャをOFFにすると正常に描画されました。で試しにボリュームテクスチャ
のプールをD3DPOOL_MANAGEDだったのをD3DPOOL_DEFAULTにして自前復旧に
変更することでデバイスロストに対処できました。…ということで、間違った情報を流して
しまいました。そういいつつ、直った理由がいまいちよく分からない上にUP系との併用に
よるバグかもしれないし、デカールと一部分だけ固定パイプラインで描画していることによる
バグかもしれない。原因は何だか特定しきれないですが、、直ったからいいんです苦笑。

2012.02.18 C++:スプリングボーン


以前ボーンの向きコンストレイントをプログラムで実装しましたが、今回はそれの応用で
動きに合わせて揺れるボーンというのを実装してみました。

実装方法としては以前の機能の他にバネ・ダンパモデルというのを使っているので、少し
ばかり紹介したいと思います。バネ・ダンパモデルはバネ係数k・ダンパ係数dを利用して
現在の併進運動エネルギーFを求めるというもので、以下のようになります。
F(t) = F(t-1) * d + V * k;
V = PrevPos - Pos;
いやぁ、とってもシンプルです。あえてこれ以上説明するとすると、高1物理で教わるバネ
の弾性力の公式F=kxの式に追加エネルギーとなるF*dがくっついただけです(というより
ここではV*k部分が追加エネルギーですが)。Vは前フレーム位置に戻ろうとする相対速度
ベクトルなので係数kを大きくするほど前フレーム方向に戻ろうと振れる力は大きくなり、
そしてdはF(t-1)を徐々の弱める働きをするので動いていない場合は揺れがなくなる、
というわけです。

ちなみに自分で独自に調べたりしたので、「実はkとdは逆なんじゃないかな…」とか、まだ
良く分かっていない処がありますが、まぁkもeもつまるところスケーリング係数という点で
同じなので、学術的な定義があってるかどうかは特に気にしていません笑。

さて、これでボーンを揺らすことができるようになりましたが、、ボーンの角度制限をちゃんと
つけないと駄目みたいです。動画では入れていませんが、試しに攻撃モーションをさせて
みると髪が頭を思いっきり貫通してしまいました;

実はボーンの角度制限読み込みだけでなく、マルチUVやLWSを利用したオブジェクト
単位の背景読み込み等など。LW回りでやりたいことはまだまだあったりします。難しい
ので後回しにしてますが苦笑;

2012.02.13 C++:レジストリを使っていないとばかり思っていたら…

ファイル 380-1.png

自作のプログラムではレジストリを使っていないものとばかり思っていましたが。。
DirectInputをDirectInput8Create()で初期化するとレジストリに勝手に登録する
みたいですね。詳しくは以下のサイトをどうぞ。
http://dodeka.net/~j2/wp/?p=163

レジストリエディタで自分のプログラムが登録されてないか確認してみると、なんと山のように
登録されていました;うわぁぁ何てこったい。

しかも今までプレイしたことのあるDirectX製ゲームも他にもずらりと登録されてるし。
…何だかなあと思ってしまいました。とりあえず、同サイトにCoCreateInstanceを
使うことでレジストリの登録を防ぐ方法が書いてあったので一安心です。

同じようにDirectInputを使っている方は一度チェックしてみることをお勧めします苦笑。

2011.11.14 C++:Grass Shader


今日はHLSLでGrass Shaderを実装してみました。もうちょっと実装するのに時間が
かかるかなと思ってましたが、、構想から完成まで1日でできてしまいました笑。

以前作成したAtmospheric Scattering Shaderと併用できるようにソースもなるべく
簡素に設計してみたため、今回はお手軽サイズということでソースを公開してみたいと
思います。基本的にほぼオリジナルな設計なので、どこかのライセンスとかには引っか
かっていない…はずです。使ってみたいという方はご自由にどうぞ~。

 // 草の傾きを時間経過で変化させる係数(0~1)
 float GrassWaveTime = 0.0f;
 // 草の傾きのスケール係数の逆数
 float InvGrassWaveScale = 1 / 200.0f;
 // 草の最大傾斜角度[ラジアン]
 float RotateRange = 20.0f
 * 0.017453292519943295769236907684886f;
 // 回転量[ラジアン](-RotateRange~+RotateRange)を取得
 // cf.frac()だけだと端を超えた場合に反対側に飛んで
 // しまうため( abs(frac(x)-0.5f) * 4 - 1 )で補正し、
 // frac(x)の値が0,1の場合は+RotateRange側、frac(x)の
 // 値が0.5の場合は-RotateRange側に傾くようにしている。
 float RotValue = ( abs( frac(
 (IN.Pos.x + IN.Pos.z) * InvGrassWaveScale + GrassWaveTime
 ) - 0.5f ) * 4 - 1 ) * RotateRange;
 // Cos,Sinを計算
 float2 CosSin;
 sincos( RotValue, CosSin.x, CosSin.y );
 // Z軸回転による座標増分値を計算
 // cf.Z軸回転は(xcos-ysin,xsin+ycos,z)だが、ここでは
 // (x,y,z)は(0,1,0)なのでy成分以外は0に省略できる。
 // また、AddPos.yの最大値は0になってほしいためy成分を
 // 1引いている。
 float3 AddPos = float3(
 -CosSin.x,
 CosSin.y - 1,
 0.0f
 );
 // Y軸座標値が大きいほど回転するようにスケーリング
 AddPos *= IN.pos.y;
 // 回転による移動値分だけ座標を変更
 Out.Pos += AddPos;

日記の使用上、インデントが汚いのは仕方ないところですね;それとこれ以外に傾きが
大きいほど頂点カラーが暗くなるように設定してたりしますが、ちょっとまだ怪しい設計
だったりするので、その部分だけカットしておきました。

いつもは新しい設計にすごく時間かかる癖に、たまにこういうことがあるんですよね。

2011.11.12 C++:日の出、日の入り


ちょっくら、Atmospheric Scattering ShaderというものをHLSLで実装してみました。
このシェーダはライトの位置によって夕焼けになったり、パラメータをいじることで青空の
度合いを調節できたりする、結構便利なシェーダだったりしますが、自分のは完全に
Atmospheric Scattering Shaderを把握できていないため、半分は独自の(いんちき)
実装方法だったりします苦笑;

こういうのは実はあらかじめ頂点カラーに仕込んでおいて似たような効果を出すことが
できるんですが。。それだと同じモデルでも頂点カラーが違うモデルごとにデータを用意
しなければならなくてデータサイズがかさばってしまうので、意外とこういうシェーダは
大事だったりします。見た目もそれなりにリッチになったし、よかったよかった。

2011.10.27 C++:SSAO等など


さてさて。今回は色々とプチアップデートが多いので、ちょっとリストアップして
紹介していきたいと思います。

・モーションにSEを親子付け
 モーションを行うと関連したサウンドが再生できるようにしました。
・モデルにモデルを親子付け
 キャラクターに剣を持たせたりできるようになりました。
・丸影描画をデカール描画に変更
 これはピクセルシェーダ負荷を抑える必要があったので急遽作成しました。実は
 丸影描画シェーダはシェーダ命令数ギリギリまで使っていてとっても重かったという…;
・モーションのストックバッファを復活
 今まで動作が不安定だったストックバッファを復活させてみました。理由は単なる
 メモリリークでした。ただ、現在は頂点シェーダ負荷がボトルネックになっている
 訳でもないのでどれくらい高速化したのかは不明です。
・SSAOシェーダ
 ピクセルシェーダ負荷を軽くしなければならなかった理由がこれをやりたかったからです。
 ちょっと!SSAOですよ奥さん!笑

ざっとこんなもんです。一つ一つは今までの実装を少し改良したりといった程度の
ものなので、それほどでも無いのですが。唯一新しい機能といえるのがSSAOシェーダ
です。これはスクリーンスペースで遮蔽している部分を計算して陰影を描画するといった
シェーダで、動画では負荷軽減のためにモデルに対してのみしか適応させていないので
分かりにくいですが薄っすらと紫がかっている部分がそうです。本当ならば全体に対して
適応したいところですが、現時点で60FPSから20FPSにまで下がってしまったので
この辺で一旦ドクターストップをかけることにしました。

理想を言えば、もっと肌理細やかな陰影を期待していたんですが。レイの計算で使用する
レイ半径を小さくしすぎると全体の陰影が弱くなってしまい、逆にレイ半径を大きくしすぎる
と細かい陰影がでなくなってしまうのです。市販のゲームでは大きいSSAOシェーダと小さ
いSSAOシェーダの2段階を使用したりするものもあるそうですが。自分の環境でそこまで
リッチな使い方はできないので、チューニングでなんとか誤魔化すのが精一杯でした。

それと今現在は球面調和ライティングも勉強しているのですが、こちらはほとんど
頂点シェーダの計算だけでお手軽にGI計算が出来るのでSSAOを中止して球面調和
ライティングを実装しようかなと考えています。うまく出来るといいなぁ。

追加:
以前の動画だとSSAOの効果が分かりにくかったので、新しく分かりやすい色に変更して
再投稿してみました。

2011.10.16 C++:パーティクルのペアレント

パーティクルシステムをちょっと改良して親子付けできるようにしたので、これで動画の
ようなトレイルパーティクルが表現できるようになりました。…て、それだけだとほとんど
説明不足なので少しだけ解説を入れときましょうか;

まずモデルからパーティクルが放出されているのは、モデルの子としてパーティクル
エミッタを設定することで表現する、というのはある程度容易に想像がつくかと思いますが。
今回はそれだけではなくパーティクルがある程度群れを成して一直線上に放出しています。
これはパーティクルの群れの先頭のパーティクルを親パーティクル、後ろのパーティクル
を子のパーティクルとして設定し、親のパーティクル位置から新しい子パーティクルを放出
させることで表現している訳です。へぇ、なるほど~。でもそれだけだったら別に親子付け
しなくてもそういう動作のパーティクル作ればいいんじゃない?って思う人いそうですね;

親子付けで動作させる一番の魅力が、動き方の幅が使い方によって無限に広がると
いうことかなと思います。例えばLWのチュートリアルではパーティクルの親子付けを
利用して打ち上げ花火を表現したりしていますが。そういう"打ち上げ→爆発"といった
複雑な動きができたりするわけです。ただこれ、親子付けというより継承の方が正しい
んですが。3D的な名称で統一したいので個人的に親子付けと呼んでます苦笑。

とりあえずパーティクルの親子付けがひと段落したので、次にボーンとモデルの親子
付けで武器を持たせてみようかなと思います。