はじめに

 hgimg4では既存の3Dモデルを読み込んで表示したり、立方体や板などの簡単な形なら専用命令で作ることができます。 さらに、自由な形状のメッシュを作成して使用することもできます。

 今回はテクスチャの頂点座標指定について調べてみました。 hgimg4でのUVマッピングについてテストなので、3D-CGにテクスチャ貼ったことがある人ならわかりきった話になります。 また法線ベクトルも指定できたので、ビルボードで煙の立体表現もやってみました。

サンプル

 HSP3付属サンプルのresフォルダーにあるqbox.pngを使用します。使える場所にファイルを作って実行してください。

 四角形のメッシュにテクスチャを貼り付けるサンプルです。 3パターンの貼り方をテストしてみました。


#include "hgimg4.as"

title "HGIMG4 Test"

	;	自由な形状(Mesh)でテクスチャのテスト
	gpreset

	gptexmat id_texmat, "res/qbox.png"	; テクスチャマテリアルを作成

	gpmeshclear			; 登録をクリアする
	l = 0.5				; サイズ

	;-----------------------------
	;	UV座標の大きさを変更
	;-----------------------------
	repeat 5
		;	カスタム3Dメッシュを初期化
		gpmeshclear
		
		;	カスタム3Dメッシュに頂点情報を追加
		; 参照するUV座標の大きさを変更しています。
		; 2, 1, 0, -1, -2
		a = - 1.0 * cnt + 2.0
		;              X,  Y,  Z,     NX,   NY,   NZ,     U,   V
		gpmeshadd p1, -l, -l,  0,    0.0,  0.0,  1.0,   0.0, 0.0	; 左下
		gpmeshadd p2,  l, -l,  0,    0.0,  0.0,  1.0,     a, 0.0	; 右下
		gpmeshadd p3, -l,  l,  0,    0.0,  0.0,  1.0,   0.0,   a	; 左上
		gpmeshadd p4,  l,  l,  0,    0.0,  0.0,  1.0,     a,   a	; 右上

		;	カスタム3Dメッシュに面情報を追加
		gpmeshpolygon p1,p2,p3,p4

		;	3Dメッシューノードを生成
		gpmesh  id_model, , id_texmat

		; 適当に配置
		setpos  id_model, 1.2*cnt-2.4, 1.3, 0
	loop

	;-----------------------------
	;	UV座標を画像の辺に沿って移動
	;-----------------------------
	repeat 5
		;	カスタム3Dメッシュを初期化
		gpmeshclear
		
		;	カスタム3Dメッシュに頂点情報を追加
		; 元の位置から少しずつUV座標をずらしています。
		; 画像の辺に沿って移動しています。
		; 0.0, 0.2, 0.4, 0.6, 0.8
		a = 0.2 * cnt
		;              X,  Y,  Z,     NX,   NY,   NZ,         U,       V
		gpmeshadd p1, -l, -l,  0,    0.0,  0.0,  1.0,   0.0    ,       a	; 左下
		gpmeshadd p2,  l, -l,  0,    0.0,  0.0,  1.0,   1.0 - a, 0.0		; 右下
		gpmeshadd p3, -l,  l,  0,    0.0,  0.0,  1.0,         a, 1.0		; 左上
		gpmeshadd p4,  l,  l,  0,    0.0,  0.0,  1.0,   1.0    , 1.0 - a	; 右上
		; 法線ベクトルを指定してみました。
;		gpmeshadd p1, -l, -l,  0,    -1.0,  -1.0,  1.0,   0.0    ,       a	; 左下
;		gpmeshadd p2,  l, -l,  0,     1.0,  -1.0,  1.0,   1.0 - a, 0.0		; 右下
;		gpmeshadd p3, -l,  l,  0,    -1.0,   1.0,  1.0,         a, 1.0		; 左上
;		gpmeshadd p4,  l,  l,  0,     1.0,   1.0,  1.0,   1.0    , 1.0 - a	; 右上

		;	カスタム3Dメッシュに面情報を追加
		gpmeshpolygon p1,p2,p3,p4

		;	3Dメッシューノードを生成
		gpmesh  id_model, , id_texmat

		; 適当に配置
		setpos  id_model, 1.2*cnt-2.4, 0.0, 0
	loop

	;-----------------------------
	;	3Dメッシュ形状と一致しない形状でのテクスチャ参照
	;-----------------------------
	repeat 5
		;	カスタム3Dメッシュを初期化
		gpmeshclear
		
		;	カスタム3Dメッシュに頂点情報を追加
		; 右側だけV方向に参照範囲を広げています。
		; 0.0, 0.2, 0.4, 0.6, 0.8
		a = 0.2 * cnt
		;              X,  Y,  Z,     NX,   NY,   NZ,     U,   V
		gpmeshadd p1, -l, -l,  0,    0.0,  0.0,  1.0,   0.0, 0.0	; 左下
		gpmeshadd p2,  l, -l,  0,    0.0,  0.0,  1.0,   1.0,  -a	; 右下
		gpmeshadd p3, -l,  l,  0,    0.0,  0.0,  1.0,   0.0, 1.0	; 左上
		gpmeshadd p4,  l,  l,  0,    0.0,  0.0,  1.0,   1.0, a+1.0	; 右上

		;	カスタム3Dメッシュに面情報を追加
		gpmeshpolygon p1,p2,p3,p4

		;	3Dメッシューノードを生成
		gpmesh  id_model, , id_texmat

		; 適当に配置
		setpos  id_model, 1.2*cnt-2.4, -1.3, 0
	loop
	
	setpos GPOBJ_CAMERA, 0,0,5		; カメラ位置を設定
	gplookat GPOBJ_CAMERA, 0,0,0		; カメラから指定した座標を見る


