🏫

CGと高校数学・大学教養数学の関連を考えてみた

7 min read

はじめに

学校で勉強する数学が Computer Graphics にどう関係してくるのか、具体例を挙げて考えてみました。関連を示すだけで、難しい数式の解説はしません(できません)。その代わり、用語には分かりやすい資料へのリンクを付けるので、興味がある部分は読んでみてください。

具体例は僕の趣味で選んでいるのでレンダリング寄りです。もちろん他にも色々な応用先があると思います。

三角関数

三角関数は CG のあらゆる分野で使われます。

ガラスのレンダリング

三角関数

光の屈折方向を計算する際に使うスネルの法則では三角関数が使われます。ガラスがレンダリングできるのはこれのおかげです。

float calcRefractSin(float inAngle, float inIOR, float outIOR)
{
  float inSin = sin(inAngle);
  float outSin = inSin * inIOR / outIOR;
  return outSin;
}

HDRI による Image-based lighting(IBL)

逆三角関数 極座標変換

HDRI を使って IBL をする際、見ている方向ベクトルから HDRI のピクセル座標を求めなければいけません。これは x, y, z の直交座標系から \theta, \phi の球面座標系への極座標変換そのものです。計算するには逆三角関数が必要です。

float theta = acos(y);
float phi = atan2(z, x);

コード内の求め方は、座標系が y-up か z-up か、右手座標系か左手座標系かなどによります。また、パラメータが 3 つから 2 つに減っているのは、元のベクトルの長さが 1 に正規化されているという条件を含んでいるためです。一般の極座標変換では半径パラメータ r も必要です。

ベクトル

CG で扱うデータの多くはベクトルです。頂点の位置も、ポリゴンの Normal も、レイの方向もベクトルです。色も RGB 色空間におけるベクトルと解釈できますし、画像のピクセル位置も uv 空間における整数のベクトルです。

シェーディング

内積

シェーディングの際、ある点が光源からどの程度照らされているかは、Normal と光源方向の内積で計算することができます。

Vec3 color = materialColor * max(0.0, dot(lightDir, normal));

Normal マッピング

外積 シュミットの直交化法

Normal マッピングを行う際には、ある点の Normal、Tangent、Bitangent が必要です。Normal と Tangent を頂点属性データから取得したとすると、Bitangent は外積を用いて計算できます。

Vec3 bitangent = cross(normal, tangent);

接空間に限らず、CG では座標系をいじることが多いのでシュミットの直交化法が必要になります。

行列

アフィン変換と逆変換

行列 逆行列 転置

オブジェクトの移動、拡縮、回転、反転などは行列として統一的に表現できます。連続した様々な変換を 1 つの行列としてまとめたり、大量のデータを一括で処理したりすることができる、超強力なツールです。

Mat4 translation(Vec3 trans)
{
  Mat4 mat { {1, 0, 0, trans.x},
             {0, 1, 0, trans.y},
             {0, 0, 1, trans.z},
             {0, 0, 0, 1      } };
  return mat;
}

Vec3 newPos = translation({1, 2, 3}) * pos;

逆行列を用いれば、変換した結果を元に戻すこともできます。ちなみに、特定の線形変換に限れば真面目に逆行列を求めるアルゴリズムを使わなくても、符号を反転したり、逆数にしたり、転置するだけでよかったりします。

レイと三角形の交差判定

行列式 クラメルの公式

レイと三角形の交差判定アルゴリズムに Tomas Moller の交差判定があります。その中で使われているクラメルの公式は、行列式を用いて連立方程式の解を求める手法です。

フーリエ変換

JPEG

離散コサイン変換

画像を保存するためのフォーマットの一つが JPEG です。JPEG では画像データを離散コサイン変換を使って大幅に圧縮します。

デノイズ

ローパスフィルタ

画像やモーションキャプチャーデータを周波数領域に変換し、ローパスフィルタを掛けることで、デノイズすることが可能です。

プローブ

球面調和関数

フーリエ変換からは少し離れますが、より発展的なイメージである球面調和関数はリアルタイムレンダリングでよく使われます。球面上のライトの情報などをプローブに保存する際にデータを大幅に圧縮できます。

微分

画像処理

画像中のエッジを抽出するには、微分を使うのが簡単です。画像はピクセルに離散化されているので、微分は単に隣のピクセルとの差分です。微分値が大きければエッジとして検出できます。

bool isEdge = abs(ddx()) > 0.01 || abs(ddy()) > 0.01;

機械学習

偏微分 勾配 勾配降下法

CG でも機械学習が普通に使われるようになりました。そこで使われる勾配降下法は、偏微分を使って勾配を求めています。

自動 UV 展開

最適化

機械学習に限らず、関数の最適化をしたい場合(最も良さげな何かを見つけたい場合)は勾配がゼロベクトルとなる場所を探すことがあります。

自動 UV 展開手法のひとつである Least Square Conformal Maps(LSCM) では、展開後の歪みを表す関数を最小化します。

物理シミュレーション

偏微分方程式

様々な物理現象、たとえば物体の変形、流体の動きなどは偏微分方程式を数値的に解くことでシミュレーションされます。具体的な手法は計算対象によって様々です。

積分

パストレーシング

モンテカルロ積分

ある点の色は、そこに入射する光を球面上で積分することで求められます(実際は BSDF や cos 項を考慮します)。パストレーシングでは、ランダムにレイをサンプリングし、その結果を平均することで積分値を推定します。この手法をモンテカルロ積分と呼びます。

Vec3 color{0.0};
for(int i = 0; i < numSamples; i++){
  Vec3 rayDir = sampleRandomDir();
  Vec3 radiance = getRadiance(rayDir);
  color += calcColor(radiance);
}
color /= numSamples;

微分も積分も、コンピュータでは基本的に「数値的に解く」ということが重要です。CG だけに留まらない話なので割愛しますが、精確な数値微分、数値積分は難しいトピックです。

複素数

3 次元回転

四元数(クォータニオン)

複素数は 2 次元の回転を表します。3 次元の回転を表すには、複素数をさらに一般化した四元数を使います。虚数単位は i だけではなく i, j, k の 3 つが導入されます。

Quat rotation = angleAxis(...);
Vec3 vector = Vec3(rotation * vector * invert(rotation));

集合と論理

ブーリアン

ブーリアンというモデリング機能は集合演算そのものです。物体 A と物体 B が重なっている部分は、 A かつ B である領域と言えます。

確率と統計

レイのサンプリング

逆関数法

ランダムなレイをサンプリングするとき、一様乱数ではなく、たとえば真上方向に飛ぶ可能性が比較的高い乱数が欲しい場合があります。その際には逆関数法を使うことで、欲しい確率分布に従った乱数が生成できます。

Subsurface Scattering(SSS)

ランダムウォーク

オフラインレンダラーは SSS をサポートしているものが一般的です。表面下でのレイの挙動はランダムウォークによってモデル化されます。

曲線

ベジェ曲線

モデリングでもアニメーションでも曲線は重要です。ベジェ曲線は CG でよく使われる曲線です。ちなみにベジェでは正円が書けないという問題が知られています。

おわり

ここまで読んでいただき、ありがとうございました。少しレンダリング寄りになってしまいましたが、とりあえず数学が CG を作ってくれていることは伝わったのではないかと思います。
僕自身も理解が浅いまま書いている部分が多々あるので、ミスがあればコメントをお願いいたします。

Discussion

ログインするとコメントできます