トップページ > 過去ログ > 記事閲覧
3Dモデルの一部が表示されない
名前:牧場王 日時: 2010/05/01 15:27

どうしても自力で解決できない問題があり、初投稿させて頂きます。 表題の通り、3Dモデルの一部が表示されない現象が発生しました。 画像を以下に保存しましたので、参照頂けると幸いです。 www1.axfc.net/uploader/Img/so/81070&key=0001 画像を見て頂けると分かると思いますが、画面上部に設置した魔方陣モデルの一部が欠けてしまっています。このモデルはXY平面と平行なのですが、平面に垂直なある位置から、手前方向にカットされてしまっています。 このような現象にお心当たりある方がいらっしゃれば、アドバイス頂けると幸いです。 なお、以下は実施済みで、現象に変化ありませんでした。 ・Zバッファの使用 ・視野角、視点の変更 ・SetCameraNearFarの変更 また、当方の環境は 開発環境:VC2008 Express DXライブラリ:恐らく最新(10/1/2頃更新) OS:Windows Vista UT 32bit SP2 GPU;nVidia GeForce 9300M ※ソースコードは、要望があり次第の提出とさせて頂きます。 (オブジェクト指向で作成しており、関連箇所の抽出が難しいため)

Page: 1 |

Re: 3Dモデルの一部が表示されない ( No.1 )
名前:管理人 日時:2010/05/01 17:51

アップしていただいた画像からは Near クリップされているように見えます SetCameraNearFar で Near クリップの値を低くすれば表示されると思いますが・・・駄目だったのでしょうか? また、カメラを対象から遠ざけてもクリップされてしまうのでしょうか?
Re: 3Dモデルの一部が表示されない ( No.2 )
名前:牧場王 日時:2010/05/01 21:06

早速のご返信有難うございます。 SetCameraNearFarでは、限界近くまで近くの物を表示するように設定しております。 カメラを対象から遠ざければ解消するのですが、他の設定との連動があり(Effectクラスの表示は全て同じ距離で設定)一筋縄では行かなかったので、他の回避策を模索していた所でした。 やはり、対象を遠ざけるしか方法は無いでしょうか...
Re: 3Dモデルの一部が表示されない ( No.3 )
名前:管理人 日時:2010/05/02 23:38

プログラムを拝見してみないとなんとも言えないのですが、カットされてしまっている部分がカメラの後ろ側に 位置していると言う事はありませんでしょうか? その場合ですと、Near の値を幾ら小さくしても画面には表示されませんが・・・
Re: 3Dモデルの一部が表示されない ( No.4 )
名前:牧場王 日時:2010/05/03 22:09

恐らく、カメラの後ろに廻っているということは無いと思っています。 当方のコードでは、以下のように使用しており ・SetCameraNearFar(100.0f, 10000.0f) ・ConvScreenPosToWorldPos(VGet(mX, mY, 0.2f)) :モデルの位置 モデルのサイズはZ方向が100.0f程度(のはず)ですので、 単純計算では十分に距離が取れていると考えています。 やはりカメラ関係の可能性が高いとのことですので、当方でも DrawSphere3Dに置き換えて同現象が再現するか等、色々と確認致します。 再度ご連絡させて頂きます。 ※この掲示板では、勝手に改行されないのですね。  文章が読みづらくすみませんでした。
Re: 3Dモデルの一部が表示されない ( No.5 )
名前:バトーキン 日時:2010/05/05 03:50

横から失礼します。 ちょうど、私も、 SetCameraNearFar() の設定でハマった所でして。 プログラムの先頭部分で、一度だけ SetCameraNearFar() を設定しても、 カメラに反映されなくて困っていたのですが、 毎フレーム、SetCameraPositionAndAngle() する直前に、 SetCameraNearFar() することで、設定が反映されるようになりました。 検証プログラムを書いてから、質問に来るつもりだったのですが、 問題の症状に関係あるかもしれないので、便乗させて頂きました。 SetCameraNearFar() の設定というのは、 何かのタイミングでリセットされることはあるのでしょうか? ( SetDrawScreen とか、ClearDrawScreen とか、SetDrawMode とか )
Re: 3Dモデルの一部が表示されない ( No.6 )
名前:牧場王 日時:2010/05/08 16:49

