import bpy import bmesh import math # This will remove all the objects. Did we really need to? # It's handy if we're going to run this a bunch of times bpy.ops.object.mode_set(mode="OBJECT") bpy.ops.object.select_all(action='SELECT') # Default action is TOGGLE bpy.ops.object.delete() bpy.ops.mesh.primitive_torus_add(major_segments=480) torus = bpy.context.active_object for i in range(len(torus.data.vertices)): theta = math.atan2(torus.data.vertices[i].co.y, torus.data.vertices[i].co.x) r = math.sqrt(math.pow(torus.data.vertices[i].co.y, 2) + math.pow(torus.data.vertices[i].co.x, 2)) c_factor = math.sin(theta * 30) / 20 torus.data.vertices[i].co.z += c_factor if r > 1.2: r += c_factor elif r < 0.8: r -= c_factor torus.data.vertices[i].co.x = r * math.cos(theta) torus.data.vertices[i].co.y = r * math.sin(theta) bpy.ops.object.mode_set(mode="EDIT") torus_mesh = bmesh.from_edit_mesh(bpy.context.object.data) color_layer = torus_mesh.loops.layers.color.new("Giraffe") for face in torus_mesh.faces: for loop in face.loops: gval = abs(math.sin(loop.vert.co.x)) bval = abs(math.sin(loop.vert.co.y)) rval = 1 - gval loop[color_layer] = (rval, gval, bval, 1.0) mat = bpy.data.materials.new("color_material") mat.use_nodes = True torus.data.materials.append(mat) bsdf = mat.node_tree.nodes.get("Principled BSDF") color_node = mat.node_tree.nodes.new(type="ShaderNodeVertexColor") color_node.layer_name = "Giraffe" mat.node_tree.links.new(color_node.outputs["Color"], bsdf.inputs["Base Color"]) bpy.ops.object.mode_set(mode="OBJECT") for area in bpy.context.screen.areas: if area.type == "VIEW_3D": for space in area.spaces: if space.type == "VIEW_3D": space.shading.type = "MATERIAL"