ベジェ境界の面光源を境界積分法で解く

導出の流れ、次数との関係、ベジェクリッピング、多角形近似・モンテカルロ法との比較、影の扱い

ベジェ曲線のまま解く 多角形(線分)で近似して解く モンテカルロ法(小円盤)で解く 光源 誤差・影

0対象と記号

光源の形が曲線で囲まれていても、点 P の照度は光源を細かく分割せずに、境界に沿った1次元の積分だけで求められます。ここでは次の設定で話を進めます。

「曲面光源」について

この解説が扱うのは、境界が曲線の平面光源です。光源面そのものが曲がっている場合は、条件つきで同じ式が使えます(第10節)。

1全体の流れ

照度の定義である面積分(2重積分)から出発し、5つのステップで「曲線ごとの1次元積分の和」にします。各ステップの中身は第2節で導きます。

  1. 光源全体にわたる面積分
    E=L∫Scos⁡θPcos⁡θQr2 dAE=L\int_S\frac{\cos\theta_P\cos\theta_Q}{r^2}\,dA

    光源上の点 Q すべてについて足し合わせる。2重積分で、分割数に誤差が依存する。

  2. 立体角に直す
    E=L∫Ωcos⁡θ dω=L n⋅∫Ωω dωE=L\int_\Omega\cos\theta\,d\omega=L\,\mathbf n\cdot\int_\Omega\boldsymbol\omega\,d\omega

    P から見た光源の広がり Ω\Omega(単位球面上の領域)だけで決まる。

  3. ストークスの定理で境界の線積分に
    ∫Ωω dω=12∮∂Ωω×dω\int_\Omega\boldsymbol\omega\,d\omega=\frac12\oint_{\partial\Omega}\boldsymbol\omega\times d\boldsymbol\omega

    領域の積分が、領域の縁に沿った積分になる。

  4. 縁を曲線 B(t)\mathbf B(t) で表す
    v(t)=B(t)−P,ω×dω=v×v′∣v∣2 dt\mathbf v(t)=\mathbf B(t)-\mathbf P,\qquad \boldsymbol\omega\times d\boldsymbol\omega=\frac{\mathbf v\times\mathbf v'}{|\mathbf v|^{2}}\,dt

    P から曲線上の点へのベクトル v\mathbf v だけで書ける。

  5. 結果:曲線ごとの1次元積分の和
    E=L2∮Cn⋅(v×v′)∣v∣2 dtE=\frac L2\oint_C\frac{\mathbf n\cdot\big(\mathbf v\times\mathbf v'\big)}{|\mathbf v|^{2}}\,dt

    境界の各曲線について tt で積分して足す。

ここから道が分かれます。境界が直線なら、最後の積分は閉じた式(Lambert の公式)になります(第3節)。境界がベジェ曲線なら被積分関数は有理関数になり、実用上は数値積分で解きます(第4節)。「曲線を線分で近似する」のは、前者の道に無理やり乗せる方法です(第6節)。

2導出を順に追う

2.1 面積分から立体角へ(ステップ 1→2)

光源上の微小面積 dAdA を P から見た立体角は dω=cos⁡θQ dA/r2d\omega=\cos\theta_Q\,dA/r^2 です。したがって cos⁡θPcos⁡θQ/r2 dA=cos⁡θP dω\cos\theta_P\cos\theta_Q/r^2\,dA=\cos\theta_P\,d\omega となります。光源側の cos⁡θQ\cos\theta_Q と 1/r21/r^2 は、面積を立体角に換算する係数そのものだったわけです。輝度 LL は方向によらず一様なので、LL を積分の外に出せます。

さらに cos⁡θP=n⋅ω\cos\theta_P=\mathbf n\cdot\boldsymbol\omega なので、照度は「光源の方向 ω\boldsymbol\omega を、光源が張る立体角の上で足し合わせたベクトルに、n\mathbf n を掛けたもの」になります。なお n⋅ω<0\mathbf n\cdot\boldsymbol\omega<0 の方向(F の水平線より下)は照度に寄与しないので、Ω\Omega は水平線より上の部分に限ります。これが第7節のクリッピングです。

平面 F 光源 S境界 C(ベジェ曲線) P n Ω P を中心とする単位球 上の像が Ω
P から見た光源 S の広がりが、単位球面上の領域 Ω です。Ω の縁は、光源の境界 C を P から球面へ射影した曲線です。照度は Ω だけで決まります。

2.2 領域の積分を縁の積分に(ステップ 2→3)

∫Ωω dω\displaystyle\int_\Omega\boldsymbol\omega\,d\omega を縁の積分にするのが、ストークスの定理です。次のように示せます。

定ベクトル a\mathbf a を1つ取り、A(x)=12 a×x\mathbf A(\mathbf x)=\tfrac12\,\mathbf a\times\mathbf x とおきます。∇×A=12(3a−a)=a\nabla\times\mathbf A=\tfrac12\big(3\mathbf a-\mathbf a\big)=\mathbf a です。単位球面(外向き法線 ω\boldsymbol\omega)でストークスの定理を使うと

∮∂ΩA⋅dω=∫Ω(∇×A)⋅ω dω  ⟹  12∮∂Ω(a×ω)⋅dω=a⋅∫Ωω dω\oint_{\partial\Omega}\mathbf A\cdot d\boldsymbol\omega=\int_\Omega(\nabla\times\mathbf A)\cdot\boldsymbol\omega\,d\omega \;\Longrightarrow\; \frac12\oint_{\partial\Omega}(\mathbf a\times\boldsymbol\omega)\cdot d\boldsymbol\omega=\mathbf a\cdot\int_\Omega\boldsymbol\omega\,d\omega

左辺はスカラー三重積の並べ替えで a⋅12∮ω×dω\mathbf a\cdot\tfrac12\oint\boldsymbol\omega\times d\boldsymbol\omega に等しく、a\mathbf a は任意なので、ステップ 3 の式が得られます。

検算:Ω\Omega が上半球なら、縁は赤道 ω=(cos⁡φ,sin⁡φ,0)\boldsymbol\omega=(\cos\varphi,\sin\varphi,0) で、ω×dω=(0,0,1) dφ\boldsymbol\omega\times d\boldsymbol\omega=(0,0,1)\,d\varphi。右辺は 12(0,0,2π)=(0,0,π)\tfrac12(0,0,2\pi)=(0,0,\pi)。左辺を直接計算した ∫cos⁡θ dω=π\int\cos\theta\,d\omega=\pi と一致します。

向き:縁は「球の外側から見て反時計回り」にたどります。これは、P から見ると時計回りです。逆向きにたどると全体の符号が反転します。実装では、光源の境界の向きを面積の符号で判定し、自動で補正します。

2.3 曲線で書く(ステップ 3→5)

縁を、パラメータ tt のベジェ曲線 B(t)\mathbf B(t) の像として表します。P から曲線上の点へのベクトルを v(t)=B(t)−P\mathbf v(t)=\mathbf B(t)-\mathbf P、r=∣v∣r=|\mathbf v|、ω=v/r\boldsymbol\omega=\mathbf v/r とすると

dω=v′r dt−v r′r2 dt⟹ω×dω=v×v′r2 dtd\boldsymbol\omega=\frac{\mathbf v'}{r}\,dt-\frac{\mathbf v\,r'}{r^{2}}\,dt \quad\Longrightarrow\quad \boldsymbol\omega\times d\boldsymbol\omega=\frac{\mathbf v\times\mathbf v'}{r^{2}}\,dt

(v×v=0\mathbf v\times\mathbf v=\mathbf 0 なので第2項が消えます。)これをステップ 3 に代入して n\mathbf n との内積を取ると、ステップ 5 の式になります。

幾何の意味:ω×dω=γ dφ\boldsymbol\omega\times d\boldsymbol\omega=\boldsymbol\gamma\,d\varphi と書けます。dφ=∣v×v′∣/∣v∣2 dtd\varphi=|\mathbf v\times\mathbf v'|/|\mathbf v|^2\,dt は、P から見た方向が dtdt の間に回る角、γ\boldsymbol\gamma はその回転面(P と曲線の接線を含む平面)の単位法線です。つまり

E=L2∮(n⋅γ) dφE=\frac L2\oint(\mathbf n\cdot\boldsymbol\gamma)\,d\varphi

は「P から見た境界の見込み角を、回転面の傾き n⋅γ\mathbf n\cdot\boldsymbol\gamma で重みづけして足したもの」です。回転面が水平(γ=±n\boldsymbol\gamma=\pm\mathbf n)なら見込み角がそのまま効き、回転面が n\mathbf n に平行なら寄与は 0 です。

3直線辺の場合:Lambert の公式(d=1d=1)

境界が線分 a→b\mathbf a\to\mathbf b(a,b\mathbf a,\mathbf b は P から両端へのベクトル)なら、v(t)=a+t(b−a)\mathbf v(t)=\mathbf a+t(\mathbf b-\mathbf a) で、次の2つが成り立ちます。

したがって ∫01∣a×b∣∣v∣2 dt\displaystyle\int_0^1\frac{|\mathbf a\times\mathbf b|}{|\mathbf v|^2}\,dt は辺全体を見込む角 β\beta(a\mathbf a と b\mathbf b のなす角)そのものです。辺の寄与は β (n⋅γ)\beta\,(\mathbf n\cdot\boldsymbol\gamma) となり、多角形の EE は

E=L2∑i=1Nβi (n⋅γi),βi=atan2⁡(∣ai×bi∣, ai⋅bi),γi=ai×bi∣ai×bi∣E=\frac L2\sum_{i=1}^{N}\beta_i\,(\mathbf n\cdot\boldsymbol\gamma_i),\qquad \beta_i=\operatorname{atan2}\big(|\mathbf a_i\times\mathbf b_i|,\ \mathbf a_i\cdot\mathbf b_i\big),\quad \boldsymbol\gamma_i=\frac{\mathbf a_i\times\mathbf b_i}{|\mathbf a_i\times\mathbf b_i|}

(Lambert の公式。頂点の並びの向きは第2.2節の向きに合わせます。)

ab 辺(線分) β P n γ P・a・b が作る平面(回転面)。γ はこの平面の法線
直線辺のあいだ、P から見た方向は同じ平面(P・a・b を含む面)の中だけで回ります。だから回転面の法線 γ が一定になり、見込み角 β をそのまま使えます。曲線では、この面が辺の上で少しずつ傾きます。

この式は平方根・逆三角関数だけで書けて、近似誤差がありません。多角形では、これが最後の答えです。

4ベジェ曲線の場合と次数

4.1 被積分関数の次数と、ベジェ形式での表し方

dd 次のベジェ曲線 B(t)=∑i=0dPi Bid(t)\mathbf B(t)=\sum_{i=0}^{d}\mathbf P_i\,B_i^d(t)(Bid(t)=(di)ti(1−t)d−iB_i^d(t)=\binom di t^{i}(1-t)^{d-i} は Bernstein 基底)では、v(t)=B(t)−P\mathbf v(t)=\mathbf B(t)-\mathbf P は、制御点 pi=Pi−P\mathbf p_i=\mathbf P_i-\mathbf P を持つ dd 次のベジェ曲線です。ステップ 5 の被積分関数を N(t)/D(t)N(t)/D(t) と書きます。

N=n⋅(v×v′),D=∣v∣2N=\mathbf n\cdot(\mathbf v\times\mathbf v'),\qquad D=|\mathbf v|^{2}

DD は 2d2d 次で、NN は素朴に数えると 2d−12d-1 次です。ところが、NN は実際には 2d−22d-2 次です。まず、冪の形で確かめます。

冪基底で数える

v(t)=∑k=0dcktk\mathbf v(t)=\sum_{k=0}^{d}\mathbf c_k t^{k}(ck\mathbf c_k は3次元ベクトル)と書くと、v′(t)=∑k=1dk cktk−1\mathbf v'(t)=\sum_{k=1}^{d}k\,\mathbf c_k t^{k-1} で、

v×v′=∑j=0d∑k=1dk (cj×ck) t j+k−1\mathbf v\times\mathbf v'=\sum_{j=0}^{d}\sum_{k=1}^{d}k\,(\mathbf c_j\times\mathbf c_k)\,t^{\,j+k-1}

です。最高次(j=k=dj=k=d)の項は cd×cd=0\mathbf c_d\times\mathbf c_d=\mathbf 0 で消えます。次の t2d−2t^{2d-2} の係数は (d−1) cd×cd−1+d cd−1×cd=−cd×cd−1(d-1)\,\mathbf c_d\times\mathbf c_{d-1}+d\,\mathbf c_{d-1}\times\mathbf c_d=-\mathbf c_d\times\mathbf c_{d-1} です。結局 NN は高々 2d−22d-2 次です。

ただし、この方法は、ベジェ形式の制御点を冪基底の係数に直し、多項式どうしを掛けています。次数が上がると桁落ちが大きくなります(下の「数値的に安定」)。

ベジェ形式のまま作る(Bernstein 基底の積の公式)

冪基底に直さなくても、NN と DD は Bernstein 係数のまま作れます。v′\mathbf v' は、制御点 qj=d (pj+1−pj)\mathbf q_j=d\,(\mathbf p_{j+1}-\mathbf p_j) の d−1d-1 次のベジェ曲線(ホドグラフ)です。Bernstein 基底の積は、次の公式で1つの基底にまとまります。

Bim(t) Bjn(t)=(mi)(nj)(m+ni+j) Bi+jm+n(t)B_i^m(t)\,B_j^n(t)=\frac{\binom mi\binom nj}{\binom{m+n}{i+j}}\,B_{i+j}^{m+n}(t)

これを、v=∑ipiBid\mathbf v=\sum_i\mathbf p_iB_i^d と v′=∑jqjBjd−1\mathbf v'=\sum_j\mathbf q_jB_j^{d-1} の積に使うと、

N(t)=∑k=02d−1nk Bk2d−1(t),nk=1(2d−1k)∑i+j=k(di)(d−1j) n⋅(pi×qj)N(t)=\sum_{k=0}^{2d-1}n_k\,B_k^{2d-1}(t),\qquad n_k=\frac{1}{\binom{2d-1}{k}}\sum_{i+j=k}\binom di\binom{d-1}{j}\ \mathbf n\cdot(\mathbf p_i\times\mathbf q_j)
D(t)=∑k=02dDk Bk2d(t),Dk=1(2dk)∑i+j=k(di)(dj) pi⋅pjD(t)=\sum_{k=0}^{2d}D_k\,B_k^{2d}(t),\qquad D_k=\frac{1}{\binom{2d}{k}}\sum_{i+j=k}\binom di\binom dj\ \mathbf p_i\cdot\mathbf p_j

となります。NN も DD も、制御点 (k/m, nk)(k/m,\ n_k) や (k/2d, Dk)(k/2d,\ D_k) を持つベジェ関数として、制御点の外積と内積だけで求まります。ツールが球の影で使う6次多項式 (a⋅v)2−cos⁡2α ∣v∣2(\mathbf a\cdot\mathbf v)^2-\cos^2\alpha\,|\mathbf v|^2 も、同じ公式で作っています。

「最高次が消える」は、Bernstein 形式では次数上げとの整合になります。この NN は 2d−12d-1 次の形ですが、実際は 2d−22d-2 次の多項式を次数上げしたものです。次数を1つ下げる漸化式

b0=n0,bi=(2d−1) ni−i bi−12d−1−i(i=1,…,2d−2)b_0=n_0,\qquad b_i=\frac{(2d-1)\,n_i-i\,b_{i-1}}{2d-1-i}\quad(i=1,\dots,2d-2)

を最後まで進めると、b2d−2=n2d−1b_{2d-2}=n_{2d-1} が(丸め誤差の範囲で)成り立ちます。これが、冪基底で「最高次の項が消える」ことに対応します。実験1で、係数を並べて確かめられます。

ベジェ形式で持つ利点は次のとおりです。

3次のベジェ曲線では、冪基底でも問題は出ません。ベジェ形式の利点が効くのは、高次のベジェ曲線(d≥5d\ge5 ほど)を扱うときと、凸包性で範囲を囲みたいときです。

実験 1:N と D を、冪基底とベジェ形式で作って比べる

ランダムな制御点の dd 次ベジェ曲線について、N(t)N(t) と D(t)D(t) の係数を、(左)冪基底に直して掛け算する方法と、(右)Bernstein 基底の積の公式の2通りで作ります。P は原点です。右の n2d−1n_{2d-1} は 0 になりません。2d−22d-2 次の多項式を次数上げした形だからで、その整合を下の行で確かめます。

4.2 次数ごとの整理

次数 ddv\mathbf vv′\mathbf v'分子 NN分母 DD∫N/D dt\int N/D\,dt を閉じた式で書くには
1(線分)1次0次0次(定数)2次逆三角関数1つ。Lambert の公式
22次1次2次4次4次方程式の根が必要(共役な根が2組)
33次2次4次6次6次方程式の根が必要(一般には代数的に解けない)
44次3次6次8次8次方程式の根が必要
dddd 次d−1d-1 次2d−22d-2 次2d2d 次2d2d 次方程式の根が必要

D(t)=∣v(t)∣2D(t)=|\mathbf v(t)|^2 は、P が曲線上にない限り実数の tt では正で、実根を持ちません。根は dd 組の複素共役な対になります。部分分数に展開すれば各対から arctan と log の項が出て、原理的には閉じた式で書けます。しかし、そのために毎回 2d2d 次方程式を数値的に解く必要があり、P や曲線が変わるたびにやり直しです。d≥2d\ge2 では、閉じた式を経由するより数値積分のほうが実用的です。線分(d=1d=1)が特別なのは、分子が定数になって根探しが不要になるからです。

4.3 被積分関数はどんな形か

被積分関数 f(t)=N/Df(t)=N/D は、tt あたりの見込み角の増え方(dφ/dtd\varphi/dt)に傾き n⋅γ\mathbf n\cdot\boldsymbol\gamma を掛けたものです。P が曲線から離れていれば緩やかですが、P が曲線に近づくと、近い点のまわりで幅がおよそ「距離 ÷ 速さ」の鋭いピークになります(ローレンツ型)。光源が測定点に近いほど、この尖りが問題になります。

実験 2:被積分関数と求積点

円盤(4本の3次ベジェ、半径 1)の境界を一周したときの ff です。横軸は曲線 0〜3 をつないだパラメータ。P は光源の真下から xx 方向にずらせます。x=1x=1 で境界の真下に来ます。○ はガウス求積の点です。

4.4 ガウス=ルジャンドル求積と適応分割

滑らかな被積分関数には、ガウス=ルジャンドル求積が向いています。nn 点の求積の誤差は ρ−2n\rho^{-2n} 程度(ρ>1\rho>1 は被積分関数の解析性で決まる)で、指数的に減ります。ρ\rho は、区間 [0,1][0,1] を焦点とするだ円のうち、最も近い複素特異点(D(t)=0D(t)=0 の複素根)に接するものの大きさで決まります。

そこで、区間を二分して ρ\rho を稼ぎます。二分するかどうかは、その区間の曲線が P にどれだけ近いかで決めます。区間の弧長が P までの距離を大きく超えると、被積分関数が区間の中で大きく変わるからです。

距離の下限を、制御点から保証する(近似ベジェクリッピング)

区間の曲線の制御点(P からの相対座標)から、第4.1節の公式で ∣v∣2|\mathbf v|^2 の Bernstein 係数 DkD_k(2d2d 次)を作ります。凸包性から、その区間で

min⁡t∣v(t)∣2 ≥ min⁡kDk\min_{t}|\mathbf v(t)|^{2}\ \ge\ \min_k D_k

が保証されます。最近点そのものを求める必要はありません。区間を de Casteljau 法で二分するたびに、下限は真の最小値に近づきます(区間幅の2乗で縮みます)。弧長の上界は、制御多角形の長さです。そこで、次の条件のとき二分します。

(制御多角形の長さ) > β min⁡kDk(β=2)(\text{制御多角形の長さ})\ >\ \beta\,\sqrt{\min_kD_k}\qquad(\beta=2)

端点と中点の3点で距離を見積もる旧方式は、3点の間を曲線が通り抜けると、距離を過大に見積もることがあります。この方式は、距離の下限が保証されます。ただし、保証されるのは距離の下限で、求積の誤差そのものではありません。

もう1つの案は、最近点 t∗t^* を求めることです。D′(t)=2 v⋅v′=0D'(t)=2\,\mathbf v\cdot\mathbf v'=0 の実根(2d−12d-1 次)なので、これもベジェクリッピングで求まります。t∗t^* で区間を分け、t∗t^* に向かって幅を半分ずつ縮めます。ここでも根を厳密に求める必要はなく、許容誤差 10−310^{-3} で打ち切っても精度は変わりませんでした。

実験 4:距離の下限を、細分して締める

円盤(4本の3次ベジェ)の曲線 0 について、∣v(t)∣2|\mathbf v(t)|^2(青)と、区間を 2L2^L 個に分けたときの制御点の最小値(帯)を描きます。帯は、その区間の ∣v∣2|\mathbf v|^2 の保証つきの下限です。赤い帯は、上の条件で「まだ二分が必要」と判定される区間、緑は「そのままガウス求積してよい」区間です。

2,400 点で比べた結果です(円盤の半径 0.7〜1.5、高さ 0.08〜3、傾き ±0.6、制御点を ±0.25 ずらした 40 通りの光源に、平面 F 上の点を60個ずつ。基準は、ガウス16点で、弧長が距離の 0.1 倍を超えたら二分した値)。

分割の判定点数最大の相対誤差RMS1点あたり
簡易(3点、弧長 > 0.6×距離)84.2×10-61.1×10-73.2 µs
保証つき下限(β=1\beta=1)84.2×10-61.2×10-76.2 µs
保証つき下限(β=2\beta=2)(既定)163.3×10-101.2×10-113.4 µs
最近点で分割(幅の半減 5 段、許容誤差 10-3)86.5×10-81.5×10-98.1 µs

次数 dd は、必要な点数をほとんど決めません。点数を決めるのは、形の滑らかさと P までの距離です。dd が上がると特異点の数(dd 組)と分子の次数が増えますが、3次で P が遠ければ 8〜10 点で機械精度に届きます(実験5)。次数が直接効くのは、次に述べる交点の計算です。

4.5 次数が効くもう1つの場所:交点の計算

境界を「水平面で切る」(第7節)、「影の輪郭と交わる」(第9節)には、曲線と平面の交点が要ります。曲線上の点が平面 m⋅v=0\mathbf m\cdot\mathbf v=0(P を通る平面)にあるという条件は、m⋅v(t)=0\mathbf m\cdot\mathbf v(t)=0 なので tt の dd 次方程式です。線分(d=1d=1)なら1次方程式で済みます。3次以上の実根は、ベジェクリッピング法で求められます(第5節)。

5ベジェクリッピング法が使える箇所

第4.5節の「dd 次方程式の実根を求める」場面は、ベジェクリッピング法(Sederberg と Nishita、1990)でまとめて解けます。もとは曲線どうしの交点を求める方法ですが、多項式の実根探しにも使えます。ツールの根探しは、この方法に入れ替えてあります。

5.1 仕組み

多項式を Bernstein 形式 p(t)=∑i=0nbi Bin(t)p(t)=\sum_{i=0}^{n}b_i\,B_i^n(t) で持ちます。点 (i/n, bi)(i/n,\ b_i) を制御点とするベジェ曲線が、ちょうど y=p(t)y=p(t) のグラフです。ベジェ曲線は制御多角形の凸包の中に入る(凸包性)ので、p(t)=0p(t)=0 の根は、凸包が tt 軸と交わる範囲の中にしかありません。

  1. 係数 bib_i がすべて同符号なら、根はありません。ここで打ち切ります。
  2. そうでなければ、区間を、凸包が tt 軸と交わる範囲 [tlo,thi][t_{lo},t_{hi}] に縮めます。縮めた区間の係数は de Casteljau 法で作ります。
  3. 区間があまり縮まなかったとき(元の7割以上が残るとき)は、二分してそれぞれを続けます(複数の根があるとき)。
  4. 区間が十分に小さくなったら、その中点を根とします。

単根の近くでは収束が速く(2次収束)、ツールの試験では平均 5〜8 回の反復で終わりました。二分法は1回に1ビットずつなので、同じ精度に40回ほどかかります。実験3で、1回ごとの様子を見られます。

厳密な根が要らないとき(近似ベジェクリッピング)

ベジェクリッピングは、根や最小値を厳密に求めなくても役に立ちます。

実験 3:ベジェクリッピングを1回ずつ進める

グラフは、いま調べている区間の多項式を、区間を [0,1] に引き伸ばして描いたものです。折れ線が制御多角形、薄い塗りが凸包、緑の帯が「凸包が tt 軸と交わる範囲」です。「1回進める」を押すと、区間がその帯に縮みます。

5.2 使えるところ、使えないところ

場所解く問題使えるか効果・注意ツール
水平面クリッピング(第7節)h(t)=n⋅B(t)−d=0h(t)=\mathbf n\cdot\mathbf B(t)-d=0(dd 次)使えるBernstein 係数は制御点の n⋅Pi−d\mathbf n\cdot\mathbf P_i-d そのもの。冪基底への変換が要らない。実装済み
影の交点(第9節)m⋅(B(t)−P)=0\mathbf m\cdot(\mathbf B(t)-\mathbf P)=0使える係数がすべて同符号なら、根を探さずに打ち切れる。P ごとに多数回呼ぶので効く。実装済み
球の輪郭との交点(第9節)(a⋅v)2−cos⁡2α ∣v∣2=0(\mathbf a\cdot\mathbf v)^2-\cos^2\alpha\,|\mathbf v|^2=0(2d2d 次。3次なら6次)使える係数は制御点の積(Bernstein 形式の積の公式)で作れる。次数が高くても同じ手続き。実装済み
光源境界の自己交差の検出曲線どうしの交点(平面)と、1本の曲線のループ使えるファットラインで互いを縮める(5.4節)。1本の曲線は8つに分け、隣り合わない組を調べる。実装済み
適応求積の分割判定(第4.4節)P から曲線までの距離の下限使える(近似)∣v∣2|\mathbf v|^2 の Bernstein 係数の最小値が、真の最小値以下という保証つきの下限。区間を細分して締める。実装済み(既定)
最近点 t∗t^*(第4.4節)v⋅v′=0\mathbf v\cdot\mathbf v'=0(2d−12d-1 次)使える(近似)許容誤差 10-3 で打ち切ってよい。分割判定としては、保証つき下限に及ばない。実装済み(選択式)
光源領域の内外判定(影の判定)点 (a,b)(a,b) が閉曲線の内側か使える右向きの半直線と各曲線の交点数。交点は y(t)=by(t)=b の実根で、係数が同符号なら即除外できる。折れ線への近似が要らない。実装済み
面積分の検算の標本各走査線と曲線の交点使える同様に y(t)=by(t)=b の実根で、走査線の区間を厳密に求める。実装済み
モンテカルロの標本の棄却判定候補の点が領域の内側か使える光源領域の内外判定と同じ。実装済み
ベジェ曲面の遮蔽物と光線の交点光線と曲面パッチの交点使える本来の用途(Nishita・Sederberg・Kakimoto、1990)。モンテカルロ法や検算で、遮蔽物が曲面のときに効く(第9.5節)。未実装
第4.2節の D(t)=0D(t)=0 の根複素根(部分分数のため)使えないベジェクリッピングは実根だけを求める。DD は実根を持たない。—
積分そのもの∫N/D dt\int N/D\,dt使えない根や交点を求める方法で、積分はしない。—
曲面の輪郭(シルエット)2変数の陰関数曲線 f(u,v)=0f(u,v)=0そのままは使えない曲線の交点や1変数の根とは別の問題(第9.4節)。—

5.3 入れ替えて分かったこと

5.4 曲線どうしの交点:ファットライン

曲線 PP と QQ の交点は、次のように求めます。PP の両端を結ぶ直線を中心に、PP の制御点をすべて含む帯(ファットライン)を作ります。QQ の各制御点までの距離を Bernstein 係数とみなし、その凸包がこの帯と交わる範囲だけに QQ の区間を縮めます。次に役割を入れ替えて PP を縮め、これを繰り返します。縮まらなければ、長いほうを二分します。

6多角形近似・モンテカルロ法との違い

6.1 3つの方針

折れ線は、1次のベジェ曲線の列です。第4.2節の表のとおり、閉じた式が得られるのは d=1d=1 だけです。そこで、光源の形と積分のどちらを近似するか、あるいは面積分を確率的に解くかで、方針が3つに分かれます。

境界積分(ベジェのまま)多角形近似モンテカルロ(小円盤)
方針形は厳密のまま、境界の積分を数値で解く形を折れ線で近似し、積分は厳密に解く光源を N 個の小円盤に置き換え、面積分を確率的に解く
次元境界の1次元積分境界の閉じた式光源全体(2次元)の抜き取り
誤差の主因求積。点数 nn に対して指数的に減る形状の近似。1/M21/M^2標本のばらつき。一様乱数なら 1/N1/\sqrt N、準乱数ならほぼ 1/N1/N
誤差の性質偏りなし。P が曲線に近いと悪化凸な光源では常に暗めばらつく(ざらつき)。小円盤の大きさによる小さな偏りもある
1回あたりの計算やや重いが、少ない点数で足りる軽い1個は軽いが、N 個要る
影輪郭との交点を解く(箱・球で実装)同じ枠組みで、交点が1次方程式になる光線が遮蔽物に当たるかを調べるだけ。形を選ばない
実装求積・根探し・区間管理が要る簡単いちばん簡単

6.2 モンテカルロ法の中身

光源領域 SS(面積 AA)に NN 個の点を、SS の中で一様になるように置きます。それぞれを、面積 A/NA/N、半径 a=A/(πN)a=\sqrt{A/(\pi N)} の小さな円盤光源とみなします。円盤光源の照度は、円盤の中心軸上の点なら解析的に求まります。

Ei=L πa2a2+d2cos⁡θPE_i=L\,\frac{\pi a^{2}}{a^{2}+d^{2}}\cos\theta_P

(dd は円盤中心までの距離。円盤の張る円錐が水平線の上にあるとき。)P が軸から外れる分は、円盤を斜めから見る分の cos⁡θQ\cos\theta_Q を掛けて補います。全体では

G≈AN∑i=1Ncos⁡θP,i cos⁡θQ,idi2+a2G\approx\frac{A}{N}\sum_{i=1}^{N}\frac{\cos\theta_{P,i}\,\cos\theta_{Q,i}}{d_i^{2}+a^{2}}

です。分母の d2+a2d^2+a^2 が要点です。小円盤を点光源とみなすと分母は d2d^2 で、小円盤の中心が P に近いと1個の値が大きくなり、ばらつきが増えます。円盤の大きさ aa を入れると、この発散が抑えられます。代わりに、a2/d2a^2/d^2 程度の小さな偏りが残りますが、NN が増えると円盤が小さくなって消えます。軸から外れる分の補正も、円盤が小さいほど正確です。

6.3 誤差と手間の比べ方

同じ円盤を、(青)ベジェのまま nn 点のガウス求積(分割なし)、(緑)1曲線を MM 本の線分で近似した多角形、(紫)NN 個の小円盤のモンテカルロ法で解いた誤差を並べます。モンテカルロは、標本を変えた複数回の RMS 誤差です。

横軸は、「評価回数」と「実測時間」を切り替えられます。評価回数は、境界積分が 4n4n(4本の曲線 × nn 点)、多角形が 4M4M(辺の数)、モンテカルロが NN です。1回の評価の重さは方式で違うので、実測時間で見ると並びが変わります。

実験 5:3つの方式の誤差と手間

基準値は、ガウス求積16点で 256 区間に分けた高精度の値です。縦軸は基準値に対する相対誤差(対数)で、下限は 10-16 で頭打ちにしています。

横軸:
ベジェのまま(ガウス n 点)多角形近似(1曲線 M 本)モンテカルロ(N 個、複数回の RMS)

実測時間は、多角形の頂点やモンテカルロの標本をあらかじめ作っておき、P の照度を求める部分だけを測っています。ブラウザや他の処理の影響で、数十% ほどばらつきます。

光源が遠い(高さ 3、x=0x=0)と、ベジェのままなら 10 点ほどで機械精度(10-15 程度)に届きます。多角形は 64 分割でも 10-4 前後、モンテカルロは同じ手間(評価 256 回)で、一様乱数なら 3×10-3 前後、Halton なら 1×10-3 前後です。光源を P に近づける(高さ 0.1、x=1x=1)と、どの方式も収束が遅くなります。モンテカルロは、小円盤が P に近い分だけばらつきが大きく、一様乱数では 256 個で 0.4 ほど、4096 個でも 0.14 ほどの相対誤差になります。

6.4 収束が速い・遅い理由

6.5 使い分け

目的向く方式理由
高い精度が要る、評価回数を抑えたい境界積分数点で機械精度に届く。多数の点を計算するときも有利。
数%の誤差でよい、リアルタイム描画多角形近似1点あたりの計算がいちばん軽く、既存の多角形光源のコードを使える。
遮蔽物の形が複雑・曲面・複数モンテカルロ光線が当たるかだけを調べればよい。形を選ばない。
影のない範囲を高精度に、影は大まかに併用光源全体は境界積分で解き、遮蔽された分だけをモンテカルロで見積もる(第9.6節)。
光源が P に近いどれも注意多角形は MM が急増、ベジェは適応分割、モンテカルロはばらつきが増える。

ツールで測った一例です(円盤、高さ 2.2、遮蔽物なし、64×64 格子、ブラウザでの実測。環境や乱数で大きく変わります)。

方式平面全体の RMS 差(最大照度比)1点あたりの時間
境界積分(既定の適応分割)基準約 7〜10 µs
多角形 16 辺1.05 %約 1.5〜2 µs
モンテカルロ 256 個(一様乱数)0.4〜2 %(乱数の引き方で変わる)約 2.5〜5 µs
モンテカルロ 4096 個(Halton)0.03〜0.04 %約 25〜30 µs

球の影を入れると差が広がります。P の1点で、誤差 1% に届くまでの時間は、境界積分が 13 µs、モンテカルロが約 7 ms でした(ツールの「精度と時間のグラフ」の結果)。影の縁では、円盤ごとの二値判定がばらつきの原因になります。

7実際の計算手順

ツールが、P ごとに行っている処理の順番です。各手順で「次数」がどこに効くかも併記します。

  1. 光源を組み立てる:光源平面の局所座標 (a,b)(a,b) で12個の制御点を持ち、世界座標に変換して4本の3次ベジェにします。
  2. 発光側の判定:P が光源平面の表側にあるか(nL⋅(P−O)>0\mathbf n_L\cdot(\mathbf P-\mathbf O)>0)。裏側なら E=0E=0。
  3. 向きの補正:局所座標での面積(シューレース公式)の符号 σ\sigma で、境界の向きを判定します。
  4. 水平面クリッピング:F より下の部分は cos⁡θP<0\cos\theta_P<0 で、そのまま入れると誤った(負の)寄与が混ざります。h(t)=n⋅(B(t)−P)h(t)=\mathbf n\cdot(\mathbf B(t)-\mathbf P) は dd 次多項式なので、その実根(ベジェクリッピングで求めます。第5節)で曲線を切り、上側の区間だけ残します。切断で生じた2点は、F 上の直線(弦)でつなぎ、その寄与は角 atan2⁡(n⋅(a×b), a⋅b)\operatorname{atan2}(\mathbf n\cdot(\mathbf a\times\mathbf b),\ \mathbf a\cdot\mathbf b) です。P が F 上にあるとき、P の水平面は F そのものなので、この切断はどの P でも同じで、1回だけ計算すれば済みます。
  5. 曲線ごとの積分:残った各区間で、適応ガウス求積により ∫n⋅(v×v′)/∣v∣2 dt\int n\cdot(v\times v')/|v|^2\,dt を求めます。区間を分けるかは、制御点から求めた距離の保証つき下限で決めます(第4.4節)。
  6. 合計:G=12 κσ∑(曲線の積分+弦の角)G=\tfrac12\,\kappa\sigma\sum(\text{曲線の積分}+\text{弦の角})。κσ=±1\kappa\sigma=\pm1 は向きの符号です。E=L GE=L\,G。
交点:h(t) = 0 の根 F との交線 弦(直線辺)を追加 残す側(n·v > 0) 捨てる側(n·v < 0)
光源平面を、P の水平面(平面 F)で切った様子。曲線は交点で切り、上側(青)だけを残します。切り口には、直線辺(緑)を1本加えます。上側の領域の境界は、青い曲線と緑の弦を合わせた閉じた輪になります。

計算の中心にあたる部分を抜き出すと、次の形です。n=(0,1,0)\mathbf n=(0,1,0) なので、外積の内積は y 成分だけになります。

// 曲線区間 [ta, tb] の  ∫ n·(v×v') / |v|²  dt   (v = B(t) − P)
function gauss8(c, ta, tb, P) {
  const h = (tb - ta) / 2, m = (ta + tb) / 2;
  let sum = 0;
  for (let k = 0; k < 8; k++) {
    const t = m + h * GX[k];                    // ガウス点
    const v  = B(c, t) - P;                     // P から曲線上の点へ
    const dv = dB(c, t);                        // 接線ベクトル
    const num = v.z * dv.x - v.x * dv.z;        // n·(v×v')   (n = (0,1,0))
    sum += GW[k] * num / dot(v, v);
  }
  return sum * h;
}

// P ひとつ分の境界積分
let s = 0;
for (const piece of clip.pieces) s += integrate(curve[piece.ci], piece.ta, piece.tb, P); // F より上の曲線
for (const chord of clip.chords) s += atan2(n·(a×b), a·b);                              // F 上の弦
const G = 0.5 * KAPPA * sigma * s;              // E = L * G

8数値で追う

円盤の光源で、第7節の手順を数値で追います。P の真下から光源の縁の真下まで動かして、各曲線の積分値がどう変わるか、多角形との差がどうなるかを見てください。

実験 6:曲線ごとの寄与と合計

光源は半径 1 の円盤(4本の3次ベジェ)、輝度 1000 cd/m²、P は平面 F 上にあり光源全体が F より上にあります。各曲線の Ii=∫n⋅(v×v′)/∣v∣2 dtI_i=\int n\cdot(v\times v')/|v|^2\,dt を高精度に求め、G=12∑IiG=\tfrac12\sum I_i を作ります。

9影の計算

光源と P のあいだに遮蔽物があるとき、境界積分のまま影(半影を含む)を扱えます。ツールが対応しているのは、直方体と球です。ここでは、考え方と、それ以外の形でどこが難しくなるかを整理します。

9.1 考え方

  1. P から見た遮蔽物の輪郭 Σ\Sigma は、単位球面上の領域です。P から Σ\Sigma の内側の方向に進むと、遮蔽物に当たります。
  2. 光が届く分は G(S)−G(S∩Σ)G(S)-G(S\cap\Sigma) です。
  3. S∩ΣS\cap\Sigma の境界は2種類です。(a) 光源の境界曲線のうち Σ\Sigma の内側の部分。(b) Σ\Sigma の輪郭のうち光源 SS の内側の部分。
光源 S の境界 C 遮蔽物の輪郭 Σ S∩Σ (a) C のうち Σ の内側(曲線のまま積分) (b) Σ の輪郭のうち S の内側
P から見た光源 S(円)と、遮蔽物の輪郭 Σ(四角形)。隠される部分は S∩Σ で、その境界は青い曲線(a)と赤い輪郭(b)からできています。

9.2 直方体(凸多面体)

9.3 球

球は、P から見ると円錐です。中心方向を a\mathbf a、半頂角を α\alpha(sin⁡α=r/D\sin\alpha=r/D、DD は P から球の中心までの距離)とすると、Σ\Sigma は a\mathbf a を中心とする半頂角 α\alpha の円(小円)の内側です。

光線で遮蔽を調べる面積分と比べ、約 4,000 点(うち影の影響あり約 1,000 点)で、差は GG で 1〜3×10-4 でした(1回だけ 6×10-3 の外れ値が出ましたが、4.8 万点の再試行では再現せず、参照値側の誤差と考えています)。

9.4 それ以外の形は難しいのか

難しいのは、形が変わるからではなく、次の3つがそろうかどうかです。(1) 輪郭 Σ\Sigma を求めて、向きの揃った閉じた輪にできる。(2) 光源境界との交点が多項式の根になる。(3) Σ\Sigma の弧の積分が閉じた式、または扱いやすい数値積分になる。直方体を含む凸多面体と球は、3つともそろいます。

凸:輪郭は1本の輪 直方体・角柱・球など 非凸:投影が重なる 和集合を作る必要がある ドーナツ:外の輪と穴 穴は向きが逆の輪
遮蔽物の輪郭 Σ の型。凸なら1本の輪ですが、非凸の物体は投影が重なって、輪の数や向きが変わります。ドーナツでは、外側の輪のほかに穴の輪ができます。
遮蔽物P から見た輪郭 Σ境界積分での扱い難しさ
凸多面体(直方体、角柱、角錐)凸な球面多角形。辺は大円弧面の表裏から輪郭をたどる。ツールの箱と同じ易しい(箱は実装済み)
球小円交点は 2d2d 次の根。弧の積分は閉じた式易しい(実装済み)
楕円体、円柱、円錐台2次曲線、または直線と楕円弧の組み合わせ交点は多項式(2d2d 次)の根で求まる。弧の積分は閉じた式にならず、数値積分が要る中程度
複数の遮蔽物各輪郭の和集合輪郭が重ならなければ足し算。重なるなら和集合が要る中〜難
光源の平面に届く遮蔽物光源側で打ち切る面が加わる面を光源の平面で切る処理が要る(ツールは未対応で、影を計算しない)中程度
非凸の多面体面の投影が重なり、輪が複数・穴を持つ投影多角形の和集合(ブーリアン演算)が要る。その後は箱と同じ難しい
ドーナツ、回転体、ベジェ曲面多項式では書けない曲線。穴や自己隠蔽がある輪郭を求める処理(2変数の零点、隠れ線処理)が要る難しい

難しい理由は、原理的に不可能だからではなく、(1) の輪郭を求める処理の実装量にあります。非凸の物体は、輪郭の一部が別の部分に隠れます。ドーナツは、外側の輪のほかに、向きの逆の輪(穴)ができます。ベジェ曲面や回転体の輪郭は、N(u,v)⋅(S(u,v)−P)=0\mathbf N(u,v)\cdot(\mathbf S(u,v)-\mathbf P)=0 を満たす点の集まりです。これは、1変数の多項式の根ではなく、2変数の陰関数曲線で、曲線としてたどり、隠れる部分を除く必要があります。

9.5 曲面の遮蔽物とベジェクリッピング

遮蔽物がベジェ曲面(球、ドーナツ、回転体をパッチで表したもの)のとき、ベジェクリッピングが効くのは、光線と曲面の交点です(Nishita・Sederberg・Kakimoto、1990)。光線が曲面パッチに当たるかを、パッチの制御点の凸包で絞り込んで判定します。

ツールは、ドーナツと回転体には対応していません。境界積分で解くには、上の「難しい」行の処理を作る必要があります。

9.6 現実的な選択肢

  1. 凸な物体は、凸多面体で近似する。球や楕円体を面で刻むと、箱と同じ処理に載せられます。多角形近似と同様に、面の数を増やすほど誤差が縮まります。
  2. 輪郭を折れ線にして、非凸の物体の和集合を作る。輪や穴を持つ多角形に対する処理が要ります。実装量は大きい代わりに、ノイズのない結果が得られます。
  3. 併用する。影のない場合の照度を境界積分で正確に求め、遮蔽される分だけをモンテカルロで見積もります。G(S)G(S) から、遮蔽された分のモンテカルロ推定を引く形で、ばらつきの大きさは、遮蔽された割合が小さいほど小さくなります。影が小さい範囲では、モンテカルロだけより精度が上がります。
  4. すべてモンテカルロにする。形を選ばず、複数の遮蔽物も扱えます。ばらつきは、標本数で抑えます。

2と3は、ツールには入れていません。

10曲面光源について

境界積分が使うのは、光源の面ではなく、P から見た光源の輪郭だけです(ステップ 2 の Ω\Omega)。式の導出は、光源が平面であることを使っていません(v(t)=B(t)−P\mathbf v(t)=\mathbf B(t)-\mathbf P は3次元の曲線なら何でもよい)。したがって、光源面が曲がっていても、次の条件がそろえば、境界曲線だけで照度が決まります。

このとき、曲面の中の形は照度に影響せず、輪郭 CC の3次元形状だけが効きます。ただし、ツールの実装は平面光源を前提にしています(発光側の判定、水平面クリッピング、影の内外判定に「境界が同一平面上にある」ことを使っています)。曲面光源を扱うには、これらを3次元の輪郭に対して作り直す必要があります。

11つまずきやすい点

症状原因と対処
結果の符号が逆になる境界をたどる向きが逆。P から見て時計回り(球の外から見て反時計回り)に揃える。
光源が F をまたぐと値がおかしい水平面クリッピングの漏れ。F より下の部分と、切り口の弦を忘れない。
P が光源の裏側にあるのに値が出る発光側の判定漏れ。裏側は E=0E=0。
光源が近いと精度が急に悪くなる被積分関数のピーク。区間を二分する(適応求積)。多角形なら分割数を増やす。
境界が自己交差していると結果が無意味領域が定義できない。制御点を動かして交差をなくす。
根探しで、区間の端の根が消える丸め誤差で係数の符号が揃う。縮めた区間に、ごくわずかな余白を足す(第5.3節)。
隣り合う曲線が、共有するアンカーで「交差」と判定される接する点を交点と誤検出している。アンカーの近傍は除外する(第5.4節)。
モンテカルロの結果がざらつく、影の縁がまだらになる点数が足りない。一様乱数なら4倍で誤差が半分。準乱数(Halton)にする、点数を増やす、影の縁は境界積分を使う。
遮蔽物が光源の平面に届くと、影が出ないツールは、光源の平面に届く遮蔽物の影を計算しない。物を小さくするか、光源を上げる。
光源の境界が P のすぐそばを通る被積分関数が鋭いピークを持ち、P が曲線上だと発散する。適応分割を使い、曲線上の点は避ける。
まとめ

境界積分法は、面積分を「境界の見込み角の重みつき和」に直す方法です。境界が線分なら閉じた式(Lambert)、dd 次のベジェ曲線なら N/DN/D(2d−22d-2 次 / 2d2d 次)の有理関数の積分で、数値求積で解きます。

NN と DD は、Bernstein 基底の積の公式で、ベジェ形式のまま(冪基底に直さずに)作れます。数値的に安定で、凸包性から範囲も囲めます。

多角形近似は形を近似して 1/M21/M^2 の誤差を出し、ベジェのままは積分を数値で解いて指数的に減る誤差を出します。モンテカルロ法は、小円盤の解析式を足す方法で、誤差は 1/N1/\sqrt N(準乱数ならほぼ 1/N1/N)ですが、形を選ばず影を扱えます。

曲線の実根や交点は、ベジェクリッピングで求めます。使えるのは、水平面クリッピング、影の交点、球の輪郭(6次)、自己交差の検出、光源領域の内外判定です。厳密な根が要らないときは、細分した制御点の最小値で距離の下限を保証する近似の使い方ができ、求積の分割判定に使っています。複素根と積分そのものには使えません。影の計算は、凸多面体と球なら境界積分で解けます。非凸の物体やドーナツは、輪郭を求める処理が難しく、モンテカルロ法か併用が現実的です。