検証が遅くなりましたが、確認結果を記載します。 ・同サイズのDrawSphere3Dに置き換え表示:不再現 ・同サイズの球体3Dモデルに置き換え表示:再現 現状、モデル使用時のみ再現しています。 なお、バトーキンさんに情報を頂いた、SetCameraNearFarの 毎フレーム実行でも、現象は変わりませんでした。 >バトーキンさん  情報頂いている中で済みませんが、当方の現象とは別現象のようです。 モデル関係の描画で注意すべきことや、実施しておいたほうが良い 設定等があれば試したいと考えております。 大変お手数ですが、ご教授宜しくお願い致します。 補足: 小出しで済みませんが、関係有ると思われる箇所のコードを 追加で以下に記載しておきます。 ----- 初期化時に実行 ----- SetCameraPositionAndTarget_UpVecY( VGet( 0.0f, 600.0f, 200.0f ), VGet( 0.0f, 0.0f, 1000.0f )); SetCameraScreenCenter( 400.0f, 150.0f ); SetCameraNearFar(100.0f, 10000.0f); int LightHdl = CreatePointLightHandle( VGet(128.0f,128.0f,128.0f),10000.0f, 0.0f, 0.002f, 0.0f ); SetFogEnable(true); SetFogColor(224, 224, 224); SetFogStartEnd( 0.0f, 2500.0f ) ; -----
Re: 3Dモデルの一部が表示されない ( No.7 )
名前:管理人 日時:2010/05/09 04:52

恐らく原因が分かりました > ConvScreenPosToWorldPos(VGet(mX, mY, 0.2f)) :モデルの位置 こちらの ConvScreenPosToWorldPos に渡すスクリーン座標のZについてですが、 このZ値の変化と変換後のワールド座標とカメラ座標との距離は内部で行われている 計算の性質上綺麗に比例していません つまりこんな感じになります 関数に渡すベクトルのZ(左)とワールド座標に変換された後の座標とカメラとの距離(右) ( SetCameraNearFar( 100.0f, 10000.0f ) ; の場合 ) 0.0f 100.0f 0.2f 124.688f 0.4f 165.563f 0.6f 246.305f 0.8f 480.769f 1.0f 10000.0f 折れ線グラフにすると分かりやすいのですが、最後の0.1f分くらいまで非常になだらかに 距離が増えていき、そこから一気に10000.0fに向かって値が増えていきます なので、ConvScreenPosToWorldPos に渡すベクトルのZ値に 0.2f を指定した場合は 戻り値のベクトルとカメラとの距離は上の表で言うと 124.688f となり、Near クリッピング面 から 24.688f しか離れていないので半径50.0fの幅を持つモデルを表示すると手前の半分くらいが Nearクリッピングされてしまいます このことを注釈に書くべきでした、申し訳ありません で、ConvScreenPosToWorldPosに渡すベクトルのZ値と変換後の座標とカメラとの距離が綺麗に 比例する方が今回牧場王さんが実装されようとしているような処理の場合は使いやすいので、 そのように動作する関数を追加しました よろしければその機能を追加したバージョンをダウンロードしてください m(_ _)m http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』、VCをお使いの場合は『リビルド』をして下さい) 追加した関数は以下の関数です // スクリーン座標をワールド座標に変換する( Z座標が線形 ) VECTOR ConvScreenPosToWorldPos_ZLinear( VECTOR ScreenPos ) ; こちらの関数では牧場王さんの意図した通りの結果が得られると思います ScreenPos.z が 0.2f だった場合の ConvScreenPosToWorldPos_ZLinear の返り値と カメラとの距離は 100.0f + ( 10000.0f - 100.0f ) * 0.2f となります ( つまり Near + ( Far - Near ) * ScreenPos.z ) よろしければお使い下さい m(_ _)m > バトーキンさん リファレンスマニュアルに載せ忘れていたのですが、 SetCameraNearFar の設定は SetGraphMode,ChangeWindowMode,SetDrawScreen のいずれかの関数を呼び出すと リセットされます、もしこれが原因でしたら申し訳ありません m(_ _;m
Re: 3Dモデルの一部が表示されない ( No.8 )
名前:牧場王 日時:2010/05/09 15:42

早速のご対応有難うございます! また、深夜迄対応頂き、大変感謝しております。 原因と、対策の内容について了解致しました。 使用させて頂き、本現象を回避出来ることを確認出来ました。 大変恐縮ですが、もう一つだけ追加で質問させて頂いても 宜しいでしょうか? 該当のモデルを画面外へ移動させる際、完全に画面から出た後に モデルを消去したいのですが、モデルが存在するにもかかわらず ある地点から急に描画されなくなるのです。 そこで仕様について確認させて頂きたいのですが、 DxLibがモデルを描画しなくても良いと判断するのは、モデルの中心 座標がカメラ視野から外れた場合でしょうか? それとも、モデルに存在する頂点が全て視野外に出た場合でしょうか?
Re: 3Dモデルの一部が表示されない ( No.9 )
名前:バトーキン 日時:2010/05/09 21:24

