1. 実装構成
本スクリプトは以下の 3 セクションで構成される。
-
3D ポケボール描画関数
plot_kocchi_ball()
球面座標(φ, θ)からメッシュを生成し、
RGB アレイによるマテリアル割り当てでポケボールを再現。 -
2D ピカチュウ描画関数
draw_pikachu()
Matplotlib のpatches(円、楕円、ポリゴン)を組み合わせて
フラットデザインのピカチュウを描画。 -
メイン実行部
if __name__ == "__main__":
3D → 2D の順でウィンドウを表示。
2. 3D Poké Ball 描画の仕組み
2.1 球面メッシュ生成
phi = np.linspace(0, np.pi, 200)
theta = np.linspace(0, 2*np.pi, 200)
phi, theta = np.meshgrid(phi, theta)
球の半径 r=1 とし、デカルト座標へ変換:
x = r * np.sin(phi) * np.cos(theta)
y = r * np.sin(phi) * np.sin(theta)
z = r * np.cos(phi)
2.2 マテリアル(色)割り当て
球全体の配列 colors に RGB 値をセットする。
colors = np.full(x.shape + (3,), [0.95, 0.95, 0.95])
部分的マスクを使い色分け:
- 上半分(赤)
- 中央帯(黒)
- 正面ボタン(白・黒・グレー)
これにより、3D ポケボールが視覚的に構築される。
2.3 3D 描画
Matplotlib の plot_surface に facecolors を渡してレンダリング:
ax.plot_surface(x, y, z, facecolors=colors, shade=True)
3. 2D Pikachu 描画の仕組み
ピカチュウは 図形プリミティブの組み合わせで構成する。
使用する要素:
| パーツ | 描画方法 |
|---|---|
| 顔 | Circle |
| 耳 | Ellipse |
| 頬 | Circle |
| 目 | Circle(白反射も Circle) |
| 鼻 | Polygon |
| 口 | NumPy 生成の曲線(cos + abs) |
例:耳(左)
ear_l = patches.Ellipse((-0.7, 1.1), 0.35, 1.0, angle=40, color='gold')
口は数式でカーブを設計:
x = np.linspace(-0.3, 0.3, 100)
y = -0.15 + 0.05*np.cos(20*x) + 0.1*np.abs(x)
ax.plot(x, y, color='black', linewidth=2)
4. 統合スクリプト
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.patches as patches
# ---------------------------------------------------------
# 3D POKÉ BALL
# ---------------------------------------------------------
def plot_kocchi_ball():
phi = np.linspace(0, np.pi, 200)
theta = np.linspace(0, 2*np.pi, 200)
phi, theta = np.meshgrid(phi, theta)
r = 1.0
x = r * np.sin(phi) * np.cos(theta)
y = r * np.sin(phi) * np.sin(theta)
z = r * np.cos(phi)
colors = np.full(x.shape + (3,), [0.95, 0.95, 0.95])
mask_top = z > 0.03
colors[mask_top] = [0.85, 0.1, 0.1]
mask_band = (z >= -0.03) & (z <= 0.03)
colors[mask_band] = [0.1, 0.1, 0.1]
r_sq = y**2 + z**2
mask_button_rim = (r_sq < 0.25**2) & (x > 0)
mask_button_inner = (r_sq < 0.15**2) & (x > 0)
mask_button_core = (r_sq < 0.10**2) & (x > 0)
colors[mask_button_rim] = [0.1, 0.1, 0.1]
colors[mask_button_inner] = [0.95, 0.95, 0.95]
colors[mask_button_core] = [0.85, 0.85, 0.85]
fig = plt.figure(figsize=(8, 8), dpi=100)
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(
x, y, z,
facecolors=colors,
rstride=1, cstride=1,
shade=True,
antialiased=False
)
ax.set_axis_off()
ax.set_box_aspect([1, 1, 1])
ax.view_init(elev=20, azim=10)
plt.title("Poké Ball", fontsize=14)
plt.show()
# ---------------------------------------------------------
# 2D PIKACHU
# ---------------------------------------------------------
def draw_pikachu():
fig, ax = plt.subplots(figsize=(6, 6))
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 2.0)
ax.set_aspect('equal')
ax.axis('off')
ear_l = patches.Ellipse((-0.7, 1.1), 0.35, 1.0, angle=40, color='gold')
ear_l_tip = patches.Ellipse((-0.88, 1.35), 0.25, 0.4, angle=40, color='black')
ear_r = patches.Ellipse((0.7, 1.1), 0.35, 1.0, angle=-40, color='gold')
ear_r_tip = patches.Ellipse((0.88, 1.35), 0.25, 0.4, angle=-40, color='black')
ax.add_patch(ear_l); ax.add_patch(ear_l_tip)
ax.add_patch(ear_r); ax.add_patch(ear_r_tip)
face = patches.Circle((0, 0), radius=1.0, color='gold')
ax.add_patch(face)
cheek_l = patches.Circle((-0.8, -0.2), 0.25, color='red')
cheek_r = patches.Circle((0.8, -0.2), 0.25, color='red')
ax.add_patch(cheek_l); ax.add_patch(cheek_r)
eye_l = patches.Circle((-0.4, 0.15), 0.13, color='black')
eye_l_high = patches.Circle((-0.45, 0.20), 0.05, color='white')
eye_r = patches.Circle((0.4, 0.15), 0.13, color='black')
eye_r_high = patches.Circle((0.35, 0.20), 0.05, color='white')
ax.add_patch(eye_l); ax.add_patch(eye_l_high)
ax.add_patch(eye_r); ax.add_patch(eye_r_high)
nose = patches.Polygon([[-0.05, 0.0],[0.05, 0.0],[0.0,-0.05]], closed=True, color='black')
ax.add_patch(nose)
x = np.linspace(-0.3, 0.3, 100)
y = -0.15 + 0.05*np.cos(20*x) + 0.1*np.abs(x)
ax.plot(x, y, color='black', linewidth=2)
plt.title("Pikachu with Matplotlib", fontsize=15)
plt.show()
# ---------------------------------------------------------
# MAIN
# ---------------------------------------------------------
if __name__ == "__main__":
plot_kocchi_ball()
draw_pikachu()
この構造により、スクリプトを実行するだけで
3D ポケボール → 2D ピカチュウ の順に表示される。

