トップページ > 記事閲覧
ライティング時のポリゴンのチラつきについて
名前:まーく 日時: 2025/01/13 02:14

素晴らしいライブラリを公開してくださり、ありがとうございます 今3Dゲームの勉強中です 公開されている下ページのサンプルをいじっています dxlib.xsrv.jp/program/dxprogram_3Dmeiro.html テクスチャをべた塗りの画像に変更しChangeLightTypePointでポイントライトを使ったところ、ポリゴンのメッシュ?が光で変に浮き出て目立った感じになり 対策を調べていましたら、粗いメッシュできれいにポイントライトを表現するにはピクセルシェーダーを使うしかないとあり、下のページのシェーダーを試してみました <剛体メッシュのポイントライトありフォンシェーディング描画> dxlib.xsrv.jp/program/dxprogram_3DModelShaderBase.html 結果、一部でポリゴンのチラつきが発生します 下に動画を投稿しました imgur.com/a/DPeAX71 原因と対策がありましたら、教えていただけると幸いです よろしくお願いいたします
メンテ

Page: 1 |

Re: ライティング時のポリゴンのチラつきについて ( No.1 )
名前:まーく 日時:2025/01/12 21:44

迷路のサンプルコードですが、少しいじりました #include "DxLib.h" #include <math.h> #define BLOCK_SIZE 1000.0f // ブロックのサイズ #define BLOCK_NUM_X 8 // X方向のブロック数 #define BLOCK_NUM_Z 8 // Z方向のブロック数 #define CAMERA_Y 500.0f // カメラの高さ #define MOVE_FRAME 30 // 移動や旋回に掛けるフレーム数 // マップ( 1:道 0:壁 ) char Map[BLOCK_NUM_Z][BLOCK_NUM_X] = { 0,0,0,0,0,0,0,0, 0,1,1,1,1,1,1,0, 0,1,1,1,1,1,1,0, 0,1,1,1,1,1,1,0, 0,1,1,1,1,1,1,0, 0,1,1,1,1,1,0,0, 0,1,1,1,1,1,1,0, 0,0,0,0,0,0,0,0, }; // WinMain int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int KabeModel; // 壁モデル int x, z; // 位置 int movx, movz; // 移動先の座標 int Muki; // 向き( 0:x軸プラス方向 1:z軸マイナス方向 2:x軸マイナス方向 3:z軸プラス方向 ) int NowInput; // 現在のフレームの入力 int FrameNo; // フレーム番号 int State; // 状態( 0:入力待ち 1:前進中 2:後退中 3:左旋回中 4:右旋回中 ) int Count; // 汎用カウンタ int i, j; // 汎用変数 float f; // 汎用変数 VECTOR CamPos; // カメラの座標 VECTOR CamDir; // カメラの向いている方向 VECTOR CamTarg; // カメラの注視点 // ウインドウモードで起動 ChangeWindowMode(TRUE); // Direct3D9Ex を使用する SetUseDirect3DVersion(DX_DIRECT3D_9EX); // DXライブラリの初期化 if (DxLib_Init() < 0) return -1; // プログラマブルシェーダーモデル2.0が使用できない場合はエラーを表示して終了 if (GetValidShaderVersion() < 200) { // エラー表示 DrawString(0, 0, "プログラマブルシェーダー2.0が使用できない環境のようです", GetColor(255, 255, 255)); // キー入力待ち WaitKey(); // DXライブラリの後始末 DxLib_End(); // ソフト終了 return 0; } //●●● 追加部分 ●●● MV1SetUseOrigShader(TRUE); int PixelShaderHandle; int VertexShaderHandle; // 頂点シェーダーを読み込む VertexShaderHandle = LoadVertexShader("NormalMesh_PointLight_PhongVS.vso"); // ピクセルシェーダーを読み込む PixelShaderHandle = LoadPixelShader("NormalMesh_PointLight_PhongPS.pso"); //●●● 追加部分 ●●● // 壁モデルの読みこみ KabeModel = MV1LoadModel("Kabe.mqo"); // 位置と向きの初期化 x = 1; z = 1; Muki = 0; // カメラの座標と向きと注視点をセットする CamPos = VGet(x * BLOCK_SIZE, CAMERA_Y, z * BLOCK_SIZE); CamDir = VGet(1.0f, 0.0f, 0.0f); CamTarg = VAdd(CamPos, CamDir); SetCameraPositionAndTarget_UpVecY(CamPos, CamTarg); //●●● 追加部分 ●●● SetLightAmbColor(GetColorF(0.5f, 0.5f, 0.5f, 1.0f)); ChangeLightTypePoint(CamPos, 4000.0f, 0.0f, 0.001f, 0.0000001f); //●●● 追加部分 ●●● // 状態の初期化 State = 0; // 描画先を裏画面にする SetDrawScreen(DX_SCREEN_BACK); //●●● 追加部分 ●●● // モデルの描画にオリジナルシェーダーを使用する設定をONにする // 使用する頂点シェーダーをセット SetUseVertexShader(VertexShaderHandle); // 使用するピクセルシェーダーをセット SetUsePixelShader(PixelShaderHandle); //●●● 追加部分 ●●● // メインループ // エスケープキーが押されるまでループ while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0) { // 画面をクリアする ClearDrawScreen(); // 現在の入力を取得する NowInput = GetJoypadInputState(DX_INPUT_KEY_PAD1); // 状態によって処理を分岐 switch (State) { case 0: // 入力待ち状態 // 上が押されたら向いている方向に移動する状態に移行する if ((NowInput & PAD_INPUT_UP) != 0) { // 向きによって移動方向が変わる switch (Muki) { case 0: movx = 1; movz = 0; break; // X軸プラス方向 case 1: movx = 0; movz = -1; break; // Z軸マイナス方向 case 2: movx = -1; movz = 0; break; // X軸マイナス方向 case 3: movx = 0; movz = 1; break; // Z軸プラス方向 } // 移動先のマスが道だったら移動する if (Map[z + movz][x + movx] == 1) { // 状態を前進中にする State = 1; Count = 0; } } // 下が押されたら向いている方向と逆方向に移動する if ((NowInput & PAD_INPUT_DOWN) != 0) { // 向きによって移動方向が変わる switch (Muki) { case 0: movx = -1; movz = 0; break; // X軸プラス方向 case 1: movx = 0; movz = 1; break; // Z軸マイナス方向 case 2: movx = 1; movz = 0; break; // X軸マイナス方向 case 3: movx = 0; movz = -1; break; // Z軸プラス方向 } // 移動先のマスが道だったら移動する if (Map[z + movz][x + movx] == 1) { // 状態を後退中にする State = 2; Count = 0; } } // 左が押されていたら向いている方向を左に90度変更する if ((NowInput & PAD_INPUT_LEFT) != 0) { // 状態を左旋回中にする State = 3; Count = 0; } // 右が押されていたら向いている方向を右に90度変更する if ((NowInput & PAD_INPUT_RIGHT) != 0) { // 状態を右旋回中にする State = 4; Count = 0; } break; case 1: // 前進中状態 // カウントを進める Count++; // カメラの座標を移動途中の座標にする CamPos = VGet(x * BLOCK_SIZE, CAMERA_Y, z * BLOCK_SIZE); CamPos = VAdd(CamPos, VScale(CamDir, BLOCK_SIZE * Count / MOVE_FRAME)); CamTarg = VAdd(CamPos, CamDir); // カウントが移動時間に達したら実座標を移動して入力待ち状態に戻る if (Count == MOVE_FRAME) { x += movx; z += movz; State = 0; Count = 0; } break; case 2: // 後退中状態 // カウントを進める Count++; // カメラの座標を移動途中の座標にする CamPos = VGet(x * BLOCK_SIZE, CAMERA_Y, z * BLOCK_SIZE); CamPos = VSub(CamPos, VScale(CamDir, BLOCK_SIZE * Count / MOVE_FRAME)); CamTarg = VAdd(CamPos, CamDir); // カウントが移動時間に達したら実座標を移動して入力待ち状態に戻る if (Count == MOVE_FRAME) { x += movx; z += movz; State = 0; Count = 0; } break; case 3: // 左旋回中状態 // カウントを進める Count++; // 向いている方向を旋回途中の方向にする switch (Muki) { case 0: f = 0.0f; break; // Xプラス方向 case 1: f = -DX_PI_F / 2.0f; break; // Zマイナス方向 case 2: f = DX_PI_F; break; // Xマイナス方向 case 3: f = DX_PI_F / 2.0f; break; // Zプラス方向 } f += DX_PI_F / 2.0f * Count / MOVE_FRAME; CamDir.x = cos(f); CamDir.z = sin(f); CamTarg = VAdd(CamPos, CamDir); // カウントが推移時間に達したら実方向を変更して入力待ち状態に戻る if (Count == MOVE_FRAME) { if (Muki == 0) { Muki = 3; } else { Muki--; } State = 0; Count = 0; } break; case 4: // 右旋回中状態 // カウントを進める Count++; // 向いている方向を旋回途中の方向にする switch (Muki) { case 0: f = 0.0f; break; // Xプラス方向 case 1: f = -DX_PI_F / 2.0f; break; // Zマイナス方向 case 2: f = DX_PI_F; break; // Xマイナス方向 case 3: f = DX_PI_F / 2.0f; break; // Zプラス方向 } f -= DX_PI_F / 2.0f * Count / MOVE_FRAME; CamDir.x = cos(f); CamDir.z = sin(f); CamTarg = VAdd(CamPos, CamDir); // カウントが推移時間に達したら実方向を変更して入力待ち状態に戻る if (Count == MOVE_FRAME) { if (Muki == 3) { Muki = 0; } else { Muki++; } State = 0; Count = 0; } break; } //●●● 追加部分 ●●● SetLightPosition(CamPos); // カメラの位置と向きをセットする SetCameraPositionAndTarget_UpVecY(CamPos, CamTarg); // マップを描画する for (i = 0; i < BLOCK_NUM_Z; i++) { for (j = 0; j < BLOCK_NUM_X; j++) { // 道ではないところは描画しない if (Map[i][j] == 0) continue; // 壁モデルの座標を変更する MV1SetPosition(KabeModel, VGet(j * BLOCK_SIZE, 0.0f, i * BLOCK_SIZE)); // 4方の壁の状態で描画するフレーム番号を変更する FrameNo = 0; if (Map[i][j + 1] == 0) FrameNo += 1; if (Map[i][j - 1] == 0) FrameNo += 2; if (Map[i + 1][j] == 0) FrameNo += 4; if (Map[i - 1][j] == 0) FrameNo += 8; // 割り出した番号のフレームを描画する MV1DrawFrame(KabeModel, FrameNo); } } // 裏画面の内容を表画面に反映する ScreenFlip(); } //●●● 追加部分 ●●● // 読み込んだ頂点シェーダーの削除 DeleteShader(VertexShaderHandle); // 読み込んだピクセルシェーダーの削除 DeleteShader(PixelShaderHandle); // DXライブラリの後始末 DxLib_End(); // ソフトの終了 return 0; }
メンテ
Re: ライティング時のポリゴンのチラつきについて ( No.2 )
名前:まーく 日時:2025/01/12 22:59