回答ありがとうございます。 なるほど、私の場合は 毎フレームのSetDrawScreen で、 値をリセットしていたようです。 問題は解決できました。ありがとうございます。
Re: 3Dモデルの一部が表示されない ( No.10 )
名前:管理人 日時:2010/05/10 01:02

> モデルが存在するにもかかわらず > ある地点から急に描画されなくなるのです。 恐らくDXライブラリの「画面内にあるかどうか」を判定するプログラムにバグがあるのだと思います > DxLibがモデルを描画しなくても良いと判断するのは、モデルの中心 > 座標がカメラ視野から外れた場合でしょうか? > それとも、モデルに存在する頂点が全て視野外に出た場合でしょうか? 描画をするかしないかは、モデルのフレーム単位で行っていて、そのフレームの頂点座標値の最大値と最小値を 使ってできるボックスが完全に視界に入っていないときに描画をしない、という処理をしています なので、この処理にバグが無い場合は「見えているはずなのにクリッピングアルゴリズムの関係上描画されない」ということは 有り得ないようになっています 幾つか思い当たる部分があるのでこのバグについては私の方だけでも再現できるかもしれませんが、 もし牧場王さんの手元で簡単に再現できるということでしたら、よろしければ 再現用のプログラムをこちらのスレッドに貼り付けていただけないでしょうか? ( とはいえ、このバグの修正ができるのは次の週末になってしまいますが orz )
Re: 3Dモデルの一部が表示されない ( No.11 )
名前:牧場王 日時:2010/05/10 04:18

早速のご連絡有難うございます。 実際のコードをUPしても非常に見難いと思われましたので、再現するコードの 一部を抜き出してサンプルプログラムを新規作成しました。 以下がソース/実行ファイル/サンプルモデルのセットです。 www1.axfc.net/uploader/He/so/277061&key=DxLib 平面モデルをZ方向に往復移動させるだけのプログラムとなっています。 ※本来このモデルにはテクスチャが張られていますが、テクスチャ  無しの方が分かり易いと思いましたので同梱していません。 大変お手数ですが、ご確認宜しくお願い致します。
Re: 3Dモデルの一部が表示されない ( No.12 )
名前:牧場王 日時:2010/05/10 05:11

済みません。自己レスさせて頂きます。 サンプルプログラムの作成過程で、何が問題か分かりました。 モデルは管理人さんのおっしゃる通り、視野から完全に出た後に消失していましたので この処理には問題無いと思われます。 問題は、カメラ座標が想定よりも前にあるということでした。 意図が伝わりにくいと思われますので、サンプルプログラムを少し修正しました。 www1.axfc.net/uploader/He/so/277062&key=DxLib このサンプルでは、視野角を120度、注視点を約60度の方向として、 視野角の手前がほぼY軸に平行になるように設定しています。 SetCameraPositionAndTarget_UpVecY( VGet( 0.0f, 600.0f, 0.0f ), VGet( 0.0f, 0.0f, 1.732f * 600.0f)); この状態で、Z=0が画面下端に来て欲しいのですが、下端が期待したよりも 手前まで写してしまっています。 上記のように設定したい場合、既存の関数で調整することは可能でしょうか?
Re: 3Dモデルの一部が表示されない ( No.13 )
名前:管理人 日時:2010/05/16 20:37

