diff --git a/bodies/sun.py b/bodies/sun.py index 13e9fba20c7892783925e1183ee2822f7f794192..2a064549d72c34c37b6d7cae0a87ba89556a0ee4 100644 --- a/bodies/sun.py +++ b/bodies/sun.py @@ -21,7 +21,8 @@ class Sun(FixedStar): def __init__(self, name="太阳", mass=1.9891e30, init_position=[0, 0, 0], init_velocity=[0, 0, 0], - color=(170, 98, 25), + # color=(170, 98, 25), + color=(255, 248, 115), # texture="sun2.jpg", texture="sun2.jpg", size_scale=1.0, distance_scale=1.0, diff --git a/common/color_utils.py b/common/color_utils.py index 7c9cfe018b10935b4ab8831f1e2b413a998264b9..b227bd53d8662a585c8d800bfc65c2b634ef9bec 100644 --- a/common/color_utils.py +++ b/common/color_utils.py @@ -34,7 +34,7 @@ def conv_to_vec4_color(colour: tuple, alpha=1): # color = ursina_color.rgba(r, g, b, a) -def white_brightest(color, min_value=220): +def white_brightest(color, min_value=180): # x = y/255*(255-min_value) + min_value r, g, b = color r = min(255, int(r / 255 * (255 - min_value) + min_value)) @@ -60,11 +60,11 @@ def brightest(color): return [r, g, b] -def fixed_star_color_brightest(c, ursina_color=False): +def fixed_star_color_brightest(c, ursina_color=False, min_value=120): if c is None: bc = (255, 255, 255) else: - bc = white_brightest(c) + bc = white_brightest(c, min_value) if ursina_color: return conv_to_vec4_color(bc) diff --git a/sim_scenes/featured/eight_stars_alignment.py b/sim_scenes/featured/eight_stars_alignment.py new file mode 100644 index 0000000000000000000000000000000000000000..d61565da124ac2f2be08d6cec9eb535a137d02d5 --- /dev/null +++ b/sim_scenes/featured/eight_stars_alignment.py @@ -0,0 +1,247 @@ +# -*- coding:utf-8 -*- +# title :模拟太阳系给天体真实时间和位置 +# description :模拟太阳系给天体真实时间和位置 +# author :Python超人 +# date :2023-07-23 +# link :https://gitcode.net/pythoncr/ +# python_version :3.8 +# ============================================================================== + +import numpy as np + +from bodies import Sun, Mercury, Venus, Earth, Mars, Asteroids, Jupiter, Saturn, Uranus, Neptune, Moon +from common.celestial_data_service import get_body_posvel, recalc_moon_position, calc_solar_acceleration, \ + set_solar_system_celestial_position, set_earth_rotation +from common.consts import SECONDS_PER_WEEK, SECONDS_PER_DAY, SECONDS_PER_HOUR, AU +from sim_scenes.func import ursina_run +from sim_scenes.universe_sim_scenes import UniverseSimScenes +from simulators.ursina.entities.body_timer import TimeData +from simulators.ursina.ui.control_ui import ControlUI +from simulators.ursina.ursina_config import UrsinaConfig +from simulators.ursina.ursina_event import UrsinaEvent +from ursina import camera, application + + +class SolarSystemRealitySim(UniverseSimScenes): + def __init__(self): + """ + + @param debug_mode: 是否为调试模式 + """ + self.show_asteroids = False + self.clock_position_center = False + self.show_earth_clouds = False + self.debug_mode = False + self.recalc_moon_pos = True + + def create_bodies(self): + """ + 创建太阳系的天体 + @return: + """ + # 由于宇宙空间尺度非常大,如果按照实际的天体大小,则无法看到天体,因此需要对天体的尺寸进行放大 + # 太阳缩放比例 + self.sun_size_scale = 0.04e2 if self.debug_mode else 0.4e2 + + # 地月缩放比例 + # 为了更好的展示效果,需要对月球的位置重新计算(使得地月距离放大,月球相对地球方向不变),重新计算位置后,地球和月球可以放大1000倍以上 + if self.recalc_moon_pos: # 重新计算月球位置 + self.earth_size_scale = 10e3 if self.debug_mode else 1e3 + self.moon_size_scale = 2e3 + else: + # 不重新计算,则地月的距离相对整个太阳系会非常近,因此,月球只放大了10倍 + self.earth_size_scale = 1e1 + self.moon_size_scale = 1e1 + + self.sun = Sun(name="太阳", size_scale=self.sun_size_scale, texture="sun.jpg") # 太阳 + self.mercury = Mercury(name="水星", size_scale=1.5e3) # 水星 + self.venus = Venus(name="金星", size_scale=1e3) # 金星 + self.earth = Earth(name="地球", texture="earth_hd.jpg", + rotate_angle=3.44, + size_scale=self.earth_size_scale) # 地球 + self.earth_clouds = Earth(name="地球云层", texture="transparent_clouds.png", show_trail=False, + rotate_angle=3.44, + size_scale=self.earth_size_scale * 1.01) # 地球云层 + self.moon = Moon(name="月球", size_scale=self.moon_size_scale) # 月球 + self.mars = Mars(name="火星", size_scale=1.2e3) # 火星 + self.asteroids = Asteroids(size_scale=1e2, parent=self.sun, rotate_angle=-20) # 模拟的小行星带 + self.jupiter = Jupiter(name="木星", size_scale=4e2) # 木星 + self.saturn = Saturn(name="土星", size_scale=4e2) # 土星 + self.uranus = Uranus(name="天王星", size_scale=10e2) # 天王星 + self.neptune = Neptune(name="海王星", size_scale=10e2) # 海王星 + # 行星 + self.planets = [self.mercury, self.venus, self.earth, self.mars, + self.jupiter, self.saturn, self.uranus, self.neptune] + # 所有天体 + self.bodies = [self.sun] + self.planets + [self.moon] + + self.camera_target = self.create_camera_target(init_position=[0, 0, -AU], size_scale=1e4) + + if self.show_earth_clouds: + self.bodies += [self.earth_clouds] + + if self.show_asteroids: + self.bodies += [self.asteroids, self.camera_target] + + def init_earth(self): + """ + 初始化地球 + @return: + """ + # 让地球显示自转轴线 + # self.earth.rotate_axis_color = (255, 255, 50) + # 如果为调试模式,则太阳光对地球无效,方便查看 + if self.debug_mode: + self.earth.set_light_disable(True) + + def show_clock(self, dt): + """ + 显示时钟 + @param dt: 时间 datetime + @return: + """ + if self.clock_position_center: + position, origin = (0, .25), (0, 0), + else: + from ursina import window + aspect_ratio = window.aspect_ratio + position, origin = (0.5 * aspect_ratio - 0.3, -0.465), (-0.5, 0.5), + # position, origin = (0.60, -0.465), (-0.5, 0.5), + + ControlUI.current_ui.show_message(dt.strftime('%Y-%m-%d %H:%M:%S'), + position=position, + origin=origin, + font="verdana.ttf", + close_time=-1) + + def set_bodies_position(self, time_data: TimeData): + """ + 设置天体的位置(包含速度和加速度的信息) + @param time_data: + @return: + """ + t = self.start_time + time_data.total_days + set_solar_system_celestial_position(self.bodies, t, self.recalc_moon_pos) + + def on_ready(self): + """ + 事件绑定后,模拟器运行前会触发 + @return: + """ + # 运行前触发 + + if self.sky_texture is not None: + from simulators.ursina.entities.sphere_sky import SphereSky + SphereSky(texture=self.sky_texture).scale = 80000 + + camera.clip_plane_near = 0.1 + camera.clip_plane_far = 100000 + + # camera.rotation_z = -20 + if self.debug_mode: + camera.fov = 30 # 调试时,拉近摄像机距离 + + # 需要按照时间和日期来控制地球的自转,所以删除控制地球自转的属性 + delattr(self.earth.planet, "rotation_speed") + delattr(self.earth.planet, "rotspeed") + + # 设置后,可以调整鼠标键盘的控制速度 + application.time_scale = 1 + + def on_timer_changed(self, time_data: TimeData): + """ + 事件绑定后,时时刻刻都会触发 + @param time_data: + @return: + """ + dt = time_data.get_datetime(str(self.start_time)) + # 设置天体的位置(包含速度和加速度的信息) + self.set_bodies_position(time_data) + # 保证地球的自转和北京时间同步 + set_earth_rotation(self.earth, dt) + # 显示时钟 + self.show_clock(dt) + + def bind_events(self): + # 运行中,每时每刻都会触发 on_timer_changed + UrsinaEvent.on_timer_changed_subscription(self.on_timer_changed) + # 运行前会触发 on_ready + UrsinaEvent.on_ready_subscription(self.on_ready) + + def run(self, + debug_mode=False, + start_time=None, + dt=None, + show_asteroids=False, + show_earth_clouds=False, + recalc_moon_pos=True, + clock_position_center=False): + """ + 模拟运行 + @param debug_mode: 是否调试模式 + @param start_time: 运行的开始时间 + @param dt: 运行速度(dt的值为秒数,表示1秒相当于dt的秒数) + @param show_asteroids: 是否显示小行星带 + @param show_earth_clouds: 地球是否显示云层(图片效果,不是真实的云层) + @param recalc_moon_pos: 为了更好的展示效果,需要对月球的位置重新计算(使得地月距离放大,月球相对地球方向不变) + @param clock_position_center: 时钟是否显示在中间 + @return: + """ + self.recalc_moon_pos = recalc_moon_pos + self.debug_mode = debug_mode + self.clock_position_center = clock_position_center + self.show_asteroids = show_asteroids + self.show_earth_clouds = show_earth_clouds + # 创建太阳系天体 + self.create_bodies() + # glows = (glow_num:10, glow_scale:1.03 glow_alpha:0.1~1) + self.sun.glows = (4, 1.005, 0.1, 160) + + # 对地球进行初始化 + self.init_earth() + # 绑定事件 + self.bind_events() + + from astropy.time import Time + from datetime import datetime + # 开始时间为空,则默认为当前时间 + if start_time is None: + self.start_time = Time.now() # 获取默认开始时间为当前时间 + elif isinstance(start_time, str): + self.start_time = Time(datetime.strptime(start_time + '+0800', '%Y-%m-%d %H:%M:%S%z'), + format='datetime') + + from common.image_utils import find_texture + self.sky_texture = find_texture("bg_pan.jpg", None) + if self.sky_texture is None: + cosmic_bg = None + else: + cosmic_bg = '' + if dt is None: + dt = 1 # 1秒=1秒 + # 使用 ursina 查看的运行效果 + # 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹 + # position = 左-右+、上+下-、前+后- + ursina_run(self.bodies, dt, + position=(0, 0.2 * AU, -3 * AU), + gravity_works=False, # 关闭万有引力的计算 + show_grid=False, + cosmic_bg=cosmic_bg, + show_camera_info=False, + timer_enabled=True) + + +if __name__ == '__main__': + # 以下展示的效果为太阳系真实的时间和位置 + sim = SolarSystemRealitySim() + sim.run( + # debug_mode=True, # 是否调试模式 + # dt=SECONDS_PER_DAY , # 1秒=1天 + dt=SECONDS_PER_HOUR, # 1秒=1小时 + # dt=SECONDS_PER_HOUR, # 1秒=1小时 + start_time='2149-12-10 12:00:00', # 九(八)星连珠的时间 # https://baijiahao.baidu.com/s?id=1654160345900112362 + # show_asteroids=True, # 是否显示小行星带(图片模拟) + show_earth_clouds=True, # 地球是否显示云层(图片效果,不是真实的云层) + # recalc_moon_pos=False, # 为了更好的展示效果,需要对月球的位置重新计算(使得地月距离放大,月球相对地球方向不变) + # clock_position_center=True # 时钟是否显示在中间 + ) diff --git a/simulators/ursina/entities/entity_utils.py b/simulators/ursina/entities/entity_utils.py index ec44a0d5333e5731e63f22a2e814ac1588672a6f..f338699d1d8bf5dadfd6e49cfff64d86242c8290 100644 --- a/simulators/ursina/entities/entity_utils.py +++ b/simulators/ursina/entities/entity_utils.py @@ -337,9 +337,12 @@ def create_fixed_star_lights(fixed_star): if hasattr(fixed_star.body_view.body, "glows"): # glows = (glow_num:10, glow_scale:1.03 glow_alpha:0.1~1) glows = fixed_star.body_view.body.glows + glow_color_min_val = 200 if glows is not None: if isinstance(glows, tuple): - if len(glows) == 3: + if len(glows) == 4: + glow_num, glow_scale, glow_alpha, glow_color_min_val = glows + elif len(glows) == 3: glow_num, glow_scale, glow_alpha = glows elif len(glows) == 2: glow_num, glow_scale = glows @@ -365,15 +368,19 @@ def create_fixed_star_lights(fixed_star): glow_entity = Entity(parent=fixed_star, model='sphere', color=_color, scale=math.pow(glow_scale, i + 1), alpha=glow_alpha) if glow_num < 5: - bright_color = color_utils.fixed_star_color_brightest(fixed_star.body_view.body.color, True) + bright_color = color_utils.fixed_star_color_brightest(fixed_star.body_view.body.color, + True, + min_value=glow_color_min_val) glow_circle = create_circle(parent=None, pos=fixed_star.position, scale=fixed_star.scale * 1.8) glow_circle.texture = find_texture("fixed_star_glow.png") glow_circle.color = bright_color glow_circle.set_light_off(True) + fixed_star_ratio = glow_circle.scale_x / fixed_star.scale_x def glow_circle_update(): glow_circle.enabled = fixed_star.enabled glow_circle.position = fixed_star.position + glow_circle.scale = fixed_star_ratio * fixed_star.scale_x glow_circle.look_at(camera) glow_circle.update = glow_circle_update diff --git a/textures/sun.jpg b/textures/sun.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cb049b20ede7720de9ffdadd189c8127f69dedd8 Binary files /dev/null and b/textures/sun.jpg differ