グラフィックプログラミングの公式とか概念について -『JavaScript』

table of contents

    JavaScript でグラフィックプログラミングに頻出する必要な数学の概念をまとめます。

    ラジアン

    普段よく使う度数法でなく弧度法のラジアン(radian)を使います。直感的ではないけど、計算量を節約するメリットがあります。ラジアンは半径が1の円の円周の長さを基準とした角度の表現で、度数法の360度は 2π です。

    JavaScript で角度(degree)をラジアンに変換する関数は次のようにかけます。


    const deg2Rad = (deg) => deg * Math.PI / 180

    三平方の定理

    直角三角形において、「直角」をはさむ2つの辺の長さを a,b、斜辺の長さを c としたとき。


    a2+b2=c2

    加法定理


    sin(α+β) = sinαcosβ + cosαsinβ cos(α+β) = cosαcosβ − sinαsinβ tan(α+β) = (tanα + tanβ) / (1 - tanαtanβ)

    等符号を反転させても成り立ちます。

    余弦定理 Law of cosines

    figure Law of cosines


    a2 = b2 + c2 - 2bc * cosA b2 = a2 + c2 - 2ac * cosB c2 = b2 + a2 - 2ab * cosC

    『2辺の長さとその間の角度』から『残り1辺の長さ』を求めたり、『3辺の長さ』から『角度』を求めるのに利用する。

    ベクトル

    ベクトルは次のような性質を持ちます。

    • 「大きさ」と「向き」を持った量のことで、2次元や3次元を数式で表現できる
    • 矢印がベクトルの「向き」を表し、長さがベクトルの「大きさ」
    • 大きさ(長さ)と向き(方向)が同じであれば「位置は関係なく等しい」

    ベクトルには「大きさ」と「向き」という概念がありますが、普段扱うような大きさだけの数値で大小表現する概念のことを、ベクトルの世界(線型代数学)ではスカラーと呼びます。

    ベクトルの大きさ(長さ)

    ベクトル a→ = (ax,ay) のとき、ベクトルの長さは三平方の定理から求めることができます。


    |a→| = √(ax2+ay2)

    Math.hypot(ax, ay)

    (ax,ay) のように記述されているとき「座標」か「ベクトル」かを判断する必要があります。ベクトルの場合は暗黙的に原点を始点とした矢印をイメージするようにします。

    単位ベクトル

    単位ベクトルはそのベクトルをその大きさで割って、大きさを1にすることにより、向きだけを持つようにしたベクトルです。向きだけを比較したり計算したい場合に利用します。


    (ax / |a→|, ay / |a→|)

    ax / Math.hypot(ax, ay) ay / Math.hypot(ax, ay)

    また大きさが1のベクトルは半径1の円の外周に重なる性質を持ちます。逆説すると、半径1の円で sin cos を利用すると単位ベクトルを求めることができます。あるベクトルを単位化してから、アークサインMath.asin()やアークコサインMath.acos() に与えると、ベクトルが成す角度を得られます。(後述)

    ベクトルの和と差

    XやY の次元ごとに計算します。


    a→ + b→ = (ax + bx, ay + by) AB→ + BC→ = AC→

    a→ - b→ = (ax - by, ay - by) AC→ − AB→ = BC→

    ベクトルの積(スカラー倍)

    ベクトルを拡縮したい場合は、ベクトルにスカラー値を掛けます。JavaScript の Math.sin() や、Math.cos() は、常に半径1の円を基準にした値を返します。これをベクトルに見立てると、ある向きに移動するための、縦横の移動量の比を得ることができます。そしてこれにスカラーを掛け合わせることで、オブジェクトの速度をコントロールに利用できます。

    ベクトルの内積 dot

    ベクトルの内積はどの次元のベクトルでも同じように求めることができますが、異なる次元のベクトル同士では計算することはできません。ベクトル同士を掛け合わせて、そのすべてを合算します。計算結果はスカラー値になります。


    const dot = (a, b) => a.x * b.x + a.y * b.y

    a→ ・ b→ = ax * bx + ay * by // 1 a→ ・ b→ = |a→||b→|cosθ // 2 a→ ・ b→ = cosθ // 単位ベクトルの場合 (長さが1)

    2の式から内積を求め、余弦定理から導かれる 2 = 1 で cosθ を求めるような使い方をよくすることがあります。また、|a→||b→| が単位ベクトルであれば、単位ベクトル同士の内積は cosθ と等しいので角度がわかる。

    ベクトルそれぞれを単位化し、内積を求め、それに Math.acos() で、ベクトル同士がなす角度θを計算できます。


    const dot = (a, b) => a.x * b.x + a.y * b.y function normalize(x, y) { const vLen = Math.hypot(x, y) return { x: x / vLen, y: y / vLen } } // 内積 const dotVal = dot(normalize(ax, ay), normalize(bx, by)) // 角度 const rad = Math.acos(dotVal)

    ベクトルの外積 cross

    外積 a→ x b→ はベクトルの掛け算で、次の性質のベクトルが求められます。

    • 向きが a→ と b→ に直角で交わる(右ネジの法則)
    • 長さが a→ と b→ を2辺とする原点からの平行四辺形OACBの面積に等しい

    a→ x b→ = (ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx) a→ x b→ = |a→||b→|sinθ a→ x b→ = sinθ

    内積と同様の特徴として、単位化されたベクトルの外積は sinθ と等しくなります。

    外積の性質を利用するとできることとして、ある面と水平なベクトルを2つを定義すると、そこからまっすぐに上に伸びるベクトルを求められ、そのベクトルの向きに応じて明るさを計算したりします。それを法線ベクトル呼び、法線ベクトルは面に対して直角のベクトルなので、面の向きを表します。

    ベクトルの内積と外積の単位円での振舞

    • 単位ベクトルの内積は cosθ
    • 単位ベクトルの外積は sinθ
    • 内積 = 0 のとき、ベクトル同士は垂直
    • 内積 > 0 のとき、cosθ < 90
    • 内積 < 0のとき、cosθ > 90
    • 外積 = 0のとき、ベクトル同士は水平
    • 外積 > 0 のとき、ベクトルAの左側にベクトルBがある
    • 外積 > 0 のとき、ベクトルAの右側にベクトルBがある

    行列

    行列は、数字や式(成分)を横(行)と縦(列)に並べたもので、m行n列の行列と呼びます。行列はベクトルを変形したり、変換したりする際に使います。

    行列の積は次のように求めます。


    [ cosΘ -sinΘ ] x [ X ] [ sinΘ cosΘ ] x [ Y ] ▼ [ cosΘX + -sinΘY ] [ sinΘX + cosΘY ] ▼ [ X ] [ Y ]

    行列はベクトルの回転に利用できます。


    const rotate2D = (vec, rad) => { const sin = Math.sin(rad) const cos = Math.cos(rad) return [vec[0] * cos + vec[1] * sin, vec[0] * sin + vec[1] * cos] }

    おわります。

    グラフィックプログラミングの公式とか概念について -『JavaScript』のアイキャッチ画像

    share

    related