ごちゃログぴこっ

はなまるデジタル創作紀行(DTM、TAS、いろいろな技術)

DeSmuMEに3D表示抑制機能を足してみた

Download Windows binary & source code (desmume 0.9.8-gfx3dHack)

ゲーム中のキャラクタの画像だけとか、地形の画像だけキャプチャしたい時ってありますよね。他のエミュレータと同じくDeSmuMEにもレイヤー表示・非表示を切り替える機能はあるのですが、ゲームによっては前景から背景に至るまで同一レイヤーで3D描画していることがあり、この場合には前述の機能は役に立ちません。

じゃあ何かしら役に立つ機能をつけてみようというのが本日の趣旨です。

改造の概要

「3D描画を部分的に抑制したい」というのが今回求める機能です。

内部的には3Dデータは多数のポリゴンで構成されています。これを位置情報に基づいて、3Dエンジンが背面〜前面にかけて描画することで処理されます。表示を抑制したければ、一部のポリゴンの描画処理をあえて行わなければ良いのです。簡単ですね。

レイヤーと同様にポリゴンの表示・非表示機能をつければ良さそうですが、困ったことにポリゴンの数は軽く100を超えるくらいには多いです。個別切り替えでは使い勝手もよくなさそうなので、「前の方のポリゴンを非表示」「後ろの方のポリゴンを非表示」という形で対応することにしました。「前の方」「後ろの方」の度合いを切り替えできるようにすることで、抑制度合に柔軟性をもたせます。

コードと使い方

0.9.8 のソースコードとの差分を作成して、改造版を作成しました。ダウンロードリンクは記事の冒頭にあります。

新しくダイアログを設けるのは実装の手間がかかるので、表示の抑制はLuaスクリプトを通じて行う形にしました。

-- desmume 0.9.8-gfx3dHack sample script

local gfx3dMin, gfx3dMax = 0.000000, 1.000000
function modifyVisibility()
	gui.text(0, 0, string.format("%f %f", gfx3dMin, gfx3dMax))
	gui.setgfx3dvisibility(gfx3dMin, gfx3dMax)
end

local keys = { {}, {} }
gui.register(function()
	keys[1] = input.get()

	if keys[1]["6"] then
		gfx3dMin = math.min(math.max(gfx3dMin - 0.001, 0.0), 1.0)
	end
	if keys[1]["7"] then
		gfx3dMin = math.min(math.max(gfx3dMin + 0.001, 0.0), 1.0)
	end
	if keys[1]["8"] then
		gfx3dMax = math.min(math.max(gfx3dMax - 0.001, 0.0), 1.0)
	end
	if keys[1]["9"] then
		gfx3dMax = math.min(math.max(gfx3dMax + 0.001, 0.0), 1.0)
	end

	modifyVisibility()

	keys[2] = keys[1]
end)

emu.registerexit(function()
	gui.setgfx3dvisibility(0.0, 1.0)
end)

追加した関数は1つだけです。

function gui.setgfx3dvisibility(gfx3dStart, gfx3dEnd)
-- gfx3dStart: 0.0 = no effect, 1.0 = hide all polygons
-- gfx3dEnd: 0.0 = hide all polygons, 1.0 = no effect

3Dポリゴンの表示割合を設定します。最前面・最背面にあるポリゴンの一部を隠すことができるようになっていて、例えば 0.2, 0.9 と指定すると、全ポリゴンのうち、最背面にある 20% のポリゴンと、最前面にある 10% (100%-90%) のポリゴンは表示されなくなります。サンプルスクリプトでは、数字の 6, 7, 8, 9 キーを使ってこの表示割合を変更できるようにしてあります(スクリプト自体の利便性は高くないので、目的に応じて改良することができると思います)。

感想

万能ではないですが、良い感じに欲しい画像が得られるようになりました。

総ポリゴン数は細かい状況の違いによって簡単に変動するので、少しゲームを操作すると表示がちらついて、思うような表示結果が継続されないという利便性の問題があります。不便さはありますが、数値を細かく調整する、欲しいフレームを狙ってキャプチャするなど、工夫次第で目的は果たせるかなあと思います。

あとは背景色が自前で指定できるとか、描画のない部分はアルファチャンネル付きの透明ピクセルとして保存できるようにするとか、そんな対応があると背景の除去や合成がぐっとしやすくなると思うのですが、今日のところは放っておくことにします。誰か興味があれば改良してくれると喜びます。

それでは、良いリッピングライフをお楽しみください☆

追伸

背景色の操作ですが、Memory Viewer で Palette 0 を操作したら変更できました。15 bit color かな?

  5000000h Engine A Standard BG Palette (512 bytes)
  5000200h Engine A Standard OBJ Palette (512 bytes)
  5000400h Engine B Standard BG Palette (512 bytes)
  5000600h Engine B Standard OBJ Palette (512 bytes)
  7000000h Engine A OAM (1024 bytes)
  7000400h Engine B OAM (1024 bytes)
  http://nocash.emubase.de/gbatek.htm#dsmemorycontrolvram

Soft Rasterizer はピクセルずれを起こすのでオススメ出来ません。OpenGLレンダリングしましょう。条件によっては選びたいエンジンが変わるかもしれませんが。