50种3D效果演示(OpenGL)
效果:
一、只需打开命令行(Windows 可用 cmd),输入:
pip install PyQt5 PyOpenGL numpy
二、用命令行进入保存 .py 文件的目录,运行:
python openGL_3d_demo.py
三、建立python文件命名openGL_3d_demo.py后粘贴代码,然后运行
import sys
import math
import time
import numpy as np
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QFont, QPalette, QColor
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QGridLayout,QTabWidget, QLabel, QFrame, QOpenGLWidget
)
from OpenGL.GL import *
from OpenGL.GLU import *# ========== 通用3D控件 ==========
class Base3DGL(QOpenGLWidget):name = "3D效果"def __init__(self, parent=None):super().__init__(parent)self.last_pos = Noneself.angle_x, self.angle_y = 20, 20self.fps = 0self._frames = 0self._last_time = time.time()self.setMinimumSize(220, 180)self.timer = QTimer(self)self.timer.timeout.connect(self.update)self.timer.start(16)def initializeGL(self):glClearColor(0.10, 0.11, 0.15, 1.0)glEnable(GL_DEPTH_TEST)glShadeModel(GL_SMOOTH)def resizeGL(self, w, h):glViewport(0, 0, w, h)glMatrixMode(GL_PROJECTION)glLoadIdentity()gluPerspective(40.0, w / float(h or 1), 1.0, 100.0)glMatrixMode(GL_MODELVIEW)def paintGL(self):self._frames += 1now = time.time()if now - self._last_time > 1.0:self.fps = self._frames / (now - self._last_time)self._last_time = nowself._frames = 0glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)glLoadIdentity()glTranslatef(0, 0, -9)glRotatef(self.angle_x, 1, 0, 0)glRotatef(self.angle_y, 0, 1, 0)self.render_scene()def mousePressEvent(self, event):self.last_pos = event.pos()def mouseMoveEvent(self, event):if self.last_pos:dx = event.x() - self.last_pos.x()dy = event.y() - self.last_pos.y()self.angle_y += dx * 0.7self.angle_x += dy * 0.7self.last_pos = event.pos()self.update()# ========== 50种3D效果 ==========# ----------- 第1页(常见几何体) -----------
class SphereGL(Base3DGL):name = "渐变球体"def render_scene(self):for i in range(30):lat0 = math.pi * (-0.5 + float(i) / 30)z0 = math.sin(lat0)zr0 = math.cos(lat0)lat1 = math.pi * (-0.5 + float(i + 1) / 30)z1 = math.sin(lat1)zr1 = math.cos(lat1)glBegin(GL_QUAD_STRIP)for j in range(32):lng = 2 * math.pi * float(j) / 32x = math.cos(lng)y = math.sin(lng)c1 = abs(x)c2 = abs(y)c3 = abs(z0)glColor3f(0.5*c1+0.2, 0.2+0.5*c2, 0.4+0.5*c3)glVertex3f(x * zr0, y * zr0, z0)c3b = abs(z1)glColor3f(0.5*c1+0.3, 0.4+0.5*c2, 0.3+0.5*c3b)glVertex3f(x * zr1, y * zr1, z1)glEnd()class CubeGL(Base3DGL):name = "彩色立方体"def render_scene(self):faces = [((1,1,1), (1,1,-1), (1,-1,-1), (1,-1,1)), # +X((-1,1,1), (-1,1,-1), (-1,-1,-1), (-1,-1,1)), # -X((1,1,1), (1,1,-1), (-1,1,-1), (-1,1,1)), # +Y((1,-1,1), (1,-1,-1), (-1,-1,-1), (-1,-1,1)), # -Y((1,1,1), (1,-1,1), (-1,-1,1), (-1,1,1)), # +Z((1,1,-1), (1,-1,-1), (-1,-1,-1), (-1,1,-1)) # -Z]colors = [(1,0,0), (0,1,0), (0,0,1), (1,1,0), (1,0,1), (0,1,1)]glBegin(GL_QUADS)for i, f in enumerate(faces):glColor3f(*colors[i])for v in f:glVertex3f(*v)glEnd()class OctahedronGL(Base3DGL):name = "多彩八面体"def render_scene(self):verts = [(1,0,0), (-1,0,0), (0,1,0), (0,-1,0), (0,0,1), (0,0,-1)]faces = [(0,2,4),(2,1,4),(1,3,4),(3,0,4),(0,2,5),(2,1,5),(1,3,5),(3,0,5)]colors = [(1,0,0),(0,1,0),(0,0,1),(1,1,0),(1,0,1),(0,1,1),(1,0.5,0.5),(0.5,1,0.5)]glBegin(GL_TRIANGLES)for i, f in enumerate(faces):glColor3f(*colors[i%len(colors)])for idx in f:glVertex3f(*verts[idx])glEnd()class IcosahedronGL(Base3DGL):name = "渐变二十面体"def render_scene(self):t = (1.0 + math.sqrt(5.0)) / 2.0verts = [(-1, t, 0), ( 1, t, 0), (-1, -t, 0), ( 1, -t, 0),( 0, -1, t), ( 0, 1, t), ( 0, -1, -t), ( 0, 1, -t),( t, 0, -1), ( t, 0, 1), (-t, 0, -1), (-t, 0, 1)]faces = [(0,11,5),(0,5,1),(0,1,7),(0,7,10),(0,10,11),(1,5,9),(5,11,4),(11,10,2),(10,7,6),(7,1,8),(3,9,4),(3,4,2),(3,2,6),(3,6,8),(3,8,9),(4,9,5),(2,4,11),(6,2,10),(8,6,7),(9,8,1)]glBegin(GL_TRIANGLES)for i, f in enumerate(faces):c = (i%3/2.0, (i*2)%5/5.0, (i*3)%7/7.0)glColor3f(*c)for idx in f:v = verts[idx]s = 0.6glVertex3f(v[0]*s, v[1]*s, v[2]*s)glEnd()class DodecahedronGL(Base3DGL):name = "炫彩十二面体"def render_scene(self):phi = (1 + 5 ** 0.5) / 2a, b = 1, 1/phiverts = [[+a,+a,+a], [+a,+a,-a], [+a,-a,+a], [+a,-a,-a],[-a,+a,+a], [-a,+a,-a], [-a,-a,+a], [-a,-a,-a],[0,+b+phi,+b], [0,+b+phi,-b], [0,-b-phi,+b], [0,-b-phi,-b],[+b,+0,+b+phi], [+b,+0,-b-phi], [-b,+0,+b+phi], [-b,+0,-b-phi],[+b+phi,+b,+0], [+b+phi,-b,+0], [-b-phi,+b,+0], [-b-phi,-b,+0]]faces = [[0,8,4,14,12], [0,12,16,2,10], [0,10,6,18,8], [8,18,19,5,4], [12,14,15,17,16],[2,16,17,1,13], [10,2,13,11,6], [6,11,7,19,18], [4,5,15,14], [1,17,15,5,9], [1,9,3,13], [3,11,13,9,7,19]]for i, face in enumerate(faces):glBegin(GL_POLYGON)c = [(i%3)/2.0, (i*2)%5/5.0, (i*3)%7/7.0]glColor3f(*c)for idx in face:v = verts[idx]glVertex3f(*[0.36*e for e in v])glEnd()class CylinderGL(Base3DGL):name = "三色圆柱体"def render_scene(self):N = 32for j, color in enumerate([(1,0,0), (0,1,0), (0,0,1)]):glColor3f(*color)glBegin(GL_QUAD_STRIP)for i in range(j*N//3,(j+1)*N//3+1):ang = 2*math.pi*i/Nx = math.cos(ang)y = math.sin(ang)glVertex3f(x, y, 1)glVertex3f(x, y, -1)glEnd()for z, c in [(1, (0.7,0.8,0.4)), (-1, (0.5,0.9,0.6))]:glColor3f(*c)glBegin(GL_TRIANGLE_FAN)glVertex3f(0,0,z)for i in range(N+1):ang = 2*math.pi*i/NglVertex3f(math.cos(ang), math.sin(ang), z)glEnd()class ConeGL(Base3DGL):name = "三色圆锥体"def render_scene(self):N = 32for cidx, color in enumerate([(1,0,0),(0,1,0),(0,0,1)]):glColor3f(*color)glBegin(GL_TRIANGLE_FAN)glVertex3f(0,0,1.3)for i in range(cidx*N//3,(cidx+1)*N//3+1):ang = 2*math.pi*i/NglVertex3f(math.cos(ang), math.sin(ang), -1)glEnd()glColor3f(0.2, 0.6, 0.4)glBegin(GL_TRIANGLE_FAN)glVertex3f(0,0,-1)for i in range(N+1):ang = 2*math.pi*i/NglVertex3f(math.cos(ang), math.sin(ang), -1)glEnd()class TorusGL(Base3DGL):name = "彩虹圆环体"def render_scene(self):R, r = 1.0, 0.36N, M = 32, 18for i in range(N):glBegin(GL_QUAD_STRIP)for j in range(M+1):for k in [0, 1]:s = 2 * math.pi * (i + k) / Nt = 2 * math.pi * j / Mx = (R + r * math.cos(t)) * math.cos(s)y = (R + r * math.cos(t)) * math.sin(s)z = r * math.sin(t)glColor3f(abs(math.cos(s)), abs(math.sin(t)), abs(math.cos(t)))glVertex3f(x, y, z)glEnd()class SpiralGL(Base3DGL):name = "多彩螺旋线"def render_scene(self):glBegin(GL_LINE_STRIP)for idx, t in enumerate(np.linspace(0, 6*math.pi, 120)):r = 1.1 + 0.2*math.sin(t*6)x = math.cos(t)*ry = math.sin(t)*rz = -1.1 + t/(6*math.pi)*2.2glColor3f(abs(x), abs(y), abs(z))glVertex3f(x, y, z)glEnd()class WaveSurfaceGL(Base3DGL):name = "渐变波浪面"def render_scene(self):N = 20for i in range(N):glBegin(GL_TRIANGLE_STRIP)for j in range(N+1):x = -2 + 4*i/Ny = -2 + 4*j/Nz1 = math.sin(x*3+y*3+self.angle_x*0.05)*0.5z2 = math.sin((x+4/N)*3+y*3+self.angle_y*0.06)*0.5glColor3f(0.5+0.5*j/N,0.5+0.5*i/N,0.5+0.25*(i+j)/N)glVertex3f(x, y, z1)glVertex3f(x+4/N, y, z2)glEnd()# ----------- 第2页(函数曲面,特殊线型等) -----------
class HeartSurfaceGL(Base3DGL):name = "心形面"def render_scene(self):glBegin(GL_POINTS)for i in range(0, 90, 1):for j in range(0, 360, 3):theta = math.radians(i)phi = math.radians(j)x = 16 * math.sin(theta)**3y = 13 * math.cos(theta) - 5 * math.cos(2*theta) - 2 * math.cos(3*theta) - math.cos(4*theta)z = 16 * math.sin(theta)**3 * math.sin(phi) / 4glColor3f(abs(math.sin(theta)), abs(math.cos(phi)), abs(math.sin(phi)))glVertex3f(x * 0.07, y * 0.07, z * 0.09)glEnd()class SineWaveGL(Base3DGL):name = "三色正弦波曲面"def render_scene(self):N = 40for i in range(N):glBegin(GL_TRIANGLE_STRIP)for j in range(N+1):x = -2 + 4*i/Ny = -2 + 4*j/Nz1 = math.sin(x*4+y*4)*0.7z2 = math.sin((x+4/N)*4+y*4)*0.7glColor3f(abs(math.sin(x)), abs(math.cos(y)), abs(z1))glVertex3f(x, y, z1)glVertex3f(x+4/N, y, z2)glEnd()class SaddleGL(Base3DGL):name = "马鞍曲面"def render_scene(self):N = 25for i in range(N):glBegin(GL_TRIANGLE_STRIP)for j in range(N+1):x = -2 + 4*i/Ny = -2 + 4*j/Nz1 = (x**2 - y**2)/4z2 = ((x+4/N)**2 - y**2)/4glColor3f(abs(z1), abs(x/2), abs(y/2))glVertex3f(x, y, z1)glVertex3f(x+4/N, y, z2)glEnd()class EggShapeGL(Base3DGL):name = "蛋形曲面"def render_scene(self):N = 24for i in range(N):lat0 = math.pi * (-0.5 + float(i) / N)z0 = math.sin(lat0)*1.2 + 0.4*math.sin(lat0)**3zr0 = math.cos(lat0)lat1 = math.pi * (-0.5 + float(i+1) / N)z1 = math.sin(lat1)*1.2 + 0.4*math.sin(lat1)**3zr1 = math.cos(lat1)glBegin(GL_QUAD_STRIP)for j in range(N+1):lng = 2 * math.pi * float(j) / Nx = math.cos(lng)y = math.sin(lng)glColor3f((j%3)/2, (i%5)/4, (j%7)/6)glVertex3f(x * zr0, y * zr0, z0)glVertex3f(x * zr1, y * zr1, z1)glEnd()class KleinBottleGL(Base3DGL):name = "克莱因瓶-彩色"def render_scene(self):N = 32for i in range(N):glBegin(GL_QUAD_STRIP)for j in range(N+1):u = 2*math.pi*i/Nv = 2*math.pi*j/Nx = (2/15)*(3+5*math.cos(u))*math.sin(u) + (2/15)*2*math.cos(u)*math.sin(v)y = (2/15)*(3+5*math.cos(u))*math.cos(u) + (2/15)*2*math.sin(u)*math.sin(v)z = (2/15)*2*math.cos(v)glColor3f(abs(math.sin(u)), abs(math.sin(v)), abs(math.cos(u)))glVertex3f(x, y, z)glEnd()class StarGL(Base3DGL):name = "星形体-三色"def render_scene(self):glBegin(GL_TRIANGLE_FAN)glColor3f(1,0,0)glVertex3f(0,0,1.1)for i in range(13):ang = i/12*2*math.pir = 1.2 if i%2==0 else 0.6glColor3f((i%3)/2,(i%4)/3,(i%5)/4)glVertex3f(r*math.cos(ang), r*math.sin(ang), -0.7)glEnd()class MobiusGL(Base3DGL):name = "莫比乌斯环"def render_scene(self):N = 60w = 0.2for i in range(N):glBegin(GL_QUAD_STRIP)for j in range(2):phi = 2*math.pi*i/Nt = -w + 2*w*jx = math.cos(phi) + t*math.cos(phi/2)*math.cos(phi)y = math.sin(phi) + t*math.cos(phi/2)*math.sin(phi)z = t*math.sin(phi/2)glColor3f(abs(math.cos(phi)), abs(math.sin(phi)), abs(t))glVertex3f(x, y, z)glEnd()class RippleGL(Base3DGL):name = "涟漪"def render_scene(self):N = 30for i in range(N):glBegin(GL_LINE_STRIP)for j in range(N+1):r = 0.2 + 1.6 * i/Ntheta = 2*math.pi*j/Nz = math.sin(r*4-theta*2)*0.3glColor3f(abs(math.sin(r)), abs(math.cos(theta)), abs(z))glVertex3f(r*math.cos(theta), r*math.sin(theta), z)glEnd()class RoseGL(Base3DGL):name = "玫瑰线"def render_scene(self):glBegin(GL_LINE_STRIP)for i in range(600):theta = i/100 * math.pir = math.sin(3*theta)*1.5x = r*math.cos(theta)y = r*math.sin(theta)z = math.cos(5*theta)glColor3f(abs(math.sin(theta)), abs(math.cos(theta)), abs(z))glVertex3f(x, y, z)glEnd()class TrefoilGL(Base3DGL):name = "三叶结"def render_scene(self):glBegin(GL_LINE_STRIP)for i in range(400):t = 2*math.pi*i/400x = math.sin(t) + 2*math.sin(2*t)y = math.cos(t) - 2*math.cos(2*t)z = -math.sin(3*t)glColor3f(abs(math.sin(t)), abs(math.cos(t)), abs(z))glVertex3f(x, y, z)glEnd()# ----------- 第3页(动态变体/动画) -----------
class BubbleGL(Base3DGL):name = "泡泡球"def render_scene(self):t = time.time()for i in range(12, 40, 3):glBegin(GL_LINE_LOOP)r = 1+0.2*math.sin(t+i)for j in range(32):ang = 2*math.pi*j/32x, y, z = r*math.sin(i)*math.cos(ang), r*math.sin(i)*math.sin(ang), r*math.cos(i)glColor3f(abs(math.sin(ang)), abs(math.cos(i)), abs(math.cos(ang)))glVertex3f(x/15, y/15, z/15)glEnd()class AnimatedWaveGL(Base3DGL):name = "动态波浪"def render_scene(self):t = time.time()N = 22for i in range(N):glBegin(GL_TRIANGLE_STRIP)for j in range(N+1):x = -2 + 4*i/Ny = -2 + 4*j/Nz1 = math.sin(x*2+y*2+t*2)*0.6z2 = math.sin((x+4/N)*2+y*2+t*2)*0.6glColor3f(0.5+0.5*math.sin(t+i), 0.6+0.4*math.cos(t+j), 0.6+0.4*math.cos(i+j))glVertex3f(x, y, z1)glVertex3f(x+4/N, y, z2)glEnd()class AnimatedSpiralGL(Base3DGL):name = "动画螺旋"def render_scene(self):t = time.time()glBegin(GL_LINE_STRIP)for idx in range(120):ang = idx/20 + tr = 1.1 + 0.2*math.sin(idx*6+t)x = math.cos(ang)*ry = math.sin(ang)*rz = math.sin(t + idx/24)*0.6glColor3f(abs(math.sin(ang)), abs(math.cos(idx)), abs(z))glVertex3f(x, y, z)glEnd()class AnimatedWaveSurfaceGL(Base3DGL):name = "动画波浪面"def render_scene(self):t = time.time()N = 18for i in range(N):glBegin(GL_TRIANGLE_STRIP)for j in range(N+1):x = -2 + 4*i/Ny = -2 + 4*j/Nz1 = math.sin(x*3+y*3+t)*0.5z2 = math.sin((x+4/N)*3+y*3+t)*0.5glColor3f(abs(math.sin(t+x)), abs(math.cos(t+y)), abs(z1))glVertex3f(x, y, z1)glVertex3f(x+4/N, y, z2)glEnd()class AnimatedTwistGL(Base3DGL):name = "动态扭曲体"def render_scene(self):t = time.time()N = 20for i in range(N):glBegin(GL_TRIANGLE_STRIP)for j in range(N+1):x = -2 + 4*i/Ny = -2 + 4*j/Nz1 = math.sin(x*3+y*3+t*1.5+i*0.2+j*0.2)*0.3z2 = math.sin((x+4/N)*3+y*3+t*1.5+i*0.2+j*0.2)*0.3glColor3f(0.5+0.5*math.sin(t+i), 0.6+0.4*math.cos(t+j), 0.8+0.2*math.cos(i+j))glVertex3f(x, y, z1)glVertex3f(x+4/N, y, z2)glEnd()class AnimatedSphereGL(Base3DGL):name = "动态呼吸球"def render_scene(self):t = time.time()for i in range(30):lat0 = math.pi * (-0.5 + float(i) / 30)z0 = math.sin(lat0)zr0 = math.cos(lat0)lat1 = math.pi * (-0.5 + float(i + 1) / 30)z1 = math.sin(lat1)zr1 = math.cos(lat1)glBegin(GL_QUAD_STRIP)for j in range(32):lng = 2 * math.pi * float(j) / 32x = math.cos(lng)y = math.sin(lng)s = 1.1 + 0.25*math.sin(t+j*0.13+i*0.11)glColor3f(abs(x), abs(y), abs(z0))glVertex3f(x * zr0 * s, y * zr0 * s, z0 * s)glVertex3f(x * zr1 * s, y * zr1 * s, z1 * s)glEnd()class AnimatedTwistTorusGL(Base3DGL):name = "动态扭曲圆环"def render_scene(self):t = time.time()R, r = 1.0, 0.36N, M = 32, 18for i in range(N):glBegin(GL_QUAD_STRIP)for j in range(M+1):for k in [0, 1]:s = 2 * math.pi * (i + k) / Nt1 = 2 * math.pi * j / M + 0.5*math.sin(t+s)x = (R + r * math.cos(t1)) * math.cos(s)y = (R + r * math.cos(t1)) * math.sin(s)z = r * math.sin(t1)glColor3f(abs(math.cos(s)), abs(math.sin(t1)), abs(math.sin(s)))glVertex3f(x, y, z)glEnd()class AnimatedExplosionGL(Base3DGL):name = "动态爆炸球"def render_scene(self):t = time.time()for i in range(20, 30):lat0 = math.pi * (-0.5 + float(i) / 30)z0 = math.sin(lat0)zr0 = math.cos(lat0)lat1 = math.pi * (-0.5 + float(i+1) / 30)z1 = math.sin(lat1)zr1 = math.cos(lat1)glBegin(GL_LINE_STRIP)for j in range(32):lng = 2 * math.pi * float(j) / 32x = math.cos(lng)y = math.sin(lng)f = 1.0+0.6*math.sin(t*2+i+j)glColor3f(abs(x*f), abs(y*f), abs(z0*f))glVertex3f(x * zr0*f, y * zr0*f, z0*f)glEnd()class AnimatedEggGL(Base3DGL):name = "动态蛋形"def render_scene(self):t = time.time()N = 24for i in range(N):lat0 = math.pi * (-0.5 + float(i) / N)z0 = math.sin(lat0)*1.2 + 0.4*math.sin(lat0+t)**3zr0 = math.cos(lat0)lat1 = math.pi * (-0.5 + float(i+1) / N)z1 = math.sin(lat1)*1.2 + 0.4*math.sin(lat1+t)**3zr1 = math.cos(lat1)glBegin(GL_QUAD_STRIP)for j in range(N+1):lng = 2 * math.pi * float(j) / Nx = math.cos(lng)y = math.sin(lng)glColor3f((j%3)/2, (i%5)/4, (j%7)/6)glVertex3f(x * zr0, y * zr0, z0)glVertex3f(x * zr1, y * zr1, z1)glEnd()class AnimatedRippleGL(Base3DGL):name = "动画涟漪"def render_scene(self):t = time.time()N = 30for i in range(N):glBegin(GL_LINE_STRIP)for j in range(N+1):r = 0.2 + 1.6 * i/Ntheta = 2*math.pi*j/Nz = math.sin(r*4-theta*2+t*2)*0.3glColor3f(abs(math.sin(r+t)), abs(math.cos(theta)), abs(z))glVertex3f(r*math.cos(theta), r*math.sin(theta), z)glEnd()# ----------- 第4页(极坐标/分形/特殊体) -----------
class HelixGL(Base3DGL):name = "三色螺旋弹簧"def render_scene(self):glBegin(GL_LINE_STRIP)for i in range(300):t = i/50x = math.cos(t)*1.2y = math.sin(t)*1.2z = t/4glColor3f(abs(math.sin(t)), abs(math.cos(t)), abs(z)%1)glVertex3f(x, y, z)glEnd()class HyperboloidGL(Base3DGL):name = "双曲面"def render_scene(self):N = 30for i in range(N):glBegin(GL_LINE_LOOP)for j in range(N):u = i*2*math.pi/Nv = j*2*math.pi/Nx = math.cosh(v)*math.cos(u)y = math.cosh(v)*math.sin(u)z = math.sinh(v)glColor3f(abs(math.sin(u)), abs(math.cos(v)), abs(z)%1)glVertex3f(x/6, y/6, z/6)glEnd()class ParaboloidGL(Base3DGL):name = "抛物面"def render_scene(self):N = 30for i in range(N):glBegin(GL_LINE_LOOP)for j in range(N):u = i*2*math.pi/Nv = j*2/Nx = v*math.cos(u)y = v*math.sin(u)z = v**2glColor3f(abs(math.sin(u)), abs(math.cos(v)), abs(z)%1)glVertex3f(x, y, z/4)glEnd()class AstroidGL(Base3DGL):name = "阿斯托洛伊德"def render_scene(self):glBegin(GL_LINE_STRIP)for i in range(400):t = 2 * math.pi * i / 400x = math.cos(t)**3y = math.sin(t)**3z = math.cos(3*t)glColor3f(abs(x), abs(y), abs(z))glVertex3f(x, y, z/2)glEnd()class SuperquadricGL(Base3DGL):name = "超二次曲面"def render_scene(self):N = 32e = 0.5for i in range(N):u = -math.pi/2 + i*math.pi/Nu2 = -math.pi/2 + (i+1)*math.pi/NglBegin(GL_QUAD_STRIP)for j in range(N+1):v = -math.pi + 2*j*math.pi/Nx1 = math.copysign(abs(math.cos(u))**e, math.cos(u))*math.copysign(abs(math.cos(v))**e, math.cos(v))y1 = math.copysign(abs(math.cos(u))**e, math.cos(u))*math.copysign(abs(math.sin(v))**e, math.sin(v))z1 = math.copysign(abs(math.sin(u))**e, math.sin(u))x2 = math.copysign(abs(math.cos(u2))**e, math.cos(u2))*math.copysign(abs(math.cos(v))**e, math.cos(v))y2 = math.copysign(abs(math.cos(u2))**e, math.cos(u2))*math.copysign(abs(math.sin(v))**e, math.sin(v))z2 = math.copysign(abs(math.sin(u2))**e, math.sin(u2))glColor3f(abs(x1), abs(y1), abs(z1))glVertex3f(x1, y1, z1)glColor3f(abs(x2), abs(y2), abs(z2))glVertex3f(x2, y2, z2)glEnd()class ButterflyGL(Base3DGL):name = "蝴蝶线"def render_scene(self):glBegin(GL_LINE_STRIP)for i in range(800):t = i/50x = math.sin(t)*(math.exp(math.cos(t)) - 2*math.cos(4*t) - math.sin(t/12)**5)y = math.cos(t)*(math.exp(math.cos(t)) - 2*math.cos(4*t) - math.sin(t/12)**5)z = math.sin(3*t)glColor3f(abs(x)%1, abs(y)%1, abs(z)%1)glVertex3f(x/3, y/3, z/2)glEnd()class LissajousGL(Base3DGL):name = "利萨茹空间曲线"def render_scene(self):glBegin(GL_LINE_STRIP)for i in range(800):t = i/100x = math.sin(3*t + math.pi/2)y = math.sin(4*t)z = math.sin(5*t)glColor3f(abs(x), abs(y), abs(z))glVertex3f(x, y, z)glEnd()class VivianiGL(Base3DGL):name = "维维亚尼曲线"def render_scene(self):glBegin(GL_LINE_STRIP)for i in range(800):t = 2*math.pi*i/800x = 1 + math.cos(t)y = math.sin(t)z = 2*math.sin(t/2)glColor3f(abs(x), abs(y), abs(z/2))glVertex3f(x/2, y/2, z/2)glEnd()class HypocycloidGL(Base3DGL):name = "内摆线"def render_scene(self):glBegin(GL_LINE_STRIP)for i in range(800):t = 2*math.pi*i/800x = 2*math.cos(t) + math.cos(2*t)y = 2*math.sin(t) - math.sin(2*t)z = math.sin(3*t)glColor3f(abs(x/2), abs(y/2), abs(z/2))glVertex3f(x/2, y/2, z/2)glEnd()class EpicycloidGL(Base3DGL):name = "外摆线"def render_scene(self):glBegin(GL_LINE_STRIP)for i in range(800):t = 2*math.pi*i/800x = 2*math.cos(t) - math.cos(2*t)y = 2*math.sin(t) - math.sin(2*t)z = math.cos(3*t)glColor3f(abs(x/2), abs(y/2), abs(z/2))glVertex3f(x/2, y/2, z/2)glEnd()# ----------- 第5页(分形/变幻/多样体) -----------
class FernGL(Base3DGL):name = "分形蕨叶"def render_scene(self):points = []x, y = 0, 0for i in range(5000):r = np.random.random()if r < 0.01:x, y = 0, 0.16*yelif r < 0.86:x, y = 0.85*x + 0.04*y, -0.04*x + 0.85*y + 1.6elif r < 0.93:x, y = 0.2*x - 0.26*y, 0.23*x + 0.22*y + 1.6else:x, y = -0.15*x + 0.28*y, 0.26*x + 0.24*y + 0.44points.append((x, y))glBegin(GL_POINTS)for px, py in points:glColor3f(0, 0.6+0.3*px, 0.2+0.5*py)glVertex3f((px-2)*0.5, (py-3)*0.5, 0)glEnd()class SierpinskiGL(Base3DGL):name = "谢尔宾斯基地毯"def render_scene(self):def draw_carpet(x, y, s, depth):if depth == 0:glColor3f(1,0.6,0.2)glVertex3f(x, y, 0)returns /= 3for dx in [-s, 0, s]:for dy in [-s, 0, s]:if dx != 0 or dy != 0:draw_carpet(x+dx, y+dy, s, depth-1)glBegin(GL_POINTS)draw_carpet(0,0,1.0,4)glEnd()class KochCurveGL(Base3DGL):name = "科赫雪花"def render_scene(self):def koch(p1, p2, depth):if depth == 0:glColor3f(0.2,0.5,1)glVertex3f(*p1)glVertex3f(*p2)else:p3 = ((2*p1[0]+p2[0])/3, (2*p1[1]+p2[1])/3, 0)p4 = ((p1[0]+2*p2[0])/3, (p1[1]+2*p2[1])/3, 0)ang = math.atan2(p2[1]-p1[1], p2[0]-p1[0]) - math.pi/3px = p3[0] + math.cos(ang)*(abs(p4[0]-p3[0]))py = p3[1] + math.sin(ang)*(abs(p4[0]-p3[0]))p5 = (px, py, 0)koch(p1, p3, depth-1)koch(p3, p5, depth-1)koch(p5, p4, depth-1)koch(p4, p2, depth-1)glBegin(GL_LINES)koch((-0.8,0.5,0), (0.8,0.5,0), 3)koch((0.8,0.5,0), (0,-0.8,0), 3)koch((0,-0.8,0), (-0.8,0.5,0), 3)glEnd()class FractalTreeGL(Base3DGL):name = "分形树"def render_scene(self):def draw_tree(x, y, angle, depth):if depth == 0: returnx2 = x + math.cos(angle)*depth*0.11y2 = y + math.sin(angle)*depth*0.11glColor3f(0.3,0.2+0.08*depth,0.1+0.03*depth)glVertex3f(x, y, 0)glVertex3f(x2, y2, 0)draw_tree(x2, y2, angle-math.pi/6, depth-1)draw_tree(x2, y2, angle+math.pi/6, depth-1)glBegin(GL_LINES)draw_tree(0,-0.7,math.pi/2,6)glEnd()class DragonCurveGL(Base3DGL):name = "龙曲线"def render_scene(self):def dragon(p1, p2, depth):if depth == 0:glColor3f(0.7,0.2,1)glVertex3f(*p1)glVertex3f(*p2)else:mx = (p1[0]+p2[0])/2 + (p2[1]-p1[1])/2my = (p1[1]+p2[1])/2 - (p2[0]-p1[0])/2m = (mx,my,0)dragon(p1, m, depth-1)dragon(p2, m, depth-1)glBegin(GL_LINES)dragon((-0.7,0,0), (0.7,0,0), 12)glEnd()class JuliaGL(Base3DGL):name = "Julia分形"def render_scene(self):glBegin(GL_POINTS)for ix in range(120):for iy in range(120):x = (ix-60)/40y = (iy-60)/40zx, zy = x, ycX, cY = -0.7, 0.27015n, max_n = 0, 30while zx*zx + zy*zy < 4 and n < max_n:tmp = zx*zx - zy*zy + cXzy, zx = 2*zx*zy + cY, tmpn += 1glColor3f(n/max_n, 0.2+0.6*n/max_n, 1-n/max_n)glVertex3f(x, y, 0)glEnd()class MandelbrotGL(Base3DGL):name = "Mandelbrot分形"def render_scene(self):glBegin(GL_POINTS)for ix in range(120):for iy in range(120):x0 = (ix-60)/40y0 = (iy-60)/40x, y = 0, 0n, max_n = 0, 30while x*x + y*y < 4 and n < max_n:xt = x*x - y*y + x0y = 2*x*y + y0x = xtn += 1glColor3f(n/max_n, 1-n/max_n, 0.7*n/max_n)glVertex3f(x0, y0, 0)glEnd()class PeanoGL(Base3DGL):name = "皮亚诺曲线"def render_scene(self):def peano(x, y, dx, dy, depth):if depth == 0:glColor3f(0.3+0.6*x,0.7-0.3*y,0.5+0.3*y)glVertex3f(x, y, 0)returnfor i in [0,1,2]:for j in [0,1,2]:peano(x+i*dx/3, y+j*dy/3, dx/3, dy/3, depth-1)glBegin(GL_POINTS)peano(-0.7,-0.7,1.4,1.4,3)glEnd()class CantorGL(Base3DGL):name = "康托三分集"def render_scene(self):def cantor(x, y, l, depth):if depth == 0:glColor3f(0.8,0.8,0.2)glVertex3f(x, y, 0)glVertex3f(x+l, y, 0)returnglColor3f(0.8,0.5,0.1+0.1*depth)glVertex3f(x, y, 0)glVertex3f(x+l, y, 0)cantor(x, y-0.1, l/3, depth-1)cantor(x+2*l/3, y-0.1, l/3, depth-1)glBegin(GL_LINES)cantor(-0.8, 0.8, 1.6, 6)glEnd()class PolygonFanGL(Base3DGL):name = "渐变扇形多边形"def render_scene(self):glBegin(GL_TRIANGLE_FAN)glColor3f(1,1,1)glVertex3f(0,0,0)for i in range(31):ang = 2*math.pi*i/30glColor3f(abs(math.sin(ang)), abs(math.cos(ang)), 0.5+0.5*math.sin(ang*3))glVertex3f(math.cos(ang), math.sin(ang), 0)glEnd()# ========== 工厂函数 ==========
def get_3d_widget_by_index(idx):page1 = [SphereGL, CubeGL, OctahedronGL, IcosahedronGL, DodecahedronGL,CylinderGL, ConeGL, TorusGL, SpiralGL, WaveSurfaceGL]page2 = [HeartSurfaceGL, SineWaveGL, SaddleGL, EggShapeGL, KleinBottleGL,StarGL, MobiusGL, RippleGL, RoseGL, TrefoilGL]page3 = [BubbleGL, AnimatedWaveGL, AnimatedSpiralGL, AnimatedWaveSurfaceGL, AnimatedTwistGL,AnimatedSphereGL, AnimatedTwistTorusGL, AnimatedExplosionGL, AnimatedEggGL, AnimatedRippleGL]page4 = [HelixGL, HyperboloidGL, ParaboloidGL, AstroidGL, SuperquadricGL,ButterflyGL, LissajousGL, VivianiGL, HypocycloidGL, EpicycloidGL]page5 = [FernGL, SierpinskiGL, KochCurveGL, FractalTreeGL, DragonCurveGL,JuliaGL, MandelbrotGL, PeanoGL, CantorGL, PolygonFanGL]allcls = page1 + page2 + page3 + page4 + page5return allcls[idx]()# ========== 主窗口 ==========
class All3DEffectsGLDemo(QMainWindow):def __init__(self):super().__init__()self.setWindowTitle("50种3D效果合集(GPU+FPS+鼠标旋转)")self.setGeometry(100, 60, 1600, 900)self.init_ui()def init_ui(self):widget = QWidget()vbox = QVBoxLayout(widget)self.setCentralWidget(widget)title = QLabel("🌈 50种3D效果演示 (OpenGL+FPS实时) 🌈")title.setFont(QFont("微软雅黑", 24, QFont.Bold))title.setAlignment(Qt.AlignCenter)title.setStyleSheet("""color:#43e97b; background: #191a25;border-radius:14px; margin:10px; padding:20px;border: 2px solid #647dee;""")vbox.addWidget(title)tabs = QTabWidget()tabs.setTabPosition(QTabWidget.West)tabs.setStyleSheet("""QTabBar::tab {background: #232338;color: #a3e0ff;font: 16px "微软雅黑";border: 2px solid #647dee;border-radius: 12px;margin: 6px;min-width: 110px;min-height: 50px;padding: 8px 18px;}QTabBar::tab:selected {background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #43e97b, stop:1 #38f9d7);color: #161623;font: bold 18px "微软雅黑";border: 3px solid #43e97b;}QTabBar::tab:hover {background: #304674;color: #fff;}QTabWidget::pane {border: 2px solid #647dee;border-radius: 16px;margin: 8px;}""")vbox.addWidget(tabs)self.widget_list = []for page in range(5):tab = QWidget()grid = QGridLayout(tab)for i in range(10):idx = page*10 + iframe = QFrame()frame.setFrameShape(QFrame.StyledPanel)frame.setStyleSheet("background:#22242e; border-radius:18px;")vlay = QVBoxLayout(frame)w = get_3d_widget_by_index(idx)self.widget_list.append(w)vlay.setContentsMargins(2,2,2,2)vlay.addWidget(w)fps_label = QLabel()fps_label.setFont(QFont("微软雅黑", 10))fps_label.setStyleSheet("color:#43e97b; margin-left:3px;")fps_label.setAlignment(Qt.AlignLeft)vlay.addWidget(fps_label)frame.fps_label = fps_labelframe.widget = wgrid.addWidget(frame, i//5, i%5)tabs.addTab(tab, f"第{page+1}页")for i in range(5): grid.setColumnStretch(i, 1)for i in range(2): grid.setRowStretch(i, 1)self.fps_timer = QTimer(self)self.fps_timer.timeout.connect(self.update_fps_labels)self.fps_timer.start(400)def update_fps_labels(self):for tab_index in range(5):tab = self.centralWidget().layout().itemAt(1).widget().widget(tab_index)grid = tab.layout()for i in range(10):frame = grid.itemAt(i).widget()w = frame.widgetframe.fps_label.setText(f"{w.name}\nFPS: {w.fps:.1f}")if __name__ == '__main__':app = QApplication(sys.argv)app.setStyle("Fusion")palette = QPalette()palette.setColor(QPalette.Window, QColor("#191a25"))palette.setColor(QPalette.WindowText, QColor("#e0eafc"))app.setPalette(palette)win = All3DEffectsGLDemo()win.show()sys.exit(app.exec_())