*main
	stick key,15
	if key&128 : end

	;addang id_model, , 0.01,
	
	redraw 0			; 描画開始
	rgbcolor $00ccdd:boxf		; 背景をクリア
	gpdraw				; シーンの描画

	color 255,255,255
	pos 8,8:mes "HGIMG4 sample"

	redraw 1			; 描画終了
	await 1000/60			; 待ち時間

	goto *main

上から1行目は、UV座標の大きさを変えたものです。
上から2行目は、画像の辺に沿ってテクスチャ頂点座標を移動したもの。
上から3行目は、右側だけテクスチャ頂点を動かしたものです。

解説1

 テクスチャを3Dメッシュに貼り付ける際、3Dメッシュの頂点をテクスチャ画像のどの位置に関連付けるかを指定する必要があります。

 テクスチャ画像側の座標を示す際に使用される座標系をUV座標系と言います。 UV座標系は、テクスチャ画像の左下を原点(0, 0)とした座標系で、右方向を+U、上方向を+Vとしています。 画像のサイズにかかわらず、画像の幅、高さそれぞれの1辺サイズを1.0とした単位の値です。 たとえば、64x48ピクセルの長方形画像があった場合、UV座標(0.5, 0.5)は(32, 24)ピクセルです。

 サンプルの最上段では、UV座標の大きさを2~-2の範囲で変更しています。 1.0以上を指定すると、テクスチャ画像がタイルのように敷き詰められます。 マイナス値を指定すると画像は反転します。サンプルではUとVの両方をマイナスにしたので、画像は点対称になっていますね。 UV座標の大きさを2~-2の範囲で変更

解説2

 サンプルの上から2行目では、4点のUV座標で作る図形の形が崩れないように座標だけ移動しています。 3Dメッシュと同じ四角形を維持したままUV座標を移動しているので、「?」の形は変わらないままです。 しかしUV座標の四角形はそれぞれで大きさが変わるので、「?」の大きさも変わっています。 3Dメッシュと同じ四角形を維持したままUV座標を移動

解説3

 3Dメッシュの右辺のUV座標だけ変更してみました。 テクスチャが思ったよりきれいに変形されませんでした。 3Dメッシュの右辺のUV座標だけ変更

gpmeshpolygonの不具合?仕様?

 hgimg4では、次の手順で自由な形状の3Dモデルを作成します。

  1. gpmeshclear命令:頂点の登録をリセット
  2. gpmeshadd命令:頂点を登録
  3. gpmeshpolygon命令:面を作る
  4. 必要な数だけ麺を作る。
  5. gpmesh命令:面の集合でノードオブジェクトを作成。

 gpmeshpolygon命令の動作が少し気になっています。面を作る際に座標を登録するのですが、たとえば四角形なら次の順番で引数に渡します。(HSP3.6)

左下、右下、左上、右上

 hgimg4は右手系なので、「左下、右下、右上、左上」なら違和感がないのですが不思議な仕様です。

法線ベクトル

 gpmeshadd 命令は、頂点ごとに法線ベクトルを設定することができます。 複数の面を繋げて使用する場合に使用するもので、何もしないと頂点や辺のエッジが強く出てしまうのでつなぎ目をなめらかに見せるための機能だと思います。 2つの面がつながる位置の法線方向を設定してやると角が目立たなくなるはずです。

 また、3Dメッシュを単独で利用する場合は、面の法線と同じ方向を指定して使用すれば思っている通りの表示になるはずです。

 この機能をうまく使うと面白い表現もできるので試してみました。 画像ファイルが必要なので、こちらの画像ファイルをダウンロードしてresフォルダに入れてから実行してください。
ダウンロード:smoke_test.png


#include "hgimg4.as"

