2014年9月13日土曜日

Maxscript その9 「座標とベクトル point3値」

ついに来てしまったpoint3。3つの値の集合体。3DCGでは非常によく使われる。座標、スケールetc。ベクトルとも呼ばれる。

point3は[]で囲み、「,」で区切って3つの数字を扱う。
[10,20,30]

プロパティ等
<node>.pos.zの「.z」などはpoint3クラスのプロパティのようだ。

計算
中に式をかける

コピー シャローコピー/ディープコピー
配列の時はdeepcopyでpoint3の時はcopyとは流石maxscript

ちなみにinteger、float、time値の場合は独立している。混乱してくる・・・。
リファレンス「変数>参照代入」を参照

-------------------------------
以下ベクトルについて。知らなくてもスクリプトで出来ることは沢山あるので特に問題ないと思う。そして何より、僕はベクトルを語れるほどベクトルの事を理解していないのである。「間違いないです」とはとても言えない。

ところでベクトルって何だろね?MAXscriptリファレンスの分かりづらさに日々イライラしているけど、ここはGJ!!と大声を出して叫びたい。GJ!!Maxscriptリファレンス!!昔はやる気があったんだね!!

という事でベクトルについて知りたい方は

「Maxscriptに関する質問と回答>実際の操作に関する質問>ベクトルの操作」を参照。

ネットから見れると思うので「Maxscript リファレンス」とかで検索してみるといいかも。

無断掲載申し訳ないがZで行こう!で非常に分かりやすく解説している。というより、Maxscriptは2bit-blogを見るよりZさんのページ見た方がいいと思う。非常に詳しく丁寧により深い情報が載っている。コードもコピペ出来るし。


位置(座標)もベクトルという事ですか?原点[0,0,0]からの位置を表しているようだ。


ベクトルは数学や物理用語なんだって。ちなみに数値を1つしか持たないものはスカラーと呼ばれるらしい。なんかどっかで見たことある気がする。

 3DCGをやる以上、ベクトルの計算などが理解出来たらそれに越したことはないとは思う。でも、難しいのも事実。しかし、意味が分からなくても、式をスクリプトの構文で記述出来れば計算してくれる。暗記の必要もない。スクリプトにはそういういい所もある。コピペでも僕は全然いいと思う。始まりはいつだってコピーから。基礎的な理解と経験。その蓄積があってようやく自分で考える事が出来るようになり、発展、応用、アイディアとかに繋がると思うんだ。それには時間がかかるんだよね。継続は力なり。

四則演算

その他
座標変換、回転したり反転したり。
<point3>*<matrix3>
<point3>*<quat>
-<point3>

関数など
3DCGソフトのscriptなのでよく行う計算を関数にしてくれてある。親切。

ベクトルの長さ
Length <Point3> ベクトルの長さ = 原点[0,0,0]からの距離
ピタゴラスの定理
p = $.pos
length = sqrt(p.x^2+p.y^2+p.z^2)


2点間の距離
distance <point3> <point3>

v = $Sphere001.pos - $Sphere002.pos
distance = sqrt(v.x^2+v.y^2+v.z^2) --もしくはpow (v.x^2+v.y^2+v.z^2) 0.5

単位ベクトル
normalize <point3>
単位ベクトル(長さが1のベクトル)を取得する。ベクトル計算の基本だろうか。



normalizeのイメージ。長さが1なので三角関数、ラジアンなどとの相性もいいらしい。ベクトルの計算は原点[0,0,0]が基本となるため、得られる単位ベクトルは原点[0,0,0]から長さ1のベクトルとなるようだ。

長さを求めた後、各要素を長さで割る。
p = $.pos
length = sqrt(p.x^2+p.y^2+p.z^2)

vn = point3 (p.x/length) (p.y/length) (p.z/length) -- nv = [ p.x/length , p.y/length , p.z/length]


内積
dot <point3> <point3>
2つのベクトルの角度を取得するためによく用いられる気がする。

p1 = $Sphere001.pos --Sphere01の位置を取得
p2 = $Sphere002.pos --Sphere02の位置を取得
p1 = normalize p1 --p1を単位ベクトルに
p2 = normalize p2 --p2を単位ベクトルに
d = dot p1 p2 --p1、p2の単位ベクトル同志の内積 = cosθ
deg = acos d --角度に変換する = θ

これをまとめると以下のようになる。
p1 = $Sphere001.pos
p2 = $Sphere002.pos
deg = acos (dot (normalize p1) (normalize p2))

