4
$\begingroup$

I am very new to Blender, so perhaps my question is so elementary. My background is mathematics and so as my first experimentation I would like to make a Mobius Strip. In mathematics we start with a square (rectangle ) and rotate one edge and attach it to its opposite edge. I tried to do the same (by merging the vertices) in Blender and I noticed that Blender respects the orientation (or maybe I am wrong), that is it defers between front and back sides of a plane. So I was wondering if there is another way to start from a plane and make a Mobius Strip?

$\endgroup$
3

4 Answers 4

4
$\begingroup$

I tried to use Bob's script on Blender 2.80, but since a lot of stuff in the Python API changed the script doesn't work anymore.

I adapted it to the new version, you may check it here: https://github.com/ArthurHDRodrigues/collection_blender_script/blob/master/mobius.py

'''
This is a adaptation(to run in Blender 2.80) of Bob's 
script to generate a mobius strip

You may find the original one here:
https://blender.stackexchange.com/questions/82480/how-to-make-a-mobius-strip
'''
import bpy
from math import *
from mathutils import *


def mobius_mesh(resolution, major_radius, minor_radius, thick):

    verts = []
    faces = []

    for i in range(resolution):

        theta = 2*pi * i/resolution
        phi = pi * i/resolution

        rot1 = Matrix.Rotation(phi, 3, [0,1,0])
        rot2 = Matrix.Rotation(theta, 3, [0,0,1])
        c1 = Vector([major_radius, 0, 0])
        
        V_0 = Vector((-thick / 2, 0, minor_radius)) @ rot1[0]
        print(V_0)
        v1 = apply(rot2,c1 +  apply(rot1,Vector((-thick / 2, 0, minor_radius))))
        v2 = apply(rot2,(c1 + apply(rot1,Vector((thick / 2, 0, minor_radius)))))
        v3 = apply(rot2,(c1 + apply(rot1,Vector((thick / 2, 0, -minor_radius)))))
        v4 = apply(rot2,(c1 + apply(rot1,Vector((-thick / 2, 0, -minor_radius)))))
        
        i1 = len(verts)
        verts.extend([v1,v2,v3,v4])

        if i+1<resolution:
            ia = i1+4
            ib = i1+5
            ic = i1+6
            id = i1+7
        else:
            ia = 2
            ib = 3
            ic = 0
            id = 1

        # faces.append( [i1+j for j in range(4) ])
        faces.append( [i1,i1+1,ib,ia])
        faces.append( [i1+1,i1+2,ic,ib])
        faces.append( [i1+2,i1+3,id,ic])
        faces.append( [i1+3,i1,ia,id])
        
    mesh = bpy.data.meshes.new("mobius")
    mesh.from_pydata(verts, [], faces)

    for p in mesh.polygons:
        p.use_smooth=True

    return mesh

def apply(matrix,vector):
    '''
    matrix,vector -> vector
    
    this function receives a matrix and a vector and returns
    the vector obtained by multipling both of them
    '''
    V_0 = vector @ matrix[0]
    V_1 = vector @ matrix[1]
    V_2 = vector @ matrix[2]
            
    return Vector((V_0,V_1,V_2))

def mission1(scn, resolution, major_radius, minor_radius, thick):

    me = mobius_mesh(resolution, major_radius, minor_radius, thick)

    ob = bpy.data.objects.new("Mesh", me)

    #me.from_pydata(vertex_list, edge_list, [])
    #me.update()
    bpy.context.collection.objects.link(ob)
    


mission1(bpy.context.scene, 36, 5, 3, 0.1)
$\endgroup$
2
  • 1
    $\begingroup$ This works nice, but I get some weird artifacts on it. $\endgroup$
    – dawn
    Mar 5, 2021 at 4:00
  • $\begingroup$ Hi, can you post the parameters that resulted the artifacts, please? Or maybe a screenshot? So I can see the artifects. $\endgroup$ Mar 13, 2021 at 19:05
3
$\begingroup$

The Mobius strip as a 2D object will run into the conflict with normals, and while it can be achieved geometry it will restrict usage. In the example below the solidify modifier 'breaks' at the connection.

Mobius Strip Normals

Depending on what your final output is, it seems it is more flexible to have a ring, essentially creating an inner and outer surface.

Mobius Ring Normals

In the comments to your original post there are some examples as to how to create both rings and strips, but for simplicity I have added another which involves rotating one split edge 180 degrees with proportional editing set to connected.

enter image description here

enter image description here

$\endgroup$
2
  • 1
    $\begingroup$ From your answer, I understand that we can merge two vertices only if their normals have the same direction. In other words, two vertices with opposite direction can't be merged. Is this a valid conclusion? So, mathematically speaking, we can only produce orientable 2D manifolds in Blender. $\endgroup$
    – user40661
    Jun 30, 2017 at 19:21
  • 1
    $\begingroup$ As far as I know a vertex cannot be bi-directional. Vertices can be merged, but only one direction is chosen. $\endgroup$
    – Patdog
    Jun 30, 2017 at 19:34
