ursina_view.py 10.8 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
M
march3 已提交
10 11 12 13
from ursina import Ursina, window, Entity, Mesh, SmoothFollow, Texture, clamp, time, camera, color, mouse, Vec2, Vec3, \
    load_texture, held_keys

# from ursina.camera import OrthographicCamera
M
march3 已提交
14 15 16 17 18
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 已提交
19 20 21 22
from bodies import Body
import random
from simulators.views.body_view import BodyView
import numpy as np
M
march3 已提交
23
import math
三月三net's avatar
三月三net 已提交
24 25
from math import sin, cos, radians
import os
M
march3 已提交
26
import matplotlib.pyplot as plt
三月三net's avatar
三月三net 已提交
27

M
march3 已提交
28
SCALE_FACTOR = 1e-7
M
march3 已提交
29 30


M
march3 已提交
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
# 创建 TorusMesh
class TorusMesh(Mesh):
    def __init__(self, radius=1, thickness=.25, radial_segments=16, tubular_segments=32):
        super().__init__()
        self.radius = radius
        self.thickness = thickness
        self.radial_segments = radial_segments
        self.tubular_segments = tubular_segments
        self.vertices = []
        self.triangles = []

        for j in range(radial_segments):
            for i in range(tubular_segments):
                a = i / tubular_segments * math.pi * 2
                b = j / radial_segments * math.pi * 2
                x = (radius + thickness * math.cos(b)) * math.cos(a)
                y = (radius + thickness * math.cos(b)) * math.sin(a)
                z = thickness * math.sin(b)
                u = i / tubular_segments
                v = j / radial_segments
                self.vertices.append((x, y, z))
                self.uvs.append((u, v))

        for j in range(radial_segments):
            for i in range(tubular_segments):
                a = i
                b = j
                c = (i + 1) % tubular_segments
                d = (j + 1) % radial_segments
                self.triangles.append((a + b * tubular_segments, b + d * tubular_segments, c + b * tubular_segments))
                self.triangles.append((c + b * tubular_segments, b + d * tubular_segments, c + d * tubular_segments))


M
march3 已提交
64
class UrsinaPlayer(FirstPersonController):
M
march3 已提交
65
    def __init__(self, position, targets=None):
M
march3 已提交
66 67 68 69
        # global planets
        super().__init__()
        # pos = planets[0].position
        camera.fov = 100
M
march3 已提交
70 71
        camera.rotation_y = 90
        self.planets = None
M
march3 已提交
72
        if targets is not None:
M
march3 已提交
73
            self.planets = []
M
march3 已提交
74
            # targets = [view.planet.parent for view in targets]
M
march3 已提交
75
            # targets_parent = Entity()
M
march3 已提交
76
            for view in targets:
M
march3 已提交
77 78 79 80 81 82
                # 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 已提交
83 84
        pos = np.array(position) * SCALE_FACTOR
        self.position = Vec3(pos[0], pos[1], pos[2])
M
march3 已提交
85 86 87 88 89 90
        # 将摄像机位置设置为 x=0、y=1、z=0 的位置
        # camera.position = Vec3(pos[0], pos[1], pos[2])
        self.position = Vec3(pos[0], pos[1], pos[2])
        # 将摄像机的观察角度绕 x 轴旋转 45 度,绕 y 轴旋转 0 度,绕 z 轴旋转 0 度
        camera.rotation = Vec3(45, 90, 0)

M
march3 已提交
91
        self.gravity = 0
M
march3 已提交
92 93
        self.vspeed = 400
        self.speed = 1000
M
march3 已提交
94 95
        self.mouse_sensitivity = Vec2(160, 160)
        self.on_enable()
M
march3 已提交
96 97
        self.rotation_speed = 80

M
march3 已提交
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
    # def space_callback(self):
    #     best_camera_position = self.best_camera_position()
    #     if best_camera_position is None:
    #         return
    #     best_pos = np.array(best_camera_position[0]) * SCALE_FACTOR
    #     camera.position, camera.rotation = best_pos, best_camera_position[1]
    #
    # def best_camera_position(self):
    #     if self.planets is None:
    #         return None
    #
    #     min_x, max_x, min_y, max_y, min_z, max_z = None, None, None, None, None, None
    #     for planet in self.planets:
    #         if min_x is None or planet.x < min_x:
    #             min_x = planet.x
    #         if max_x is None or planet.x > max_x:
    #             max_x = planet.x
    #         if min_y is None or planet.y < min_y:
    #             min_y = planet.y
    #         if max_y is None or planet.y > max_y:
    #             max_y = planet.y
    #         if min_z is None or planet.z < min_z:
    #             min_z = planet.z
    #         if max_z is None or planet.z > max_z:
    #             max_z = planet.z
    #     x = (min_x + max_x) / 2
    #     y = (min_y + max_y) / 2
    #     z = (min_z + max_z) / 2
    #     distance = max(max_x - min_x, max_y - min_y, max_z - min_z) * 1.5
    #     return (x, y + distance, z - distance), (0, -90, 0)
M
march3 已提交
128 129 130 131 132 133 134 135 136 137 138 139 140 141

    # def camera_adj(self, targets):
    #     # 创建一些物体
    #     # targets = []
    #     # for i in range(10):
    #     #     targets.append(Entity(model='cube', color=color.random_color(), position=(i * 2 - 10, i % 2 * 2 - 1, 0)))
    #
    #     # 计算所有物体的平均位置
    #     avg_pos = sum(np.array([target.position for target in targets]))/ len(targets)
    #
    #     # 创建一个OrthographicCamera,使其位于所有目标的中心位置,并面向下方
    #     # camera = OrthographicCamera()
    #     camera.position = avg_pos + (0, 0, 20)
    #     camera.rotation_x = -90
M
march3 已提交
142

M
march3 已提交
143 144


M
march3 已提交
145 146 147 148 149 150
    def input(self, key):
        if key == "escape":
            if mouse.locked:
                self.on_disable()
            else:
                sys.exit()
M
march3 已提交
151
        return super().input(key)
M
march3 已提交
152 153 154
        # elif key == "space":
        #     self.space_callback()
        # Input.bind('space', space_callback)
M
march3 已提交
155

M
march3 已提交
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
    # def _update(self):
    #     # # {'left mouse': 0, 'left': 0, 'left shift': 0, 'space': 1, 'w': 0, 's': 0, 'd': 0, 'a': 0, 'shift': 0})
    #     # if held_keys["left mouse"]:
    #     #     self.on_enable()
    #     # if held_keys["left shift"]:
    #     #     self.y -= self.vspeed
    #     # if held_keys["space"]:
    #     #     self.y += self.vspeed
    #     # WASD keys
    #
    #     if held_keys['f']:
    #         camera.fov += 1
    #     if held_keys['r']:
    #         camera.fov -= 1
    #     # camera.position
    #     # self.rotation_y += held_keys['d'] * self.rotation_speed * time.dt
    #     # self.rotation_y -= held_keys['a'] * self.rotation_speed * time.dt
    #     # self.rotation_x += held_keys['w'] * self.rotation_speed * time.dt
    #     # self.rotation_x -= held_keys['s'] * self.rotation_speed * time.dt
    #
    #     forward = self.forward * (held_keys['w'] - held_keys['s'])
    #     right = self.right * (held_keys['d'] - held_keys['a'])
    #
    #     self.position += (forward + right) * self.speed * time.dt
    #     # if held_keys['w']:
    #     #     camera.position += camera.forward * time.dt
    #     # if held_keys['s']:
    #     #     camera.position -= camera.forward * time.dt
    #     # if held_keys['a']:
    #     #     camera.position -= camera.right * time.dt
    #     # if held_keys['d']:
    #     #     camera.position += camera.right * time.dt
    #     #
    #     # # Mouse control
    #     # camera.rotation_y += held_keys['right mouse'] * mouse.velocity[0] * 20
    #     # camera.rotation_x -= held_keys['right mouse'] * mouse.velocity[1] * 20
    #     # camera.rotation_x = clamp(camera.rotation_x, -90, 90)
M
march3 已提交
193

三月三net's avatar
三月三net 已提交
194 195

class Planet(Entity):
M
march3 已提交
196 197
    def __init__(self, body_view: BodyView):
        self.body_view = body_view
