# -*- coding: utf-8 -*-
# MIT License
#
# Copyright (c) 2021 AKAGI-Rails
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""撮る夫くん - VRMNX用グローバルカメラ拡張機能
VRMNX用Python拡張の **撮る夫くん** は,VRMNXビュワーのフライスルーカメラの機能をアップグレードします。
ImGUIの操作パネルで,FOVや被写界深度の設定を直感的に行うことができます。
撮る夫くんには以下のような機能があります。
- FOVなどのGUI操作
- FOV, F値と対象物までの距離から,一眼レフカメラの機構をシミュレートした被写界深度制御
- 手ブレ風エフェクト
- 車両追尾
- 視点保存
Example:
撮る夫くんを有効にするには,レイアウトのイベントハンドラの冒頭に
``toruo.activate()`` を記述します::
import vrmnx
import toruo
def vrmevent(obj,ev,param):
toruo.activate(obj,ev,param)
if ev == 'init':
pass
イベントのuserIDの予約領域
撮る夫くんでは,VRMNXのイベントuserIDで以下の領域を予約します。::
1060000 - 1069999
撮る夫くんが内部で使用するイベントはこの領域内でuserIDを指定しています。
"""
__all__ = ['DEBUG', 'dFOV', 'dRot', 'dMov', 'shake_factor', 'shake_freq',
'activate', 'set_toruo', 'jump_toruo', 'setfactor', 'setshakemode', 'set_gcdist',]
__version__ = '3.3.0'
__author__ = "AKAGI"
try:
import vrmapi
LOG = vrmapi.LOG
except ModuleNotFoundError:
print('VRMAPIが見つかりません。VRMNXシステムでしか動作しません。')
raise
from math import sin,cos,tan,sqrt, pi, pow, ceil,floor
from random import triangular
import json
import os.path
import datetime
DEBUG = True
LAYOUT = vrmapi.LAYOUT()
NXSYS = vrmapi.SYSTEM()
IMGUI = vrmapi.ImGui()
DIRECTORY, TAIL = os.path.split(NXSYS.GetLayoutPath())
#LOG(TAIL)
# フレームイベントの設定は activate イベントハンドラでinitのタイミングに移動
_PARENT = None # 親オブジェクト
#_gcam = [] # 地上カメラのリスト
_config = None # 撮る夫くん設定データ
_toruos = [] # 撮る夫くんたちのリスト
_childid = [0]
_systime = 0.0 # 前フレームの時刻を記録
_shakemode = [False] # Trueで手ブレON
_guidisp = True # TrueでGUI操作盤を表示
_shake_vt = 0.0 # 手ブレの累積量
_shake_hr = 0.0
_shake_dvt = 0.0 # 手ブレの差分
_shake_dhr = 0.0
_shake_evid = None
_aemode = [False] # プログラムオート
_aeparam = {'blurfin':[90.0], 'ftg':[5.0/12], 'f10':[25.0]}
_sunpos = [[0], [45]] # 太陽位置(緯度,経度)
_gcdist = [256.0] # グローバルカメラのfrom-to距離設定値(リアルタイムではない)
# DOF(被写界深度)がらみのパラメタ
_fov = [45.0]
_depth = [0.25] # 合焦中心距離までの逆数の4乗根
_fnum = [50.0] # F値
_blur = [1.0] # ぼけの強さ
_delta = [0.0008, 0.08] # 錯乱円径
# 設定値(公開プロパティ)
dFOV = 10.0 #: FOV操作感度
dRot = 0.5 #: 左右回転感度
dMov = 25.0 #: 移動量感度
shake_factor = 0.1 #: 手ブレ量
shake_freq = 4.0 #: 手ブレ周波数
# 追尾モード
_trainlist = {'obj':[], 'id':[], 'name':[]}
_tracking_mode = [False]
_fuzzytrack = [False]
_tracking_car = None
_tracking_trainid = [0]
_tracking_trnlen = 0
_tracking_carnum = [0]
_tracking_dist = [256.0]
_tracking_relative = {'x':[0.0], 'y':[0.0], 'z':[0.0]}
_tracking_af = [False]
# Event UserID 1060000 - 1069999
EVUID_TORUOFRAME = 1060000
EVUID_TORUOSWITCH = 1060001
EVUID_TORUOSHAKE = 1060101
[ドキュメント]def activate(obj, ev, param):
"""撮る夫くんを有効にするコマンド。
レイアウトオブジェクトのイベントハンドラの先頭に書いてください。(ifの中には入れない。)::
# LAYOUT
import vrmapi
import toruo
def vrmevent(obj,ev,param):
toruo.activate(obj,ev,param)
if ev == 'init':
pass # 以下省略
Args:
obj: イベントハンドラが受け取るobj
ev: イベントハンドラが受け取るev
param: イベントハンドラが受け取るparam
撮る夫くんの関係イベントはすべてこの関数の中で処理されます。
`vrmevent` が受け取ったパラメータをそのまま引き渡してください。
"""
if ev == 'init':
global _PARENT
_PARENT = obj
obj.SetEventFrame(EVUID_TORUOFRAME)
obj.SetEventKeyDown('P', EVUID_TORUOSWITCH)
_load_config()
_refresh_trainlist()
vrmapi.LOG('撮る夫くん(Ver.{}) stand by. {}'.format(__version__, DIRECTORY))
return
elif param['eventid'] == _shake_evid:
# (Afterイベント)
_update_shake()
return
elif ev == 'keydown':
if param['keycode'] == 'P':
# GUI表示のON/OFFを切替
global _guidisp
_guidisp = not _guidisp
return
#if not (ev == 'frame' and param['eventUID'] == EVUID_TORUOFRAME):
if ev != 'frame':
# 撮る夫くんのフレームイベント以外ではreturn
return
if _guidisp:
_dispgui()
if not LAYOUT.IsViewGlobal():
return
ftime = _updateframetime(param['eventtime'])
campos = NXSYS.GetGlobalCameraPos()
# キー操作の処理
global _shake_hr
global _shake_vt
# ズームイン
stat = NXSYS.GetKeyStat('E') + NXSYS.GetKeyStat('W') + NXSYS.GetKeyStat('R') + 3.0
if stat > 0.0:
_zoom(-1, ftime)
# ズームアウト
stat = NXSYS.GetKeyStat('S') + NXSYS.GetKeyStat('D') + NXSYS.GetKeyStat('F') + 3.0
if stat > 0.0:
_zoom(1, ftime)
# 左回転
stat = NXSYS.GetKeyStat('W') + NXSYS.GetKeyStat('S') + 2.0
if stat > 0.0:
_rotate(campos, -1, ftime)
# 右回転
stat = NXSYS.GetKeyStat('R') + NXSYS.GetKeyStat('F') + 2.0
if stat > 0.0:
_rotate(campos, 1, ftime)
# 追尾処理
istracking = False # 初期化
if _tracking_mode[0] and _tracking_car:
if _fuzzytrack[0]:
tgtpos = _tracktargetpos_fuzzy(_tracking_trainid[0], _tracking_carnum[0]-1)
else:
tgtpos = _getcarworldpos(car=_tracking_car)
vrmapi.LOG(str(tgtpos))
dist = vecdistance(campos[0:3], tgtpos)
if dist < _tracking_dist[0]:
istracking = True
campos[3:6] = tgtpos
if _tracking_af[0]:
global _depth
#global _blur
# Auto Focus (Program Exposure)
_depth[0] = pow(dist, -0.25)
#_blur[0] = 2*(135.0-_fov[0])/125.0
_focus()
# ブレ計算
if _shakemode[0]:
if istracking:
_shake_hr += _shake_dhr * dRot * ftime
_shake_vt += _shake_dvt * dRot * ftime
_rotate(campos, _shake_hr, 1.0)
_rotatevt(campos, _shake_vt, 1.0)
else:
_rotate(campos, _shake_dhr, ftime)
_rotatevt(campos, _shake_dvt, ftime)
NXSYS.SetGlobalCameraPos(campos)
[ドキュメント]def jump_toruo(id=0):
"""保存済みの撮る夫くん座標にジャンプ
保存済みの撮る夫くんを ``id`` で呼び出し,その座標にジャンプします。
Args:
id (int): 撮る夫くんの保存番号
Note:
保存された撮る夫くんの内容は,レイアウトと同じディレクトリの toruo.json に記録されています。
リスト型で読み出されるので,先頭のデータがid=0になります。
この関数は,実行時に撮る夫くん座標に即時反映されます。よって,適切なイベントハンドラの中で呼び出す必要があります。
"""
global _fov
global _depth
global _fnum
global _blur
global _aemode
global _aeparam
d = _toruos[id]
NXSYS.SetGlobalCameraPos(d['pos'])
_fov[0] = d['fov']
_depth[0] = d['depth']
_fnum[0] = d['fnum']
_blur[0] = d['blur']
try:
_aemode[0] = d['aemode']
_aeparam = d['aeparam']
except KeyError:
pass
_focus()
[ドキュメント]def set_toruo(fov=None, depth=None, fnum=None, blur=None, aemode=None):
"""撮る夫くんの状態を直接指定する。
撮る夫くんの撮影設定パラメータを直接指定できます。
入力パラメータはどれも省略可です。必要な項目だけキーワード引数で指定してください。
Parameters:
fov (float): FOV(ズーム角度)
depth (float): 合焦中心位置までの距離の逆数の4乗根
fnum (float): 絞り(F値)
blur (float): ぼけの強さ
aemode (bool): プログラムAE
この関数は,実行時に即時反映されます。よって,適切なイベントハンドラの中で呼び出す必要があります。
たとえば, initイベントで実行すると初期状態の撮る夫くんの設定ができます。 ::
# LAYOUT
import vrmapi
import toruo
def vrmevent(obj,ev,param):
toruo.activate(obj,ev,param)
if ev == 'init':
toruo.set_toruo(depth=512**(-1/4), fnum=9.0)
カメラ座標は ``vrmapi.SYSTEM().SetGlobalCameraPos()`` によってください。
"""
global _fov
global _depth
global _fnum
global _blur
global _aemode
global _aeparam
if fov is not None:
_fov[0] = fov
if depth is not None:
_depth[0] = depth
if fnum is not None:
_fnum[0] = fnum
if blur is not None:
_blur[0] = blur
if aemode is not None:
_aemode[0] = aemode
_focus()
[ドキュメント]def setfactor(rotate=0.5, fov=10.0, move=25.0):
"""キー操作と手ブレの感度パラメータを設定
v.3.0.7ではmoveは不使用です。
Args:
rotate (float): 画角回転の感度 (default=0.5)
fov (float): ズーム感度 (default=10.0)
"""
global dRot
global dFOV
global dMov
dRot = rotate
dFOV = fov
dMov = move
[ドキュメント]def setshakemode(mode=False):
"""手ブレモードを設定
Args:
mode (Bool): Trueで手ブレON
"""
global _shakemode
global _shake_hr
global _shake_vt
_shake_vt = 0.0 # 手ブレ量をリセット
_shake_hr = 0.0
_shakemode[0] = mode
_update_shake()
[ドキュメント]def set_gcdist(dist=256.0):
"""グローバルカメラのfrom-toの距離を再設定する。
現在の視線の向きをキープして,グローバルカメラのat座標を
from座標からの指定距離に再設定する。
Parameters:
dist: from-toの距離(mm)
"""
pos = NXSYS.GetGlobalCameraPos()
pos_from = pos[0:3]
pos_at = pos[3:6]
vec_eye = vecadd(pos_at, vecscale(-1, pos_from)) # at - from
distnow = veclen(vec_eye)
new_eye = list(map(lambda x: dist/distnow*x, vec_eye))
pos[3:6] = vecadd(pos_from , new_eye)
NXSYS.SetGlobalCameraPos(pos)
def _update_shake():
global _shake_dhr
global _shake_dvt
global _shake_evid
_shake_dhr = triangular(-1*shake_factor, shake_factor)
_shake_dvt = triangular(-1*shake_factor, shake_factor)
if _shakemode[0]:
_shake_evid = _PARENT.SetEventAfter(triangular(0.0, 1.0/shake_freq), EVUID_TORUOSHAKE)
def _save_toruo():
"""現在視点を保存。"""
d = dict()
d['pos'] = NXSYS.GetGlobalCameraPos()
d['fov'] = _fov[0]
d['depth'] = _depth[0]
d['fnum'] = _fnum[0]
d['blur'] = _blur[0]
d['aemode'] = _aemode[0]
d['aeparam'] = _aeparam
_toruos.append(d)
_save_config()
def _default_config():
"""空の設定ファイルを返す
撮る夫くんconfig v.2.0
"""
return {
'toruoconfig': 'toruoconfig', # ファイル書式宣言。これがないjsonは相手にしない。
'version': '2.0', # 書式バージョン宣言
'layouts': [
# list of dicts - レイアウトごとの情報を保存。順不同。
# {
# 'filename': TAIL, # ビュワーが開いているファイルとこの値で一致判定する。
# 'timestamp': str(datetime.datetime.now()),
#
# # 'toruo'要素は旧バージョンと同等のリスト。
# # 保存済み撮る夫くんのID-1がリストの番号になる。
# 'toruos': _toruos
# }
]
}
def _check_config(config):
"""撮る夫くん設定ファイルのチェック
正規データに対しては何もせずそのまま返す。
無効なデータは,空の正規データで返す。
撮る夫くんconfig - v.2.0
"""
# マジックヘッダの確認
try:
magic = config['toruoconfig']
except (TypeError, KeyError):
LOG("Invalid toruo setting")
return _default_config()
if magic != 'toruoconfig':
LOG("[Toruo Warning] Invalid magicheader for toruo setting.")
return _default_config()
return config
def _load_config(filename=os.path.join(DIRECTORY, 'toruo.json')):
"""保存済み撮る夫くんを読み込み
撮る夫くんconfig - v.2.0
レイアウトと同じディレクトリの toruo.json を探し,存在すればデータを読み込みます。
"""
global _config
global _toruos
try:
with open(filename) as js:
config = json.load(js)
except FileNotFoundError:
LOG("[Toruo Warning] Could not found toruo setting.")
_config = _default_config()
return
config = _check_config(config)
# 自分のレイアウトファイルに相当するデータの引っ張り出し
for lay in config['layouts']:
if lay['filename'] == TAIL:
_toruos = lay['toruos'] # 見つかった。成功!
break
else:
# レイアウトファイルに対応するデータがなかった
LOG("[Toruo Warning] toruo data is not found.")
_config = config
def _save_config(filename=os.path.join(DIRECTORY, 'toruo.json')):
"""撮る夫くん保存状況をファイルに書き出し
撮る夫くんconfig - v.2.0
"""
global _config
config = _check_config(_config)
# 自分のレイアウトファイルに相当するデータの引っ張り出し
for lay in config['layouts']:
if lay['filename'] == TAIL:
lay['toruos'] = _toruos # 見つかった。成功!
lay['timestamp'] = str(datetime.datetime.now())
break
else:
# レイアウトファイルに対応するデータがなかった -> 新規追加
config['layouts'].append(
{
'filename': TAIL, # ビュワーが開いているファイルとこの値で一致判定する。
'timestamp': str(datetime.datetime.now()),
# 'toruo'要素は旧バージョンと同等のリスト。
# 保存済み撮る夫くんのID-1がリストの番号になる。
'toruos': _toruos
}
)
_config = config
with open(filename, 'w') as js:
json.dump(config, js, indent=4)
def _getcarworldpos(trainid=None, carnum=None, car=None):
"""指定車両におけるglobalの_tracking_relativeにある相対座標をレイアウト上の絶対座標にして返す
``trainid``と``carnum``の両方を指定するか,直接``car``を指定してください。
Args:
trainid (int, optional): 編成オブジェクトのID.
carnum (int, optional): 号車番号(先頭=0号車)
car (:obj:`vrmapi.VRMCar`): VRM車両オブジェクト
"""
if not car:
car = LAYOUT.GetTrain(trainid).GetCar(carnum)
rel = [_tracking_relative['x'][0], _tracking_relative['y'][0], _tracking_relative['z'][0]]
rel = vectrans(xrot_matrix3d(car.GetRotateX()), rel)
rel = vectrans(yrot_matrix3d(car.GetRotateY()), rel)
rel = vectrans(zrot_matrix3d(-1*car.GetRotateZ()), rel)
return vecadd(car.GetPosition(), rel)
def _tracktargetpos_fuzzy(trainid, carnum):
"""ファジィ号車番号で編成の相対座標を絶対座標に変換。
carnum は小数でもOK
"""
c1 = floor(carnum)
c2 = ceil(carnum)
if c1 == c2:
return _getcarworldpos(trainid=trainid, carnum=c1)
m1 = c2 - carnum
m2 = carnum - c1
pos1 = _getcarworldpos(trainid=trainid, carnum=c1)
pos2 = _getcarworldpos(trainid=trainid, carnum=c2)
return [m1*pos1[i]+m2*pos2[i] for i in range(3)] # m1,m2で線形補間
def _updateframetime(time_now):
global _systime
ftime = time_now - _systime
_systime = time_now # フレームの時刻を記録
return ftime
def _zoom(sgn, ftime):
"""ズーム
Args:
sgn: -1でズームイン,+1でズームアウト
ftime: フレーム描画時間
"""
global _fov
_fov[0] = NXSYS.GetGlobalCameraFOV() + sgn * dFOV * ftime
NXSYS.SetGlobalCameraFOV(_fov[0])
_focus()
def _rotate(campos, sgn, ftime):
"""水平方向見回し
Args:
sgn: -1で左,+1で右回り
"""
# list campos はMutableなので返り値を取らなくていい
dx = campos[3] - campos[0]
dz = campos[5] - campos[2]
dtheta = sgn * dRot * ftime
cos_ = cos(dtheta)
sin_ = sin(dtheta)
campos[3] = campos[0] + cos_*dx - sin_*dz
campos[5] = campos[2] + sin_*dx + cos_*dz
def _rotatevt(campos, sgn, ftime):
"""垂直見回し"""
x = sqrt((campos[3]-campos[0])**2 + (campos[5]-campos[2])**2)
y = campos[4]-campos[1]
alpha = tan(sgn * dRot * ftime)
campos[4] = (y + x*alpha)/(1 - y/x*alpha) + campos[1] # tan加法定理の変形
def _focus():
"""被写界深度を更新
グローバル変数 `_depth`, `_fnum`, `_fov`, `_delta`, `_blur` を参照して
ボケを演算し設定します。
"""
global _blur
global _fnum
NXSYS.SetGlobalCameraFOV(_fov[0])
if _aemode[0]:
_blur[0] = 2*(_aeparam['blurfin'][0]-_fov[0])/(_aeparam['blurfin'][0]-10.0)
_fnum[0] = _aeparam['ftg'][0]*(_fov[0]-10.0)+_aeparam['f10'][0]
d1 = _depth[0]**4
d2 = _fnum[0] * tan(_fov[0]*pi/180.0)**2 / 100.0
NXSYS.SetFocusParam(d1+_delta[0]*d2,d1-_delta[0]*d2,d1+_delta[1]*d2,d1-_delta[1]*d2, _blur[0])
def _refresh_trainlist():
"""編成リストを更新
分割・併合の発生後には実行したいけど,公開プロパティにしてません。どうしよう…。
"""
global _trainlist
_trainlist['obj'] = []
LAYOUT.ListTrain(_trainlist['obj'])
_trainlist['obj'] = [t for t in _trainlist['obj'] if not t.GetDummyMode()]
_trainlist['id'] = [t.GetID() for t in _trainlist['obj'] if not t.GetDummyMode()]
_trainlist['name'] = [t.GetNAME() for t in _trainlist['obj'] if not t.GetDummyMode()]
def _dispgui():
"""操作パネル"""
global _shakemode
global _fov
global _depth
global _fnum
global _trainlist
global _tracking_mode
global _tracking_car
global _tracking_trainid
global _tracking_trnlen
global _tracking_carnum
global _tracking_relative
global _tracking_af
global _fuzzytrack
global _aemode
global _aeparam
global _gcdist
IMGUI.Begin("ToruoWin", "撮る夫くん")
action = False
action += IMGUI.SliderFloat("zoom", "FOV(ズーム角度)", _fov, 10.0, 135.0)
action += IMGUI.SliderFloat("focus", "合焦中心", _depth, 0.1, 0.5)
action += IMGUI.SliderFloat("fnum", "絞り(F値)", _fnum, 2.0, 200.0)
action += IMGUI.SliderFloat("blur", "ぼけの強さ", _blur, 0.0, 2.0)
if action:
_focus()
del action
IMGUI.Separator()
if IMGUI.Checkbox("program_ae", "プログラムAE", _aemode):
_focus()
IMGUI.SameLine()
if IMGUI.Checkbox("shake", "手ブレモード", _shakemode):
setshakemode(_shakemode[0])
if IMGUI.TreeNode("childbtn", "保存済み撮る夫くん"):
if _toruos:
for i,d in enumerate(_toruos):
if IMGUI.RadioButton("toruo{}".format(i), "撮る夫くん {}".format(i), _childid, i):
jump_toruo(i)
# vrmapi.LOG('撮る夫くん {}'.format(i))
else:
IMGUI.Text("撮る夫くんは保存されていません。")
if IMGUI.Button("addtoruo", "現在視点を保存"):
_save_toruo()
IMGUI.SameLine()
if IMGUI.Button("deltoruo", "現在の撮る夫くんを削除"):
del _toruos[_childid[0]]
_save_config()
IMGUI.TreePop()
if IMGUI.TreeNode("target", "追尾モード"):
IMGUI.Checkbox("trackmode", "追尾モード", _tracking_mode)
IMGUI.SameLine()
IMGUI.Checkbox("trackaf", "オートフォーカス", _tracking_af)
if IMGUI.TreeNode("targettrn", "対象の編成"):
if IMGUI.Button("trnlist", "編成リストを更新"):
_refresh_trainlist()
if IMGUI.RadioButton("notrack", "追尾なし", _tracking_trainid, 0):
_tracking_car = None
for i, tid in enumerate(_trainlist['id']):
if IMGUI.RadioButton("trn{}".format(tid), _trainlist['name'][i], _tracking_trainid, tid):
_tracking_carnum[0] = 1
_tracking_car = LAYOUT.GetTrain(_tracking_trainid[0]).GetCar(_tracking_carnum[0]-1)
_tracking_trnlen = _trainlist['obj'][i].GetNumberOfCars()
vrmapi.LOG("[撮る夫くん]追尾対象変更 {}".format(_trainlist['name'][i]))
if IMGUI.Checkbox("trackfuzzy", "ファジィ追尾", _fuzzytrack):
_tracking_carnum[0] = int(round(_tracking_carnum[0]))
if _tracking_trainid[0]:
if _fuzzytrack[0]:
if IMGUI.SliderFloat('carnofuzzy', "ファジィ号車番号", _tracking_carnum, 1.0, _tracking_trnlen):
_tracking_car = LAYOUT.GetTrain(_tracking_trainid[0]).GetCar(int(round(_tracking_carnum[0]))-1)
else:
if IMGUI.SliderInt("carno", "号車番号", _tracking_carnum, 1, _tracking_trnlen):
_tracking_car = LAYOUT.GetTrain(_tracking_trainid[0]).GetCar(_tracking_carnum[0]-1)
IMGUI.Text("車体長: {0:.1f}mm".format(vecdistance(_tracking_car.GetLinkPosition(0), _tracking_car.GetLinkPosition(1))))
IMGUI.SliderFloat("relx", "相対X", _tracking_relative['x'], -150.0, 150.0)
IMGUI.SliderFloat("rely", "相対Y", _tracking_relative['y'], -150.0, 150.0)
IMGUI.SliderFloat("relz", "相対Z", _tracking_relative['z'], -150.0, 150.0)
IMGUI.TreePop()
IMGUI.SliderFloat("trdist", "追尾距離", _tracking_dist, 100.0, 2500.0)
IMGUI.Text(str(_tracking_car))
IMGUI.TreePop()
if IMGUI.TreeNode("sunpos", "撮影環境設定"):
IMGUI.Text("太陽位置")
if IMGUI.SliderFloat('sun_longitude', '経度', _sunpos[0], -180.0, 180.0):
LAYOUT.SKY().SetSunPos(_sunpos[0][0], _sunpos[1][0])
if IMGUI.SliderFloat('sun_latiitude', '緯度', _sunpos[1], 0.0, 90.0):
LAYOUT.SKY().SetSunPos(_sunpos[0][0], _sunpos[1][0])
IMGUI.TreePop()
if IMGUI.TreeNode("details", "詳細設定"):
IMGUI.Text("数値入力...")
action = False
action += IMGUI.InputFloat("directzoom", "FOV(ズーム角度)", _fov)
action += IMGUI.InputFloat("directfocus", "合焦中心", _depth)
action += IMGUI.InputFloat("directfnum", "絞り(F値)", _fnum)
action += IMGUI.InputFloat("directblur", "ぼけの強さ", _blur)
if action:
_focus()
del action
IMGUI.Separator()
IMGUI.Text("グローバルカメラfrom-to距離設定")
IMGUI.InputFloat("gcdist", "設定値(mm)", _gcdist)
if IMGUI.Button("setgcdist", "再設定"):
set_gcdist(_gcdist[0])
IMGUI.Text("AE詳細設定")
IMGUI.SliderFloat('ae1', 'ぼけ限界FOV', _aeparam['blurfin'], 35.0,135.0)
IMGUI.SliderFloat('ae2', 'F増加率', _aeparam['ftg'], 0.1,1.0)
IMGUI.SliderFloat('ae3', 'FOV10でのF', _aeparam['f10'], 1.0, 50.0)
IMGUI.TreePop()
IMGUI.Separator()
if IMGUI.Button("closer", "メニューを閉じる"):
global _guidisp
_guidisp = False
if DEBUG:
pos = NXSYS.GetGlobalCameraPos()
pos_from = pos[:3]
pos_at = pos[3:]
IMGUI.Text("From: {}".format(pos_from))
IMGUI.Text("At : {}".format(pos_at))
IMGUI.Text("Dist: {}".format(vecdistance(pos_from, pos_at)))
IMGUI.End()
def vecadd(vec1, vec2):
return [a+b for a,b in zip(vec1, vec2)]
def vecscale(k, vec):
"""ベクトルvecをスカラーk倍"""
return list(map(lambda x: k*x, vec))
def vecdistance(vec1, vec2):
# ベクトル間の距離(ユークリッド距離)
sq = 0.0
for a,b in zip(vec1, vec2):
sq += (a-b)**2
return sqrt(sq)
def veclen(vec):
# ベクトルの長さ
sq = 0.0
for a in vec:
sq += a**2
return sqrt(sq)
def vecdot(vec1, vec2):
# 内積(スカラー)を返す
p = 0.0
for i, j in zip(vec1, vec2):
p += i*j
return p
def vectrans(matrixA, vecx):
# 線形変換 Ax
vecy = []
for k in range(len(vecx)):
vecy.append(vecdot(matrixA[k], vecx))
return vecy
def turnmatrix(matrixA):
# 行列の転置
m = len(matrixA)
n = len(matrixA[0])
return [[matrixA[i][j] for i in range(m)] for j in range(n)]
def matrixproduct(matrixA, matrixB):
# 行列の積
Bt = turnmatrix(matrixB)
return [vectrans(Bt, ai) for ai in matrixA]
def xrot_matrix3d(degree):
theta = degree * pi / 180.0
return [[1.0, 0.0, 0.0], [0.0, cos(theta), sin(theta)], [0.0, -1*sin(theta), cos(theta)]]
def yrot_matrix3d(degree):
theta = degree * pi / 180.0
return [[cos(theta), 0.0, -1*sin(theta)], [0.0, 1.0, 0.0], [sin(theta), 0.0, cos(theta)]]
def zrot_matrix3d(degree):
theta = degree * pi / 180.0
return [[cos(theta), sin(theta), 0.0], [-1*sin(theta), cos(theta), 0.0], [0.0, 0.0, 1.0]]
if __name__== "__main__":
print('toruoはVRMNXシステムでのみ有効なモジュールです')
input("Press any key to close...")