Newer
Older
InforSystem / py / gravity_simulation_ui.py
@Karen Saito Karen Saito on 25 Jun 2 KB upload
import bpy
import numpy as np

# UIプロパティ登録
def register_props():
    bpy.types.Scene.gravity_strength = bpy.props.FloatProperty(
        name="重力定数 G",
        default=1.0,
        min=0.1,
        max=5.0,
        step=0.1,
        precision=2
    )

# 軌道シミュレーション実行関数
def calculate_orbit(context):
    G = context.scene.gravity_strength
    M = 1000
    pos = np.array([5.0, 0.0])  # 初期位置(固定)
    vel = np.array([0.0, 10.0]) # 初期速度(固定)
    dt = 0.01
    steps = 400
    positions = []

    # 既存オブジェクト削除
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete(use_global=False)

    # 太陽
    bpy.ops.mesh.primitive_uv_sphere_add(radius=1, location=(0, 0, 0))
    sun = bpy.context.object
    sun.name = "Sun"
    mat = bpy.data.materials.new("SunMat")
    mat.diffuse_color = (1.0, 0.5, 0.0, 1)
    sun.data.materials.append(mat)

    # 地球
    bpy.ops.mesh.primitive_uv_sphere_add(radius=0.3, location=(pos[0], pos[1], 0))
    earth = bpy.context.object
    earth.name = "Earth"
    mat = bpy.data.materials.new("EarthMat")
    mat.diffuse_color = (0.2, 0.5, 1.0, 1)
    earth.data.materials.append(mat)

    for _ in range(steps):
        r_vec = -pos
        dist = np.linalg.norm(r_vec)
        acc = G * M * r_vec / dist**3
        vel += acc * dt
        pos += vel * dt
        positions.append(pos.copy())

    # アニメーション設定
    scene = context.scene
    scene.frame_start = 1
    scene.frame_end = steps
    frame = 1
    for p in positions:
        earth.location = (p[0], p[1], 0)
        earth.keyframe_insert(data_path="location", frame=frame)
        frame += 1

# UIパネル
class GravityOnlyPanel(bpy.types.Panel):
    bl_label = "重力定数で軌道観察"
    bl_idname = "VIEW3D_PT_gravity_only"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'OrbitSim'

    def draw(self, context):
        layout = self.layout
        layout.prop(context.scene, "gravity_strength")
        layout.operator("orbit.recalc", text="再計算")
        layout.operator("screen.animation_play", text="▶ アニメ再生")

# 再計算ボタン
class RecalcOrbitOperator(bpy.types.Operator):
    bl_idname = "orbit.recalc"
    bl_label = "軌道を再計算"

    def execute(self, context):
        calculate_orbit(context)
        self.report({'INFO'}, "軌道を再計算しました")
        return {'FINISHED'}

# 登録と解除
classes = [GravityOnlyPanel, RecalcOrbitOperator]

def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    register_props()

def unregister():
    for cls in reversed(classes):
        bpy.utils.unregister_class(cls)
    del bpy.types.Scene.gravity_strength

# 登録して初回計算を自動実行
if __name__ == "__main__":
    register()
    calculate_orbit(bpy.context)