Creating A Sphere From Python?

Hi All,

I was trying to track down the code that Blender uses to generate the sphere primitive but I can not seem to find it. It must be hard coded in C. I am looking for a python solution.

But I was able to almost approximate that using the Torus code with a major radius of 0.0. Then the minor radius takes over and forms a sphere. But there are extra little vertical and horizontal faces in the mesh using this technique. I would like the cleanest sphere possible.

Torus Code:


def add_torus(major_rad, minor_rad, major_seg, minor_seg):
    from math import cos, sin, pi
    from mathutils import Vector, Quaternion

    PI_2 = pi * 2.0
    z_axis = 0.0, 0.0, 1.0

    verts = []
    faces = []
    i1 = 0
    tot_verts = major_seg * minor_seg
    for major_index in range(major_seg):
        quat = Quaternion(z_axis, (major_index / major_seg) * PI_2)

        for minor_index in range(minor_seg):
            angle = 2 * pi * minor_index / minor_seg

            vec = quat * Vector((major_rad + (cos(angle) * minor_rad),
                                 0.0,
                                 (sin(angle) * minor_rad),
                                 ))

            verts.extend(vec[:])

            if minor_index + 1 == minor_seg:
                i2 = (major_index) * minor_seg
                i3 = i1 + minor_seg
                i4 = i2 + minor_seg

            else:
                i2 = i1 + 1
                i3 = i1 + minor_seg
                i4 = i3 + 1

            if i2 >= tot_verts:
                i2 = i2 - tot_verts
            if i3 >= tot_verts:
                i3 = i3 - tot_verts
            if i4 >= tot_verts:
                i4 = i4 - tot_verts

            # stupid eekadoodle
            if i2:
                faces.extend([i1, i3, i4, i2])
            else:
                faces.extend([i2, i1, i3, i4])

            i1 += 1

    return verts, faces

Does anyone know how I could alter this code to just produce a sphere instead of a torus?

Thanks

Hi Atom,

this should do it:


def CalcSphere(radius, nrPolar, nrAzimuthal):
    dPolar = math.pi / (nrPolar - 1)
    dAzimuthal = 2.0 * math.pi / (nrAzimuthal)
    
    
    # 1/2: vertices
    verts = []
    currV = mathutils.Vector((0.0, 0.0, radius))        # top vertex
    verts.append(currV)
    for iPolar in range(1, nrPolar - 1):                # regular vertices
        currPolar = dPolar * float(iPolar)
        
        currCosP = math.cos(currPolar)
        currSinP = math.sin(currPolar)
        
        for iAzimuthal in range(nrAzimuthal):
            currAzimuthal = dAzimuthal * float(iAzimuthal)
        
            currCosA = math.cos(currAzimuthal)
            currSinA = math.sin(currAzimuthal)
            
            currV = mathutils.Vector((currSinP * currCosA, currSinP * currSinA, currCosP)) * radius
            verts.append(currV)
    currV = mathutils.Vector((0.0, 0.0, - radius))        # bottom vertex
    verts.append(currV)
    
    
    # 2/2: faces
    faces = []
    for iAzimuthal in range(nrAzimuthal):                # top faces
        iNextAzimuthal = iAzimuthal + 1
        if iNextAzimuthal >= nrAzimuthal: iNextAzimuthal -= nrAzimuthal
        faces.append([0, iAzimuthal + 1, iNextAzimuthal + 1])
        
    for iPolar in range(nrPolar - 3):                    # regular faces
        iAzimuthalStart = iPolar * nrAzimuthal + 1
        
        for iAzimuthal in range(nrAzimuthal):
            iNextAzimuthal = iAzimuthal + 1
            if iNextAzimuthal >= nrAzimuthal: iNextAzimuthal -= nrAzimuthal
            faces.append([iAzimuthalStart + iAzimuthal, iAzimuthalStart + iAzimuthal + nrAzimuthal, iAzimuthalStart + iNextAzimuthal + nrAzimuthal, iAzimuthalStart + iNextAzimuthal])
        
    iLast = len(verts) - 1
    iAzimuthalStart = iLast - nrAzimuthal
    for iAzimuthal in range(nrAzimuthal):                # bottom faces
        iNextAzimuthal = iAzimuthal + 1
        if iNextAzimuthal >= nrAzimuthal: iNextAzimuthal -= nrAzimuthal
        faces.append([iAzimuthalStart + iAzimuthal, iLast, iAzimuthalStart + iNextAzimuthal])
        
            
    return verts, faces

It does takes a bit of juggling with the indices near the poles. It produces 1 single vertex at each pole. It produces triangular faces near the poles, and quads elsewhere.

Howdy,

Had a quick go at this too, changing the face vert order gives some weird results.
Done with the equation of a sphere

http://upload.wikimedia.org/math/9/e/3/9e32cf9af726870981af4cf154ea874b.png
http://upload.wikimedia.org/math/3/f/4/3f44e350a2d0f0a9dd636b4e0049375a.png
http://upload.wikimedia.org/math/9/2/6/9261110138f668d178f1f9f03630111a.png

assumed center was 0, 0, 0. Also creates poles with segment x verts in single loc.


import bpy
from math import radians, sin, cos
#create a sphere


verts = []
edges =[]
faces = []
mesh = bpy.data.meshes.new("Sphere")
segments = 16
rings = 32
phi = 0
r = 5.0
for ring in range(rings+1):
    phi = ring * radians(180) / rings
    for segment in range(segments + 1):
        theta = segment * radians(360) / segments
        x = r * cos(theta) * sin(phi)
        y = r * sin(theta) * sin(phi)
        z = r * cos(phi)
        verts.append((x, y, z))
    if ring:
        for segment in range(segments):
            s = segments + 1
            faces.append([(ring - 1) * s + segment,
                          (ring - 1) * s + segment + 1,
                          (ring) * s + segment + 1,
                          (ring) * s + segment])
mesh.from_pydata(verts, edges, faces)


obj = bpy.data.objects.new("Sphere", mesh)
bpy.context.scene.objects.link(obj)


Thanks Fellows,

That works out fine. I think Guy’s solution is a little better for what I need and looks more like the ‘official’ sphere that Blender generates.


The batFinger solution while geometrically equivalent has some kind of smoothing issue I was unable to resolve.


I am releasing a Sphere Generator node in Blendrgaph and would like to use the code with credit, of course.

By all means, feel free to use that code.
Some kind of credit would be nice, of course… :slight_smile: