ursina_view.py 9.5 KB
Newer Older
三月三net's avatar
三月三net 已提交
1 2 3 4 5 6 7 8 9
# -*- coding:utf-8 -*-
# title           :ursina天体视图
# description     :ursina天体视图(天体效果展示用,需要安装 ursina)
# 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
三月三net's avatar
三月三net 已提交
10
from ursina import Ursina, window, Entity, Mesh, SmoothFollow, Texture, clamp, time, \
三月三net's avatar
三月三net 已提交
11
    camera, color, mouse, Vec2, Vec3, Vec4, \
三月三net's avatar
三月三net 已提交
12
    load_texture, held_keys, destroy
M
march3 已提交
13 14

# from ursina.camera import OrthographicCamera
M
march3 已提交
15 16 17 18 19
from math import sin, cos, radians
from ursina.prefabs.first_person_controller import FirstPersonController
import sys
import random as rd
import os
三月三net's avatar
三月三net 已提交
20 21
from bodies import Body
import random
三月三net's avatar
三月三net 已提交
22

三月三net's avatar
三月三net 已提交
23
from common.color_utils import adjust_brightness, to_vec4_color
三月三net's avatar
三月三net 已提交
24
from simulators.views.body_view import BodyView
三月三net's avatar
三月三net 已提交
25
from simulators.views.ursina_mesh import create_sphere, create_torus, create_body_torus
三月三net's avatar
三月三net 已提交
26
import numpy as np
M
march3 已提交
27
import math
三月三net's avatar
三月三net 已提交
28

三月三net's avatar
三月三net 已提交
29
SCALE_FACTOR = 5e-10
三月三net's avatar
三月三net 已提交
30 31
# 旋转因子为1,则为正常的转速
ROTATION_SPEED_FACTOR = 1.0
三月三net's avatar
三月三net 已提交
32
ROTATION_SPEED_FACTOR = 0.01
M
march3 已提交
33 34


三月三net's avatar
三月三net 已提交
35 36
class UrsinaPlayer(FirstPersonController):
    """
M
march3 已提交
37

三月三net's avatar
三月三net 已提交
38
    """
三月三net's avatar
三月三net 已提交
39 40
    body_rotation_speed_control = 1.0

M
march3 已提交
41
    def __init__(self, position, targets=None):
M
march3 已提交
42
        super().__init__()
三月三net's avatar
三月三net 已提交
43 44
        # camera.fov = 2000 # 100
        # camera.rotation_y = 90
M
march3 已提交
45
        self.planets = None
M
march3 已提交
46
        if targets is not None:
M
march3 已提交
47
            self.planets = []
M
march3 已提交
48
            # targets = [view.planet.parent for view in targets]
M
march3 已提交
49
            # targets_parent = Entity()
M
march3 已提交
50
            for view in targets:
M
march3 已提交
51 52 53 54 55 56
                # view.planet.parent = targets_parent
                self.planets.append(view.planet)
            # self.camera_adj(planets)
            #     # planets.append(view.planet)
            #
            # camera.add_script(SmoothFollow(targets_parent, offset=(0, 8, -20)))
M
march3 已提交
57
        pos = np.array(position) * SCALE_FACTOR
三月三net's avatar
三月三net 已提交
58
        # self.position = Vec3(pos[0], pos[1], pos[2])
M
march3 已提交
59
        # 将摄像机位置设置为 x=0、y=1、z=0 的位置
三月三net's avatar
三月三net 已提交
60
        camera.position = Vec3(pos[0], pos[1], pos[2])
三月三net's avatar
三月三net 已提交
61
        # self.position = Vec3(pos[0], pos[1], pos[2])
M
march3 已提交
62
        # 将摄像机的观察角度绕 x 轴旋转 45 度,绕 y 轴旋转 0 度,绕 z 轴旋转 0 度
三月三net's avatar
三月三net 已提交
63 64
        # camera.rotation = Vec3(45, 90, 0)
        camera.rotation = Vec3(0, 0, 0)
M
march3 已提交
65

三月三net's avatar
三月三net 已提交
66 67 68 69
        # self.gravity = 0
        # self.vspeed = 400
        # self.speed = 1000
        # self.mouse_sensitivity = Vec2(160, 160)
M
march3 已提交
70
        self.on_enable()
三月三net's avatar
三月三net 已提交
71
        # self.rotation_speed = 80
M
march3 已提交
72

M
march3 已提交
73 74 75 76 77 78
    def input(self, key):
        if key == "escape":
            if mouse.locked:
                self.on_disable()
            else:
                sys.exit()
M
march3 已提交
79
        return super().input(key)
M
march3 已提交
80

三月三net's avatar
三月三net 已提交
81 82

class Planet(Entity):
M
march3 已提交
83 84
    def __init__(self, body_view: BodyView):
        self.body_view = body_view
三月三net's avatar
三月三net 已提交
85
        self.rotation_speed = self.body_view.body.rotation_speed
