|
@@ -2,6 +2,7 @@ import pygame
|
|
|
from pygame.locals import *
|
|
from pygame.locals import *
|
|
|
from OpenGL.GL import *
|
|
from OpenGL.GL import *
|
|
|
from OpenGL.GLU import *
|
|
from OpenGL.GLU import *
|
|
|
|
|
+import math
|
|
|
|
|
|
|
|
def draw_wire_cube():
|
|
def draw_wire_cube():
|
|
|
"""绘制线框立方体"""
|
|
"""绘制线框立方体"""
|
|
@@ -75,9 +76,74 @@ def draw_solid_cube():
|
|
|
glVertex3fv(vertices[vertex])
|
|
glVertex3fv(vertices[vertex])
|
|
|
glEnd()
|
|
glEnd()
|
|
|
|
|
|
|
|
-def draw_small_cube(position, size=0.4):
|
|
|
|
|
|
|
+# 字体初始化
|
|
|
|
|
+font = None
|
|
|
|
|
+
|
|
|
|
|
+def init_font():
|
|
|
|
|
+ global font
|
|
|
|
|
+ pygame.font.init()
|
|
|
|
|
+ font = pygame.font.SysFont('arial', 24)
|
|
|
|
|
+
|
|
|
|
|
+def draw_text_at_position(text, position):
|
|
|
|
|
+ """在3D空间中指定位置绘制文本"""
|
|
|
|
|
+ global font
|
|
|
|
|
+ if font is None:
|
|
|
|
|
+ init_font()
|
|
|
|
|
+
|
|
|
|
|
+ # 创建文本表面
|
|
|
|
|
+ text_surface = font.render(text, True, (255, 255, 255)) # 白色文字
|
|
|
|
|
+ text_data = pygame.image.tostring(text_surface, "RGBA", True)
|
|
|
|
|
+
|
|
|
|
|
+ # 保存当前矩阵状态
|
|
|
|
|
+ glPushMatrix()
|
|
|
|
|
+
|
|
|
|
|
+ # 移动到目标位置
|
|
|
|
|
+ glTranslatef(position[0], position[1], position[2])
|
|
|
|
|
+
|
|
|
|
|
+ # 获取模型视图矩阵,使文本面向摄像机
|
|
|
|
|
+ matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
|
|
|
|
|
+
|
|
|
|
|
+ # 使文本始终面向摄像机(billboard效果)
|
|
|
|
|
+ glLoadIdentity()
|
|
|
|
|
+ # 恢复摄像机视角,但保持位置
|
|
|
|
|
+ glTranslatef(position[0], position[1], position[2])
|
|
|
|
|
+
|
|
|
|
|
+ # 创建纹理
|
|
|
|
|
+ texture_id = glGenTextures(1)
|
|
|
|
|
+ glBindTexture(GL_TEXTURE_2D, texture_id)
|
|
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
|
|
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
|
|
|
|
|
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, text_surface.get_width(),
|
|
|
|
|
+ text_surface.get_height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, text_data)
|
|
|
|
|
+
|
|
|
|
|
+ # 计算文本尺寸以适当缩放
|
|
|
|
|
+ width = text_surface.get_width()
|
|
|
|
|
+ height = text_surface.get_height()
|
|
|
|
|
+ scale_factor = 0.05 # 缩放因子
|
|
|
|
|
+
|
|
|
|
|
+ # 绘制带纹理的四边形来显示文本
|
|
|
|
|
+ glEnable(GL_TEXTURE_2D)
|
|
|
|
|
+ glEnable(GL_BLEND)
|
|
|
|
|
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
|
|
|
|
+
|
|
|
|
|
+ glBegin(GL_QUADS)
|
|
|
|
|
+ glTexCoord2f(0, 0); glVertex3f(-width * scale_factor/2, -height * scale_factor/2, 0.01) # 稍微高于小正方体表面
|
|
|
|
|
+ glTexCoord2f(1, 0); glVertex3f(width * scale_factor/2, -height * scale_factor/2, 0.01)
|
|
|
|
|
+ glTexCoord2f(1, 1); glVertex3f(width * scale_factor/2, height * scale_factor/2, 0.01)
|
|
|
|
|
+ glTexCoord2f(0, 1); glVertex3f(-width * scale_factor/2, height * scale_factor/2, 0.01)
|
|
|
|
|
+ glEnd()
|
|
|
|
|
+
|
|
|
|
|
+ glDisable(GL_TEXTURE_2D)
|
|
|
|
|
+
|
|
|
|
|
+ # 清理纹理
|
|
|
|
|
+ glDeleteTextures([texture_id])
|
|
|
|
|
+
|
|
|
|
|
+ glPopMatrix()
|
|
|
|
|
+
|
|
|
|
|
+def draw_small_cube(position, cube_number, size=0.4):
|
|
|
"""绘制一个小正方体
|
|
"""绘制一个小正方体
|
|
|
position: 小正方体的位置 (x, y, z)
|
|
position: 小正方体的位置 (x, y, z)
|
|
|
|
|
+ cube_number: 小正方体的编号 (从1开始)
|
|
|
size: 小正方体的大小 (默认为0.4,即大正方体的一半减去0.1单位)
|
|
size: 小正方体的大小 (默认为0.4,即大正方体的一半减去0.1单位)
|
|
|
"""
|
|
"""
|
|
|
x, y, z = position
|
|
x, y, z = position
|
|
@@ -112,10 +178,62 @@ def draw_small_cube(position, size=0.4):
|
|
|
# 绘制每个面
|
|
# 绘制每个面
|
|
|
for surface in surfaces:
|
|
for surface in surfaces:
|
|
|
glBegin(GL_QUADS)
|
|
glBegin(GL_QUADS)
|
|
|
- glColor4f(1.0, 1.0, 0.0, 0.1) # 黄色,20%透明度(更不透明,更显眼)
|
|
|
|
|
|
|
+ glColor4f(1.0, 1.0, 0.0, 0.3) # 黄色,30%透明度
|
|
|
for vertex in surface:
|
|
for vertex in surface:
|
|
|
glVertex3fv(vertices[vertex])
|
|
glVertex3fv(vertices[vertex])
|
|
|
glEnd()
|
|
glEnd()
|
|
|
|
|
+
|
|
|
|
|
+ # 在小正方体上方绘制编号文本
|
|
|
|
|
+ draw_text_at_position(str(cube_number), (x, y, z + size/2 + 0.05)) # 在小正方体顶部稍高处显示编号
|
|
|
|
|
+
|
|
|
|
|
+def hsv_to_rgb(h, s, v):
|
|
|
|
|
+ """将HSV颜色值转换为RGB颜色值
|
|
|
|
|
+ h: 色相 (0-1)
|
|
|
|
|
+ s: 饱和度 (0-1)
|
|
|
|
|
+ v: 明度 (0-1)
|
|
|
|
|
+ 返回: RGB元组 (r, g, b),每个值在0-1之间
|
|
|
|
|
+ """
|
|
|
|
|
+ if s == 0.0:
|
|
|
|
|
+ return v, v, v
|
|
|
|
|
+
|
|
|
|
|
+ i = int(h * 6)
|
|
|
|
|
+ f = (h * 6) - i
|
|
|
|
|
+ p = v * (1 - s)
|
|
|
|
|
+ q = v * (1 - s * f)
|
|
|
|
|
+ t = v * (1 - s * (1 - f))
|
|
|
|
|
+
|
|
|
|
|
+ i %= 6
|
|
|
|
|
+ if i == 0:
|
|
|
|
|
+ return v, t, p
|
|
|
|
|
+ if i == 1:
|
|
|
|
|
+ return q, v, p
|
|
|
|
|
+ if i == 2:
|
|
|
|
|
+ return p, v, t
|
|
|
|
|
+ if i == 3:
|
|
|
|
|
+ return p, q, v
|
|
|
|
|
+ if i == 4:
|
|
|
|
|
+ return t, p, v
|
|
|
|
|
+ if i == 5:
|
|
|
|
|
+ return v, p, q
|
|
|
|
|
+
|
|
|
|
|
+def draw_number_labels(screen, small_cube_positions):
|
|
|
|
|
+ """在屏幕角落绘制编号标签"""
|
|
|
|
|
+ pygame.font.init()
|
|
|
|
|
+ font = pygame.font.SysFont('arial', 16)
|
|
|
|
|
+
|
|
|
|
|
+ # 绘制编号列表
|
|
|
|
|
+ for i, pos in enumerate(small_cube_positions):
|
|
|
|
|
+ num = i + 1
|
|
|
|
|
+ text = f"#{num}: ({pos[0]:.2f}, {pos[1]:.2f}, {pos[2]:.2f})"
|
|
|
|
|
+ text_surface = font.render(text, True, (255, 255, 255)) # 白色文字
|
|
|
|
|
+ # 在屏幕左上角垂直排列显示
|
|
|
|
|
+ screen.blit(text_surface, (10, 10 + i * 20))
|
|
|
|
|
+
|
|
|
|
|
+ # 如果标签太多,限制显示数量
|
|
|
|
|
+ if i >= 19: # 只显示前20个,避免超出屏幕
|
|
|
|
|
+ text_surface = font.render("...", True, (255, 255, 255))
|
|
|
|
|
+ screen.blit(text_surface, (10, 10 + 20 * 20))
|
|
|
|
|
+ break
|
|
|
|
|
|
|
|
def main():
|
|
def main():
|
|
|
# 内部小正方体每条边的数量(完全立方数:inner_cube^3个小正方体)
|
|
# 内部小正方体每条边的数量(完全立方数:inner_cube^3个小正方体)
|
|
@@ -123,7 +241,7 @@ def main():
|
|
|
|
|
|
|
|
pygame.init()
|
|
pygame.init()
|
|
|
display = (800, 600)
|
|
display = (800, 600)
|
|
|
- pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
|
|
|
|
|
|
|
+ screen = pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
|
|
|
|
|
|
|
|
pygame.display.set_caption("透明3D正方体与内部小正方体")
|
|
pygame.display.set_caption("透明3D正方体与内部小正方体")
|
|
|
|
|
|
|
@@ -167,8 +285,9 @@ def main():
|
|
|
# 小正方体边长 = spacing * 0.8 (留一些间隙)
|
|
# 小正方体边长 = spacing * 0.8 (留一些间隙)
|
|
|
small_cube_size = min(spacing * 0.8, 0.8) # 限制最大尺寸
|
|
small_cube_size = min(spacing * 0.8, 0.8) # 限制最大尺寸
|
|
|
|
|
|
|
|
- for pos in small_cube_positions:
|
|
|
|
|
- draw_small_cube(pos, size=small_cube_size)
|
|
|
|
|
|
|
+ # 绘制编号的小正方体
|
|
|
|
|
+ for i, pos in enumerate(small_cube_positions):
|
|
|
|
|
+ draw_small_cube(pos, i+1, size=small_cube_size)
|
|
|
|
|
|
|
|
# 绘制外部大透明正方体
|
|
# 绘制外部大透明正方体
|
|
|
draw_solid_cube()
|
|
draw_solid_cube()
|
|
@@ -177,6 +296,25 @@ def main():
|
|
|
glColor3f(1.0, 1.0, 1.0) # 白色线框
|
|
glColor3f(1.0, 1.0, 1.0) # 白色线框
|
|
|
draw_wire_cube()
|
|
draw_wire_cube()
|
|
|
|
|
|
|
|
|
|
+ # 切换到2D模式绘制编号标签
|
|
|
|
|
+ glDisable(GL_DEPTH_TEST)
|
|
|
|
|
+ glMatrixMode(GL_PROJECTION)
|
|
|
|
|
+ glPushMatrix()
|
|
|
|
|
+ glLoadIdentity()
|
|
|
|
|
+ glOrtho(0, 800, 600, 0, -1, 1) # 设置2D正交投影
|
|
|
|
|
+ glMatrixMode(GL_MODELVIEW)
|
|
|
|
|
+ glPushMatrix()
|
|
|
|
|
+ glLoadIdentity()
|
|
|
|
|
+
|
|
|
|
|
+ # 绘制编号标签
|
|
|
|
|
+ draw_number_labels(screen, small_cube_positions)
|
|
|
|
|
+
|
|
|
|
|
+ # 恢复3D模式
|
|
|
|
|
+ glPopMatrix()
|
|
|
|
|
+ glMatrixMode(GL_PROJECTION)
|
|
|
|
|
+ glPopMatrix()
|
|
|
|
|
+ glEnable(GL_DEPTH_TEST)
|
|
|
|
|
+
|
|
|
pygame.display.flip()
|
|
pygame.display.flip()
|
|
|
clock.tick(60)
|
|
clock.tick(60)
|
|
|
|
|
|