M
march3 已提交
198 199 200
        # self.angle = 0  # random.uniform(0.0005, 0.01)
        # self.fastMode = 0
        # self.rotation = (random.randint(0, 360) for i in range(3))
三月三net's avatar
三月三net 已提交
201
        self.rotspeed = random.uniform(0.25, 1.5)
M
march3 已提交
202 203 204
        self.rotMode = 'x'  # random.choice(["x", "y", "z"])
        self.name = body_view.name

M
march3 已提交
205
        pos = body_view.position * body_view.body.distance_scale * SCALE_FACTOR
M
march3 已提交
206 207
        scale = body_view.body.diameter * body_view.body.size_scale * SCALE_FACTOR

三月三net's avatar
三月三net 已提交
208 209
        # texture = eval(f"{_type}_texture")
        # e = os.path.exists(texture)
M
march3 已提交
210
        # texture = self.__set_texture(body_view.texture)
M
march3 已提交
211
        texture = load_texture(body_view.texture)
M
march3 已提交
212 213

        # 将贴图旋转90度
三月三net's avatar
三月三net 已提交
214 215 216 217
        super().__init__(model="sphere",
                         scale=scale,
                         texture=texture,
                         color=color.white,
M
march3 已提交
218 219
                         position=pos,
                         rotation=(0, 0, 0))
三月三net's avatar
三月三net 已提交
220

M
march3 已提交
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
    # def __set_texture(self, image_file):
    #     """
    #     设置纹理图片到天体
    #     :param image_file:
    #     :return:
    #     """
    #     outfile = image_file.replace('.png', '_rotate.png').replace('.jpg', '_rotate.jpg')
    #     from PIL import Image
    #     # 打开原始图片
    #     image = Image.open(image_file)
    #     # 顺时针旋转90度
    #     rotated_image = image.rotate(90, expand=True)
    #
    #     # 保存旋转后的图片
    #     rotated_image.save(outfile)
    #
    #     return outfile

    def turn(self):
M
march3 已提交
240 241 242 243 244
        # if self.name != "sun":
        #     if self.fastMode:
        #         angle *= 200
        # self.x = self.x * cos(radians(angle)) - self.y * sin(radians(angle))
        # self.y = self.x * sin(radians(angle)) + self.y * cos(radians(angle))
M
march3 已提交
245
        pos = self.body_view.position * SCALE_FACTOR
三月三net's avatar
三月三net 已提交
246

M
march3 已提交
247 248 249
        self.x = -pos[1]
        self.y = pos[2]
        self.z = pos[0]
M
march3 已提交
250

M
march3 已提交
251
        self.rotation_y -= self.rotspeed
M
march3 已提交
252

三月三net's avatar
三月三net 已提交
253 254 255 256 257 258 259 260 261 262 263 264
    def input(self, key):
        if key == "enter":
            self.fastMode = 1 - self.fastMode


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

    def __init__(self, body: Body):
        BodyView.__init__(self, body)
M
march3 已提交
265 266 267 268 269 270 271 272 273
        self.velocity = body.velocity
        # 将列表元素往后移动一位,最后一位变为第一位
        # a1 = a[1:] + [a[0]]
        # self.velocity = np.concatenate((body.velocity[1:], [body.velocity[0]]))

        # 将列表元素往前移动一位,第一位变为最后一位
        # a2 = [a[-1]] + a[:-1]
        # self.velocity = np.concatenate((np.array([body.velocity[-1]]), body.velocity[0:2]))

M
march3 已提交
274
        self.planet = Planet(self)
M
march3 已提交
275 276 277 278 279 280 281 282 283
        if body.has_rings:
            self.create_rings()

    def create_rings(self):
        ring = Entity(model='torus', texture='textures/saturnRings.jpg', scale=(4, 4), double_sided=True)

        # ring = Entity(model=TorusMesh(radius=self.body.diameter * 100, thickness=.5), texture='textures/saturnRings.jpg', scale=3)
        ring.world_parent = self.planet
        ring.position = self.planet.position
三月三net's avatar
三月三net 已提交
284 285

    def update(self):
M
march3 已提交
286
        self.planet.turn()
三月三net's avatar
三月三net 已提交
287 288 289 290 291

    def appear(self):
        pass

    def disappear(self):
M
march3 已提交
292
        self.planet.disable()