C4Dのカメラ視点の中心を基準に動作する簡易エフェクタネタを見て
AviUtl用に考えてみました。
またちょっとしたスクリプト制御を使った遊びをしてみました。
Camfx=function(dist,P,A,B)
local Dist_P_AB = function(P,A,B)
local Sub=function(a,b)
return {b[1]-a[1],b[2]-a[2],b[3]-a[3]}
end
local Length=function(v)
return (v[1]*v[1] + v[2]*v[2] + v[3]*v[3] )^.5
end
local Cross = function(vl,vr)
return {
(vl[2] * vr[3]) - (vl[3] * vr[2]),
(vl[3] * vr[1]) - (vl[1] * vr[3]),
(vl[1] * vr[2]) - (vl[2] * vr[1])
}
end
local AB=Sub(A,B)
local AP=Sub(A,P)
return Length(Cross(AB,AP)) / Length(AB)
end
local P = P or {obj.ox,obj.oy,obj.oz}
local c=obj.getoption("camera_param")
local A,B=A or {c.tx,c.ty,c.tz},B or {c.x,c.y,c.z}
P = {P[1]+obj.x,P[2]+obj.y,P[3]+obj.z}
local dist=dist or 100
local L = Dist_P_AB(P,A,B)
local l = (L<dist and L) or dist
return l/dist
end
この関数はカメラ視線の中心から一定範囲内の距離を0~1の値にします。
カメラ正面の場合は0、カメラ正面からdistで指定した距離になると1になり、それ以上増えません。
distは影響範囲を入力、
Pはオブジェクトの座標(={x,y,z})を入力します。
Pは省略すると相対座標(={obj.ox, obj.oy, obj.oz} )が自動で入ります。
※基準座標は内部で加算されます。
AとBは基本不要ですがA、B其々三次元座標を入れるとA,Bを通る線との距離を計算します。
まずは空いているオブジェクトにスクリプト制御を使用し
上のコードをコピペします。
するとそれ以降はCamfxでこのエフェクターがどこでも呼び出せるようになります。
エフェクターと言っていますがただ0~1の値を出すだけです。
それでは実際にこの関数を使って遊んでみます。
まずはカメラを制御を用意し。
サイズ200程度の四角形を出して、そこへオブジェクト分割をかけます。
9x9 程度に分割します。
そののちにスクリプト制御を使用し、以下のコードを書いてみます。
local L = Camfx(200)
obj.zoom = 1-L
どうでしょう、カメラ正面から外れると小さくなるはずです。
以下説明。
変数Lに「カメラ正面なら1, 正面から200pixel離れたら0になる値」が入ります。
local と変数の頭につけておくと、このスクリプトの内部でのみ使用できる値になります。
obj.zoomは画像の拡大率を示す変数です。変数の値を変えると拡大率を変更できます。
obj.zoomが0だと拡大率が0
obj.zoomが1だと拡大率100となります。
obj.zoomが2なら拡大率は200です。
ここでは 1-Lにして動作を反転しています。
local L = Camfx(200)
obj.zoom = 1-L
obj.effect("単色化", "強さ", L*100, "color", 0xdd0000, "輝度を保持する",0)
今度は色が変化するはずです。
以下説明。
obj.effectは拡張編集のフィルターを使用する関数です。
括弧の中の最初の文字に使いたいフイルターの名前を入力します。
スクリプトでの「文字」とは" " や ’ ’で囲まれた文字のことを指します。
単色化 ではダメで "単色化" 又は '単色化' と入れます。
そして変更したいエフェクトのパラメータ名とその数値を "パラメータ名" ,数値 と続けて入れます。
obj.effect(
"単色化",
"強さ", L*100,
"color" ,0xdd0000,
"輝度を保持する",0
)
カッコの中ならこのように改行しても平気です。カンマで区切るのを忘れずに。
ただし、最後にはカンマをつけません。
単色化フィルターの強さは0~100なのでLを100倍にしておきました。
さらに追加してみます
local L = Camfx(200)
obj.zoom = 1-L
obj.effect("単色化", "強さ", L*100, "color", 0xdd0000, "輝度を保持する",0)
obj.ox = obj.ox*(1-L) + obj.ox
obj.oy = obj.oy*(1-L) + obj.oy
なんだか面白動きになりませんでしたか。
obj.ox = obj.ox*(1-L) + obj.ox
obj.oy = obj.oy*(1-L) + obj.oy
obj.ox, obj.oy (obj.oz) はスクリプトで座標を移動させる場合に使う変数です。
個別オブジェクトなどもこの数値を使って予めその場所に移動している、という状態です。
ここでは自分自身の位置に倍率を掛ける形になりますが
obj.ox = 200*(1-L) + obj.ox
obj.oy = 500*(1-L) + obj.oy
このように好きな数値を入れても楽しいと思います。
ちょっとアレンジしてみます
local L = Camfx(200)
--obj.zoom=(1-L)
obj.effect("単色化" ,"強さ", L*100, "color", 0xdd0000, "輝度を保持する",0 )
local rdx = obj.rand(-200,200,1, 1)
local rdy = obj.rand(-200,200,2, 1)
local rdzoom = obj.rand(0,200,3,1)/100
obj.ox = rdx*(1-L) + obj.ox*L
obj.oy = rdy*(1-L) + obj.oy*L
obj.rx = (rdx+rdy)*3*L
obj.zoom = rdzoom*(1-L) + obj.zoom*L
カメラ目線と合うとワシャーっと広がる何かになりました。
-- obj.zoom=(1-L)
local rdx = obj.rand(-200,200,1, 1)
local rdy = obj.rand(-200,200,2, 1)
local rdzoom = obj.rand(0,200,3,1)/100
-- とマイナスを続けることでその行をを無効化します
rdx,rdy に-200から200までのランダムな値をいれています。
rdzoomは0~2.00の値です。
obj.rand は指定した範囲でランダムな整数を出す関数です。
obj.rand( 最小値, 最大値, seed, frame ) と四つ値を指定します。
得られる値は整数なので小数点以下がほしい場合は大きな値を入れてから割ります。
obj.rand(0,200,seed,frame)/100 --(0~2.00 までの値)
seedはランダムな値の羅列を発生させる元になる値で、
最小値,最大値,seed が同じなら毎回同じ値の羅列になります。
ただし seedはどうやら内部で (seed + obj.layer + obj.index)
といった感じにレイヤー位置と個別オブジェクトのインデックスが自動で入るようです。tabun。
seedをマイナスにすると純粋なseed値だけになり必ず同じ羅列になります。
frameは発生したランダムな羅列の何番目を呼ぶかを指定します。
frameに何もいれなかった場合は一フレーム毎に1づつ増えていきます。
※個別オブジェクトは勝手にseed値が変化しますのであえてここではframe値を固定しています。
obj.ox = rdx*(1-L) + obj.ox*L
obj.oy = rdy*(1-L) + obj.oy*L
obj.rx = (rdx+rdy)*3*L
obj.zoom = rdzoom*(1-L) + obj.zoom*L
それから座標にランダムな値と元の座標を入れ替える計算をします。
obj.rxはx軸回転を変更します。値は適当です。
どうでしたでしょうか。なかなかおもしろいですよね。
AviUtlのスクリプトはリアルタイムで反応するので楽しいですが
記述中はスクリプト制御のチェックを外しておいたほうが無難です。
迂闊に obj=xx などとobjを書き換えてしまうと
スクリプトがすべて死ぬので注意しましょう。(起動しなおせば戻ります。)