From 8515a2085297d20ba10e4a6b31a22da5edd371a0 Mon Sep 17 00:00:00 2001 From: march3 Date: Tue, 14 Nov 2023 12:56:17 +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 --- objs/halley_comet.py | 3 +- simulators/ursina/entities/planet.py | 37 +++++-- simulators/ursina/ursina_mesh.py | 148 ++++++++++++++++++++++----- 3 files changed, 157 insertions(+), 31 deletions(-) diff --git a/objs/halley_comet.py b/objs/halley_comet.py index 35acf12..04478d3 100644 --- a/objs/halley_comet.py +++ b/objs/halley_comet.py @@ -50,7 +50,7 @@ class HalleComet(RockSnow): super().__init__(**params) # create_cone(radius, height, subdivisions, r=0.1) # self.comet_info = (0.18, 2.0, 100, 0.2) - self.comet_info = (0.05, 0.18, 2, 100) + self.comet_info = (0.07, 0.20, 2, 100) from ursina.prefabs.primitives import Shader @@ -110,6 +110,7 @@ if __name__ == '__main__': halle_comet.planet.rotation_x = 90 halle_comet.planet.shader = shader, halle_comet.planet.init_scale = halle_comet.planet.scale_x * 2 + halle_comet.planet.comet_trail.set_alpha(0.1) # halle_comet.planet.init_update = halle_comet.planet.update diff --git a/simulators/ursina/entities/planet.py b/simulators/ursina/entities/planet.py index 940d579..df3db86 100644 --- a/simulators/ursina/entities/planet.py +++ b/simulators/ursina/entities/planet.py @@ -186,18 +186,41 @@ class Planet(Entity): texture = find_texture("comet_trail.png") self.comet_trail = Entity(parent=self, model=comet_mesh, texture=texture, scale=20, position=(0, 0, 0), - rotation=(0, 90, 90), double_sided=True, alpha=0.8) - self.comet_sphere = Entity(parent=self, model="sphere", texture="", - color=color.white, scale=2.2, double_sided=True, alpha=0.6) + rotation=(0, 90, 90), double_sided=True, alpha=1) + self.comet_trail.comet_trail_index = 0 + comet_num = 2 + for i in range(1, comet_num): + c = Entity(parent=self.comet_trail, model=create_comet_trail(*comet_info), + texture=texture, scale=1 + i * 0.01, + position=(0, 0, 0), + rotation=(0, 0, 0), double_sided=True, alpha=1) + c.set_light_off() + c.comet_trail_index = i + + # self.comet_sphere = Entity(parent=self, model="sphere", texture="", + # color=color.white, scale=2.2, double_sided=True, alpha=0.6) def set_alpha(alpha): - self.comet_trail.alpha = alpha - self.comet_sphere.alpha = alpha + self.comet_trail.enabled = (alpha > 0.01) + if self.comet_trail.enabled: + self.comet_trail.alpha = alpha / 2 + for c in self.comet_trail.children: + c.enabled = (alpha > 0.01) + if c.enabled: + c.alpha = alpha / 2 + # self.comet_sphere.alpha = alpha + + def comet_trail_update(): + import random + # self.comet_trail.rotation_x += 1 + for c in self.comet_trail.children: + c.rotation_y += (random.randint(-20, 20) / 10) self.comet_trail.set_alpha = set_alpha - + self.comet_trail.update = comet_trail_update + # set_alpha(0.8) # 设置行星环不受灯光影响,否则看不清行星环 self.comet_trail.set_light_off() - self.comet_sphere.set_light_off() + # self.comet_sphere.set_light_off() def create_rotate_entity(self): """ diff --git a/simulators/ursina/ursina_mesh.py b/simulators/ursina/ursina_mesh.py index 00f3197..2fc403d 100644 --- a/simulators/ursina/ursina_mesh.py +++ b/simulators/ursina/ursina_mesh.py @@ -187,28 +187,6 @@ def create_comet_trail(head_radius, trail_radius, height, subdivisions): normals = [] # 法线列表 uvs = [] # UV坐标列表 - # 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) * head_radius * 10) - # 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)) - # 生成圆台底部的顶点和UV坐标 for i in range(subdivisions): angle = 2 * math.pi * i / subdivisions @@ -235,17 +213,138 @@ def create_comet_trail(head_radius, trail_radius, height, subdivisions): next_bottom_index = (i + 1) % subdivisions # 下一个顶部顶点索引 next_top_index = (i + 1) % subdivisions + subdivisions - # 侧面三角形 tris.append((bottom_index, next_bottom_index, top_index)) tris.append((next_bottom_index, next_top_index, top_index)) + # 侧面法线 + normal = (verts[top_index] - verts[bottom_index]).cross( + verts[next_bottom_index] - verts[bottom_index]).normalized() + normals.append(normal) + normals.append(normal) + + # 生成半圆形的顶点和UV坐标 + # for i in range(subdivisions): + # angle = 2*math.pi * i / subdivisions + # x = head_radius * math.cos(angle) + # z = head_radius * math.sin(angle) + # verts.append(Vec3(x, -1, z)) + # uvs.append(Vec2(i / subdivisions, 1)) + + for i in range(subdivisions // 2 + 1): + angle1 = 0.5 * math.pi * i / (subdivisions // 2) + for j in range(subdivisions): + angle2 = 2 * math.pi * j / subdivisions + x = head_radius * math.sin(angle1) * math.cos(angle2) + y = -head_radius * math.cos(angle1) + z = head_radius * math.sin(angle1) * math.sin(angle2) + verts.append(Vec3(x, y, z)) + # uvs.append(Vec2(j / subdivisions, i / (subdivisions // 2))) + if i < subdivisions // 2: + # 生成半圆球体的三角面索引和法线 + index1 = subdivisions * 2 + i * subdivisions + j + index2 = subdivisions * 2 + i * subdivisions + (j + 1) % subdivisions + index3 = subdivisions * 2 + (i + 1) * subdivisions + j + index4 = subdivisions * 2 + (i + 1) * subdivisions + (j + 1) % subdivisions + tris.append((index1, index3, index2)) + tris.append((index2, index3, index4)) + # normal1 = (verts[index1] - Vec3(0, height, 0)).normalized() + # normal2 = (verts[index2] - Vec3(0, height, 0)).normalized() + # normal3 = (verts[index3] - Vec3(0, height, 0)).normalized() + # normal4 = (verts[index4] - Vec3(0, height, 0)).normalized() + # normals.append(normal1) + # normals.append(normal2) + # normals.append(normal3) + # normals.append(normal4) + + # # 生成半圆形的三角面索引和法线 + # for i in range(subdivisions - 1): + # index1 = i + subdivisions * 2 + # index2 = i + 1 + subdivisions * 2 + # index3 = subdivisions * 2 + # tris.append((index1, index2, index3)) + # normal = (verts[index1] - verts[index3]).cross( + # verts[index2] - verts[index3]).normalized() + # normals.append(normal) + + return Mesh(vertices=verts, triangles=tris, normals=normals, uvs=uvs, mode='triangle') + +def create_comet_trail2(head_radius, trail_radius, height, subdivisions): + """ + 创建一个彗星尾巴 + @param head_radius: 圆台底部的半径 + @param trail_radius: 圆台顶部的半径 + @param height: 圆台的高度 + @param subdivisions: 细分数,用于控制圆台和半圆球体的光滑度 + @return: Mesh对象,表示创建的圆台和半圆球体 + """ + verts = [] # 顶点列表 + tris = [] # 三角面索引列表 + normals = [] # 法线列表 + uvs = [] # UV坐标列表 + + # 生成圆台底部的顶点和UV坐标 + for i in range(subdivisions): + angle = 2 * math.pi * i / subdivisions + x = head_radius * math.cos(angle) + z = head_radius * math.sin(angle) + verts.append(Vec3(x, 0, z)) + uvs.append(Vec2(i / subdivisions, 0)) + + # 生成圆台顶部的顶点和UV坐标 + for i in range(subdivisions): + angle = 2 * math.pi * i / subdivisions + x = trail_radius * math.cos(angle) + z = trail_radius * math.sin(angle) + verts.append(Vec3(x, height, z)) + uvs.append(Vec2(i / subdivisions, 1)) + + # 生成圆台侧面的顶点、法线和三角面 + for i in range(subdivisions): + # 底部顶点索引 + bottom_index = i + # 顶部顶点索引 + top_index = i + subdivisions + # 下一个底部顶点索引 + next_bottom_index = (i + 1) % subdivisions + # 下一个顶部顶点索引 + next_top_index = (i + 1) % subdivisions + subdivisions + # 侧面三角形 + tris.append((bottom_index, next_bottom_index, top_index)) + tris.append((next_bottom_index, next_top_index, top_index)) # 侧面法线 normal = (verts[top_index] - verts[bottom_index]).cross( verts[next_bottom_index] - verts[bottom_index]).normalized() normals.append(normal) normals.append(normal) + # 生成半圆球体的顶点、法线和三角面 + for i in range(subdivisions // 2 + 1): + angle1 = math.pi * i / (subdivisions // 2) + for j in range(subdivisions): + angle2 = 2 * math.pi * j / subdivisions + x = head_radius * math.sin(angle1) * math.cos(angle2) + y = head_radius * math.cos(angle1) + height + z = head_radius * math.sin(angle1) * math.sin(angle2) + verts.append(Vec3(x, y, z)) + uvs.append(Vec2(j / subdivisions, i / (subdivisions // 2))) + if i < subdivisions // 2: + # 生成半圆球体的三角面索引和法线 + index1 = subdivisions * 2 + i * subdivisions + j + index2 = subdivisions * 2 + i * subdivisions + (j + 1) % subdivisions + index3 = subdivisions * 2 + (i + 1) * subdivisions + j + index4 = subdivisions * 2 + (i + 1) * subdivisions + (j + 1) % subdivisions + tris.append((index1, index3, index2)) + tris.append((index2, index3, index4)) + normal1 = (verts[index1] - Vec3(0, height, 0)).normalized() + normal2 = (verts[index2] - Vec3(0, height, 0)).normalized() + normal3 = (verts[index3] - Vec3(0, height, 0)).normalized() + normal4 = (verts[index4] - Vec3(0, height, 0)).normalized() + normals.append(normal1) + normals.append(normal2) + normals.append(normal3) + normals.append(normal4) + return Mesh(vertices=verts, triangles=tris, normals=normals, uvs=uvs, mode='triangle') @@ -794,5 +893,8 @@ if __name__ == '__main__': create_circle_line() + # Entity(model=create_half_sphere(0.05, 100), texture='brick', color=color.yellow, double_sided=True) + Entity(model=create_comet_trail(0.05, 0.18, 2, 100), texture='brick', color=color.yellow, double_sided=True) + EditorCamera() app.run() -- GitLab