This is not my work but i am trying to get it to work. Its a script i found online to generate a bianchi Pinkall surface, apparently it worked at one point but now does not. If something can make it work that would be incredible as i am trying to generate the object in 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 #rayon de la corale à tester sous : analyticphysics.com/Higher Dimensions/Interactive Bianchi-Pinkall Flat Tori.htm
n=3 #Nbre de sous rotation ou de pétaile
b=0.36 #rayon internet de la fleur
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:
# Subdivide red triangle
P = A + (B - A) / goldenRatio
result += [(0, C, P, B), (1, P, C, A)]
else:
# Subdivide blue triangle
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
# Create des tirangles du coquillage
# Create wheel of red triangles around the origin
#x = f(u,v) = u + uv2 – (1/3)u3, y = g(u,v) = v + u2v – (1/3)v3, z = h(u,v) = u2 – v2.
def createSurfaceBianchiPinkall():
triangles = []
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)
r = math.acos(w)/math.pi/math.sqrt(1-w*w);
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)
r = math.acos(w)/math.pi/math.sqrt(1-w*w);
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)
r = math.acos(w)/math.pi/math.sqrt(1-w*w);
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)
r = math.acos(w)/math.pi/math.sqrt(1-w*w);
D = Vector((x*r,y*r,z*r))
triangles.append((0, A, C, D))
return triangles
# Generate map of tiling
listTriangles = createSurfaceBianchiPinkall()
#for x in range(subDivIterations):
# listTriangles = subdivide(listTriangles)
# Construction du coquilage
# Construct the lists necessary for generation of geometry
listVertices = []
listFaces = []
for triangle in listTriangles:
# write the vertex coords to the list, and remember the vertex indices
# In Blender, the mesh data stores each vertex as a tuple of 3 floats.
newVertex1 = (triangle[1][0],triangle[1][1],triangle[1][2])
newVertex2 = (triangle[2][0],triangle[2][1],triangle[2][2])
newVertex3 = (triangle[3][0],triangle[3][1],triangle[3][2])
listVertices.append(newVertex1)
newVertex1_i = len(listVertices) - 1
listVertices.append(newVertex2)
newVertex2_i = len(listVertices) - 1
listVertices.append(newVertex3)
newVertex3_i = len(listVertices) - 1
# write to the list of edges
# Define the faces by index numbers. Each faces is defined by 4 consecutive integers.
# For triangles you need to repeat the first vertex also in the fourth position.
newFace = (newVertex1_i,newVertex2_i,newVertex3_i)
listFaces.append(newFace)
mesh = bpy.data.meshes.new("SurfaceBianchiPinkallMesh") # create a new mesh
ob = bpy.data.objects.new("SurfaceBianchiPinkall", mesh) # create an object with that mesh
ob.location = Vector((0,0,0)) #by.context.scene.cursor_location # position object at 3d-cursor
bpy.context.scene.objects.link(ob) # Link object to scene
# Fill the mesh with verts, edges, faces
mesh.from_pydata(listVertices,[],listFaces) # edges or faces should be [], or you ask for problems
mesh.validate(True)
#mesh.update(calc_edges=True) # Update mesh with new data
I tried to use VScode to look at the python script but i dont know python so… this is all for a present for someone special.
There could be a number of things causing issues, for one the code you attached doesn't follow proper python indenting. If we fix that we may proceed with the real modifications which are simply the result of Blender 2.8+ refactoring.
From the Blender 2.8 change log for collections we learn
Layers and groups have been replaced by collections.
For us this means your line 121, bpy.context.scene.objects.link(ob)
, now throws AttributeError: bpy_prop_collection: attribute "link" not found
as the link property has been placed under bpy.context.scene.objects
as per the documentation. Concreatly this means you need to replace line 121 with
bpy.context.collection.objects.link(ob)
The next error we get TypeError: Mesh.validate(): required parameter "verbose" to be a keyword argument!
, this originates from line 124, mesh.validate(True)
, the issue is quite simple, to avoid ambiguity with the clean_customdata
parameter we simply need to specify we are providing the verbosity hence we replace line 124 with
mesh.validate(verbose=True)
I was able to valid this working on Blender 3.4 and 4.0.
I've attached the full modified code bellow (with my recreation of the indentation) as well as a screenshot of the successful output.
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 #rayon de la corale à tester sous : analyticphysics.com/Higher Dimensions/Interactive Bianchi-Pinkall Flat Tori.htm
n=3 #Nbre de sous rotation ou de pétaile
b=0.36 #rayon internet de la fleur
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:
# Subdivide red triangle
P = A + (B - A) / goldenRatio
result += [(0, C, P, B), (1, P, C, A)]
else:
# Subdivide blue triangle
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
# Create des tirangles du coquillage
# Create wheel of red triangles around the origin
#x = f(u,v) = u + uv2 – (1/3)u3, y = g(u,v) = v + u2v – (1/3)v3, z = h(u,v) = u2 – v2.
def createSurfaceBianchiPinkall():
triangles = []
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)
r = math.acos(w)/math.pi/math.sqrt(1-w*w);
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)
r = math.acos(w)/math.pi/math.sqrt(1-w*w);
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)
r = math.acos(w)/math.pi/math.sqrt(1-w*w);
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)
r = math.acos(w)/math.pi/math.sqrt(1-w*w);
D = Vector((x*r,y*r,z*r))
triangles.append((0, A, C, D))
return triangles
# Generate map of tiling
listTriangles = createSurfaceBianchiPinkall()
#for x in range(subDivIterations):
# listTriangles = subdivide(listTriangles)
# Construction du coquilage
# Construct the lists necessary for generation of geometry
listVertices = []
listFaces = []
for triangle in listTriangles:
# write the vertex coords to the list, and remember the vertex indices
# In Blender, the mesh data stores each vertex as a tuple of 3 floats.
newVertex1 = (triangle[1][0],triangle[1][1],triangle[1][2])
newVertex2 = (triangle[2][0],triangle[2][1],triangle[2][2])
newVertex3 = (triangle[3][0],triangle[3][1],triangle[3][2])
listVertices.append(newVertex1)
newVertex1_i = len(listVertices) - 1
listVertices.append(newVertex2)
newVertex2_i = len(listVertices) - 1
listVertices.append(newVertex3)
newVertex3_i = len(listVertices) - 1
# write to the list of edges
# Define the faces by index numbers. Each faces is defined by 4 consecutive integers.
# For triangles you need to repeat the first vertex also in the fourth position.
newFace = (newVertex1_i,newVertex2_i,newVertex3_i)
listFaces.append(newFace)
mesh = bpy.data.meshes.new("SurfaceBianchiPinkallMesh") # create a new mesh
ob = bpy.data.objects.new("SurfaceBianchiPinkall", mesh) # create an object with that mesh
ob.location = Vector((0,0,0)) #by.context.scene.cursor_location # position object at 3d-cursor
bpy.context.collection.objects.link(ob) # Link object to scene
# Fill the mesh with verts, edges, faces
mesh.from_pydata(listVertices,[],listFaces) # edges or faces should be [], or you ask for problems
mesh.validate(verbose=True)
#mesh.update(calc_edges=True) # Update mesh with new data