# -*- coding:utf-8 -*- # title :ursina entity 工具 # description :ursina entity 工具 # author :Python超人 # date :2023-02-11 # link :https://gitcode.net/pythoncr/ # python_version :3.8 # ============================================================================== # pip install -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com ursina from ursina import Ursina, window, Entity, Mesh, SmoothFollow, Texture, clamp, time, \ camera, color, mouse, Vec2, Vec3, Vec4, Text, \ load_texture, held_keys, destroy, PointLight, DirectionalLight, distance from simulators.ursina.entities.body_trail import BodyTrail, BodyTrailLine from simulators.ursina.ursina_config import UrsinaConfig from common.color_utils import adjust_brightness, conv_to_vec4_color, get_inverse_color from simulators.ursina.ursina_mesh import create_torus from common.func import find_file import math import numpy as np def create_name_text(parent): """ @param parent: @return: """ text_color = parent.body.text_color b_color = parent.body_view.color name_text = Text(parent.body_view.body.name, scale=1, billboard=True, parent=parent, font=UrsinaConfig.CN_FONT, background=True, origin=(0, 0)) name_text.background.color = color.rgba(b_color[0], b_color[1], b_color[2], 0.3) name_text.resolution = 24 # parent.name_text.scale = parent.scale if text_color is None: text_color = get_inverse_color(b_color) else: text_color = (text_color[0] / 255, text_color[1] / 255, text_color[2] / 255) name_text.set_light_off() name_text.color = color.rgba(text_color[0], text_color[1], text_color[2], 1) parent.name_text = name_text parent.body.name_text = name_text return name_text def trail_init(parent, scale): """ 拖尾球体的初始化 @return: """ # 存放拖尾球体 parent.trails = {} # 根据天体的颜色获取拖尾的颜色 trail_color = conv_to_vec4_color(parent.body_view.body.trail_color) trail_color = adjust_brightness(trail_color, 0.4) parent.trail_color = color.rgba(trail_color[0], trail_color[1], trail_color[2], 0.6) if hasattr(parent.body, "trail_scale_factor"): if parent.body.trail_scale_factor is not None: parent.trail_scale = parent.body.trail_scale_factor * scale else: # 拖尾球体的大小为该天体的 1/5 parent.trail_scale = scale / 5 else: # 拖尾球体的大小为该天体的 1/5 parent.trail_scale = scale / 5 if parent.trail_scale < 1: # 如果太小,则 pass def distance_between_two_points(point_a: Vec3, point_b: Vec3) -> float: """ @param point_a: @param point_b: @return: """ # 计算两点在 x、y、z 三个坐标轴上的差值 diff_x = point_a.x - point_b.x diff_y = point_a.y - point_b.y diff_z = point_a.z - point_b.z # 计算两点之间的距离 distance = math.sqrt(diff_x ** 2 + diff_y ** 2 + diff_z ** 2) return distance def create_trails(parent): """ 创建拖尾 @return: """ # 当前天体的位置 try: pos = parent.position except Exception as e: print(parent.body_view.body) if not hasattr(parent, "destroy_all"): parent.destroy_all() return if not hasattr(parent, "trails"): return trails_keys = parent.trails.keys() trail_int_scale = 1.2 # 如果有拖尾 if len(trails_keys) > 0: # 获取最后一个拖尾的位置 last_key = list(trails_keys)[-1] last_pos = parent.trails[last_key] # 获取拖尾与当前天体的位置 last_pos_distance = distance_between_two_points(pos, last_pos) self_pos_distance = distance_between_two_points(pos, parent.position) # # 如果拖尾在天体的内部也不要生成 # if self_pos_distance < self.scale_x + (self.trail_scale / 2): # pass if UrsinaConfig.trail_type == "curve_line": # 如果位置比较近,就不创建拖尾了,保证拖尾间隔一定的距离 # if last_pos_distance < parent.trail_scale * trail_int_scale / 5: if last_pos_distance < 10: return else: # 如果位置比较近,就不创建拖尾了,保证拖尾间隔一定的距离 # 间隔距离不小于1.2倍的拖尾球体 if last_pos_distance < parent.trail_scale * trail_int_scale * UrsinaConfig.trail_factor: return if UrsinaConfig.trail_type == "line": trail = create_trail_line(parent, pos) # 拖尾为线条 elif UrsinaConfig.trail_type == "curve_line": trail = create_trail_curve_line(parent, pos) # 拖尾为曲线条 else: trail = create_trail_sphere(parent, pos) # 拖尾为球体 if trail is not None: create_trail_info(parent.body, trail) # 创建拖尾球体,并作为字典的key,存放拖尾球体的位置 parent.trails[trail] = pos # 计算拖尾球体超过的数量 trail_overflow_count = len(parent.trails) - UrsinaConfig.trail_length if trail_overflow_count > 0: # 如果拖尾球体超过的数量,就删除之前的拖尾球体 for entity, pos in parent.trails.items(): destroy(entity) trail_overflow_count -= 1 if trail_overflow_count <= 0: break def create_trail_sphere(parent, pos): """ 在天体当前的位置创建一个拖尾球体 @param pos: @return: """ # sphere = create_sphere(1,6) diamond sphere trail = BodyTrail(color=parent.trail_color, scale=parent.trail_scale * UrsinaConfig.trail_factor, position=pos) # trail.set_color_off() # trail.set_color_scale_off() # trail.enabled = False return trail # def merge_vectors(vectors): # # 计算速度的大小 # x, y, z = vectors[0], vectors[1], vectors[2] # value = math.sqrt(x ** 2 + y ** 2 + z ** 2) # # 计算速度的方向 # direction = (x / value, y / value, z / value) # # 返回速度大小和速度方向 # return value, direction def create_directional_light(position, target=None, shadows=False, light_num=1, light_color=None): """ 创建平行光(DirectionalLight) @param position: 光源位置 @param target: 光源指向目标 @param shadows: 是否支持阴影 @param light_color: 光的颜色 @return: """ from ursina.shaders import lit_with_shadows_shader from ursina import Vec2, Vec4, Entity # shader = lit_with_shadows_shader # shader.default_input = { # 'texture_scale': Vec2(1, 1), # 'texture_offset': Vec2(0, 0), # 'shadow_color': Vec4(0.1, 0.1, 0.1, .5), # } # Entity.default_shader = shader if shadows: Entity.default_shader = lit_with_shadows_shader if light_color is None: light_color = color.white else: light_color = color.rgba(light_color[0] / 255, light_color[1] / 255, light_color[2] / 255, 1) lights = [] for i in range(light_num): light = DirectionalLight(position=position, intensity=10, range=10, color=light_color) lights.append(light) if shadows: for light in lights: light.shadows = lit_with_shadows_shader if target is not None: for light in lights: if hasattr(target, "planet"): if hasattr(target.planet, "main_entity"): light.look_at(target.planet.main_entity) else: light.look_at(target.planet) else: light.look_at(target) if shadows: return lit_with_shadows_shader else: return None def create_trail_line(parent, pos): """ 在天体当前的位置创建一个拖尾球体 @param pos: @return: """ trail = None if hasattr(parent, "trail_last_pos"): trail_last_pos = parent.trail_last_pos if distance(pos, trail_last_pos) > 0: value, direction = get_value_direction_vectors(pos - trail_last_pos) trail = BodyTrailLine(color=parent.trail_color, scale=parent.trail_scale * UrsinaConfig.trail_factor, thickness=UrsinaConfig.trail_thickness_factor, position=trail_last_pos, direction=Vec3(direction)) trail.set_light_off() parent.last_trail = trail parent.trail_last_pos = pos return trail def create_trail_curve_line(parent, pos): """ 在天体当前的位置创建一个拖尾曲线 @param pos: @return: """ trail = None if hasattr(parent, "trail_last_pos"): trail_last_pos = parent.trail_last_pos if distance(pos, trail_last_pos) > 0: trail = Entity(model=Mesh( vertices=((pos[0], pos[1], pos[2]), (trail_last_pos[0], trail_last_pos[1], trail_last_pos[2])), mode='line', thickness=UrsinaConfig.trail_thickness_factor), color=parent.trail_color, alpha=0.5) trail.set_light_off() parent.last_trail = trail parent.trail_last_pos = pos return trail def create_rings(parent): """ 创建行星环(使用土星贴图) @return: """ rings_texture = 'textures/saturnRings.jpg' rings_texture = find_file(rings_texture) # 行星环偏移角度 # parent.ring_rotation_x = 80 # 创建行星环 # parent.ring = Entity(parent=parent.planet, model='circle', texture=rings_texture, scale=3.5, # rotation=(parent.ring_rotation_x, 0, 0), double_sided=True) # 行星环偏移角度 parent.ring_rotation_x = 80 # 创建行星环 torus = create_torus(0.7, 1.2, 64) parent.ring = Entity(parent=parent, model=torus, texture=rings_texture, scale=1, rotation=(parent.ring_rotation_x, 0, 0), double_sided=True) # 设置行星环不受灯光影响,否则看不清行星环 parent.ring.set_light_off() return parent.ring def clear_trails(parent): """ @param parent: @return: """ if not hasattr(parent, "trails"): return # 删除拖尾 for entity, pos in parent.trails.items(): destroy(entity) parent.trails.clear() def create_fixed_star_lights(fixed_star): """ 创建恒星的发光的效果、并作为灯光源 @param entity: @return: """ # 如果是恒星(如:太阳),自身会发光,则需要关闭灯光 fixed_star.set_light_off() # lights = [] # # 创建多个新的 Entity 对象,作为光晕的容器 # _color = color.rgba(1.0, 0.6, 0.2, 1) 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 if glows is not None: if isinstance(glows, tuple): if len(glows) == 3: glow_num, glow_scale, glow_alpha = glows elif len(glows) == 2: glow_num, glow_scale = glows glow_alpha = None else: glow_num = glows glow_scale = 1.02 glow_alpha = None if glow_num > 0: glow_alphas = [0, 0.5, 0.4, 0.3, 0.2, 0.1] if glow_alpha is None: if glow_num < len(glow_alphas) - 1: glow_alpha = glow_alphas[glow_num] else: glow_alpha = glow_alphas[-1] # _color = color.white _color = fixed_star.body_view.body.color _color = color.rgba(_color[0] / 255, _color[1] / 255, _color[2] / 255, 1) for i in range(glow_num): glow_entity = Entity(parent=fixed_star, model='sphere', color=_color, scale=math.pow(glow_scale, i + 1), alpha=glow_alpha) if hasattr(fixed_star.body_view.body, "light_on"): if fixed_star.body_view.body.light_on: for i in range(2): # 创建 PointLight 对象,作为恒星的灯光源 light = PointLight(parent=fixed_star, # model="sphere", scale=10, intensity=10, range=10, color=color.white) def get_value_direction_vectors(vectors): # 计算速度的大小 x, y, z = vectors[0], vectors[1], vectors[2] value = math.sqrt(x ** 2 + y ** 2 + z ** 2) # 计算速度的方向 direction = (x / value, y / value, z / value) # 返回速度大小和速度方向 return value, direction # return value, (direction[1], direction[0], direction[2]) # return value, (direction[1], direction[2], direction[0]) # return value, (-direction[1], direction[2], direction[0]) def create_trail_info(body, trail): velocity = get_value_direction_vectors(body.velocity) acceleration = get_value_direction_vectors(body.acceleration) vel_value = velocity[0] # km/s acc_value = acceleration[0] # km/s² vel_direction = velocity[1] vel_direction = np.array(vel_direction) * 5 acc_direction = acceleration[1] acc_direction = np.array(acc_direction) * 2 vel_position = vel_direction # vel_position = (vel_position[0], vel_position[1], vel_position[2]) acc_position = acc_direction # acc_position = (acc_position[0], acc_position[1], acc_position[2]) if trail is not None: trail.entity_infos = {"velocity": [vel_value, vel_direction, vel_position], "acceleration": [acc_value, acc_direction, acc_position]}