サンプルをアップしていただきありがとうございます まず、やはりDXライブラリの視界に入っているかどうかを判定する処理にバグがありました、 よろしければこちらをお使い下さい m(_ _;m http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』、VCをお使いの場合は『リビルド』をして下さい) そして牧場王さんの計算で導き出された値を SetCameraPositionAndTarget_UpVecY に代入しても Z=0.0f の位置が画面下端にならないのは SetCameraScreenCenter で3D表示の消失点を 画面上方にずらしているからです( ちなみに視界に入っているかどうかを判定する処理のバグも この関数の設定を考慮していないのが原因でした ) ずれた分だけ視線の方向を変える計算をしてみたのですが、複雑な計算になってしまったので 少し手抜きをすることにしました #define SCREEN_HEIGHT 600 #define EYE_Y 600.0f void SetScreenBottomZ( void ) { float BottomZ, TopZ, TestZ, Sa ; VECTOR ScreenPos ; // 視線方向として試す一番小さなZ座標 BottomZ = -10000.0f ; // 視線方向として試す一番大きなZ座標 TopZ = 10000.0f ; // 最初に試すZ座標を算出( TopZ と BottomZ の中間 ) TestZ = ( TopZ + BottomZ ) / 2.0f ; // 条件が揃うまでループ for(;;) { // (0.0f, EYE_Y, 0.0f) から ( 0.0f, 0.0f, TestZ ) を見るカメラをセット SetCameraPositionAndTargetAndUpVec( VGet( 0.0f, EYE_Y, 0.0f ), VGet( 0.0f, 0.0f, TestZ ), VGet( 0.0f, 0.0f, 1.0f ) ); // Z が 0 の時のスクリーン座標を取得する ScreenPos = ConvWorldPosToScreenPos( VGet( 0.0f, 0.0f, 0.0f ) ) ; // 画面下端の座標( SCREEN_HEIGHT )との差を計算する Sa = ScreenPos.y - SCREEN_HEIGHT ; if( Sa < 0.0f ) Sa = -Sa ; // 差を得たいので、マイナスの場合はプラスにする // もし差が 0.01f ドット以下だったらループから抜ける if( Sa < 0.01f ) break ; // 結果が画面下端より高いかどうか( y座標値が小さいかどうか )で処理を分岐 if( ScreenPos.y < SCREEN_HEIGHT ) { // 今まで試した中で一番小さいZ値よりも大きかったらBottomZを今回試した値に変更 if( BottomZ < TestZ ) BottomZ = TestZ ; } else { // 今まで試した中で一番大きいZ値よりも小さかったらBottomZを今回試した値に変更 if( TopZ > TestZ ) TopZ = TestZ ; } // 次に試すZ座標を算出( TopZ と BottomZ の中間 ) TestZ = ( TopZ + BottomZ ) / 2.0f ; } } この関数を実行すると、視点の座標 (x,y,z) = ( 0.0f, 600.0f, 0.0f ) から丁度 z座標が0.0f の 位置を画面の下端になるようにカメラの視線方向を設定します 仕組みとしては、希望の視点( 0.0f, 600.0f, 0.0f )から、Z軸上のどこかを注視点にすれば画面の 下端に Z の原点がくるはずなので、それを計算で導き出すのではなく、プログラムで色んな視線を 試してその座標を探してしまおうというものです 例えば最初はカメラの注視点を ( 0.0f, 0.0f, 0.0f ) としてみます、するとZの原点のスクリーン上のy座標は 70になったとします、今回のケースの場合は注視点のZ値を大きくすればするほどスクリーン座標に変換されたときの y座標も大きくなるので、希望するy座標( 画面下端の y座標 )より小さかったということは注視点のZ座標を もっと大きくする必要があるということが分かります  なので今度は ( 0.0f, 0.0f, 5000.0f ) を注視点として、再度Zの原点のスクリーンy座標を調べると、 今度は4400になりました、今度は行き過ぎたわけです  この時点で目的の注視点のZ座標は 0 以上 5000 以下の何処かにあるということがわかりますので、今度は中間を取って 2500 で調べてみます、すると今度は y座標は 2235 になりました、これで目的の注視点のZ座標は 0 以上 2500 以下の何処か ということになります ・・・という感じで、徐々に調べる範囲を狭めて行き、最終的にZ軸の原点が画面下端に限りなく近づいたらそこでループから抜けます 何回も設定をしなおして試すので処理負荷は複雑な計算式一回で導き出すよりかなり重いですが、それほど頻繁に行うわけでなければ 特に問題は無いと思います
Re: 3Dモデルの一部が表示されない ( No.14 )
名前:牧場王 日時:2010/05/16 22:50

度々のご対応有難うございます! 成程、良く分かりました。 過去ログに同様の質問が無かったのが疑問でしたが、 SetCameraScreenCenter起因ということで納得しました。 SetCameraScreenCenterを呼び出した後に、追加頂いた SetScreenBottomZ を 使用させて頂きます。 2010対応等でご多忙の中、大変お手数をお掛けしました。
Re: 3Dモデルの一部が表示されない ( No.15 )
名前:牧場王 日時:2010/05/16 23:20

※1点、私の上記記載に間違いがあったので訂正しておきます。 SetScreenBottomZ は SetCameraScreenCenter の中で呼ばれているので、 こちらが意識的に呼ぶ必要は無いということですね。 (使用しようとしたら、外部関数になっていなかったので気付きました) 失礼を致しました。
Re: 3Dモデルの一部が表示されない ( No.16 )
名前:管理人 日時:2010/05/16 23:36

あ、すいません SetScreenBottomZ はDXライブラリの関数ではありません No.13 に書き込んだ関数をそのままコピー&ペーストして お使い下さい m(_ _)m

Page: 1 |