アドベントカレンダーの最終12/25には、クリスマスツリーを描いてみます!アドベントカレンダーで12月半ばに作った、 菊の花みたいな、ベルヌーイのスケート型の変形を利用します。
完成形
12月に作った菊の花を応用して極座標系を使い、パッチ面(反射面)の作成など、レンダリング機能を利用して、こんなモミの木を描いていきます。gif動画は、🎅サンタさんが、そりに乗って空へ向かう感じを出してみました。
モミの木の外観
まず、モミの木の外観を描きます。幹部分をくるくると回しながら、下から上へだんだんと径を小さくしていきます。自然の木みたいに、適当にでこぼこして枝の長さに違いが出るようにしたいので、木全体の、外観の形を先に作ってしまいます。
ケーキの上のクリームみたいですね。プロットには半径(rではじまる)と 中心角(t)の径極座標系を使いますが、回り具合の係数に割り切れる数を持っていくと、一周回った時に、下の枝と上の枝が重なって不自然になってしまうので、適当な数(ここでは、4.7)できれいに割り切れないようにしています。
clear;
t = 0:.1:10 * pi;
r = t + sin(t * 4.7);
x = r.*cos(t);
y = r.*sin(t);
z = (-1) * t;
figure;
plot3(x, y, z, '-', 'LineWidth', 1.5);
axis off;
% change view
ax= gca;
ax.View = [-56.2028 40.0977];
さらに枝の長さもばらばらに見せたいので、sin関数を使って波ができるようにしていきます。この程度で、モミの木らしくなります。
func = @(t) sqrt(cos(2*t) ) ;
rsqared = func(t);
r2 = sqrt(rsqared);
x = r2.*r.*cos(t);
y = r2.*r.*sin(t);
z = (-1) * t;
figure;
plot3(x, y, z, '-', 'LineWidth', 1.5);
axis off;
% change view
ax= gca;
ax.View = [-56.2028 40.0977];
これで、枝の長さに関する計算は終わりです。
枝の追加
上で作った輪郭に、以前作成した菊の花みたいな枝葉を を合わせていきます。この段階はただのもじゃもじゃな針金みたいに見えますね。
t = 0: 0.1:100 * pi;
r = t /17+ sin(t /17 * 4.7);
rsqared = func(t);
r2 = sqrt(rsqared);
x = r2.*r.*cos(t/5.3);
y = r2.*r.*sin(t/5.3);
z = (-1) * t;
figure;
plot3(x, y, z, '-', 'LineWidth', 1.5);
axis off;
% change view
ax= gca;
ax.View = [-68.4315 13.1706];
パッチの作成と彩色
最後に、tree の外観に沿って、三角形のパッチを当てていきます。さきほどの、針金アート上の点を連続して二つ取り、木の中央部分の少し上 (h = 100)をつないで三角形を作ります。すべてのパッチ面の頂点を、まとめて行列で指定しているので、実行はpatch関数の一行だけです。
h = 100;
% vertex 1
x1 = x(1:end-1);
y1 = y(1:end-1);
z1 = z(1:end-1);
% vertex 2
x2 = x(2:end);
y2 = y(2:end);
z2 = z(2:end);
% vertex 3 (enter vertex)
x0 = x2 * 0;
y0 = y2 * 0;
z0 = z2 + h;
% fit to the patch grammer
xp = [x1; x2; x0];
yp = [y1; y2; y0];
zp = [z1; z2; z0];
% draw 3D tree
figure;
colormap winter;
col = 256 - round(t(1:end-1) * 255/ length(t)) ;
col = col';
p = patch(xp, yp, zp, col);
p.SpecularStrength = .5;
p.DiffuseStrength = .5;
p.EdgeColor = 'none';
p.EdgeAlpha = .2;
p.FaceAlpha = .8;
% place light
Lt = light( "Style","local","Position",[500, 20, 20]);
lighting gouraud;
% change view
ax = gca;
ax.View = [ 157.2923 15.0940];
ax.Position = [ 0.1300 0.1100 0.7750 0.8150];
grid on;
パッチができたあとは、彩色をしますが、色の指定の仕方に少し癖があり、col は、カラーマップの何番目の色、という指定の仕方をします。先に、colormap 関数で、カラーマップを作っておく必要があります。ここでは、既定にある winter というグラデーションを、向きを逆にして使いました。なお、パッチのプロパティ変数(内容は行列) CData を変更することで、RGBの3要素で指定することも可能なようです。
Care about presents
クリスマスの有名な歌では、I don't care about presents ですが、描画では、モミの下にプレゼントの箱なんかを描いてもいいかもしれません。パッチは、座標の指定の順番によって、表の面と裏の面が決まるので、箱を自力で書くといい勉強になります。
また来年
今年のアドベントカレンダーでは、cos 関数や sin 関数を使った、伝統的によく知られた関数式を応用して、さまざまなものを作ってみました。パスカルの🐌カタツムリや、グランディの🌹バラなど、17 - 18 世紀に、まだ、PCみたいな便利な機械がないときに、数学が好きな人々が手で計算して紙にプロットして調べたものです。
今は、こうして立体を描くのも簡単にできてしまいますが、学校の数学の時間に、ゲーム感覚で、こんな風に手で動かして学ぶ学習方法があったら、三角関数や方程式、そして行列にも、もっと興味が湧いてくるかもしれませんね。
ここまで読んでくださり、ありがとうございます! 皆様によい1年がありますように、心からお祈りします。
2023年 Emiko SH