From 4e5febd073c1a29e18f45fec19d574610d1978cd Mon Sep 17 00:00:00 2001 From: march3 Date: Thu, 30 Mar 2023 13:23:46 +0800 Subject: [PATCH] =?UTF-8?q?Python=E8=B6=85=E4=BA=BA-=E5=AE=87=E5=AE=99?= =?UTF-8?q?=E6=A8=A1=E6=8B=9F=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/image_utils.py | 16 ++++- sim_scenes/func.py | 61 +++++------------- sim_scenes/interest/text_bodies.py | 10 +-- sim_scenes/interest/the_eye_of_god.py | 10 +-- sim_scenes/interest/utils/body_utils.py | 51 ++++++++++----- sim_scenes/solar_system/solar_system_2.py | 2 +- simulators/ursina_simulator.py | 77 ++--------------------- 7 files changed, 81 insertions(+), 146 deletions(-) diff --git a/common/image_utils.py b/common/image_utils.py index bf870c8..fc3fe0c 100644 --- a/common/image_utils.py +++ b/common/image_utils.py @@ -170,7 +170,21 @@ def rgb_to_hex(rgb): def find_texture_root_path(): - paths = [os.path.join('.', 'textures'), os.path.join('..', 'textures'), os.path.join('..', '..', 'textures')] + """ + 查找纹理图片的目录 + @return: + """ + paths = [os.path.join('.', 'textures')] + # paths = [os.path.join('.', 'textures'), os.path.join('..', 'textures'), + # os.path.join('..', '..', 'textures'), os.path.join('..', '..', '..', 'textures'), + # os.path.join('..', '..', '..', '..', 'textures')] + for i in range(1, 5): + p = [] + for j in range(i): + p.append("..") + p.append('textures') + paths.append(os.path.join(*p)) + for path in paths: if os.path.exists(path): return path diff --git a/sim_scenes/func.py b/sim_scenes/func.py index 8c921ce..1ffeb7a 100644 --- a/sim_scenes/func.py +++ b/sim_scenes/func.py @@ -57,8 +57,8 @@ def mayavi_run(bodies, dt=SECONDS_PER_WEEK, def ursina_run(bodies, dt=SECONDS_PER_HALF_DAY, position=(0, 0, 0), - # view_azimuth=0, - light=True, + # view_azimuth=0, 摄像头观测方位角,可选,float类型(以度为单位,0-360) + # ignore_mass: 忽略所有天体的引力 cosmic_bg=None, bg_music=None, show_grid=True, @@ -67,22 +67,21 @@ def ursina_run(bodies, save_as_json=None, view_closely=False): """ - - :param bodies: 天体 - :param dt: 单位:秒,按时间差进行演变,值越小越精确,但演变速度会慢。 - :param position: 摄像头位置 - :param view_azimuth: 摄像头观测方位角,可选,float类型(以度为单位,0-360) - :param light: 使用灯光效果 - :param cosmic_bg: 宇宙背景图片 - :param show_grid: 是否显示空间网格 - :param save_as_json: 将所有天体的信息保存为 json 文件 - :param ignore_mass: 忽略所有天体的引力 - :return: + ursina 模拟器运行天体 + @param bodies: 天体集合 + @param dt: 单位:秒,按时间差进行演变,值越小越精确,但演变速度会慢。 + @param position: 摄像头位置 + @param cosmic_bg: 宇宙背景图片 + @param bg_music: 背景音乐 + @param show_grid: 是否显示空间网格 + @param show_trail: 是否显示拖尾 + @param show_name: 是否显示天体名称 + @param save_as_json: 将所有天体的信息保存为 json 文件 + @param view_closely: 是否近距离查看天体 + @return: """ from simulators.ursina_simulator import UrsinaSimulator, UrsinaPlayer - from ursina import application, Sequence, camera, held_keys, time, clamp, Entity, Text, color - from ursina.prefabs.first_person_controller import FirstPersonController body_sys = System(bodies) if show_name: @@ -101,37 +100,6 @@ def ursina_run(bodies, view_azimuth = 0 # 暂时未用 player = UrsinaPlayer(position, view_azimuth, simulator.ursina_views) - # # player = FirstPersonController(model='cube', y=-1e20, color=color.orange, origin_y=-5000, speed=8) - # # player.on_disable() - # # player.position = position - # - # player = FirstPersonController() - # cube = Entity(model='cube', color=color.red, scale=2) - # player.parent = cube # 设置 FirstPersonController 的父实体为 cube - # cube.position = position # 修改父实体的位置,从而间接地修改 FirstPersonController 的位置 - - # # 创建一个实体(在屏幕中央)和一个摄像机 - # TODO: 未使用 - # entity = Entity(model='cube', position=(0, 0, 5), scale=2) - # camera = Camera() - # - # # 设置初始的 FOV 值(默认值为 90) - # camera.fov = 60 - # - # # 创建一个用于显示当前 FOV 值的文本 - # fov_text = Text(text=f'FOV: {camera.fov}', position=(-0.5, 0.4), scale=2) - # # 每一帧更新摄像机 FOV 值 - # def update(): - # # 通过鼠标滚轮来调整 FOV 值 - # camera.fov -= held_keys['scroll'] * 10 * time.dt - # # 限制 FOV 值的范围(1 到 120 之间) - # camera.fov = clamp(camera.fov, 1, 120) - # # 更新文本内容 - # fov_text.text = f'FOV: {camera.fov:.2f}' # 保留两位小数 - # - # # 将摄像机移到实体旁边,并对着它 - # camera.position = entity.position + (0, 0, -5) - # camera.look_at(entity.position) def callback_update(): UrsinaEvent.on_application_run() @@ -146,7 +114,6 @@ def ursina_run(bodies, if show_trail: UrsinaConfig.show_trail = show_trail simulator.run(dt, - light=light, cosmic_bg=cosmic_bg, show_grid=show_grid, bg_music=bg_music, diff --git a/sim_scenes/interest/text_bodies.py b/sim_scenes/interest/text_bodies.py index a4b350b..aabc2c3 100644 --- a/sim_scenes/interest/text_bodies.py +++ b/sim_scenes/interest/text_bodies.py @@ -20,14 +20,14 @@ def show_text_bodies(): """ D = 6000 # camera_pos = 左-右+、上+下-、前+后- - camera_pos = (-130 * D, 0, -6000 * D) + camera_pos = (D, D, -7000 * D) - bodies: list = gen_bodies_from_image(pixel_image="./images/python.png", texture="color_body.jpg", + bodies: list = gen_bodies_from_image(pixel_image="./images/python.png", texture="color_body.png", params={"camera_pos": camera_pos}) - bg = FixedStar(name="bg", texture="fixed_star.png", mass=5e31, color=(0xff, 0xf8, 0xd4), - init_position=[3000 * D, 260 * D, 100 * D], # [ 远+近- , 左+右- , 上+下-] + # 放一个恒星作为背景 + bg = FixedStar(name="bg", texture="fixed_star.png", mass=2e32, color=(0xff, 0xf8, 0xd4), + init_position=[6000 * D, 450 * D, 100 * D], # [ 远+近- , 左+右- , 上+下-] ignore_mass=True) - bg.light_on = True bodies.append(bg) # 使用 ursina 查看的运行效果 diff --git a/sim_scenes/interest/the_eye_of_god.py b/sim_scenes/interest/the_eye_of_god.py index a6feaa6..3dae2da 100644 --- a/sim_scenes/interest/the_eye_of_god.py +++ b/sim_scenes/interest/the_eye_of_god.py @@ -19,14 +19,14 @@ def show_eye_of_god(): """ D = 6000 # camera_pos = 左-右+、上+下-、前+后- - camera_pos = (-100 * D, 0, -6000 * D) + camera_pos = (D, D, -7000 * D) - bodies: list = gen_bodies_from_image(pixel_image="./images/eye.png", + bodies: list = gen_bodies_from_image(pixel_image="./images/eye.png", texture="color_body.jpg", params={"camera_pos": camera_pos}) - bg = FixedStar(name="bg", texture="fixed_star.png", mass=5e31, color=(0xff, 0xf8, 0xd4), - init_position=[3000 * D, 200 * D, 100 * D], # [ 远+近- , 左+右- , 上+下-] + # 放一个恒星作为背景 + bg = FixedStar(name="bg", texture="fixed_star.png", mass=2e32, color=(0xff, 0xf8, 0xd4), + init_position=[6000 * D, 400 * D, 100 * D], # [ 远+近- , 左+右- , 上+下-] ignore_mass=True) - # bg.light_on = False bodies.append(bg) # 使用 ursina 查看的运行效果 diff --git a/sim_scenes/interest/utils/body_utils.py b/sim_scenes/interest/utils/body_utils.py index a841749..1163f9d 100644 --- a/sim_scenes/interest/utils/body_utils.py +++ b/sim_scenes/interest/utils/body_utils.py @@ -8,10 +8,27 @@ # ============================================================================== from bodies import ColorBody import random - +import math from PIL import Image +def get_scaled_body_pos(camera_pos, body_pos, scale_factor): + # 计算天体和摄像机的距离 + dist = math.sqrt((camera_pos[0] - body_pos[0]) ** 2 + + (camera_pos[1] - body_pos[1]) ** 2 + + (camera_pos[2] - body_pos[2]) ** 2) + # 缩放天体的大小 + scaled_dist = dist * scale_factor + # 计算摄像机和天体的连线向量 + vector = [body_pos[0] - camera_pos[0], body_pos[1] - camera_pos[1], body_pos[2] - camera_pos[2]] + # 计算单位向量 + unit_vector = [vector[0] / dist, vector[1] / dist, vector[2] / dist] + # 根据缩放后的距离和单位向量计算天体的新位置 + new_pos = [camera_pos[0] + unit_vector[0] * scaled_dist, camera_pos[1] + unit_vector[1] * scaled_dist, + camera_pos[2] + unit_vector[2] * scaled_dist] + return new_pos + + def gen_bodies_from_image(pixel_image, params, texture="color_body.png"): """ 根据像素图片以及参数,自动生成星球,注意图片像素不能太多,否则会导致电脑运行太慢 @@ -22,9 +39,14 @@ def gen_bodies_from_image(pixel_image, params, texture="color_body.png"): D = 6000 mass = 0.9e25 + camera_pos = params["camera_pos"] + def get_position(pos, scale): - # [ 远+近- , 左+右- , 上+下-] - return pos[0] + (scale - 1.0) * 300 * (random.randint(90, 110)) * D, pos[1], pos[2] + # return get_scaled_body_pos((camera_pos[2], camera_pos[0], camera_pos[1]), pos, scale) + return get_scaled_body_pos((camera_pos[2], camera_pos[1], camera_pos[0]), pos, scale) + + # # [ 远+近- , 左+右- , 上+下-] + # return pos[0] + (scale - 1.0) * 300 * (random.randint(90, 110)) * D, pos[1], pos[2] # return pos[0], pos[1], pos[2] params["ColorBody"] = ColorBody @@ -49,9 +71,10 @@ def gen_bodies_from_image(pixel_image, params, texture="color_body.png"): # 以图片像素为坐标,每个像素点到中心的距离 distance_to_center = pow(pow(w - width / 2, 2) + pow(h - height / 2, 2), 1 / 2) # 让 body 从中心开始,离摄像机越远, body 的缩放值越大(scale 就越大,) - scale = (distance_to_center / (distance_hw * 10) + 1) # 中心最近 1.0 ~ 1.05 + scale = (distance_to_center / (distance_hw * 1.2) + 1) # 中心最近 1.0 ~ 1.25 + # scale = scale + (random.randint(100, 200) / 1000) # TODO: 队列反向排列(中心最远 1.05 ~ 1.0) - # scale = 1.05 - scale + 1.0 + # scale = 1.25 - scale + 1.0 # print(scale) # 获取像素的颜色 pixel = img.getpixel((w, h)) @@ -66,10 +89,14 @@ def gen_bodies_from_image(pixel_image, params, texture="color_body.png"): return eval(bodies_str, params) -if __name__ == '__main__': - import random - from bodies import Body +def get_scaled_body_pos_test(): + camera_pos = [0, 0, 0] + body_pos = [1, 2, 3] + scale_factor = 2 + print(get_scaled_body_pos(camera_pos, body_pos, scale_factor)) +if __name__ == '__main__': + # get_scaled_body_pos_test() D = 600 mass = 0.9e25 # camera_pos = 左-右+、上+下-、前+后- @@ -79,14 +106,8 @@ if __name__ == '__main__': def get_position(pos, scale): # [ 远+近- , 左+右- , 上+下-] return pos[0] + (scale - 1.0) * 300 * (random.randint(90, 110)) * D, pos[1], pos[2] - # return pos[0], pos[1], pos[2] - bodies: list = gen_bodies_from_image(pixel_image="../images/eye.png", - params={"D": D, - "Body": Body, - "mass": mass, - "get_position": get_position, - "camera_pos": camera_pos}) + params={"camera_pos": camera_pos}) print(bodies) diff --git a/sim_scenes/solar_system/solar_system_2.py b/sim_scenes/solar_system/solar_system_2.py index a3e878f..2404aca 100644 --- a/sim_scenes/solar_system/solar_system_2.py +++ b/sim_scenes/solar_system/solar_system_2.py @@ -44,4 +44,4 @@ if __name__ == '__main__': # 使用 ursina 查看的运行效果 # 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹 # position = 左-右+、上+下-、前+后- - ursina_run(bodies, SECONDS_PER_YEAR, position=(0, 2 * AU, -11 * AU)) + ursina_run(bodies, SECONDS_PER_YEAR, position=(0, 2 * AU, -11 * AU),show_grid=False) diff --git a/simulators/ursina_simulator.py b/simulators/ursina_simulator.py index 25250cd..69e2974 100644 --- a/simulators/ursina_simulator.py +++ b/simulators/ursina_simulator.py @@ -179,81 +179,21 @@ class UrsinaSimulator(Simulator): # position=(0, 0, 0), # rotation=(0, 0, 0)) - # def __add_glow(self, entity, intensity=2, light_color=color.white, attenuation=3): - # """ - # 未用,保留代码 - # :param entity: - # :param intensity: - # :param light_color: - # :param attenuation: - # :return: - # """ - # lights = [] - # import math - # for i in range(5): - # glow_entity = Entity(parent=entity, model='sphere', color=color.rgba(1.0, 0.6, 0.2, 1), - # scale=math.pow(1.03, i), alpha=0.2) - # lights.append(glow_entity) - # # 创建一个新的 Entity 对象,作为光晕的容器 - # # glow_entity = Entity(parent=entity, model='sphere', scale=entity.scale * 1.2) - # # 创建 PointLight 对象,并设置它的属性 - # for i in range(2): - # light = PointLight(parent=lights[0], intensity=intensity, color=light_color, attenuation=attenuation) - # lights.append(light) - # - # # 把 Entity 对象放到星星的后面,使得光晕看起来像是从星星发出来的 - # glow_entity.world_position = entity.world_position - # glow_entity.world_parent = entity.parent - # glow_entity.y += entity.scale_y * 0.1 - # glow_entity.depth_test = False - # return lights - - # def create_fixed_star_lights(self, entity): - # """ - # 创建恒星的发光的效果、并作为灯光源 - # :param entity: - # :return: - # """ - # - # # 如果是恒星(如:太阳),自身会发光,则需要关闭灯光 - # entity.set_light_off() - # - # lights = [] - # # 创建多个新的 Entity 对象,作为光晕的容器 - # for i in range(10): - # glow_entity = Entity(parent=entity, model='sphere', color=color.rgba(1.0, 0.6, 0.2, 1), - # scale=math.pow(1.03, i), alpha=0.1) - # - # lights.append(glow_entity) - # for i in range(2): - # # 创建 PointLight 对象,作为恒星的灯光源 - # light = PointLight(parent=entity, intensity=10, range=10, color=color.white) - # lights.append(light) - # - # # light = DirectionalLight(shadows=True, direction=Vec3(0, 0, 1), color=color.white) - # # light.look_at(Vec3(0, 0, -1)) - # # light = SpotLight(parent=entity,shadows=True, direction=Vec3(1,1,1), color=color.white) - # - # return lights - def run(self, dt, **kwargs): window.title = '宇宙模拟器' + + # 默认非近距离查看 view_closely = False if "view_closely" in kwargs: view_closely = kwargs["view_closely"] if view_closely: + # 近距离查看 # 设置 camera 的裁剪面和位置 camera.clip_plane_near = 0.01 camera.fov = 60 - # 一定要够大,如果小于 Sky(texture=texture).scale = 50000,宇宙背景就会出现黑色方洞 - # camera.clip_plane_far = 100000 - - # camera.position = (0, 10, -20) - # camera.rotation_x = -30 - # interval_fator 能让更新天体运行状态(位置、速度)更精确 # 设定时间间隔为0.01秒 self.interval_fator = 0.01 @@ -263,13 +203,6 @@ class UrsinaSimulator(Simulator): self.interval = datetime.timedelta(seconds=self.interval_fator) self.last_time = datetime.datetime.now() - datetime.timedelta(seconds=2) - if "light" in kwargs: - if kwargs["light"]: - for v in self.ursina_views: - if v.body.is_fixed_star: - # self.lights = self.create_fixed_star_lights(v.planet) - pass - if "show_grid" in kwargs: if kwargs["show_grid"]: WorldGrid() @@ -309,8 +242,8 @@ class UrsinaSimulator(Simulator): bg_music = find_file(bg_music) if bg_music is None: - # bg_music = "../sounds/universe_04.mp3" - bg_music = "../none" + # bg_music = "../sounds/universe_04.mp3" # 默认背景音乐 + bg_music = "../none" # 默认没有背景音乐 if os.path.exists(bg_music): audio = Audio(bg_music, pitch=1, loop=True, autoplay=True) -- GitLab