From d08eecb4c432f8969118b00707f90b3b7c499412 Mon Sep 17 00:00:00 2001 From: march3 Date: Tue, 14 Mar 2023 21:34:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=AA=E9=98=B3=E7=B3=BB=E4=B8=89=E4=BD=93?= =?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 --- scenes/solar_system_2.py | 2 +- simulators/views/ursina_mesh.py | 210 ++++++++++++++++++++++++++++++++ simulators/views/ursina_view.py | 116 +++++------------- 3 files changed, 244 insertions(+), 84 deletions(-) create mode 100644 simulators/views/ursina_mesh.py diff --git a/scenes/solar_system_2.py b/scenes/solar_system_2.py index 26183e5..4e4f3e0 100644 --- a/scenes/solar_system_2.py +++ b/scenes/solar_system_2.py @@ -38,4 +38,4 @@ if __name__ == '__main__': # mayavi_run(bodies, SECONDS_PER_WEEK, view_azimuth=-45, view_distance=3e9, view_focalpoint=[5e2, 5e2, 5e2]) - ursina_run(bodies, SECONDS_PER_YEAR, position=(0, 0, 0)) \ No newline at end of file + ursina_run(bodies, SECONDS_PER_WEEK, position=(0, 0, 0)) \ No newline at end of file diff --git a/simulators/views/ursina_mesh.py b/simulators/views/ursina_mesh.py new file mode 100644 index 0000000..50ef6f2 --- /dev/null +++ b/simulators/views/ursina_mesh.py @@ -0,0 +1,210 @@ +# -*- 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 +from ursina import Ursina, window, Entity, Mesh, EditorCamera, color, mouse, Vec2, Vec3, load_texture,Texture +from math import pi, sin, cos +import numpy as np +import math + + +def create_sphere(radius, subdivisions): + """ + 创建一个球体 + :param radius: + :param subdivisions: + :return: + """ + # 生成球体的顶点、UV坐标uvs、法线tris和三角面 + verts = [] + tris = [] + normals = [] + uvs = [] + + for y in range(subdivisions + 1): + for x in range(subdivisions + 1): + x_segment = x / subdivisions + y_segment = -y / subdivisions + x_pos = cos(x_segment * 2 * pi) * sin(y_segment * pi) + y_pos = cos(y_segment * pi) + z_pos = sin(x_segment * 2 * pi) * sin(y_segment * pi) + + verts.append(Vec3(x_pos, y_pos, z_pos) * radius) + uvs.append(Vec2(x_segment, y_segment)) + normals.append(Vec3(x_pos, y_pos, z_pos)) + + for y in range(subdivisions): + for x in range(subdivisions): + first = (y * (subdivisions + 1)) + x + second = first + subdivisions + 1 + # tris.append((first, second + 1, second)) + # tris.append((first, first + 1, second + 1)) + + tris.append((second, second + 1, first)) + tris.append((second + 1, first + 1, first)) + + # 反转面法线 + # for i in range(len(tris)): + # a, b, c = tris[i] + # tris[i] = (c, b, a) + # normals[a], normals[b], normals[c] = -Vec3(*normals[c]), -Vec3(*normals[b]), -Vec3(*normals[a]) + # normals[a], normals[b], normals[c] = -Vec3(*normals[a]), -Vec3(*normals[b]), -Vec3(*normals[c]) + # 翻转球体 + # for i in range(len(normals)): + # normals[i] = -normals[i] + + return Mesh(vertices=verts, triangles=tris, normals=normals, uvs=uvs, mode='triangle') + + +def create_body_torus(inner_radius, outer_radius, subdivisions): + vertices = [] + uvs = [] + normals = [] + triangles = [] + + # 计算圆环顶点、法向量和纹理坐标 + for i in range(subdivisions): + for j in range(subdivisions): + # 计算纹理坐标 + u = i / subdivisions + v = j / subdivisions + # 计算球面坐标系下的角度 + theta = u * math.pi * 2 + phi = v * math.pi * 2 + + # 计算圆环顶点位置 + x = (outer_radius + inner_radius * math.cos(phi)) * math.cos(theta) + y = inner_radius * math.sin(phi) * (inner_radius / 20) + z = (outer_radius + inner_radius * math.cos(phi)) * math.sin(theta) + + # 计算圆环顶点法向量 + nx = math.cos(theta) * math.cos(phi) + ny = math.sin(phi) + nz = math.sin(theta) * math.cos(phi) + + vertices.append((x, y, z)) + normals.append((nx, ny, nz)) + uvs.append((u, v)) + + # 计算圆环三角形面片 + for i in range(subdivisions): + for j in range(subdivisions): + i1 = i + j1 = j + i2 = (i + 1) % subdivisions + j2 = (j + 1) % subdivisions + + p1 = i1 * subdivisions + j1 + p2 = i2 * subdivisions + j1 + p3 = i2 * subdivisions + j2 + p4 = i1 * subdivisions + j2 + + triangles.append((p1, p2, p3)) + triangles.append((p1, p3, p4)) + # uvs = [[u * 2, v] for u, v in uvs] + # 创建 mesh 对象 + mesh = Mesh(vertices=vertices, uvs=uvs, normals=normals, triangles=triangles, mode='triangle') + + return mesh + + +def create_torus(inner_radius, outer_radius, subdivisions): + verts = [] + tris = [] + + for i in range(subdivisions): + angle = i * (360 / subdivisions) + x = np.cos(angle * np.pi / 180) + y = np.sin(angle * np.pi / 180) + + # create vertices for inner radius + inner_x = x * inner_radius + inner_y = y * inner_radius + verts.append((inner_x, inner_y, 0)) + + # create vertices for outer radius + outer_x = x * outer_radius + outer_y = y * outer_radius + verts.append((outer_x, outer_y, 0)) + + # create triangles + first_index = i * 2 + second_index = (i * 2 + 2) % (subdivisions * 2) + third_index = (i * 2 + 1) % (subdivisions * 2) + fourth_index = (i * 2 + 3) % (subdivisions * 2) + + tris.append((first_index, second_index, third_index)) + tris.append((third_index, second_index, fourth_index)) + + # create uvs + uvs = [] + for i in range(len(verts)): + # 计算纹理坐标 + u = i / subdivisions + v = i / subdivisions + + angle = i * (360 / (subdivisions * 2)) + u = -angle / 360 + # v = angle / 360 + + + # angle = i * (360 / (subdivisions * 2)) + # u = angle / 360 + # v = -(outer_radius - inner_radius) / outer_radius * 0.5 + uvs.append((u, v)) + + # create normals + normals = [] + for i in range(len(verts)): + angle = i * (360 / subdivisions) + x = np.cos(angle * np.pi / 180) + y = np.sin(angle * np.pi / 180) + normals.append((x, y, 0)) + + # create mesh + mesh = Mesh(vertices=verts, triangles=tris, uvs=uvs, normals=normals, mode='triangle') + + # add color attribute + # mesh.colorize() + + return mesh + + +if __name__ == '__main__': + app = Ursina() + # # 使用 Mesh 类创建球体 + texture = "../../textures/saturn.jpg" + textureRings = '../../textures/saturnRings.jpg' + + # 创建球体 + sphere = create_sphere(1, 32) + entity = Entity(model=sphere, texture=texture, color=color.white) + # 创建光晕 + # glow_entity = Entity(parent=entity, model='sphere', color=color.rgb(1,1,1,0.1), + # scale=2.1, alpha=0.1) + # + + torus = create_body_torus(0.8, 2, 64) + textureRings = load_texture(textureRings) + # textureRings.wrap_x = 'repeat' + # textureRings.wrap_y = 'repeat' + # # 将纹理重复 2 次 + # textureRings.uv_scale = (2, 2) + torus = create_torus(1.5, 3, 64) + entity = Entity(model=torus, texture=textureRings, rotation=(85, 0, 0), double_sided=True) + # entity.texture.repeat = 2 + # entity.texture.apply() + # entity.texture.wrap_v = 'repeat' + # entity.texture.uv_scale = (2, 2) + + # entity.texture.wrap = Texture.repeat + entity.texture.wrap_x = 2 + entity.texture.wrap_y = 2 + + EditorCamera() + app.run() diff --git a/simulators/views/ursina_view.py b/simulators/views/ursina_view.py index 28faf46..e62919e 100644 --- a/simulators/views/ursina_view.py +++ b/simulators/views/ursina_view.py @@ -7,7 +7,8 @@ # 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, \ +from ursina import Ursina, window, Entity, Mesh, SmoothFollow, Texture, clamp, time, \ + camera, color, mouse, Vec2, Vec3, Vec4,\ load_texture, held_keys # from ursina.camera import OrthographicCamera @@ -18,7 +19,9 @@ import random as rd import os from bodies import Body import random + from simulators.views.body_view import BodyView +from simulators.views.ursina_mesh import create_sphere, create_body_torus import numpy as np import math @@ -32,6 +35,8 @@ class UrsinaPlayer(FirstPersonController): """ """ + body_rotation_speed_control = 1.0 + def __init__(self, position, targets=None): super().__init__() @@ -74,82 +79,6 @@ class UrsinaPlayer(FirstPersonController): return super().input(key) -from math import pi, sin, cos - - -# def create_sphere(radius, subdivisions): -# # 生成球体的顶点、UV坐标、法线和三角面 -# # radius = 1 -# # subdivisions = 16 -# theta = np.linspace(0, 2 * np.pi, subdivisions + 1) -# phi = np.linspace(0, np.pi, subdivisions + 1) -# u = np.linspace(0, 1, subdivisions + 1) -# v = np.linspace(0, 1, subdivisions + 1) -# verts = [] -# uvs = [] -# normals = [] -# for i in range(len(theta)): -# for j in range(len(phi)): -# x = radius * np.sin(phi[j]) * np.cos(theta[i]) -# y = radius * np.sin(phi[j]) * np.sin(theta[i]) -# z = radius * np.cos(phi[j]) -# verts.append((x, y, z)) -# uvs.append((u[i], v[j])) -# normals.append((x / radius, y / radius, z / radius)) -# -# tris = [] -# for i in range(len(theta)): -# for j in range(len(phi)): -# a = i * (subdivisions + 1) + j -# b = (i + 1) * (subdivisions + 1) + j -# tris.append((a, b, a + 1)) -# tris.append((a + 1, b, b + 1)) -# -# # # 反转面法线 -# # for i in range(len(tris)): -# # a, b, c = tris[i] -# # tris[i] = (c, b, a) -# # normals[a], normals[b], normals[c] = -Vec3(*normals[a]), -Vec3(*normals[b]), -Vec3(*normals[c]) -# # normals[a], normals[b], normals[c] = -Vec3(*normals[a]), -Vec3(*normals[b]), -Vec3(*normals[c]) -# -# # 创建球体 Mesh 对象并设置材质 -# sphere_mesh = Mesh(vertices=verts, uvs=uvs, normals=normals, triangles=tris, mode='triangle') -# return sphere_mesh - -def create_sphere(radius, subdivisions): - verts = [] - tris = [] - normals = [] - uvs = [] - - for y in range(subdivisions + 1): - for x in range(subdivisions + 1): - x_segment = x / subdivisions - y_segment = y / subdivisions - x_pos = cos(x_segment * 2 * pi) * sin(y_segment * pi) - y_pos = cos(y_segment * pi) - z_pos = sin(x_segment * 2 * pi) * sin(y_segment * pi) - - verts.append(Vec3(x_pos, y_pos, z_pos) * radius) - uvs.append(Vec2(x_segment, y_segment)) - normals.append(Vec3(x_pos, y_pos, z_pos)) - - for y in range(subdivisions): - for x in range(subdivisions): - first = (y * (subdivisions + 1)) + x - second = first + subdivisions + 1 - tris.append((first, second + 1, second)) - tris.append((first, first + 1, second + 1)) - - # 反转面法线 - for i in range(len(tris)): - a, b, c = tris[i] - tris[i] = (c, b, a) - # normals[a], normals[b], normals[c] = -Vec3(*normals[a]), -Vec3(*normals[b]), -Vec3(*normals[c]) - - return Mesh(vertices=verts, triangles=tris, normals=normals, uvs=uvs, mode='triangle') - - class Planet(Entity): def __init__(self, body_view: BodyView): self.body_view = body_view @@ -160,7 +89,7 @@ class Planet(Entity): pos = body_view.position * body_view.body.distance_scale * SCALE_FACTOR scale = body_view.body.diameter * body_view.body.size_scale * SCALE_FACTOR - subdivisions = 32 # int(scale*20) + subdivisions = 32 # int(scale*20) if hasattr(body_view, "texture"): texture = load_texture(body_view.texture) @@ -174,7 +103,8 @@ class Planet(Entity): texture=texture, color=color.white, position=pos, - rotation=(0, 0, 0)) + rotation=(0, 0, 0), + double_sided=True) def turn(self): pos = self.body_view.position * SCALE_FACTOR @@ -215,17 +145,37 @@ class UrsinaView(BodyView): if body.has_rings: self.create_rings() + # 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() + def create_rings(self): """ 创建行星环(使用土星贴图) :return: """ - # 行星环偏移角度 - self.ring_rotation_x = 75 - # 创建行星环 - self.ring = Entity(parent=self.planet, model="circle", texture='../textures/saturnRings.jpg', scale=2, + # # # 行星环偏移角度 + # self.ring_rotation_x = 80 + # # 创建行星环 + # 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) + + self.ring_rotation_x = 0 + torus = create_body_torus(0.3, 1, 32) + self.ring = Entity(parent=self.planet, model=torus, texture='../textures/saturnRings.jpg', scale=1, rotation=(self.ring_rotation_x, 0, 0), double_sided=True) + # 设置行星环不受灯光影响,否则看不清行星环 self.ring.set_light_off() -- GitLab