import bpy
import numpy as np
import math
# 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)
# 背景を黒に設定
world = bpy.data.worlds["World"]
bg = world.node_tree.nodes.get("Background")
if bg:
bg.inputs[0].default_value = (0, 0, 0, 1)
# 太陽(オレンジ)
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"
mat2 = bpy.data.materials.new("EarthMat")
mat2.diffuse_color = (0.2, 0.5, 1.0, 1)
earth.data.materials.append(mat2)
# ライト追加
light_data = bpy.data.lights.new(name="SunLight", type='SUN')
light_data.energy = 5.0
light = bpy.data.objects.new(name="SunLight", object_data=light_data)
bpy.context.collection.objects.link(light)
light.location = (0, 0, 0)
light.rotation_euler = (math.radians(45), 0, 0)
# カメラ追加
bpy.ops.object.camera_add(location=(10, -10, 6), rotation=(math.radians(60), 0, math.radians(45)))
camera = bpy.context.object
bpy.context.scene.camera = camera
# 軌道計算
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)