M
march3 已提交
86 87 88
        self.rotMode = 'x'  # random.choice(["x", "y", "z"])
        self.name = body_view.name

三月三net's avatar
三月三net 已提交
89 90 91
        self.trails = {}
        self.trail_len = 100

三月三net's avatar
三月三net 已提交
92 93 94
        # 根据天体的颜色获取拖尾的颜色
        trail_color = to_vec4_color(self.body_view.body.color)
        trail_color = adjust_brightness(trail_color, 0.4)
三月三net's avatar
三月三net 已提交
95
        self.trail_color = color.rgba(trail_color[0], trail_color[1], trail_color[2], 0.6)
三月三net's avatar
三月三net 已提交
96

M
march3 已提交
97
        pos = body_view.position * body_view.body.distance_scale * SCALE_FACTOR
M
march3 已提交
98 99
        scale = body_view.body.diameter * body_view.body.size_scale * SCALE_FACTOR

三月三net's avatar
三月三net 已提交
100
        subdivisions = 32  # int(scale*20)
三月三net's avatar
三月三net 已提交
101

三月三net's avatar
三月三net 已提交
102
        if hasattr(body_view, "texture"):
三月三net's avatar
三月三net 已提交
103 104 105
            texture = load_texture(body_view.texture)
        else:
            texture = None
M
march3 已提交
106

三月三net's avatar
三月三net 已提交
107
        if hasattr(self.body_view.body, "torus_stars"):
三月三net's avatar
三月三net 已提交
108
            model = create_torus(0.86, 1.02, 64, 4)
三月三net's avatar
三月三net 已提交
109 110 111 112 113
            rotation = (90, 0, 0)
        else:
            model = create_sphere(0.5, subdivisions)
            rotation = (0, 0, 0)

三月三net's avatar
三月三net 已提交
114
        super().__init__(
三月三net's avatar
三月三net 已提交
115
            # model="sphere",
三月三net's avatar
三月三net 已提交
116
            model=model,
三月三net's avatar
三月三net 已提交
117 118 119 120
            scale=scale,
            texture=texture,
            color=color.white,
            position=pos,
三月三net's avatar
三月三net 已提交
121
            rotation=rotation,
三月三net's avatar
三月三net 已提交
122
            double_sided=True)
三月三net's avatar
三月三net 已提交
123

三月三net's avatar
三月三net 已提交
124 125
        if hasattr(self.body_view.body, "torus_stars"):
            # 非一个天体,星环(主要模拟小行星群)
三月三net's avatar
三月三net 已提交
126
            self.set_light_off()
三月三net's avatar
三月三net 已提交
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
        else:
            # 一个天体
            # 拖尾球体的大小为该天体的 1/5
            self.trail_scale = scale / 5
            if self.trail_scale < 1:
                # 如果太小,则
                pass

    def distance_between_two_points(self, point_a: Vec3, point_b: Vec3) -> float:
        # 计算两点在 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(self):
        pos = self.position
        trails_keys = self.trails.keys()
        if len(trails_keys) > 0:
            last_key = list(trails_keys)[-1]
            last_pos = self.trails[last_key]
            distance = self.distance_between_two_points(pos, last_pos)
            if distance < self.trail_scale * 1.2:
                return

        self.trails[self.create_trail(pos)] = pos
        trail_more = len(self.trails) - self.trail_len
        if trail_more > 0:
            for entity, pos in self.trails.items():
                # entity.visible = False
                # entity.disable()
                # del entity
                destroy(entity)
                trail_more -= 1
                if trail_more <= 0:
三月三net's avatar
三月三net 已提交
166 167
                    break

三月三net's avatar
三月三net 已提交
168 169
    def create_trail(self, pos):
        # pos = pos * SCALE_FACTOR
三月三net's avatar
三月三net 已提交
170
        # sphere = create_sphere(0.5, 10)
三月三net's avatar
三月三net 已提交
171 172 173 174 175 176
        trail = Entity(model="sphere", color=self.trail_color, scale=self.trail_scale, position=pos)  # ,
        # trail.x = pos[0]
        # trail.y = pos[1]
        # trail.z = pos[2]
        trail.set_light_off()
        return trail
三月三net's avatar
三月三net 已提交
177

M
march3 已提交
178
    def turn(self):
M
march3 已提交
179
        pos = self.body_view.position * SCALE_FACTOR
三月三net's avatar
三月三net 已提交
180

M
march3 已提交
181 182 183
        self.x = -pos[1]
        self.y = pos[2]
        self.z = pos[0]
M
march3 已提交
184

三月三net's avatar
三月三net 已提交
185 186 187 188 189 190 191 192
        dt = 0
        if hasattr(self.body_view.body, "dt"):
            dt = self.body_view.body.dt
        if self.rotation_speed is None or dt == 0:
            self.rotspeed = 0
            # 旋转速度和大小成反比(未使用真实数据)
            # self.rotspeed = 30000 / self.body_view.raduis  # random.uniform(1.0, 2.0)
        else:
