Xangle/Yangle 05 - 明暗を設定しよう
影をつけると一気に3次元ぽくなりますよね。ということで前回(Xangle/Yangle 04 - エフェクトを組み合わせよう - MUGEN製作のメモ置き場)作った立方体を上からの光で照らしてみようと思います
上からの光とは言いましたが、とりあえず一般的な場合、自由な位置に光源を置いた場合を考えてみます
2つ考えてみました
A:光源からの光が面で反射し、カメラに入ってくる大きさで明るさを判断
B:光源からの光が面に当たるその面積で明るさを判断
光源の位置を(Lx,Ly,Lz)とします
面の位置を(x,y,z)とします
A
①光源から面までの直線L(の方向ベクトル)を考える
②面の法線ベクトル(面に直角な直線のベクトル)を考える
③Lの面での反射ベクトルを考える
④そのZ成分の大きさ(つまり反射した光のうちカメラに向かう大きさ)で明るさを判断する
①直線Lは、
L:
で表されます。tが-∞から∞まで高速で反復すれば直線になるってことです
②angle,xangle,yangle全てが0(回転していない)のとき、面の法線ベクトルは(0,0,-1)なので、その面が行う回転と同じだけ(0,0,-1)を回転させれば、それが面の法線ベクトルになります
面が行う回転行列をかけて、
=
α:xangleの値
β:yangleの値
です
(x-y-zオイラー角)は、
を見てください。上の方の回転行列RxRyRzのとこ
③
反射ベクトル = 入射ベクトル + 2×(-入射ベクトル・法線ベクトル)×法線ベクトル
(入射ベクトル = Lの方向ベクトル)
=
|(D)| = √[ (x - Lx)^2 + (y - Ly)^2 + (z - Lz)^2 ] これで割るとベクトルの大きさ(長さ)が1になります
計算合ってる。。。よね?多分こうなります。
④
ただZ成分を抜き出すだけ
反射ベクトルZ成分 =
以上です。ただこれを記述するのはメンドウなので、簡略化します
光源が真上の太陽としましょう。昼間です
太陽は果てしなく遠くにあり、真上なので
Lx = x
Ly << y ( |Ly| >> |y| )
Lz = z
となります。(y軸は下方向正です)
|Ly| >> |y| なので、 (y - Ly)/|(D)| はほとんど -Ly/|(D)| なんです
これらを代入して、、、
反射ベクトル =
2sinαcosα(cosβ)^2
とこうなります。随分簡単になりました。
B
①光源から面までの直線Lの方向ベクトルを考える
②面の法線ベクトル(面に直角な直線のベクトル)を考える
③その2つの角度で明るさを判断する
①、②はAと同じです
③
=
|D1| = √[ (x - Lx)^2 + (y - Ly)^2 + (z - Lz)^2 ]
|D2| = √[ (sinβ)^2 + (-sinαcosβ)^2 + (-cosαcosβ)^2 ]
以上です。ただこれを記述するのはメンドウなので、簡略化します(Aと同じこと書きます)
光源が真上の太陽としましょう。昼間です
太陽は果てしなく遠くにあり、真上なので
Lx = x
Ly << y ( |Ly| >> |y| )
Lz = z
となります。(y軸は下方向正です)
|Ly| >> |y| なので、 (y - Ly)/|(D)| はほとんど -Ly/|(D)| なんです
これらを代入して、、、
角度θ =
arccos[ (sinαcosβ) / √(sin^2β + sin^2αcos^2β + cos^2αcos^2β) ]
=
arctan[ { √(sin^2β + cos^2αcos^2β) }/(sinαcosβ) ]
となります。Aほど簡単にはなってくれませんね
ではこれをMUGENに記述します
ModifyExplodに、
type = ModifyExplod
…
Trans = AddAlpha
Alpha = x,0
の2行を追加します。xは0~256まで。x = 256で変化なし、x = 0で真っ暗になります
つまり明暗を記述するというよりは暗さ加減を記述します。SFF登録時点で明るめの画像を登録した方がいいかな
Explodのownpalを0にして本体の色を変える方法もありますが、ループ記述できませんので注意です
type = ModifyExplod
…
Trans = AddAlpha
Alpha = fvar(x),0
; ↑(A)or(B)
とすると、Aなら
[State -2, var];明るさ:光沢
type = varset
trigger1 = 1
fvar(A) = (128 + (2*sin(fvar(α)*(pi/180))*cos(fvar(α)*(pi/180))*(cos(fvar(β)*(pi/180))**2))*64)
Aの場合、反射ベクトルZ成分 = 2sinαcosα(cosβ)^2 は、-2~2の範囲です。64倍して-128~128の範囲になります。さらに、128を足して0~256の範囲にします
つまり、128 + (反射ベクトルZ成分)*64
Bなら
[State -2, var];明るさ:通常
type = varset
trigger = 法線ベクトルが↑を向いているとき
fvar(B) = (180 - abs(atan((((sin(fvar(β)*(pi/180))**2) + (cos(fvar(α)*(pi/180))*cos(fvar(β)*(pi/180)))**2)**0.5)/(sin(fvar(α)*(pi/180))*cos(fvar(β)*(pi/180)))))*(180/pi))*(128/90)
[State -2, var];明るさ:通常
type = varset
trigger = 法線ベクトルが↓を向いているとき
fvar(B) = abs(atan((((sin(fvar(β)*(pi/180))**2) + (cos(fvar(α)*(pi/180))*cos(fvar(β)*(pi/180)))**2)**0.5)/(sin(fvar(α)*(pi/180))*cos(fvar(β)*(pi/180)))))*(180/pi)*(128/90)
Bの場合、角度が0に近いほど明るいことになります。arctanは-π/2~π/2までしか返しませんが、符号を考える必要がないので絶対値(abs)にします。これは法線ベクトルy成分が上を向いている場合です。
下を向いている場合は角度が0に近いほど光源と反対を向くので暗くなります。
絶対値にして0~π/2、*(180/pi)で0~90、上を向いているなら180からひいて90~180、90で割って128をかけると、下を向いているとき0~128、上を向いているとき128~256になります
つまり、 ( 180 - (角度)*(180/pi) )*(128/90) ...上を向いている場合
法線ベクトルは②で考えましたが、回転角度0で(0,0,-1)にしていることに注意です。面によっては(0,0,1)かもしれません。付属Explodを考えたときに基準Explodにたいしてどのように回転させたのかによって変わります
結果こうなります。これはAの場合。というか記述が楽だから全部Aでやればいいんじゃない
おまけ。Alpha = 128,256としてみた
でもまあ格ゲー再現にこんな技術使わないよね