気づいたことがあるので追記します このサンプルに dxlib.xsrv.jp/program/dxprogram_3Dmeiro.html SetUseDirect3DVersion(DX_DIRECT3D_9EX); を追加しただけで同じ現象が発生しました SetUseDirect3DVersion(DX_DIRECT3D_11); だと発生しません それならばと思って上にあげたシェーダー使用のコードにDX_DIRECT3D_11 を指定すると nvwgf2umx.pdb シンボルが読み込まれていないといったエラーが発生します C:\Windows\System32\DriverStore\FileRepository\nvmdsig.inf_amd64_0f7e9ba88a9008a9\nvwgf2umx.dll 私の環境ですが Windows10でVisual Studio Community Edition グラボはGeforce RTX2060を使用しています
メンテ
Re: ライティング時のポリゴンのチラつきについて ( No.3 )
名前:管理人 日時:2025/01/13 01:05

手元でも dxprogram_3Dmeiro.html のプログラムに SetUseDirect3DVersion(DX_DIRECT3D_9EX); を追加すると 移動時に一瞬壁が消える現象を確認しました ただ、こちらの現象、ScreenFlip(); の後に WaitTimer( 100 ); を記載するなどウェイトを入れると 再現しなくなる等、原因は不明です Direct3D 11 と Direct3D 9 のクリッピングアルゴリズムの違い等が 関係しているかもしれませんが、単純に Direct3D 9 のバグかもしれません ただ、大きな壁を2つの三角形ポリゴンで表示するというのは少々粗すぎる気がするので、Kabe.mqo の 壁一面辺り2ポリゴンではなく、もっと細かくポリゴンを使う形にしてみました( 縦横8分割して、1面辺り 128ポリゴン使うようにしました ) すると本件の現象が発生しなくなったので、よろしければまーくさんが使用されている壁モデルも 壁1面を2ポリゴンではなくもっと細かく分割してみてください m(_ _)m <サンプルデータの Kabe.mqo も分割数を増やしたモデルに変更しました> https://dxlib.xsrv.jp/program/Data/Kabe.zip > それならばと思って上にあげたシェーダー使用のコードにDX_DIRECT3D_11 を指定すると >  > nvwgf2umx.pdb シンボルが読み込まれていないといったエラーが発生します > C:\Windows\System32\DriverStore\FileRepository\nvmdsig.inf_amd64_0f7e9ba88a9008a9\nvwgf2umx.dll Direct3D 9 用のシェーダーは Direct3D 11 では使用できませんので、DX_DIRECT3D_11 を指定する場合は 使用するシェーダーも Direct3D 11 用のものを用意する必要があります ただ > テクスチャをべた塗りの画像に変更しChangeLightTypePointでポイントライトを使ったところ、ポリゴンのメッシュ?が光で変に浮き出て目立った感じになり こちらの対策につきましては、リファレンスには載っていませんが SetUsePixelLighting という関数に TRUE を渡して呼び出すことでピクセル単位のライティングが行われてポリゴンが強調されなくなりますので、 よろしければシェーダーを使用する代わりに DxLib_Init の呼び出し後に SetUsePixelLighting( TRUE ); という 記述を増やしてみてください m(_ _)m // ピクセル単位でライティングを行うかどうかを設定する // Flag TRUE:ピクセル単位のライティングを行う FALSE:頂点単位のライティングを行う( デフォルト ) int SetUsePixelLighting( int Flag ) ;
メンテ
Re: ライティング時のポリゴンのチラつきについて ( No.4 )
名前:まーく(解決) 日時:2025/01/13 02:14

返信ありがとうございます 新しいKabe.qmoでは綺麗なポイントライトが表現されるのを確認いたしました 実は自分でメタセコイアと格闘しながら全フレーム分を2〜4分割して試していたのですが、やはり光り加減がおかしいと感じて諦めていました 分割数が足りなかったのですね... あれから調べてこちらのスレッドを見つけ、DX9がダメならDX11対応済みのシェーダーを使わせてもらおうかなと思っていましたが dxlib.xsrv.jp/cgi/patiobbs/patio.cgi?mode=view&no=4202 最後に教えてくださったSetUsePixelLightingですべて解決しました シェーダーの勉強をする覚悟でいました... ありがとうございましたm(_ _)m
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存