前回の日記でPythonでベジエ曲線を描いたが、今回はベジエ曲面(Bezier patches)を描く。
ベジエ曲面は、以下の式で表される。
は、前回の日記で説明したバーンスタイン(Bernstein)多項式である。
は、平面上に格子状に配置した制御点で、m, nは、それぞれu軸、v軸方向の制御点の次数である。
曲面の四隅は、制御点の四隅を通る。
Pythonのコード例
ベジエ曲面をPythonで記述すると以下のようになる。
import scipy.misc as scm import numpy as np import matplotlib.pyplot as plt def bernstein(n, i, t): return scm.comb(n, i) * t**i * (1 - t)**(n-i) def bezier_patches(m, n, u, v, q): p = np.zeros(2) for i in range(m + 1): for j in range(n + 1): p += bernstein(m, i, u) * bernstein(n, j, v) * q[i, j] return p q = np.array([ [[0, 0], [0, 1], [0, 3], [0, 5]], [[1, 1], [1, 2], [1, 4], [1, 6]], [[2, 1], [2, 3], [2, 5], [2, 6]], [[4, 1], [4, 3], [4, 4], [4, 5]], [[5, 0], [6, 1], [6, 3], [5, 5]], ]) list1 = [] for u in np.linspace(0, 1, 10): list2 = [] for v in np.linspace(0, 1, 10): list2.append(bezier_patches(4, 3, u, v, q)) list1.append(list2) P = np.array(list1) for i in range(10): plt.plot(P[i].T[0], P[i].T[1], color='g') P_T = np.array([P[j, i] for j in range(10)]) plt.plot(P_T.T[0], P_T.T[1], color='g') for i in range(5): plt.plot(q[i].T[0], q[i].T[1], '--o', color='b') for j in range(4): q_T = np.array([q[i, j] for i in range(5)]) plt.plot(q_T.T[0], q_T.T[1], '--o', color='b') plt.show()
次数m=4, n=3の制御点を配置して、ベジエ曲面を横軸、縦軸方向にそれぞれ10本の線にして描画している。
関数bezier_patchesのfor文は、リスト内包と行列の積を使って記述すると以下のようになる。
def bezier_patches(m, n, u, v, q): return np.dot([bernstein(n, j, v) for j in range(n + 1)], np.tensordot([bernstein(m, i, u) for i in range(m + 1)], q, axes=1))
実行結果
緑の線がベジエ曲面、青の点線が制御点の格子を表している。
参考文献
- コンピュータグラフィックス (新世代工学シリーズ), 前川 佳徳 (著), オーム社