3
$\begingroup$

Since I like blender's embedded python interpreter I use python code to construct any mathematical thing I dream up.

For a möbius strip I wrote http://web.purplefrog.com/~thoth/blender/python-cookbook/mobius-strip.html which I include here (for version 2.79):

import bpy
from math import *
from mathutils import *


def mobius_mesh(resolution, major_radius, minor_radius, thick):

    verts = []
    faces = []

    for i in range(resolution):

        theta = 2*pi * i/resolution
        phi = pi * i/resolution

        rot1 = Matrix.Rotation(phi, 3, [0,1,0])
        rot2 = Matrix.Rotation(theta, 3, [0,0,1])
        c1 = Vector([major_radius, 0, 0])
        v1 = rot2*(c1 + rot1 * Vector([-thick / 2, 0, minor_radius]) )
        v2 = rot2*(c1 + rot1 * Vector([thick / 2, 0, minor_radius]) )
        v3 = rot2*(c1 + rot1 * Vector([thick / 2, 0, -minor_radius]) )
        v4 = rot2*(c1 + rot1 * Vector([-thick / 2, 0, -minor_radius]) )

        i1 = len(verts)
        verts.extend([v1,v2,v3,v4])

        if i+1<resolution:
            ia = i1+4
            ib = i1+5
            ic = i1+6
            id = i1+7
        else:
            ia = 2
            ib = 3
            ic = 0
            id = 1

        # faces.append( [i1+j for j in range(4) ])
        faces.append( [i1,i1+1,ib,ia])
        faces.append( [i1+1,i1+2,ic,ib])
        faces.append( [i1+2,i1+3,id,ic])
        faces.append( [i1+3,i1,ia,id])

    #print (verts)
    #print (faces)
    mesh = bpy.data.meshes.new("mobius")
    mesh.from_pydata(verts, [], faces)
    mesh.validate(True)

    for p in mesh.polygons:
        p.use_smooth=True

    return mesh

def mission1(scn, resolution, major_radius, minor_radius, thick):

    mesh = mobius_mesh(resolution, major_radius, minor_radius, thick)

    obj = bpy.data.objects.new("mobius strip", mesh)
    scn.objects.link(obj)

    mod = obj.modifiers.new("edge split", 'EDGE_SPLIT')


mission1(bpy.context.scene, 36, 5, 1, 0.1)

For blender 2.8 you will have to replace scn.objects.link with scn.collection.objects.link. For blender 2.9 you will have to replace the rotn * with rotn @ because of (TypeError: Element-wise multiplication: not supported between 'Matrix' and 'Vector')

You will notice that the special case where ! (i+1<resolution) which binds the end of the strip to the start has a little twist to cope with the möbiusness. This twist would not be necessary for a torus.

mobius strip in edit mode

With some practice you can write python to construct any mesh you like out of whatever mathematical structure you want.

$\endgroup$
1
  • $\begingroup$ For some reason I´m getting an error in line 21. I´m using the latest Blender version. $\endgroup$
    – dawn
    Mar 5, 2021 at 4:05
2
$\begingroup$

This is an old question-- which makes it pretty surprising that during this time nobody ever gave a curve-based solution?

I think that curves are the easiest way to do this:

enter image description here

Careful: that's not a cyclic curve. That's a non-cylic curve with 5 different control points, two of which have the exact same location (and handles), but which have a twist that is offset by 180 degrees. That lets us interpolate the curve smoothly across the entire structure. In order, the tilts of the controls are 0, 45, 90, 135, 180 degrees.

I've added a weld modifier to the curve to join the end and the beginning. And I'm showing it with face orientation overlay so that you can see the normals are all pointing outwards (after giving the curve object a bevel and extrusion.)

The simplest way to make this particular object: make a bezier circle. Enter edit. Change all handles to free. Duplicate one segment of the curve. Toggle cyclic on the curve. Fill the hole created by toggling cyclic with the duplicated segment: rotate as needed; connect two coincident controls; dissolve the segment between those coincident controls. Enter tilts manually for all controls. Edit curve geometry settings as desired.

This is not a one-sided 'thin' mesh. The bevel property, generated by curve, makes it a solidified mesh, solidified about the center of the curve. Just as there is no such thing as a one-sided surface in reality (even a paper moebius strip is a volume, not a surface), one-sided surfaces in Blender or almost any other rendering engine are going to give you undesirable results (but if you want, just disable the bevel on the curve and play with it!)

$\endgroup$

You must log in to answer this question.