Blender中Bianchi-Pinkall曲面生成脚本故障修复请求
修复后的Bianchi-Pinkall曲面生成脚本
我从网上找了这个生成Bianchi-Pinkall曲面的脚本,据说以前能正常运行,但现在在Blender里跑不起来。我不懂Python,试过用VSCode查看也解决不了问题,想把这个脚本修好来做3D模型当礼物。
修复后的完整代码
import bpy import math from mathutils import Vector import numpy subDivIterations = 5 valminu=0 valmaxu=math.pi*2 valminv=0 valmaxv=math.pi*2 resolutionu=150 resolutionv=150 pasu = (valmaxu - valminu) / resolutionu pasv = (valmaxv - valminv) / resolutionv a=0.93 # 珊瑚半径,可调整 n=3 # 花瓣/子旋转数量 b=0.36 # 花形半径,可调整 c=0 d=0 k=15 varu= valminu varv= valminv goldenRatio = (1 + math.sqrt(5)) / 2 def subdivide(triangles): result = [] for color, A, B, C in triangles: if color == 0: # 细分红色三角形 P = A + (B - A) / goldenRatio result += [(0, C, P, B), (1, P, C, A)] else: # 细分蓝色三角形 Q = B + (A - B) / goldenRatio R = B + (C - B) / goldenRatio result += [(1, R, C, A), (1, Q, R, B), (0, R, Q, A)] return result # 创建曲面三角形 def createSurfaceBianchiPinkall(): triangles = [] epsilon = 1e-8 # 避免除以零的小数值 for varu in numpy.arange(valminu, valmaxu, pasu): for varv in numpy.arange(valminv, valmaxv, pasv): gamma = a+b*math.sin(2*n*varv) x = math.cos(varu+varv)*math.cos(gamma) y = math.sin(varu+varv)*math.cos(gamma) z = math.cos(varu-varv)*math.sin(gamma) w = math.sin(varu-varv)*math.sin(gamma) # 处理w接近1时的除以零问题 denominator = math.sqrt(max(1-w*w, epsilon)) r = math.acos(w)/(math.pi*denominator) A = Vector((x*r,y*r,z*r)) varva = varv + pasv gamma = a+b*math.sin(2*n*varva) x = math.cos(varu+varva)*math.cos(gamma) y = math.sin(varu+varva)*math.cos(gamma) z = math.cos(varu-varva)*math.sin(gamma) w = math.sin(varu-varva)*math.sin(gamma) denominator = math.sqrt(max(1-w*w, epsilon)) r = math.acos(w)/(math.pi*denominator) B = Vector((x*r,y*r,z*r)) varua = varu + pasu gamma = a+b*math.sin(2*n*varva) x = math.cos(varua+varva)*math.cos(gamma) y = math.sin(varua+varva)*math.cos(gamma) z = math.cos(varua-varva)*math.sin(gamma) w = math.sin(varua-varva)*math.sin(gamma) denominator = math.sqrt(max(1-w*w, epsilon)) r = math.acos(w)/(math.pi*denominator) C = Vector((x*r,y*r,z*r)) triangles.append((0, A, B, C)) gamma = a+b*math.sin(2*n*varv) x = math.cos(varua+varv)*math.cos(gamma) y = math.sin(varua+varv)*math.cos(gamma) z = math.cos(varua-varv)*math.sin(gamma) w = math.sin(varua-varv)*math.sin(gamma) denominator = math.sqrt(max(1-w*w, epsilon)) r = math.acos(w)/(math.pi*denominator) D = Vector((x*r,y*r,z*r)) triangles.append((0, A, C, D)) return triangles # 生成曲面网格数据 listTriangles = createSurfaceBianchiPinkall() # 如需细分可取消注释下面两行 # for x in range(subDivIterations): # listTriangles = subdivide(listTriangles) # 构建顶点和面数据(优化重复顶点问题) listVertices = [] vertex_map = {} listFaces = [] for triangle in listTriangles: verts = [] for vec in triangle[1:]: # 把向量转成可哈希的元组,用于判断是否已存在 vert_tuple = (round(vec.x, 6), round(vec.y, 6), round(vec.z, 6)) if vert_tuple not in vertex_map: vertex_map[vert_tuple] = len(listVertices) listVertices.append(vert_tuple) verts.append(vertex_map[vert_tuple]) listFaces.append(tuple(verts)) # 创建Blender网格和对象 mesh = bpy.data.meshes.new("SurfaceBianchiPinkallMesh") ob = bpy.data.objects.new("SurfaceBianchiPinkall", mesh) ob.location = Vector((0,0,0)) # 适配Blender 2.8+的集合链接方式 bpy.context.collection.objects.link(ob) # 填充网格数据 mesh.from_pydata(listVertices, [], listFaces) mesh.validate(clean_customdata=True) mesh.update()
修复说明
- 适配Blender新版本API:把旧版的
bpy.context.scene.objects.link(ob)换成了Blender 2.8+支持的bpy.context.collection.objects.link(ob),解决对象无法链接到场景的问题。 - 解决数值计算错误:添加了
epsilon小值,避免计算sqrt(1-w²)时出现除以零的情况,防止脚本崩溃。 - 优化顶点存储:用字典记录已存在的顶点,避免重复添加相同顶点,大幅减少模型的顶点数量,提升性能。
- 保留细分功能:原脚本的细分迭代功能被注释,如需更高精度的曲面,可取消注释对应的两行代码(注意:高迭代次数会大幅增加计算量)。
内容的提问来源于stack exchange,提问作者Jack4789
相关产品推荐
相关产品推荐

