# How to create a sphere with different ring vertex count by scripting?

This question is related to this one: How to distribute the objects on a sphere evenly? I wonder if there's a way to create a sphere, in which every vertex loop's count is decreased according to its vertical position by scripting (let's say every ring count starting from the top of the sphere to the midlle of it is decreased by 6 vertices- as pictured below)? Is there a way to create a sphere and define it's individual ring's count by scripting?

P.s. I don't know if a tittle of my question is right. If not feel free to change it.

I think, there is no perfect solution to this problem, though:

What is the problem:

• Chords of each circle need to be regular in both directions (latitude, longitude)
• But this chords length need to correspond to a latitude of this sphere
• And this latitude may not correspond to an entire amount of the chord length

So the result is only an approximation.

The code without the UI:

import bpy
from math import pi, cos, sin

#Create a new mesh from a geometry
def CreateMesh( scene, name, location, vertices, edges, polygons ):
mesh = bpy.data.meshes.new( name )
obj = bpy.data.objects.new( name, mesh )
obj.location = location

scene.objects.active = obj
obj.select = True

mesh.from_pydata( vertices, edges, polygons )
mesh.update()

return obj

#Merge new vertices (a ring) to previous one
def MergeGeometry( vertices, edges, newVertices ):
base = len( vertices )
vertices += newVertices
newVerticesAmount = len( newVertices )
if newVerticesAmount > 2:
edges += [(base + i, base + int((i+1) % newVerticesAmount) ) for i in range( newVerticesAmount )]
elif newVerticesAmount == 2:
edges += [(base, base + 1)]
return vertices, edges

#Calculate a circle
def Circle( z, r, verticesAmount ):
baseAngle = 2 * pi / verticesAmount
return [(r * cos(i * baseAngle), r * sin(i * baseAngle), z) for i in range( verticesAmount )]

#Calculate the sphere
def HomogeneousSphereBySegments( segments, r ):
vertices, edges = [], []

if segments % 2 == 0:
ringAmount = segments // 2
baseAngle = pi / ringAmount
chord = 2 * r * sin( pi / segments )
arc = 2 * pi * r / segments
else:
#If odd we have to shift the angle from the 'equator'
ringAmount = segments // 2
baseAngle = pi / ringAmount
chord = 2 * r * cos( baseAngle / 2 ) * sin( pi / segments )
arc = 2 * pi * r * cos( baseAngle / 2 ) / segments

#First pole
vertices += [(0,0,-r)]

for i in range( 1, ringAmount ):
angle = (i * baseAngle) - (pi / 2)
z = r * sin( angle )
localR = abs( r * cos( angle ) )
verticesAmount = int( 2 * pi * localR / arc )
vertices, edges = MergeGeometry( vertices, edges, Circle( z, localR, verticesAmount ) )
print( ringAmount, baseAngle, angle, z, localR )

#Second pole
vertices += [(0,0,r)]

return vertices, edges


Blend file with code usable as an operator (add mesh, 'Homogeneous Sphere'):

• Thank you for your effort. The fact you can easily edit the sphere's parameters via operator panel make it a perferct answer. Amazing! May 2 '17 at 10:59

You can use bmesh.ops.create_circle() to add a circle to a mesh, then use bmesh.ops.translate() to put it into position, unless you create a matrix and pass it to create_circle.

You use the pythagorean theorem to get the size of each ring to get a spherical result.

And if you think the following math is out, it is because the diameter parameter for create_circle appears to actually be the radius.

import bpy
import bmesh
from math import sqrt

ring_verts = [32,32,32,30,24,18,12,6]

def get_diameter(z):

bm = bmesh.new()
for i,v in enumerate(ring_verts):
z = step_size * i
diam = get_diameter(z)
ret = bmesh.ops.create_circle(bm, cap_ends=False, diameter=diam, segments=v)
bmesh.ops.translate(bm, verts=ret['verts'], vec=(0.0,0.0,z))

me = bpy.data.meshes.new("Mesh")
bm.to_mesh(me)
bm.free()

scene = bpy.context.scene
obj = bpy.data.objects.new("Object", me)