|
|||||||||||||||||||||
■Twitter: @FumioNonaka / Facebook Page: CreateJS
Creators MeetUp 珍味ベクトル外積3種盛り本稿は、2014年1月18日土曜日に催された第12回「Creators MeetUp」で務めた一席「新しいCreateJSのマウスイベント」のまとめとして書いた。サンプルコードはjsdo.itに掲げている。また、当日の映像はUSTREAM録画として公開された。
ベクトルの中でも「外積」は、考え方のわかりにくい計算といえる。だが、いきなり概念を捉えようとするのでなく、何に使えるのかを知れば、計算式そのものは簡単な四則演算だ。今回は2次元のベクトルに絞って、3つのインタラクティブなサンプルを例に、外積がどう使われているのかをご紹介する。 01 ベクトルの外積とは3次元空間におけるベクトルAとBの外積はA×Bで表され、つぎのようなベクトルとして定められる。 表001■3次元ベクトルの外積A×Bで求められるベクトル
図001■3次元ベクトルの外積 2次元のxy平面上のベクトルの外積は、つねにz軸と同じ角度の(平行な)ベクトル(xy成分値が0)になる。そこで、2次元ベクトルの外積は、ベクトルでなく、3次元ベクトルの場合のz成分(座標)値で定められた。2次元平面のベクトルA(ax, ay)とB(bx, by)の外積は、つぎの簡単な四則演算の式で表される。その値は、ベクトルAに対してBが右ネジの位置にあるとき正、左ネジの位置にあれば負となる(図002)。 【2次元ベクトルA(ax, ay)とB(bx, by)の外積】図002■2次元ベクトルの外積の正負は位置が右ネジか左ネジかで決まる 一般に、外積の計算に交換法則は成立たない。2次元ベクトルでは、計算の順序を逆にすると、外積の値の正負が変わる。
で、それが何の役に立つか? 3つのインタラクティブなサンプルをご紹介する。 02 面の向きが表か裏かを調べる3次元空間のオブジェクトを画面に(透視)投影するときは、描く順序を整えなければならない(図003)。一般には、配列の並べ替え(Array.sort()メソッド)により、重ね順を定める(gihyo.jp連載第19回「3次元空間で弾むオブジェクトとz座標による重ね順の並べ替え」の「オブジェクトの重なりをz座標値の順に並べ替える」がその例)。しかし、配列エレメントの並べ替えは負荷が高い。 図003■3次元のオブジェクトは描く順序を整えなければならない
しかし、閉じた凸の多面体であれば、裏返った面は描かなければ済む。面の裏表は、2次元ベクトルの外積から調べられる。
面の3頂点からふたつのベクトルを定め、予め表のときの位置関係を(たとえば右ネジに)決めておく(図004)。 図004■3頂点から定めたふたつのベクトルの位置関係を予め決める 右ネジを表としたなら、画面に投影したとき左ネジになった面は裏返ったことになる(AKB48に見る右ネジと左ネジ)。右ネジか左ネジかは、外積の正負で確かめられる(図005)。裏向きの面を描かなければ、表向きの面の重ね順は気にしなくてよい。 図005■外積の正負から面の向きを調べて裏返った面は描かない
つぎのコード001は、面を描く関数(drawFaces())が、取出した面の頂点座標(facePoints)から裏表を確かめて、表向きの面だけを描く。面の裏表を調べる関数(isFront())は、3頂点座標から定めたふたつのベクトル(point0とpoint1)の外積(crossProduct2D())が0以上かどうかを返した。 コード001■面の頂点座標から定めたベクトルの外積により表向きの面のみを描く
前掲コード001は、つぎのサンプル001から抜書きした。このサンプルはgihyo.jp連載「HTML5のCanvasでつくるダイナミックな表現―CreateJSを使う」の次回第20回「 立方体のワイヤーフレームを水平に回す」(1月最後の週に公開予定)から3回にわたって解説する予定だ。 [追記: 2014/02/07] 外積で面の裏表を調べる手法は、第21回「水平に回す立方体の面を塗る」で解説した。 サンプル001■立方体をマウスポインタの位置に応じてx軸およびy軸で回す03 ふたつの直線の交点を求めるつぎは、ふたつの直線の交点を求める。線分が直接交わらないときは、直線に延ばして交点を導く。 サンプル002■ふたつの直線の交点を求めるこうした場合、直線をつぎのような式で表し、連立2元1次方程式として解くことが多い(図006)。ただ、この式ではy軸に平行な直線(x = n)が示せないので、別に考えることになる。また、2直線が平行な場合も分けなければならない。 y = mx + n 図006■直線の1次方程式 ふたつの線分(ACとBD)の交点は、一方(BD)を底辺として他方の端(AとC)を結んだ三角形の面積比(△ABD/△CBD)で分けられた点(AP/CP)と捉えることができる。 図007■線分はふたつの三角形の面積の比率で分けられる ふたつのベクトルがつくる三角形の面積は外積の半分の大きさに等しい。すると、線分(AC)に対する交点(P)までの比率(AP / AC)はつぎの式で導ける。この考え方によるなら、2直線が平行の場合(BD×AB + BD×BC = 0)のみ分ければ足りる。 AP / AC = (BD×AB / 2) / {(BD×AB / 2) + (BD×BC / 2)} = BD×AB / (BD×AB + BD×BC) したがって、点AとCの座標をそれぞれ(ax, ay)および(cx, xy)とし、ベクトルの外積から求めた比率(AP / AC = BD×AB / (BD×AB + BD×BC))をkとすると、交点P(x, y)の座標はつぎのとおりだ。 x = ax + k×(cx - ax) 前掲サンプル002から抜書きした、上記の計算式により交点を求める関数(getIntersection())が、つぎのコード002だ。外積を返す関数(crossProduct2D())は、前掲コード001と変わらない。サンプル002について、詳しくは「平面上の2直線の交点を外積で求めるサンプルコード」をお読みいただきたい。 コード002■平面上の2直線の交点を外積で求める
04 回す力のかかりやすさを決める最後は、ドラッグする勢いでオブジェクトを回す。「intentionallies」のインタラクティブな表現だ。回りやすさやその速さには、てこの原理が働く(「つりあいとてこ」参照)。支点から遠い力点に、てこに対して垂直に力を加えると能率がよい(図008)。 図008■てこと力を加える向き オブジェクトを回す力のかかり方は、てこの長さと垂直方向にかけた力で決まる。この掛け算は、ふたつのベクトルを2辺とする平行四辺形の面積に等しい。つまり、てこ(r)とかけた力(F)の外積(r×F)に比例するということだ(図009)。物理では「力のモーメント」として説明される。 図009■回す力のかかり方はてこと力の外積に比例する 以下のサンプル003の中で、回す速さを決める関数(drag())は、つぎのコード003のように定めた。オブジェクト(card)の中心(重心)からドラッグするマウスポインタの座標(mouseXとmouseY)までをてこのベクトル(radius)とする。そして、マウスポインタの動き(force)との外積(moment)を求めて、回す角速度(angularVelocity)に加えた。なお、角速度には調整係数(ratio)が乗じてある。 コード003■重心からドラッグする座標とマウスポインタの動きの外積で回す角速度を定める
サンプル003のスクリプトは、『WebクリエイターのためのCreateJSスタイルブック』03-01「EaselJS でインスタンスをドラッグする勢いで加速して回す」で解説した。 サンプル003■インスタンスをドラッグする勢いで加速して回す作成者: 野中文雄 Copyright © 2001-2014 Fumio Nonaka. All rights reserved. |
|||||||||||||||||||||