陰と影

 hgimg4のライトについて調べてみました。ライトでゲームの雰囲気が変わりますし、暗いダンジョンの探索や派手な演出などでもライトを使いたいですよね。

 ライトを知る前に、まずはカゲについて理解しておく必要があります。 カゲは2種類に分けて取り扱います。陰(かげ、shade、シェード)と影(かげ、shadow、シャドウ)です。どちらも「カゲ」ですが明確な使い分けがされています。

陰と影を知ってワンランク上のデッサンへ
https://dessinlaboratory.com/shade/shadow01.html

 物体表面の光があたっていな部分がで、 物体に光が遮られて地面に落ちている暗い部分の方をと言います。 CG用語でも同様の使い分けが行われていて、カゲを作る仕組みもそれぞれ異なります。

 そしてここからが重要です。 現在(HSP3.6、3.7β1、3.7β2)のhgimg4では、(シャドウ)を作る機能がついていません。 ライトでは(シェード)を作る事ができますが、はできません。

ライトの種類

 hgimg4では3種類の光源を作成できます。

項目 ディレクショナルライト ポイントライト スポットライト
機能 方向のみを持った光源 座標と影響範囲を持った光源 座標と方向、影響範囲を持った光源
説明  平行光。
無限遠に光源がある場合の光。光源が遠いと光はほぼ平行に降り注ぐ。ただし3D-CGの場合は「ほぼ」ではなく完全な平行です。
 点光源。
光源が1点で、全方位に光を放射する。
 指向性を持つ点光源。
点光源の光の放射を制限して、ある方向にだけ光を放射している。
現実での例 太陽光 ロウソクなど 球場、ステージのスポットライト、懐中電灯など
GPU負荷
上限個数 1~10個(初期値1) 0~10個(初期値0) 0~10個(初期値0)
備考
  • オブジェクトID:GPOBJ_LIGHT
  • アンビエント(環境)カラーが指定できる。

アンビエントカラー

 アンビエントカラーは、環境光(アンビエントライト)とか呼ばれるものです。

 現実においては、光が直接当たらない部分(影、陰)であっても真っ黒になることはありません。少し明るさがあります。 これは周囲のさまざまな物体や床や壁に当たった光が複雑に反射して、暗い部分に光を届けているためです。

 光が届く経路は複雑で、反射は1回とは限らず複数反射していることもあります。 このように複雑な反射をCGの世界で正確に再現しようとすると計算時間が足りなくなってしまいます。 そこでCGでは、環境光という空間全体を照らす照明を使ってカゲが明るくなる現象を再現しています。

 アンビエントカラーは、ディレクショナルライトに設定して使用します。 複数のディレクショナルライトを使用する場合は、カレントライトのライトオブジェクトのインデックス0番に指定した1つのアンビエントカラーだけが有効になります。 カタカナばっかりでわかりにくいですね。複数個準備できますが、実際に有効にできるアンビエントカラーは 1 個だけということです。

ディレクショナルライトのサンプル

 ディレクショナルライトを使ったサンプルを作ってみました。


#include "hgimg4.as"

title "HGIMG4 Test"

	;	ディレクショナルライト
	;	・光の方向を変える
	;	・アンビエントカラー
	;
	gpreset

	;	ライト
	;gpresetlight 1
	setcls CLSMODE_SOLID, $404040		; 背景色
	setcolor GPOBJ_LIGHT, 0.3,0.3,0.3	; 標準ライトカラーを設定
	setang GPOBJ_LIGHT, deg2rad(-45)

	;	標準アンビエントカラー
	amb = 0.1
	setdir GPOBJ_LIGHT, amb, amb, amb

	;	カメラ
	setpos   GPOBJ_CAMERA, 0,2  ,6		; カメラ位置を設定
	gplookat GPOBJ_CAMERA, 0,0.3,0		; カメラから指定した座標を見る

	;	3Dモデルを生成
	;	(生成される3Dモデルはカレントライトの影響を受けます)
	gpbox  id_model, 1			; 箱ノードを生成する
	setpos id_model, 0, 0.5, 0
	setang id_model, 0, deg2rad(45)

	gpfloor id_floor, 40,40, $808080	; 床ノードを追加



