いいね、「ここから実装」が一番楽しいところだね。
オクタヘドラルマップ+ノイズ関数+チャンクサンプリングで、最低限「惑星として破綻しない」Pythonコードを書いてみる。

ここでは:

  • 惑星=連続関数 height(dir)
  • チャンク=その関数のサンプリング
  • ノイズは noise ライブラリ(Perlin)を想定(なければ自作に差し替え可)

という前提でいくね。


1. オクタヘドラルマップ(方向ベクトル → 2D)

import math
from noise import pnoise2  # pip install noise

def dir_to_octa_uv(x, y, z):
    # 正規化
    length = math.sqrt(x*x + y*y + z*z)
    x /= length
    y /= length
    z /= length

    s = abs(x) + abs(y) + abs(z)
    x_ = x / s
    y_ = y / s
    z_ = z / s

    if z_ >= 0:
        u = x_
        v = y_
    else:
        u = (1 - abs(y_)) * (1 if x_ >= 0 else -1)
        v = (1 - abs(x_)) * (1 if y_ >= 0 else -1)

    U = (u + 1.0) * 0.5
    V = (v + 1.0) * 0.5
    return U, V

2. 緯度経度 → 方向ベクトル

def latlon_to_dir(lat_rad, lon_rad):
    # 緯度φ, 経度λ
    phi = lat_rad
    lam = lon_rad
    x = math.cos(phi) * math.cos(lam)
    y = math.sin(phi)
    z = math.cos(phi) * math.sin(lam)
    return x, y, z

3. 惑星の height 関数(大陸+山脈)

def planet_height(lat_rad, lon_rad, seed=0):
    x, y, z = latlon_to_dir(lat_rad, lon_rad)
    U, V = dir_to_octa_uv(x, y, z)

    # スケール調整(大陸=低周波、山脈=高周波)
    scale_continent = 1.5
    scale_mountain  = 8.0

    c = pnoise2(U * scale_continent, V * scale_continent, octaves=4, repeatx=1024, repeaty=1024, base=seed)
    m = pnoise2(U * scale_mountain,  V * scale_mountain,  octaves=3, repeatx=1024, repeaty=1024, base=seed+100)

    # -1〜1 → 0〜1
    c = (c + 1.0) * 0.5
    m = (m + 1.0) * 0.5

    # 大陸+山脈の合成
    h = c + m * 0.4
    return h  # 0〜1

4. チャンクサンプリング(緯度経度グリッド)

ここでは「緯度経度ベースのチャンク」として、
lat0, lon0 を左上とする res×res グリッドをサンプリングする例。

def sample_chunk(lat0_deg, lon0_deg, dlat_deg, dlon_deg, res=64, seed=0):
    chunk = [[0.0 for _ in range(res)] for _ in range(res)]
    for j in range(res):
        for i in range(res):
            lat_deg = lat0_deg - j * dlat_deg / res
            lon_deg = lon0_deg + i * dlon_deg / res
            lat_rad = math.radians(lat_deg)
            lon_rad = math.radians(lon_deg)
            h = planet_height(lat_rad, lon_rad, seed=seed)
            chunk[j][i] = h
    return chunk

5. 使い方イメージ

if __name__ == "__main__":
    # 例:赤道付近の 10°×10° チャンク
    chunk = sample_chunk(
        lat0_deg=5.0,
        lon0_deg=-5.0,
        dlat_deg=10.0,
        dlon_deg=10.0,
        res=128,
        seed=42
    )

    # ここで chunk を Roblox 用 heightmap に変換したり、
    # PNG に書き出したりできる

ここから先は:

  • チャンクを「緯度経度」ではなく「オクタ空間のタイル」として切る
  • height から「海/陸/山脈/河川」を分類する
  • 惑星パラメータ(半径・海面・プレート活動度)を関数に組み込む

みたいな方向に伸ばせる。
このコード、どこを次に「OS 化」したくなる?