三月三net's avatar
三月三net 已提交
193
            # 是通过月球保持一面面对地球,调整得到
三月三net's avatar
三月三net 已提交
194
            self.rotspeed = self.rotation_speed * (dt / 3600) / 2.4 * ROTATION_SPEED_FACTOR  # / 60 / 24
三月三net's avatar
三月三net 已提交
195 196
            # rotation_speed 度/小时  dt 秒 = (dt / 3600)小时

M
march3 已提交
197
        self.rotation_y -= self.rotspeed
M
march3 已提交
198

三月三net's avatar
三月三net 已提交
199 200 201 202 203 204 205
        # 有时候第一个位置不正确,所以判断一下有历史记录后在创建
        if len(self.body_view.body.his_position()) > 1:
            self.create_trails()
        # self.animate_position(Vec2(2, 0), duration=1)
        # from  ursina import Trail
        # 给实体添加拖尾效果
        # trail = Trail(self)
三月三net's avatar
三月三net 已提交
206

三月三net's avatar
三月三net 已提交
207 208 209
    # def input(self, key):
    #     if key == "enter":
    #         self.fastMode = 1 - self.fastMode
三月三net's avatar
三月三net 已提交
210 211 212 213 214 215 216 217 218


class UrsinaView(BodyView):
    """
    ursina天体视图(天体效果展示用)
    """

    def __init__(self, body: Body):
        BodyView.__init__(self, body)
M
march3 已提交
219 220
        self.velocity = body.velocity

M
march3 已提交
221
        self.planet = Planet(self)
M
march3 已提交
222 223 224
        if body.has_rings:
            self.create_rings()

三月三net's avatar
三月三net 已提交
225 226 227 228 229 230 231 232 233 234 235 236 237 238
    #     self.create_glow()
    #
    # def create_glow(self):
    #     # self.body.color
    #     # for i in range(1):
    #     b_color = self.body.color
    #     color = Vec4(b_color[0], b_color[1], b_color[2], 0.2)
    #         # glow_entity = Entity(parent=self.planet, model='sphere', color=color,
    #         #                      scale=math.pow(1.2, i), alpha=0.2)
    #
    #     glow_entity = Entity(parent=self.planet, model='sphere', color=color,
    #                          scale=1.01, alpha=0.1)
    #     glow_entity.set_light_off()

M
march3 已提交
239
    def create_rings(self):
三月三net's avatar
三月三net 已提交
240
        """
三月三net's avatar
三月三net 已提交
241
        创建行星环(使用土星贴图)
三月三net's avatar
三月三net 已提交
242 243
        :return:
        """
三月三net's avatar
三月三net 已提交
244
        # 行星环偏移角度
三月三net's avatar
三月三net 已提交
245
        # self.ring_rotation_x = 80
三月三net's avatar
三月三net 已提交
246
        # 创建行星环
三月三net's avatar
三月三net 已提交
247 248 249
        # self.ring = Entity(parent=self.planet, model='circle', texture='../textures/saturnRings.jpg', scale=3.5,
        #                    rotation=(self.ring_rotation_x, 0, 0), double_sided=True)

三月三net's avatar
三月三net 已提交
250
        # 行星环偏移角度
三月三net's avatar
三月三net 已提交
251
        self.ring_rotation_x = 80
三月三net's avatar
三月三net 已提交
252
        # 创建行星环
三月三net's avatar
三月三net 已提交
253
        torus = create_torus(0.7, 1.2, 64)
三月三net's avatar
三月三net 已提交
254
        self.ring = Entity(parent=self.planet, model=torus, texture='../textures/saturnRings.jpg', scale=1,
三月三net's avatar
三月三net 已提交
255 256 257
                           rotation=(self.ring_rotation_x, 0, 0), double_sided=True)

        # 设置行星环不受灯光影响,否则看不清行星环
三月三net's avatar
三月三net 已提交
258
        self.ring.set_light_off()
三月三net's avatar
三月三net 已提交
259 260

    def update(self):
三月三net's avatar
三月三net 已提交
261
        """
三月三net's avatar
三月三net 已提交
262

三月三net's avatar
三月三net 已提交
263 264 265 266
        :return:
        """
        self.planet.turn()
        # 如果有行星环
三月三net's avatar
三月三net 已提交
267
        if hasattr(self, "ring"):
三月三net's avatar
三月三net 已提交
268 269 270 271
            # 如果有行星环,则不让行星环跟随行星转动
            self.ring.rotation = -Vec3(self.planet.rotation_x - self.ring_rotation_x,
                                       self.planet.rotation_y,
                                       self.planet.rotation_z)
三月三net's avatar
三月三net 已提交
272 273 274 275 276

    def appear(self):
        pass

    def disappear(self):
三月三net's avatar
三月三net 已提交
277 278
        destroy(self.planet)
        # self.planet.disable()