diff --git a/blend/.DS_Store b/blend/.DS_Store new file mode 100644 index 0000000..011ae52 --- /dev/null +++ b/blend/.DS_Store Binary files differ diff --git a/blend/earth1.glb b/blend/earth1.glb new file mode 100644 index 0000000..26faa8c --- /dev/null +++ b/blend/earth1.glb Binary files differ diff --git a/blend/earth_texture.jpg b/blend/earth_texture.jpg new file mode 100644 index 0000000..a26a410 --- /dev/null +++ b/blend/earth_texture.jpg Binary files differ diff --git a/blend/gravity_simulation.blend b/blend/gravity_simulation.blend index 8b341a5..7a13baa 100644 --- a/blend/gravity_simulation.blend +++ b/blend/gravity_simulation.blend Binary files differ diff --git a/blend/gravity_simulation.py b/blend/gravity_simulation.py new file mode 100644 index 0000000..6108a96 --- /dev/null +++ b/blend/gravity_simulation.py @@ -0,0 +1,123 @@ +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) diff --git a/blend/gravity_simulation_ui b/blend/gravity_simulation_ui new file mode 100644 index 0000000..76a2a9f --- /dev/null +++ b/blend/gravity_simulation_ui @@ -0,0 +1,144 @@ +import bpy +import numpy as np + +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([8.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.use_nodes = True + nodes = mat.node_tree.nodes + links = mat.node_tree.links + + for node in nodes: + nodes.remove(node) + + tex_image = nodes.new(type='ShaderNodeTexImage') + img_path = "/Users/saitokaren/koeki/git/InforSystem/blend/sun_texture.jpg" + tex_image.image = bpy.data.images.load(img_path) + + emission = nodes.new(type='ShaderNodeEmission') + material_output = nodes.new(type='ShaderNodeOutputMaterial') + + tex_image.location = (-300, 0) + emission.location = (0, 0) + material_output.location = (300, 0) + + links.new(tex_image.outputs['Color'], emission.inputs['Color']) + links.new(emission.outputs['Emission'], material_output.inputs['Surface']) + + sun.data.materials.append(mat) + + bpy.ops.object.light_add(type='SUN', location=(0, 0, 0)) + light = bpy.context.object + light.data.energy = 3 + light.rotation_euler = (np.radians(135), 0, 0) + + 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.use_nodes = True + nodes = mat.node_tree.nodes + links = mat.node_tree.links + + for node in nodes: + nodes.remove(node) + + tex_image = nodes.new(type='ShaderNodeTexImage') + img_path = "/Users/saitokaren/koeki/git/InforSystem/blend/earth_texture.jpg" + tex_image.image = bpy.data.images.load(img_path) + + bsdf = nodes.new(type='ShaderNodeBsdfPrincipled') + material_output = nodes.new(type='ShaderNodeOutputMaterial') + + links.new(tex_image.outputs['Color'], bsdf.inputs['Base Color']) + links.new(bsdf.outputs['BSDF'], material_output.inputs['Surface']) + + earth.data.materials.append(mat) + + scene = context.scene + scene.frame_start = 1 + scene.frame_end = steps + rotation_z_earth = 0.0 + rotation_z_sun = 0.0 + + for frame in range(1, steps + 1): + 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()) + + earth.location = (pos[0], pos[1], 0) + earth.keyframe_insert(data_path="location", frame=frame) + + rotation_z_earth += 0.1 + earth.rotation_euler = (0, 0, rotation_z_earth) + earth.keyframe_insert(data_path="rotation_euler", frame=frame) + + rotation_z_sun += 0.05 + sun.rotation_euler = (0, 0, rotation_z_sun) + sun.keyframe_insert(data_path="rotation_euler", frame=frame) + +class GravityOnlyPanel(bpy.types.Panel): + bl_label = "重力定数で軌道観察" + bl_idname = "VIEW3D_PT_gravity_only" + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_category = '重力定数' + + 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) diff --git a/blend/gravity_simulation_ui.py b/blend/gravity_simulation_ui.py new file mode 100644 index 0000000..c7f83ab --- /dev/null +++ b/blend/gravity_simulation_ui.py @@ -0,0 +1,180 @@ +import bpy +import numpy as np + +# シーンに新規FloatProperty「gravity_strength」を登録する関数 +def register_props(): + bpy.types.Scene.gravity_strength = bpy.props.FloatProperty( + name="重力定数 G", # UIに表示される名前 + default=1.0, # デフォルト値 + min=0.1, # 最小値 + max=5.0, # 最大値 + step=0.1, # ステップ幅(UIでの操作用) + precision=2 # 小数点以下の桁数 + ) + +# 軌道計算とアニメーション作成を行う関数 +def calculate_orbit(context): + G = context.scene.gravity_strength # UIで設定した重力定数を取得 + M = 1000 # 太陽の質量(任意の単位) + pos = np.array([8.0, 0.0]) # 地球の初期位置(x=8, y=0) + vel = np.array([0.0, 10.0]) # 地球の初期速度(x=0, y=10) + 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" + + # 太陽のマテリアルを作成(Emissionシェーダーで光らせ、テクスチャを貼る) + mat = bpy.data.materials.new("SunMat") + mat.use_nodes = True + nodes = mat.node_tree.nodes + links = mat.node_tree.links + + # 初期ノードを全削除 + for node in nodes: + nodes.remove(node) + + # 画像テクスチャノードを作成し、テクスチャ画像を読み込む + tex_image = nodes.new(type='ShaderNodeTexImage') + img_path = "/Users/saitokaren/koeki/git/InforSystem/blend/texture/sun_texture.jpg" + tex_image.image = bpy.data.images.load(img_path) + + # Emissionノード(光を発するマテリアル) + emission = nodes.new(type='ShaderNodeEmission') + + # マテリアル出力ノード + material_output = nodes.new(type='ShaderNodeOutputMaterial') + + # ノードの見やすい配置(任意) + tex_image.location = (-300, 0) + emission.location = (0, 0) + material_output.location = (300, 0) + + # 画像の色をEmissionノードの色入力に接続 + links.new(tex_image.outputs['Color'], emission.inputs['Color']) + + # Emissionノードの出力をMaterial Outputに接続 + links.new(emission.outputs['Emission'], material_output.inputs['Surface']) + + # 作成したマテリアルを太陽に割り当てる + 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" + + # 地球のマテリアル作成(Principled BSDFでテクスチャを貼る) + mat = bpy.data.materials.new("EarthMat") + mat.use_nodes = True + nodes = mat.node_tree.nodes + links = mat.node_tree.links + + # 初期ノード削除 + for node in nodes: + nodes.remove(node) + + # 地球テクスチャ読み込み + tex_image = nodes.new(type='ShaderNodeTexImage') + img_path = "/Users/saitokaren/koeki/git/InforSystem/blend/texture/earth_texture.jpg" + tex_image.image = bpy.data.images.load(img_path) + + # Principled BSDF(物理ベースシェーダー) + bsdf = nodes.new(type='ShaderNodeBsdfPrincipled') + + # マテリアル出力ノード + material_output = nodes.new(type='ShaderNodeOutputMaterial') + + # 接続:テクスチャの色 → ベースカラー入力 + links.new(tex_image.outputs['Color'], bsdf.inputs['Base Color']) + + # 接続:BSDF出力 → マテリアル出力 + links.new(bsdf.outputs['BSDF'], material_output.inputs['Surface']) + + # 地球にマテリアル割り当て + earth.data.materials.append(mat) + + # --- アニメーション設定 --- + scene = context.scene + scene.frame_start = 1 + scene.frame_end = steps + rotation_z_earth = 0.0 + rotation_z_sun = 0.0 + + for frame in range(1, steps + 1): + # 地球に働く重力加速度の計算(単純な万有引力) + r_vec = -pos + dist = np.linalg.norm(r_vec) + acc = G * M * r_vec / dist**3 + + # 速度と位置の更新(Euler法) + vel += acc * dt + pos += vel * dt + positions.append(pos.copy()) + + # 地球の位置更新とキーフレーム挿入 + earth.location = (pos[0], pos[1], 0) + earth.keyframe_insert(data_path="location", frame=frame) + + # 地球の自転角度を増やし、回転を設定・キーフレーム挿入 + rotation_z_earth += 0.1 + earth.rotation_euler = (0, 0, rotation_z_earth) + earth.keyframe_insert(data_path="rotation_euler", frame=frame) + + # 太陽の自転(地球より遅く回転) + rotation_z_sun += 0.05 + sun.rotation_euler = (0, 0, rotation_z_sun) + sun.keyframe_insert(data_path="rotation_euler", frame=frame) + +# 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 = '重力定数' + + 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) diff --git a/blend/gravity_simulation_ui_txt b/blend/gravity_simulation_ui_txt new file mode 100644 index 0000000..c8021de --- /dev/null +++ b/blend/gravity_simulation_ui_txt @@ -0,0 +1,188 @@ +import bpy +import numpy as np + +# シーンに新規FloatProperty「gravity_strength」を登録する関数 +def register_props(): + bpy.types.Scene.gravity_strength = bpy.props.FloatProperty( + name="重力定数 G", # UIに表示される名前 + default=1.0, # デフォルト値 + min=0.1, # 最小値 + max=5.0, # 最大値 + step=0.1, # ステップ幅(UIでの操作用) + precision=2 # 小数点以下の桁数 + ) + +# 軌道計算とアニメーション作成を行う関数 +def calculate_orbit(context): + G = context.scene.gravity_strength # UIで設定した重力定数を取得 + M = 1000 # 太陽の質量(任意の単位) + pos = np.array([8.0, 0.0]) # 地球の初期位置(x=8, y=0) + vel = np.array([0.0, 10.0]) # 地球の初期速度(x=0, y=10) + 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" + + # 太陽のマテリアルを作成(Emissionシェーダーで光らせ、テクスチャを貼る) + mat = bpy.data.materials.new("SunMat") + mat.use_nodes = True + nodes = mat.node_tree.nodes + links = mat.node_tree.links + + # 初期ノードを全削除 + for node in nodes: + nodes.remove(node) + + # 画像テクスチャノードを作成し、テクスチャ画像を読み込む + tex_image = nodes.new(type='ShaderNodeTexImage') + img_path = "/Users/saitokaren/koeki/git/InforSystem/blend/texture/sun_texture.jpg" + tex_image.image = bpy.data.images.load(img_path) + + # Emissionノード(光を発するマテリアル) + emission = nodes.new(type='ShaderNodeEmission') + + # マテリアル出力ノード + material_output = nodes.new(type='ShaderNodeOutputMaterial') + + # ノードの見やすい配置(任意) + tex_image.location = (-300, 0) + emission.location = (0, 0) + material_output.location = (300, 0) + + # 画像の色をEmissionノードの色入力に接続 + links.new(tex_image.outputs['Color'], emission.inputs['Color']) + + # Emissionノードの出力をMaterial Outputに接続 + links.new(emission.outputs['Emission'], material_output.inputs['Surface']) + + # 作成したマテリアルを太陽に割り当てる + sun.data.materials.append(mat) + + # --- 光源の作成 --- + # 光源は別物。SUNタイプのライトを作成し、太陽から斜め45度の方向に配置 + bpy.ops.object.light_add(type='SUN', location=(0, 0, 0)) + light = bpy.context.object + light.data.energy = 3 # 光の強さ(数値が大きいほど明るい) + # 光が斜めから当たるように角度を設定(135度=太陽から見て斜め上方向) + light.rotation_euler = (np.radians(135), 0, 0) + + # --- 地球オブジェクトの作成 --- + bpy.ops.mesh.primitive_uv_sphere_add(radius=0.3, location=(pos[0], pos[1], 0)) + earth = bpy.context.object + earth.name = "Earth" + + # 地球のマテリアル作成(Principled BSDFでテクスチャを貼る) + mat = bpy.data.materials.new("EarthMat") + mat.use_nodes = True + nodes = mat.node_tree.nodes + links = mat.node_tree.links + + # 初期ノード削除 + for node in nodes: + nodes.remove(node) + + # 地球テクスチャ読み込み + tex_image = nodes.new(type='ShaderNodeTexImage') + img_path = "/Users/saitokaren/koeki/git/InforSystem/blend/texture/earth_texture.jpg" + tex_image.image = bpy.data.images.load(img_path) + + # Principled BSDF(物理ベースシェーダー) + bsdf = nodes.new(type='ShaderNodeBsdfPrincipled') + + # マテリアル出力ノード + material_output = nodes.new(type='ShaderNodeOutputMaterial') + + # 接続:テクスチャの色 → ベースカラー入力 + links.new(tex_image.outputs['Color'], bsdf.inputs['Base Color']) + + # 接続:BSDF出力 → マテリアル出力 + links.new(bsdf.outputs['BSDF'], material_output.inputs['Surface']) + + # 地球にマテリアル割り当て + earth.data.materials.append(mat) + + # --- アニメーション設定 --- + scene = context.scene + scene.frame_start = 1 + scene.frame_end = steps + rotation_z_earth = 0.0 + rotation_z_sun = 0.0 + + for frame in range(1, steps + 1): + # 地球に働く重力加速度の計算(単純な万有引力) + r_vec = -pos + dist = np.linalg.norm(r_vec) + acc = G * M * r_vec / dist**3 + + # 速度と位置の更新(Euler法) + vel += acc * dt + pos += vel * dt + positions.append(pos.copy()) + + # 地球の位置更新とキーフレーム挿入 + earth.location = (pos[0], pos[1], 0) + earth.keyframe_insert(data_path="location", frame=frame) + + # 地球の自転角度を増やし、回転を設定・キーフレーム挿入 + rotation_z_earth += 0.1 + earth.rotation_euler = (0, 0, rotation_z_earth) + earth.keyframe_insert(data_path="rotation_euler", frame=frame) + + # 太陽の自転(地球より遅く回転) + rotation_z_sun += 0.05 + sun.rotation_euler = (0, 0, rotation_z_sun) + sun.keyframe_insert(data_path="rotation_euler", frame=frame) + +# 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 = '重力定数' + + 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) diff --git a/blend/index.blend b/blend/index.blend new file mode 100644 index 0000000..b6463fa --- /dev/null +++ b/blend/index.blend Binary files differ diff --git a/blend/moon_texture.jpg b/blend/moon_texture.jpg new file mode 100644 index 0000000..81e639c --- /dev/null +++ b/blend/moon_texture.jpg Binary files differ diff --git a/blend/simulation.blend b/blend/simulation.blend new file mode 100644 index 0000000..30b0d1c --- /dev/null +++ b/blend/simulation.blend Binary files differ diff --git a/blend/simulation.blend1 b/blend/simulation.blend1 new file mode 100644 index 0000000..6226a29 --- /dev/null +++ b/blend/simulation.blend1 Binary files differ diff --git a/blend/simulation.py b/blend/simulation.py new file mode 100644 index 0000000..d4b2582 --- /dev/null +++ b/blend/simulation.py @@ -0,0 +1,127 @@ +import bpy +import numpy as np +import math + +# 設定:スケール・パス +AU = 20.0 +earth_radius = 0.3 +sun_radius = 5.0 +moon_radius = 0.08 +moon_distance = 0.7 + +G = 1.0 +M = 1000 +dt = 0.01 +steps = 400 + +# 画像ファイル +earth_image_path = "earth_texture.jpg" +sun_image_path = "sun_texture.jpg" +moon_image_path = "moon_texture.jpg" + +# 初期化:全削除・背景黒 +bpy.ops.object.select_all(action='SELECT') +bpy.ops.object.delete(use_global=False) + +bg = bpy.data.worlds["World"].node_tree.nodes.get("Background") +if bg: + bg.inputs[0].default_value = (0, 0, 0, 1) + +# 関数:画像テクスチャを貼る +def apply_texture(obj, image_path): + mat = bpy.data.materials.new(name=obj.name + "_Mat") + mat.use_nodes = True + nodes = mat.node_tree.nodes + links = mat.node_tree.links + + bsdf = nodes.get("Principled BSDF") + tex_image = nodes.new(type='ShaderNodeTexImage') + img = bpy.data.images.load(image_path) + tex_image.image = img + links.new(tex_image.outputs['Color'], bsdf.inputs['Base Color']) + + obj.data.materials.clear() + obj.data.materials.append(mat) + +# 太陽(自転+テクスチャ) +bpy.ops.mesh.primitive_uv_sphere_add(radius=sun_radius, location=(0, 0, 0)) +sun = bpy.context.object +sun.name = "Sun" +apply_texture(sun, sun_image_path) + +# ========================================== +# 地球(公転・自転+テクスチャ) +# ========================================== +pos = np.array([AU, 0.0]) +vel = np.array([0.0, 7.07]) # √(GM/r) = √(1000/20) +bpy.ops.mesh.primitive_uv_sphere_add(radius=earth_radius, location=(pos[0], pos[1], 0)) +earth = bpy.context.object +earth.name = "Earth" +apply_texture(earth, earth_image_path) + +# ========================================== +# 月(地球周囲を公転・自転+テクスチャ) +# ========================================== +bpy.ops.mesh.primitive_uv_sphere_add(radius=moon_radius, location=(pos[0] + moon_distance, pos[1], 0)) +moon = bpy.context.object +moon.name = "Moon" +apply_texture(moon, moon_image_path) + +# ========================================== +# カメラとライト +# ========================================== +bpy.ops.object.camera_add(location=(70, -70, 40), rotation=(math.radians(60), 0, math.radians(45))) +bpy.context.scene.camera = bpy.context.object + +light_data = bpy.data.lights.new(name="SunLight", type='SUN') +light = bpy.data.objects.new(name="SunLight", object_data=light_data) +bpy.context.collection.objects.link(light) +light.location = (0, 0, 0) + +# ========================================== +# アニメーション処理 +# ========================================== +scene = bpy.context.scene +scene.frame_start = 1 +scene.frame_end = steps + +sun_rot = 0.0 +earth_rot = 0.0 +moon_rot = 0.0 +moon_angle = 0.0 +moon_speed = 2 * math.pi / 50 # 月の1公転 = 50フレーム + +for frame in range(1, steps + 1): + # 地球の公転 + r_vec = -pos + dist = np.linalg.norm(r_vec) + acc = G * M * r_vec / dist**3 + vel += acc * dt + pos += vel * dt + + # 自転更新 + sun_rot += 2 * math.pi / 300 + earth_rot += 2 * math.pi / 50 + moon_rot += 2 * math.pi / 50 + + # 地球:位置・回転 + earth.location = (pos[0], pos[1], 0) + earth.rotation_euler = (0, 0, earth_rot) + earth.keyframe_insert(data_path="location", frame=frame) + earth.keyframe_insert(data_path="rotation_euler", frame=frame) + + # 月:地球の周囲を回る + 自転 + moon_angle += moon_speed + moon.location = ( + pos[0] + moon_distance * math.cos(moon_angle), + pos[1] + moon_distance * math.sin(moon_angle), + 0 + ) + moon.rotation_euler = (0, 0, moon_rot) + moon.keyframe_insert(data_path="location", frame=frame) + moon.keyframe_insert(data_path="rotation_euler", frame=frame) + + # 太陽の自転 + sun.rotation_euler = (0, 0, sun_rot) + sun.keyframe_insert(data_path="rotation_euler", frame=frame) + diff --git a/blend/sun1.glb b/blend/sun1.glb new file mode 100644 index 0000000..2bae4cf --- /dev/null +++ b/blend/sun1.glb Binary files differ diff --git a/blend/texture/earth_texture.jpg b/blend/texture/earth_texture.jpg new file mode 100644 index 0000000..7dcab8a --- /dev/null +++ b/blend/texture/earth_texture.jpg Binary files differ diff --git a/blend/texture/moon_texture.jpg b/blend/texture/moon_texture.jpg new file mode 100644 index 0000000..81e639c --- /dev/null +++ b/blend/texture/moon_texture.jpg Binary files differ diff --git a/blend/texture/sun_texture.jpg b/blend/texture/sun_texture.jpg new file mode 100644 index 0000000..a26a410 --- /dev/null +++ b/blend/texture/sun_texture.jpg Binary files differ diff --git a/blend/videos/g03.mp4 b/blend/videos/g03.mp4 new file mode 100644 index 0000000..498c296 --- /dev/null +++ b/blend/videos/g03.mp4 Binary files differ diff --git a/blend/videos/g10.mp4 b/blend/videos/g10.mp4 new file mode 100644 index 0000000..ceea41b --- /dev/null +++ b/blend/videos/g10.mp4 Binary files differ diff --git a/blend/videos/g50.mp4 b/blend/videos/g50.mp4 new file mode 100644 index 0000000..2fe82c8 --- /dev/null +++ b/blend/videos/g50.mp4 Binary files differ