外積(リファレンスでは乗積
cross <point3> <point3>
2つのベクトルで定義された平面に対して垂直な3番目のベクトルを取得。右回りのルール

ポリゴンで考えると以下の感じだと思う。原点0、点A、点Bで作れられる面に対して垂直な法線の向きを取得。長さは四角形の面積(三角形の面積*2)となるようだ。「ベクトル 外積」などで画像を検索すると沢山出てくると思う。

(長さは適当)

右回りのルールという事なのでAとBが逆だと多分こうなる。
(長さは適当)

詳しくは
「リファレンス>Maxscriptに関する質問と回答>実際の走査に関する質問>編集可能メッシュの走査>UVWモディファイ屋のギズモの位置を選択した面に合わせる方法はありますか」を参照。
-------------------------------------
ランダムなポイントを得る
random <point3> <point3>


この他にもノイズ関数など様々な関数などが準備されている

--------------------
リファレンスの例を取り上げてみる。サラッと紹介しているけどとっても大事な気がするんだ。
distanceは距離だから分かりやすいけど、lengthだよね。原点からの距離を測る関数なのになんで2点間の距離と答えが同じになるのか・・・。
length (b-a)はこう考える。
a-a は0になる。aの位置を原点に持ってきたとも言える。
b-aは同じ分だけbをオフセットした事になる。
なので、length (b-a)はaの分だけオフセットしたbの位置から原点[0,0,0]までの距離になる。3Dやってて良かった。空間をイメージ出来る!

(A,Bの位置は適当です)

a-bはその逆でbを原点に来るようにオフセットしたとも考えらる。
この原点[0,0,0]の位置にオフセットするという考え方結構大事な気がする。
2つのベクトルを引くと2点間のベクトルを取得出来る。上の例では長さを出しているから答えは同じになってるけど

B-A = AからBのベクトル
A-B = BからAのベクトル

V = B - A で得られるベクトルV

V = A - B で得られるベクトルV

原点基準だとベクトルの計算がとてもやりやすく・・・

最初に引いた分戻してあげる(足す)と・・・。これは移動だけど、回転する時とかも同じだと思う。Bを中心にAを回転したい。とか。

ある点Yからの2つのベクトルの角度が知りたかったら全てのポイントをオフセットして、ある点Yが[0,0,0]に来るようにしてから計算したら楽だもんね。多分楽だと思う。
--------------------
ノード共通のプロパティ <node>.dir
<node>.dirとすると、そのノードのローカルz方向の単位ベクトルを取得、設定する事が出来る。


シリンダーの.dirの数値をティーポットに渡すと向きが同じになる。

3D空間で考えるとv1は原点から長さ1のベクトル

長さを100倍にして・・・

シリンダーの所に持ってきて・・・

それをティーポットの位置に渡してやると、シリンダーの向いてる直線上にティーポットが移動する。

最初に取得したベクトルを反転すると、こうなる。

エディター用にまとめると

obj1 = $Cylinder001
obj2 = $Teapot001
mult = 100
v = obj1.dir -- 反転したいときは -obj.dir
obj2.dir = v
obj2.pos = v * mult + obj1.pos
--------------------------
シリンダーをティーポットの方に向かせる
ありがとう.dir

--------------------
2点の間にオブジェクトをおく

答え:位置コンストレイントを使う

また、やってしまった。中間点は簡単。2点の平均値でいいと思う。

では、AB間の直線上で動かしたいときはどうするか?

---------------------
a = $Sphere001
b = $Sphere002
c = $Sphere003

mult = 0.2 -- 20%の位置 2.0でも-2.0でもOK

v = b.pos - a.pos
v *= mult
c.pos = v + a.pos
------------------------------------------

------------------------------------------
-- %で指定したい場合
a = $Sphere001
b = $Sphere002
c = $Sphere003

mult = 75 --75% 150%でも-100%でもいける

v = b.pos - a.pos
v *= (mult / 100.0) --float値になるように100.0で割ってあげる。こういう時に値のタイプが重要に。もし、75/100とinteger同志の割り算したら答えが0になってしまう。
c.pos = v + a.pos

これをスクリプトコントローラーなどで使えば、俺俺位置コンストレイントの完成ですね。

さらに
c.dir = normalize v などすればCの向きを移動方向に変えれる気がする。
------------------------------------------
UVWモディファイヤのギズモの位置を選択した面に合わせる方法はありますか

これもやってみようと思う。

法線位置合わせを使う。出来た。

この流れもういいよね。簡単な方法から。3点の平均値をティーポットの位置に渡してやる

法線の向きの単位ベクトルをティーポットの.dirプロパティに渡す。終わり。

------------------------------------------
リファレンスのように向きを指定する場合。



vz = normalize (cross (p2-p1) (p3-p1))    -- p2-p1、p3-p1としてp1が[0,0,0]に行くような位置にオフセットしてから計算をしている。

vx = normalize (cross [0,0,1] vz) --[0,0,1]が黄色の矢印。赤の矢印を取得

vy = normalize (cross vz vx) --緑の矢印を取得


$teapot001.transform = matrix3 -vx vy vz posとして向き変えてみたり。

------------------------------------------
tips:普段の仕事では、一回の処理をして結果が得られるようなスクリプト(「ツール>評価」で実行されるようなもの。スクリプトを使った痕跡が残らないもの)以外は、出来るだけ標準機能で出来きないかをまず考えるようにしている。考えてスクリプトでないと厳しいと判断したときはスクリプトを使う。位置コンストレイントで出来ることをスクリプトコントローラーで組まれたシーンをもらっても・・・ね・・・。
------------------------------------------
tips:パーティクルを動かすのもベクトル。
pCont.particleSpeed = [0.0, 0.0, 1.0]
------------------------------------------
tips:ベクトル計算の分かりやすいサイト発見。

ゲームプログラミング技術集

------------------------------------------
tips:ノードプロパティTransformについて

transformプロパティはmatrix3値となっている。
matrix3は4つの値を持ち
matrix3 <X方向ベクトル> <Y方向のベクトル> <Z方向のベクトル> <オフセット(位置)>
となっているようなので・・・。

obj = $Sphere001
obj.transform = matrix3 [1,0,0] [0,1,0][0,0,1] [0,0,0]
とした場合、オブジェクトの変換はリセットされる。

obj.transform = matrix3 [2,0,0] [0,2,0][0,0,2] [0,0,0]
と各ベクトルの長さを2倍にした場合「変換リセット、スケールは2倍」となるようだ。

1 件のコメント:

  1. とても分かりやすいです!まとめありがとうございます!

    返信削除