レイアウトで写真を撮る際に逆光だなーとか影が横から欲しいなーと思ったとき、VRMNXでは天候や太陽の角度などがビュワーから自由に変更できます。
地味に非常にありがたい機能ですが、この光源(=太陽)をフレーム毎に少しずつ動かせばオープンワールドのような「時の流れ」を表現できるのでは、と思っていました。
作成しようとしたとき、傾きとかを計算するのが大変だなーと感じたので未着手だったのですが、ありがたい事に同じことを考えた方がVRMレイアウト公開所にアップロードされているのを見つけたので紹介したいと思います。
C-PONさんの「
太陽再現スクリプト」は季節による太陽高度の傾き変化も計算に含めたリアルタイム天球シミュレーションになっています。
基本的な数値は自作のImGuiから参照や操作が可能。
太陽の動きに合わせて背景の変更や現在時刻を示す時計もスプライトで描画されています。
サンプルレイアウトはスターターキットで動きます。
夜になると列車が駅に停まります。
以下は「太陽再現スクリプト」を流用してCaldiaが遊ぶ用に改造した内容になります。
1.時計のオミット
現時点の最新バージョン(6.0.0.223)ではスプライトの終了処理に不具合があるらしく、自環境ではビュワー終了時に異常終了となります。。
後述の仕様を取り込むと目まぐるしく動くこと、他のレイアウトへ導入する際にスプライト用のリソースを追加する手間を省くため等の理由から、時計を非表示にします。
以下の部分をコメントアウトします。
#global sprite
#sprite = obj.CreateSprite()
#sprite.LoadSystemTexture(lodict['clrs'])
#if lodict['stokei']:
# stokei(obj)
2.ゲーム速度の倍化
太陽再現スクリプトは現実と同じ速度で動きますが、そこまでのんびり過ごすのはせっかちな現代人には厳しいです。
鉄道博物館のジオラマ運転や一般的なゲームでも、1日の表現はもっと短いサイクルで回しています。
いくつかのゲームを確認したところ、概ね30秒か1分でゲーム内の1時間、つまり6分~12分で1日になるものが多いようです。
今回は1日を6分、120倍でゲーム内時間を進むようにします。
変数「lodict['hayasa']」が時間の加速度を表しているので、ここを「120」に変更します。
lodict['hayasa'] = 120 #時間の加速度1で現実速度
3.処理の省略(負荷軽減)とタイミング調整
「lodict['anime']」を天球書き換え用に用意します。
# 太陽と天球のアニメーション速度(秒) 現実速度1なら10分で動作
lodict['anime'] = 1200 / lodict['hayasa']
これはtenkyuメソッドで毎フレームで「100/lodict['hayasa']」を計算している処理を初回のみで済ませる負荷軽減策になります。
ついでに文字数を削減するため「vrmapi.LAYOUT().SKY()」を「sky」変数に代入します。
処理に変化はありませんが、全体の文字数が減り、可読性が向上します。
# 天球書き換え
def tenkyu(obj):
sky = vrmapi.LAYOUT().SKY()
lodict=obj.GetDict()
if lodict['lat'] < 18 and lodict['iro']==0:
lodict['iro']=1
sky.LoadSkyImage(1,lodict['yuurs'])
sky.SetAnimeSkyFactor(1.0, lodict['anime'])
sky.SetSunType(6, lodict['anime'])
if lodict['lat'] < -6 and lodict['iro']==1:
lodict['iro']=1.5
sky.SetSunType(5, lodict['anime'])
if lodict['lat'] < -10 and lodict['iro']!=2:
lodict['iro']=2
sky.LoadSkyImage(0,lodict['yorrs'])
sky.SetAnimeSkyFactor(0, lodict['anime'])
sky.SetSunType(3, lodict['anime'])
if lodict['lat'] > -7 and lodict['iro']==2:
lodict['iro']=1.8
sky.LoadSkyImage(1,lodict['yuurs'])
sky.SetAnimeSkyFactor(1, lodict['anime'])
sky.SetSunType(1, lodict['anime'])
if lodict['lat'] > 12 and lodict['iro']!=0:
lodict['iro']=0
sky.LoadSkyImage(0,lodict['hirrs'])
sky.SetAnimeSkyFactor(0, lodict['anime'])
sky.SetSunType(0, lodict['anime'])
条件分岐の数値も細かく弄っています。
ゲーム速度を加速したことで既存のアニメーションタイミングでは一瞬で天球が切り替わってしまうため、
もっと時間を掛けて緩やかに変化するようにしています。
また、現実では日の出前や日没後も太陽光は回折して届くため、明るい時間が長くなるように調節しています。
4.処理の追加外出し
太陽再現スクリプトは「sunsim.py」という外部ファイルに処理が固められていますが、天球リソース指定などの一部処理はレイアウトスクリプトに書かれています。
レイアウトファイルに記述するスクリプトを可能な限り減らしたいので、残りのコードも「sunsim.py」へ移動させます。
def vrmevent(obj,ev,param):
sunsim.vrmevent(obj,ev,param)
def vrmevent(obj,ev,param):
if ev =='init':
init(obj)
obj.SetEventFrame()
elif ev == 'frame':
window(obj)
def init(obj):
lodict=obj.GetDict()
lodict['hirrs']=1 #天球昼リソース番号
lodict['yuurs']=2 #天球夕リソース番号
lodict['yorrs']=3 #天球夜リソース番号
これでレイアウトオブジェクトには実質2行で組み込めるようになります。
以上の改造により、6分で1日の時間経過をアニメーションで楽しめるようになります。
他にも雲や霧を表示させたり、複数の天球テクスチャをランダムで変化させたりする仕組みも楽しそうです。
上記改造コードはC-PONさんが許可頂ければgithubにでもアップロードしようと思います。