title "HGIMG4 Test"

	;	自由な形状(Mesh)でテクスチャのテスト
	; 作った3Dメッシュでビルボードを再現
	gpreset
	t = 0.0

	;-----------------------------
	;	箱を作成
	;-----------------------------
	gptexmat id_texmat_qbox, "res/qbox.png"
	gpbox  id_box, 0.5, -1, id_texmat_qbox		; 箱ノードを追加
	setpos id_box,	0, 0.25, 0

	;-----------------------------
	;	UV座標を画像の辺に沿って移動
	;-----------------------------
	gpmeshclear			;	カスタム3Dメッシュを初期化
	gptexmat id_texmat, "res/smoke_test.png"	; テクスチャマテリアルを作成
	; gptexmat id_texmat, "res/qbox.png"		; 確認用
	
	;	カスタム3Dメッシュに頂点情報を追加
	; 頂点の法線を球体があるかのような向きに向けています。
	l = 0.5				; サイズ
	;              X,  Y,  Z,      NX,    NY,   NZ,       U,   V
	gpmeshadd p1, -l, -l,  0,    -1.0,  -1.0,  1.0,   0.0, 0.0	; 左下
	gpmeshadd p2,  l, -l,  0,     1.0,  -1.0,  1.0,   1.0, 0.0	; 右下
	gpmeshadd p3, -l,  l,  0,    -1.0,   1.0,  1.0,   0.0, 1.0	; 左上
	gpmeshadd p4,  l,  l,  0,     1.0,   1.0,  1.0,   1.0, 1.0	; 右上

	;	カスタム3Dメッシュに面情報を追加
	gpmeshpolygon p1,p2,p3,p4

	;	3Dメッシューノードを生成
	gpmesh  id_model, , id_texmat

	; 適当に配置
	setpos  id_model, 0.0, 1.0, 0


*main
	stick key,15
	if key&128 : end

	;	作成した面が常にカメラの向きになるように調整
	; ビルボード
	t += deg2rad(1.0)
	setang id_model, , t,

	
	setpos   GPOBJ_CAMERA, 3.0*sin(t), 1.0, 3.0*cos(t)
	gplookat GPOBJ_CAMERA, 0, 1, 0

	
	
	redraw 0			; 描画開始
	rgbcolor $00ccdd:boxf		; 背景をクリア
	gpdraw				; シーンの描画

	color 255,255,255
	pos 8,8:mes "HGIMG4 sample"

	redraw 1			; 描画終了
	await 1000/60			; 待ち時間

	goto *main

 実行すると箱の上に煙が配置されています。光源位置を変えるため、カメラ位置を箱中心に移動しています。 煙は立体的に見えるでしょうか。見えないこともない、ぐらいでしょうか。

 ビルボードを使った煙の表現です。四角形のメッシュ1個にテクスチャを貼り付けて、常にカメラの方向を向くように回転しています。 hgimg4でビルボードをどうやるのかわからなかったので、なんちゃってビルボードです。 計算負荷の小ささから昔から使用されているテクニックみたいです。

 ポイントは2つ。まずテクスチャ画像は白と透明色だけの煙画像で、画像そのものには陰や立体の情報はありません。 もう一つは、gpmeshadd命令で指定する法線方向です。法線方向を面と同じ向きにせず、面を凸レンズ状の形状と仮定して頂点位置の法線を指定しています。 これだけで面は平面ではなく曲面としてレンダリングされます。

 サンプルの煙テクスチャ画像は、FireAlpacaで作成しました。ツール花に使ってもいいのですが、参考として作成手順は次の通り。
「煙の色」レイヤーは白で塗りつぶし。
「雲模様[マスク]」は レイヤー>追加マスク で作ったマスクレイヤーです。模様は、 フィルタ>雲模様 で作成しました。
「煙の形[マスク]」もマスクレイヤーで、丸い形になるようにエアブラシペンを使って白丸で切り抜きました。
最後に透過pngで保存すれば完成です。 3Dメッシュの右辺のUV座標だけ変更

 昔3D-CGの解説記事でこの方法を読んだときからやってみたいと思っていたんですが、やってみると期待したほど立体的でもないですね。 ビルボードで負荷軽減を行いつつも完全には立体感を失わない方法なので、ゲームの雰囲気次第では使えそうです。 記事は「3Dゲームファンのためのグラフィックス講座」だったかな?本になったせいなのか昔の記事が読めなくなっている…。

まとめ

 自由な形状のメッシュを作成するのは、なかなかの手間だということがわかりました。 基本的には、3Dモデルデータ(.gpbファイル)を準備したほうがいいようです。 どうしても状況によって異なる形やテクスチャのモデルが必要になった場合には、便利な機能ですね。

 便利ですが制限事項もあります。作成した3Dモデルの頂点座標やUV座標は、作成後にHGIMG4の命令だけで変更することができません。 形状を変形したりテクスチャを動かしたりしたい場合は、シェーダーを利用するか、3Dモデルをdelobjで削除して作り直す必要があります。 作り直す方の例としてこちらをどうぞ。

HSP3.6 HGIMG4 で疑似鏡
https://qiita.com/hta393939/items/f15f5000d880a8e5c93f

 また、UVマッピングを行う際は、なるべく元の3Dメッシュと形状が大きく変わらないようにしたほうが良さそうですね。 これは3Dモデルデータ(.gpbファイル)でも同じかもしれませんね。

 法線ベクトルもできれば3Dモデルデータ(.gpbファイル)で準備しておいたほうが作業しやすいと思います。