1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

3D Poké Ball と 2D Pikachu

Last updated at Posted at 2025-11-19

1. 実装構成

本スクリプトは以下の 3 セクションで構成される。

  1. 3D ポケボール描画関数 plot_kocchi_ball()
    球面座標(φ, θ)からメッシュを生成し、
    RGB アレイによるマテリアル割り当てでポケボールを再現。

  2. 2D ピカチュウ描画関数 draw_pikachu()
    Matplotlib の patches(円、楕円、ポリゴン)を組み合わせて
    フラットデザインのピカチュウを描画。

  3. メイン実行部 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_surfacefacecolors を渡してレンダリング:

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 ピカチュウ の順に表示される。


image.png

image.png

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?