プロフィール

Na-7

Author:Na-7
SE(システムエンジニア)として約15年間システム系ソフト会社を勤めあげ、2008年3月退社。現在、ゲーム制作会社設立を目指して活動中。


アクセスカウンター


最新記事


最新コメント


最新トラックバック


月別アーカイブ


カテゴリ


DATE: CATEGORY:スポンサー広告
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
DATE: CATEGORY:三国志軍記開発
t-pot
t-pot
プロのゲームプログラマーのサイト。文字化けする場合は、ブラウザの表示設定を日本語(EUC)とすること。



◎HLSLの型と精度の問題

以前、HLSL内で頂点からパターン番号を取得し、パターンを3種類判別してテクスチャを表示する所までやりました。まずその状態に戻そうとしたのですが、パターン番号をうまく判別することができません。

調べていくと、こちらの記事に「整数計算は確実ではない」とあります。パターン番号は8桁整数で管理していたので、もしやこれが原因かと思い、float型に置き換えましたが、それでも思うようにいきません。

どうやら、パターン番号をColor.aに代入し、頂点シェーダからピクセルシェーダに受け渡す際に「1.0以上の値は自動的に丸められる」ようです。結局、以前と同じく「全て小数点以下にずらしてから受け渡す」ことにしました。

output.Color.a = input.Depth / 10000000;
(input.Depthにパターン番号が格納されている)

しかし、上記の処置を施しても、パターン番号が正確に判別できません。小数点以下3桁以内の値は取得できていて、小数点以下4桁目以降の値は取得できていないようでした。

「おかしいなぁ…いくらなんでもfloat型の有効桁数が3桁ってことはないはずだが…」と思いつつfloat型の有効桁数を確認すると「10進数では約7桁(完全なのは6桁まで)」とありました。

げっ、そんなに少なかったっけ?
今のパターン番号は8桁管理なので、1~2桁足りません。

まぁ、その問題は後で考え直すとして、今は有効桁数が6桁にも満たないことが問題です。もしかして「情報落ち」による誤差が発生しているのかと思い、一旦double型に変換してから計算してみましたが、駄目でした。



◎PIX登場

これ以上は実際の値を確認しないと、よくわかりません。というわけで、PIXを起動しました。シェーダーデバッガとして本格的に使うのは、これが初めてです。

適当なピクセルのレンダリング状況をPIXで確認すると…おや?少なくともPIXの画面を見る限り、Color.aの値は0.000~1.000、つまり小数点以下3桁までのようです。

本当に3桁しか無いのか、まいったな~(><)



◎値の受け渡し

有効桁数3桁ではパターン番号情報としては足りなさすぎるので、Color.aの他にピクセルシェーダにパターン番号を渡す方法を探ります。

・記憶域の修飾子
 →static、extern、uniform、sharedいずれを用いても
  ピクセルシェーダへの受け渡し不可。
 →(余談)DirectX HLSLには「nointerpolation:ピクセル
  シェーダーに渡す前に、頂点シェーダーの出力を
  補間しない」という修飾子がありました。欲しい…。

・定数レジスタ
 →Direct3D 9のasmシェーダーのリファレンスには、
  浮動小数点型定数レジスタがピクセルシェーダー
  入力レジスタと記述されていますが、
  このレジスタをHLSLで直接制御する方法が不明。
 →HLSL上では、適当に宣言した変数は
  自動的に定数レジスタに格納されるようですが、
  ピクセルシェーダから参照すると0になります。
  (:register(c0)などと指定した場合も同様)

・Color1セマンティクス
 →このセマンティクスを利用すると、値の受け渡しに成功。

というわけで、Color1セマンティクスの.r/.g/.b/.aに2桁ずつ番号を分解して格納し、ピクセルシェーダに受け渡すことにしました。



◎計算の誤差

output.patternNumber.a = (input.Depth % 100) / 100;

上記の計算結果をPIXで確認すると、誤差が0.005ありました。GPUによって差があるとは思いますが、誤差が0.5%もあったのはちょっと驚きです。

最近のパソコンって、意外といい加減なんですね…。



◎同志発見!

いろいろ調べていたら、こちらのQ&Aを見付けました。

最初は気付きませんでしたが、これって今私がやってることと一緒ですね!このQ&Aは過去に見掛けたことがありましたが、質問内容を読んで関係無いと判断し、ずっとスルーしてました(^^;

というわけで、Q&Aを参考に、以下のように変更します。

・VertexElementUsage.Depth → TextureCoordinateに変更
・誤差はround関数で対応する

あとは、頂点フォーマットにパターン番号を格納する「型」を何にするか、ですね。



◎頂点フォーマットの型

「今のパターン番号は8桁管理なので、float型では1~2桁足りない」という問題がありました。

float型でダメならint型にしたかったのですが、VertexElementFormatには単純な(1Dの)int型が存在しません。

う~ん…こうなると、Short4型が一番効率良さそうですね。



◎ベクトル型情報のパック

頂点フォーマットのパターン番号をshort[4]として、パターン番号を分解したら、地形表示がおかしくなりました。頂点バッファのサイズ指定を間違えたかと思って調べていたら「Short4構造体」を発見。short[4]ではなく、これを使ってパックしろってことだったんですね。

…ところが、このShort4型でパックする方法がさっぱり解りません。

こちらの記事を読んで「C#のインターフェイスとは何か?」ぐらいは理解したつもりですが、実際にXNAのIPackedVectorインターフェイスやPackFromVector4メソッドを使おうとしても、標準的な実装方法が全然分かりません。

・IPackedVectorは頂点フォーマットの引数の型として
 使用するものなのか?別途クラスか構造体を
 用意する必要があるのか?

・インターフェイスには実態が無い。PackFromVector4
 メソッドの実態はどのように用意すべきなのか?

ここで相当ハマりましたが、結局パック方法は解明できませんでした。サンプルも全然見当たらないし…遺憾ではありますが、Short4は諦めて、Vector4にします。



◎次回予告

4月になったので、次回は「3月の反省と4月の目標」です。

スポンサーサイト

テーマ : ゲーム製作 関連 - ジャンル : ゲーム

コメント

Short4

はじめまして。
シェーダ周りは試行錯誤が必要と思いますが、
Short4についてに一言。次の方法で作れます。
new Microsoft.Xna.Framework.Graphics.PackedVector.Short4(1.0f, 2.0f, 3.0f, 4.0f);

ありがとうございます

XELFさんはじめまして。
今後ともよろしくお願いします。

>次の方法で作れます。

コンストラクタを利用するのですね。ありがとうございます。早速試してみます。

解決しました

4/9の記事に書きましたが、Short4の問題は無事解決しました。

XELFさん、どうもありがとうございました。

コメントの投稿


管理者にだけ表示を許可する

トラックバック


この記事にトラックバックする(FC2ブログユーザー)



copyright © ゲーム制作の舞台裏 all rights reserved.Powered by FC2ブログ
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。