*main
	stick key,15+256
	if key&128 : end
	redraw 0			; 描画開始

	;	サンプル
	if 1 {
		;	ディレクショナルライト サンプル
		; 光源の向きを回転
		addang GPOBJ_LIGHT, 0, 0.02, 0
	} else {
		;	アンビエントカラー サンプル
		; アンビエントカラーをゆっくり変更
		setdir GPOBJ_LIGHT, amb, 0, 0
		amb += 0.005
		if amb > 1.0 : amb = 0.0
	}
	
	gpdraw				; シーンの描画

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

	; アンビエントカラー
	mes "アンビエントカラー:" + int(amb*255) + ", 0, 0"
	

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

	goto *main

 斜め上から当てているディレクショナルライトの向きをY軸中心に回転させています。 光源の初期の向きは -Z方向であるようです。

 次のように修正すると、アンビエントカラーのサンプルになります。


	;	サンプル
;	if 1 {
	if 0 {
		;	ディレクショナルライト サンプル
		; 光源の向きを回転
		addang GPOBJ_LIGHT, 0, 0.02, 0
	} else {
		;	アンビエントカラー サンプル
		; アンビエントカラーをゆっくり変更
		setdir GPOBJ_LIGHT, amb, 0, 0
		amb += 0.005
		if amb > 1.0 : amb = 0.0
	}

 空間全体を照らす赤い光(アンビエントカラー)を徐々に強くしています。 光があたっている部分や陰になっている部分など、場所にかかわらずアンビエントカラーの赤い光があたっています。ただし背景は影響を受けないようですね。

 さらにこんなふうに書き換えると、アンビエントカラーがまったくない状態を確認できます。 まずディレクショナルライトのサンプルに戻して、上の方に書いてあるアンビエントカラーの設定を次のように書き換えます。


	;	標準アンビエントカラー
	amb = 0.0	;0.1
	setdir GPOBJ_LIGHT, amb, amb, amb

 今までそれなりに明るかった陰の部分は真っ黒になります。アンビエントカラーの効果がよくわかると思います。

ライト作成手順

 ライトはノードとは違って、作って配置すればいいというものではないようです。 基本的には次のような手順が必要です。

  • シーンを作り始めたときに、使う個数を決める。
  • カレントライトを作る。
  • カレントライトをオブジェクトに関連付ける。

 カレントライトは、実際に使用する1個以上のライトのセットです。 カレントライトに登録していないライトは使用されません。

 シーン作成後に何もしなければ、ディレクショナルライト1個がカレントライトになり、この後作成されるすべてのノードオブジェクトに適用されます。 いつもライトを設定して無くても明るさがあったのは、前述の手順を自動でやってくれていたわけです。

 ライトを増やしたりポイントライトを使ったりしたい場合は、上記の作業が必要になります。 もう少し細かく手順を見てみます。

  1. シーンを初期化するとライトの設定もデフォルト設定に戻ります。
  2. 使用するライトを初期化(gpresetlight
    使用するライトの個数を宣言します。
  3. ノードを作る(gpnullなど)
  4. ノードをライトに設定する(gplight
  5. 使いたいライトをカレントライトに登録(gpuselight

 この後にノードオブジェクトを作成すると、現在のカレントライトが適用されます。 ノードオブジェクトを作成した後にカレントライトを変更した場合は、setobjlightでオブジェクトにカレントライトを再設定する必要があります。

 サンプルで使い方を確認してみます。
ライトの作成手順のサンプル実行結果


#include "hgimg4.as"

title "HGIMG4 Test"

	;	カレントライト
	;
	gpreset
	setcls CLSMODE_SOLID, $404040		; 背景色
	sdim comment, 64, 4

	; --------------------
	;	ライト
	; --------------------
	gpresetlight 3

	; 標準ライトカラーを設定
	;setcolor GPOBJ_LIGHT, 0.8, 0.8, 0.8

	; 白
	gpnull     LIGHT_W
	gplight    LIGHT_W, GPOBJ_LGTOPT_NORMAL
	setcolor   LIGHT_W, 0.8, 0.8, 0.8
	setang     LIGHT_W, deg2rad(-60), deg2rad(0)
;	setdir     LIGHT_W, 0, 0, 0

	; 赤
	gpnull   LIGHT_R
	gplight  LIGHT_R, GPOBJ_LGTOPT_NORMAL
	setcolor LIGHT_R, 0.8, 0, 0
	setang   LIGHT_R, deg2rad(-60), deg2rad(90)
;	setdir   LIGHT_R, 0, 0, 0

	; 緑
	gpnull   LIGHT_G
	gplight  LIGHT_G, GPOBJ_LGTOPT_NORMAL
	setcolor LIGHT_G, 0, 0.8, 0
	setang   LIGHT_G, deg2rad(-60), deg2rad(0)
;	setdir   LIGHT_G, 0, 0, 0

	; 青
	gpnull   LIGHT_B
	gplight  LIGHT_B, GPOBJ_LGTOPT_NORMAL
	setcolor LIGHT_B, 0, 0, 0.8
	setang   LIGHT_B, deg2rad(-60), deg2rad(-90)
;	setdir   LIGHT_B, 0, 0, 0

	; 黒
	gpnull   LIGHT_BL
	gplight  LIGHT_BL, GPOBJ_LGTOPT_NORMAL
	setcolor LIGHT_BL, 0, 0, 0
;	setdir   LIGHT_BL, 0, 0, 0

	; 真っ黒
	; アンビエントカラーも黒にする
	gpnull   LIGHT_BL2
	gplight  LIGHT_BL2, GPOBJ_LGTOPT_NORMAL
	setcolor LIGHT_BL2, 0, 0, 0
	setdir   LIGHT_BL2, 0, 0, 0	; アンビエントカラー


	; --------------------
	;	カメラ
	; --------------------
	setpos   GPOBJ_CAMERA, 0,2  ,7		; カメラ位置を設定
	gplookat GPOBJ_CAMERA, 0,0.3,0		; カメラから指定した座標を見る

	; --------------------
	;	標準ライト
	; --------------------
	;	3Dモデルを生成
	;	(生成される3Dモデルはカレントライトの影響を受けます)
	gpbox  id_box, 1			; 箱ノードを生成する
	setpos id_box, -3, 0.5, 0
;	setang id_box, 0, deg2rad(45)

	; --------------------
	;	カレントライトを作った後にオブジェクトを作成
	; --------------------
	; 赤と青と緑
	;	ライトオブジェクトをカレントライトに登録
	gpuselight LIGHT_R, 0
	gpuselight LIGHT_G, 1
	gpuselight LIGHT_B, 2
	
	gpclone id_boxc(0), id_box
	setpos  id_boxc(0), -1.5, 0.5, 0
	comment(0) = "赤\n緑\n青"

	; --------------------
	;	カレントライトを変更後にオブジェクトを作成
	; --------------------
	; 赤と青
	gpuselight LIGHT_R, 0
	gpuselight LIGHT_BL, 1
	gpuselight LIGHT_B, 2

	gpclone id_boxc(1), id_box
	setpos  id_boxc(1), 0, 0.5, 0
	comment(1) = "赤\n青"

	; --------------------
	;	オブジェクト作成後にカレントライトを変更
	; --------------------
	; 緑と青
	gpclone id_boxc(2), id_box
	setpos  id_boxc(2), 1.5, 0.5, 0
	; ライトを適用
	gpuselight LIGHT_BL, 0
	gpuselight LIGHT_G, 1
	gpuselight LIGHT_B, 2
	setobjlight id_boxc(2)
	comment(2) = "青\n緑"

	; --------------------
	;	真っ黒
	; --------------------
	; アンビエントカラーも黒
	gpuselight LIGHT_BL2, 0	; 個の色のアンビエントカラーが有効になる
	gpuselight LIGHT_BL, 1	; LIGHT_BL2でもいい
	gpuselight LIGHT_BL, 2	; LIGHT_BL2でもいい

	gpclone id_boxc(3), id_box
	setpos  id_boxc(3), 3, 0.5, 0
	comment(3) = "真っ黒"
	
	; --------------------
	;	床
	; --------------------
	; ライトの設定を元に戻したい。
	; gpuselight GPOBJ_LIGHT, 0	; エラー
	gpuselight LIGHT_W, 0
	gpuselight LIGHT_BL, 1
	gpuselight LIGHT_BL, 2
	gpfloor id_floor, 40,40, $808080	; 床ノードを追加

	;	オブジェクトに適用後にライトの設定を変更
	;setcolor LIGHT_BL2, 1, 1, 1
	;setdir   LIGHT_BL2, 0.2, 0.2, 0.2
	;setang   LIGHT_BL2, 0, deg2rad(45), deg2rad(60)


*main
	stick key,15+256
	if key&128 : end
	redraw 0			; 描画開始

	;	箱を回転
	addang id_box,     0, 0.02, 0
	addang id_boxc(0), 0, 0.02, 0
	addang id_boxc(1), 0, 0.02, 0
	addang id_boxc(2), 0, 0.02, 0
	addang id_boxc(3), 0, 0.02, 0

	gpdraw				; シーンの描画

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

	;	説明を表示
	color
	getpos id_box, px, py, pz
	gpcnvaxis vx, vy, vz,  px, py, pz, 0
	pos vx, vy+100
	mes "標準ライト"
	repeat 4
		getpos id_boxc(cnt), px, py, pz
		gpcnvaxis vx, vy, vz,  px, py, pz, 0
		pos vx, vy+100
		mes comment(cnt)
	loop

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

	goto *main

 実行すると箱が5つ表示されます。 箱はすべて同じ色で、それぞれ別々のカレントライトを適用しています。 ライトの色と方向を箱で確認することができるようになっています。

 カレントライトに登録できるライトの上限数は、gpresetlight命令で設定します。 gplightで作成するライトの個数ではありません。 上限数がそれぞれ 10 個までとか少なすぎーとか思われるかもしれませんが、 ライトは負荷が高い処理です。個数制限はやむを得ません。

ライト作成手順サンプルの解説

 最初にシーン内で使用するライトとして、ディレクショナルライトを3つ確保します。 ライトは負荷が高い部類の処理になるのだそうで、あまりたくさん設定することが出来ないような作りになっています。

gpresetlight 3

 次に gpnull, gplight を使ってライトオブジェクトを作ります。 ライト色は、setcolor命令でノードに設定された色がそのまま使用されます。 作成したライトの一覧表です。

オブジェクトID アンビエントカラー
GPOBJ_LIGHT白(デフォルト)デフォルト
LIGHT_W デフォルト
LIGHT_R デフォルト
LIGHT_G デフォルト
LIGHT_B デフォルト
LIGHT_BL デフォルト
LIGHT_BL2

 サンプルの一番左の箱は、標準ライト(GPOBJ_LIGHT)をそのまま使用しています。

 左から2番目と3番目は、gpuselightでカレントライトを新しく作った後にオブジェクトを作成しています。 2番目は3色の光、3番目は2色の光(3個中の1個のライトを黒にしている)を当てています。


	; --------------------
	;	カレントライトを作った後にオブジェクトを作成
	; --------------------
	; 赤と青と緑
	;	ライトオブジェクトをカレントライトに登録
	gpuselight LIGHT_R, 0
	gpuselight LIGHT_G, 1
	gpuselight LIGHT_B, 2
	
	gpclone id_boxc(0), id_box
	setpos  id_boxc(0), -1.5, 0.5, 0
	comment(0) = "赤\n緑\n青"

	; --------------------
	;	カレントライトを変更後にオブジェクトを作成
	; --------------------
	; 赤と青
	gpuselight LIGHT_R, 0
	gpuselight LIGHT_BL, 1
	gpuselight LIGHT_B, 2

	gpclone id_boxc(1), id_box
	setpos  id_boxc(1), 0, 0.5, 0
	comment(1) = "赤\n青"

 左から4番目は、ノードオブジェクトを作成後にカレントライトを作成して適用しています。 setobjlight命令でノードオブジェクトに現在のカレントライトを適用し直しています。


	; --------------------
	;	オブジェクト作成後にカレントライトを変更
	; --------------------
	; 緑と青
	gpclone id_boxc(2), id_box
	setpos  id_boxc(2), 1.5, 0.5, 0
	; ライトを適用
	gpuselight LIGHT_BL, 0
	gpuselight LIGHT_G, 1
	gpuselight LIGHT_B, 2
	setobjlight id_boxc(2)
	comment(2) = "青\n緑"

 一番右は、アンビエントカラーの影響を確認しています。 「登録するライトオブジェクトのインデックス」を0にしたライトのアンビエントカラーが適用されるようです。


	; --------------------
	;	真っ黒
	; --------------------
	; アンビエントカラーも黒
	gpuselight LIGHT_BL2, 0	; 個の色のアンビエントカラーが有効になる
	gpuselight LIGHT_BL, 1	; LIGHT_BL2でもいい
	gpuselight LIGHT_BL, 2	; LIGHT_BL2でもいい

	gpclone id_boxc(3), id_box
	setpos  id_boxc(3), 3, 0.5, 0
	comment(3) = "真っ黒"

 完全に真っ黒になりましたね。コナンの犯人もびっくりの黒さです。 うまく応用するとなにかに使えそうですね。何かはわかりませんが。

 何だかわからなくなってきましたね。整理します。 ライトの作成手順のサンプル実行結果

左から012
1番目GPOBJ_LIGHT
2番目LIGHT_R LIGHT_G LIGHT_B
2番目LIGHT_R LIGHT_BLLIGHT_B
4番目LIGHT_BL LIGHT_G LIGHT_B
5番目LIGHT_BL2LIGHT_BLLIGHT_BL

 なお、オブジェクトにカレントライトを適用したあとでもライトの調整は可能です。 色や向き、アンビエントカラーが変更できます。 カレントライトの適用は、オブジェクトに適用するライトの割当を決める作業というイメージでよさそうですね。


	;	オブジェクトに適用後にライトの設定を変更
	setcolor LIGHT_BL2, 1, 1, 1
	setdir   LIGHT_BL2, 0.2, 0.2, 0.2
	setang   LIGHT_BL2, 0, deg2rad(45), deg2rad(60)

 サンプルではコメントにしているので、コメント解除していろいろ試してみてください。

ポイントライトのサンプル

 ポイントライトは、点光源です。 作り方は基本的にディレクショナルライトと同じですが、gplight 命令で「range(1) : 影響範囲パラメーター」を指定できます。 この引数は、光が届く半径を指定する値です。この半径より遠い場所は、光が届きません。

 光の届き具合や調整方法を確認するサンプルです。


#include "hgimg4.as"

title "HGIMG4 Test"

	;	ポイントライト
	;
	gpreset

	;	ライト
	gpresetlight 1, 4
	setcls CLSMODE_SOLID, $404040		; 背景色
	setcolor GPOBJ_LIGHT, 0,0,0			; 標準ライトカラーを設定

	;	標準アンビエントカラー
	amb = 0.0	; 数値を大きくするとノードオブジェクトの配置が見やすくなります。
	setdir GPOBJ_LIGHT, amb, amb, amb

	;	カメラ
	setpos   GPOBJ_CAMERA, 0,2  ,6		; カメラ位置を設定
	gplookat GPOBJ_CAMERA, 0,0.3,0		; カメラから指定した座標を見る

	;	ライトを生成
	x = -2.0 , 0.0, 2.0	; 配置
	h =  0.05, 0.5, 0.5	; 高さ
	r =  0.5 , 0.5, 1.0	; 影響半径
	repeat 3
		gpnull   id_light(cnt)
		gplight  id_light(cnt), GPOBJ_LGTOPT_POINT, r(cnt)
		setcolor id_light(cnt), 1, 1, 1
		setpos   id_light(cnt), x(cnt), h(cnt), 0.55
			; 壁側面のすぐ近くに配置(ギリギリよりも少し離したほうが中心部が明るい)
		gpuselight id_light(cnt), cnt
	loop

	; 箱を光源に設定
	gpbox    id_boxL, 0.2
	;setcolor id_boxL, 1, 0.5, 0.5	; setcolorはgplightの前に設定しても光の色にならない。
	gplight  id_boxL, GPOBJ_LGTOPT_POINT, 3
	setpos   id_boxL, 0, 2, 1
	setcolor id_boxL, 1, 0.5, 0.5
	setcolor id_boxL, 0, 0, 0	; この行をコメントにすると光ります。
	gpuselight id_boxL, 3


	;	3Dモデルを生成
	; 箱ノード(壁)を生成
	gpbox    id_box, 1
	setscale id_box, 10, 1, 1
	setpos   id_box, 0, 0.5, 0
	
	; 床ノードを追加
	gpfloor id_floor, 40,40, $808080



*main
	stick key,15+256
	if key&128 : end
	redraw 0			; 描画開始

	gpdraw				; シーンの描画

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


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

	goto *main

 結果を確認しやすくするために、環境光をゼロにしています。 また光の確認と寸法の目印として高さ 1 の壁を設置しています。

 はじめにライトの個数を指定します。 環境光を設定したいのでディレクショナルライト1個。 スポットライトは4個使います。

	gpresetlight 1, 4

 あとはディレクショナルライトを作るのとほぼ同じです。 あまり難しくはないですね。ちなみに光源の座標を壁の中に設定しても地面に光があたります。 違和感ありますがそういうものです。この光はオブジェクトを突き抜けて届く光です。影できませんしね。

 さて光源はヌルノードに限らず、gpboxで作った箱などのノードオブジェクトに設定できます。 といってもオブジェクト自身が光るのではなく、オブジェクトの中心座標に点光源が配置されるだけのようです。


	; 箱を光源に設定
	gpbox    id_boxL, 0.2
	;setcolor id_boxL, 1, 0.5, 0.5	; setcolorはgplightの前に設定しても光の色にならない。
	gplight  id_boxL, GPOBJ_LGTOPT_POINT, 3
	setpos   id_boxL, 0, 2, 1
	setcolor id_boxL, 1, 0.5, 0.5
;	setcolor id_boxL, 0, 0, 0	; この行をコメントにすると光ります。
	gpuselight id_boxL, 3

 黒い箱が赤い光を放っています。 箱の中心(内部)に光源があるだけで、箱表面は光っていません。

スポットライトのサンプル

 スポットライトは…スポットライト状の光です。点光源の光の範囲を円すい状に制限したような感じのものです。 作り方はポイントライトとほぼ同じですが、gplight 命令で「inner(0.5): 内側の減衰パラメーター」と「outer(1) : 外側の減衰パラメーター」を指定できます。 この引数は、どちらも光の広がり角度を指定する値です。境界をぼやけた感じにするため、内側と外側でそれぞれ範囲角度を設定できるようになっています。

 角度については後述するので、まずはサンプルで使い方を確認してみます。


#include "hgimg4.as"

title "HGIMG4 Test"

	;	スポットライト
	;
	gpreset

	;	ライト
	gpresetlight 1, , 3
	setcls CLSMODE_SOLID, $404040		; 背景色
	setcolor GPOBJ_LIGHT, 0,0,0			; 標準ライトカラーを設定

	;	標準アンビエントカラー
	amb = 0.10	; 数値を大きくするとノードオブジェクトの配置が見やすくなります。
	setdir GPOBJ_LIGHT, amb, amb, amb

	;	カメラ
	setpos   GPOBJ_CAMERA, 0,2  ,6		; カメラ位置を設定
	gplookat GPOBJ_CAMERA, 0,0.3,0		; カメラから指定した座標を見る

	;	ライトを生成
	x = -2.0, 0.0, 2.0	; 配置
	h =  0.5, 1.0, 1.0	; 高さ
	r =  1.0, 1.0, 2.0	; 影響半径
	i =  0.5, 0.5, 0.5	; 内側の減衰
	o =  1.0, 1.0, 1.0	; 外側の減衰
	repeat 3
		gpnull   id_light(cnt)
		gplight  id_light(cnt), GPOBJ_LGTOPT_SPOT, r(cnt), i(cnt), o(cnt)
		setcolor id_light(cnt), 1, 1, 1
		setpos   id_light(cnt), x(cnt), h(cnt), 0.55
			; 壁側面のすぐ近くに配置(ギリギリよりも少し離したほうが中心部が明るい)
		setang   id_light(cnt), deg2rad(-90)
		gpuselight id_light(cnt), cnt
	loop


	;	3Dモデルを生成
	; 箱ノード(壁)を生成
	gpbox    id_box, 1
	setscale id_box, 10, 2, 1
	setpos   id_box, 0, 1.0, 0
	
	; 床ノードを追加
	gpfloor id_floor, 40,40, $808080



*main
	stick key,15+256
	if key&128 : end
	redraw 0			; 描画開始

	gpdraw				; シーンの描画

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


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

	goto *main

 壁際にスポットライトを設置しています。それぞれ設置位置と、影響の半径を変えたものを並べています。 スポットライトの照射方向は -Z 方向を向いているようなので、X軸方向に -90 度回転させて照射方向を下に向けています。

setang   id_light(cnt), deg2rad(-90)

あとはうまく調整してください。

スポットライトの調整

 うまく調整と言っても、パラメーターの意味が不明瞭では困りますね。 gplight命令でスポットライト作成する際のパラメーターを図にしてみました。
スポットライトのパラメーター

range(1) : 影響範囲パラメーター
光が届く距離。光源からの距離(半径)で指定する。
inner(0.5): 内側の減衰パラメーター
扇形の開き角度を中央からの角度で指定する。単位はラジアン。πのとき全方向、π/2のとき半分。 この角の内側では光の強さは変わらない。この角度より外側に行くほど光が弱くなる。
outer(1) : 外側の減衰パラメーター
扇形の開き角度を中央からの角度で指定する。単位はラジアン。πのとき全方向、π/2のとき半分。 この角度の外側に光は届かない。

 動作を確認するためのサンプルです。 ←,→で調整する項目を選択して、↑,↓で数値調整してください。 最初は「影響範囲」を大きくして光を床面に十分届かせてから、他のパラメーターを変更した方がいいでしょう。


#include "hgimg4.as"

title "HGIMG4 Test"

	;	ポイントライト
	; ←,→で調整する項目を選択
	; ↑,↓で数値調整
	;
	gpreset

	;	ライト
	gpresetlight 1, , 1
	setcls CLSMODE_SOLID, $404040		; 背景色
	setcolor GPOBJ_LIGHT, 0,0,0			; 標準ライトカラーを設定

	;	標準アンビエントカラー
	amb = 0.10	; 数値を大きくするとノードオブジェクトの配置が見やすくなります。
	setdir GPOBJ_LIGHT, amb, amb, amb

	;	カメラ
	setpos   GPOBJ_CAMERA, 0,2  ,6		; カメラ位置を設定
	gplookat GPOBJ_CAMERA, 0,0.3,0		; カメラから指定した座標を見る

	;	ライトを生成
	gpnull   id_light
	gplight  id_light, GPOBJ_LGTOPT_SPOT
	setcolor id_light, 1, 1, 1
	setpos   id_light, 0.0, 1.5, 0.55
	setang   id_light, deg2rad(-90)
	gpuselight id_light, 0


	;	3Dモデルを生成
	; 箱ノード(壁)を生成
	gpbox    id_box, 1
	setscale id_box, 10, 2, 1
	setpos   id_box, 0, 1.0, 0


	; 床ノードを追加
	; gpfloorで作ったオブジェクトは、setobjlightに使用できないようです。
;	gpfloor id_floor, 40,40, $808080
	gpbox    id_floor, 1, $808080
	setscale id_floor, 10.0, 0.1, 10.0
	setpos   id_floor, 0, 0.05, 0
	

	;	パラメータ
	range  = 1.0	; 影響範囲
	inner  = 0.5	; 内側の減衰
	outer  = 1.0	; 外側の減衰
	select = 0
	mode   = "", "", "", ""

*main
	stick key,2+8+256
	if key&128 : end

	;	選択
	; ←,→で調整する項目を選択
	if key & 1 : select--	;←
	if key & 4 : select++	;→
	if select > 3 : select = 0
	if select < 0 : select = 3
	mode = "", "", "", ""
	mode(select) = "←"
	
	;	数値調整
	; ↑,↓で数値調整
	v = 0.0
	if key & 2 : v =  0.01	;↑
	if key & 8 : v = -0.01	;↓
	if select = 0 : range += v
	if select = 1 : inner += v
	if select = 2 : outer += v
	if select = 3 {
		; 内側の減衰と外側の減衰を同じ比率で調整
		; z = outer / inner
		; inner += v
		; outer = inner * z
		
		; 内側の減衰と外側の減衰の差を維持したまま調整
		z = outer - inner
		inner += v		
		outer = inner + z
	}

	redraw 0			; 描画開始

	;	スポットライトを再設定
	gplight     id_light, GPOBJ_LGTOPT_SPOT, range, inner, outer
	gpuselight  id_light, 0
	setobjlight id_box
	setobjlight id_floor

	gpdraw				; シーンの描画

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

	mes "←,→キーで数値を変更する項目を選んでください。\n↑,↓キーで数値を変更できます。\r\n"
	mes "影響範囲 :" + range + " " + mode(0)
	mes "内側の減衰:" + inner + " " + mode(1)
	mes "外側の減衰:" + outer + " " + mode(2)
	mes "内外連動        " + mode(3)
	
	redraw 1			; 描画終了
	await 1000/60			; 待ち時間

	goto *main

 内側と外側の減衰の値が逆転すると、光る範囲が反転しておもしろいですね。 数値をマイナスや3.14を超える値にしてみて動きを確認してみてください。 また「内外連動」は、内側と外側の減衰の値の差を維持したまま同時に変更します。

 変更したパラメーターは、gplightで再設定します。 gplightで変更してしまうと、カレントライトに登録し直してsetobjlightでオブジェクトに再設定するまで変更結果が反映されません。


	;	スポットライトを再設定
	gplight     id_light, GPOBJ_LGTOPT_SPOT, range, inner, outer
	gpuselight  id_light, 0
	setobjlight id_box
	setobjlight id_floor

 そしてここで注意点。 gpfloorで作成したオブジェクトは、setobjlightに使用できないようです。(バグかな?) このサンプルでは、gpboxで床を作って代用しています。

まとめ

ライトの種類

ディレクショナルライト平行光
ポイントライト 点光源
スポットライト 指向性をもたせた点光源

 カレントライトに登録できる個数には制限があります。上手に節約して使いましょう。

ライトの作り方

  1. gpresetでシーンをリセットするとライトもリセットされる
  2. gpresetlightで個数を指定
  3. ライトにするノードを作る(ヌルノード、箱ノードなど)
  4. gplightでノードをライトにする
  5. gpuselightでカレントライトを設定する。カレントライトには、gpresetlightで指定した個数のライトが設定できる。
  6. ノードを作るとカレントライトの影響を受けるノードになる。 すでにノードを作成済みなら、setobjlightで新しいカレントライトをノードに適用する。

 こんな感じでしょうか。カレントライトの取り扱いが少し難しいですね。 しかしノードオブジェクトごとにまったく違う光を当てたりできるので、うまく使うとおもしろい効果が得られそうな気もします。 例えば…影とか?