こんにちは,
I’m n- also known as A-na5.
I’ve been using Blender for several years. recent works are making 3D models based on mathematical expressions. However, I’ve just started studying Blender – Python API (https://docs.blender.org/api/) since last month. Please let me know if there are any mistakes.
Inspiration and References
A new 3-d four-wing smooth autonomous chaotic systems

Modeling
How To Make “A 3-D Four-Wing Attractor” with Blender in Python
import bpy
import platform
print("Blender " + bpy.app.version_string)
print("Python " + platform.python_version())
# Blender 2.77 (sub 3)
# Python 3.5.1

Setting
Choose Screen Layout > Scripting
Window > Toggle System Console
Create a new text data block
Creating curve with chaotic attractors
import bpy
def wang_sun(a, b, c, d, e, f):
return lambda x, y, z: (
a*x + c*y*z,
b*x + d*y - x*z,
e*z + f*x*y
)
def make_components(func, max_iteration, x=0, y=0, z=0, dt=0.1):
verts = []
edges = []
faces = []
i = 0
while i < max_iteration:
xn, yn, zn = func(x, y, z)
x = x + xn*dt
y = y + yn*dt
z = z + zn*dt
verts.append((x, y, z))
i = i + 1
return verts, edges, faces
def generate_curve(func, max_iteration, curve_name, *start_xyz):
verts, edges, faces = make_components(func, max_iteration, *start_xyz)
w = 1
curvedata = bpy.data.curves.new(name=curve_name, type='CURVE')
curvedata.dimensions = '3D'
obj = bpy.data.objects.new(curve_name, curvedata)
obj.location = (0, 0, 0)
bpy.context.scene.objects.link(obj)
polyline = curvedata.splines.new('POLY')
polyline.points.add(len(verts)-1)
for num in range(len(verts)):
polyline.points[num].co = (verts[num])+(w,)
obj.select = True
obj.show_bounds = True
wang_sun_params = (("a", 0.2), ("b", -0.01), ("c", 1.0), ("d", -0.4), ("e", -1.0), ("f", -1.0))
wang_sun_start = (0.15, 0.1 , 0.2, 0.05)
n = 20000
name = "wang-sun"
param = (v for k,v in wang_sun_params)
attract = wang_sun(*param)
generate_curve(attract, n, name, *wang_sun_start)
Run

Resizing Objects
import bpy
def resize_objects(objects_name, *, axis="z", size=10):
obj = bpy.data.objects[objects_name]
bpy.context.scene.update()
obj.select = True
bpy.context.scene.objects.active = obj
bo = bpy.context.object
dimX = bo.dimensions[0]
dimY = bo.dimensions[1]
dimZ = bo.dimensions[2]
if axis == "x":
s = size/dimX
elif axis == "y":
s = size/dimY
else:
s = size/dimZ
bo.scale[0] = 1*s
bo.scale[1] = 1*s
bo.scale[2] = 1*s
bpy.ops.object.transform_apply(
location=False,
rotation=False,
scale=True
)
name = "wang-sun"
s = 10
resize_objects(name, axis="z", size=s)
Run

Curve to mesh
import bpy
def mesh_from_curve(curve_name, *, fill_mode='BACK', bevel_depth=0.05):
obj = bpy.data.objects[curve_name]
bpy.ops.object.select_all(action='DESELECT')
obj.select = True
bpy.context.scene.objects.active = obj
bo = bpy.context.object
bo.data.fill_mode = fill_mode
bo.data.bevel_depth = bevel_depth
bpy.ops.object.shade_flat()
bpy.ops.object.convert(target='MESH')
obj.data.name = curve_name
name = "wang-sun"
mesh_from_curve(name, fill_mode='BACK', bevel_depth=0.05)
Run
Duplicate
import bpy
import bmesh
def duplicate_checker_select(mesh_name, *, nth=3):
for offset in range(nth):
bpy.ops.object.select_all(action='DESELECT')
obj = bpy.data.objects[mesh_name]
scn = bpy.context.scene
obj.select = True
scn.objects.active = obj
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_mode(type="FACE")
bpy.ops.mesh.select_all(action='DESELECT')
me = obj.data
bm = bmesh.from_edit_mesh(me)
bm.faces.ensure_lookup_table()
index_offset = 0
for faces in bm.faces:
index_offset = faces.index + offset
if faces.index % nth == 0:
index_select = index_offset if index_offset < len(me.polygons) else index_offset - len(me.polygons)
bm.faces[index_select].select = True
bmesh.update_edit_mesh(me, True)
bpy.ops.mesh.duplicate()
bpy.ops.mesh.separate(type='SELECTED')
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.select_all(action='DESELECT')
obj.select = True
bpy.context.scene.objects.active = obj
bpy.ops.object.delete(use_global=False)
name = "wang-sun"
duplicate_checker_select(name, nth=10)
Run

Export to sketchfab.timeframe
import bpy
import os
def export_txt_sketchfab_timeframe(path, sec):
if os.path.isdir(path) is False:
# os.makedirs(path)
print("'path' is missing")
return 0
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_by_type(type='MESH')
objList = [obj.name for obj in bpy.context.selected_objects]
objList = sorted(objList)
timeframe = open(path + 'sketchfab.timeframe', 'w')
with timeframe as text:
for objects in objList:
text.write(sec + " " + objects + ".ply" + "\n")
bpy.ops.object.select_all(action='DESELECT')
print("writing " + path + "sketchfab.timeframe done")
# "~/Desktop/attractor/Wang-Sun/"
# "/Users/your-name/Desktop/attractor/Wang-Sun/"
# "C:/Users/your-name/Desktop/attractor/Wang-Sun/"
sec = "0.1"
path = "/path/to/"
export_txt_sketchfab_timeframe(path, sec)
# print(os.makedirs.__doc__)
"""
Recursive directory creation function. Like mkdir(),
but makes all intermediate-level directories needed to contain the leaf directory.
Run

Creating Wire-Frame Models
# bevel = 0.05 bevel = 0.01 n = 20000 name = "wang-sun" param = (v for k,v in wang_sun_params) # 2) Run attract = wang_sun(*param) generate_curve(attract, n, name, *wang_sun_start) # 3) Run resize_objects(name) # 4) Run mesh_from_curve(name, bevel_depth=bevel)
Run

Adding objects to sketchfab.timeframe
import bpy
import os
def append_objects_to_sketchfab_timeframe(path, objects_name):
if os.path.isdir(path) is False:
# os.makedirs(path)
print("'path' is missing")
return 0
obj = bpy.data.objects[objects_name]
bpy.ops.object.select_all(action='DESELECT')
obj.select = True
timeframe = open(path + 'sketchfab.timeframe', 'r')
lines = timeframe.readlines()
timeframe.close()
timeframe = open(path + 'sketchfab.timeframe', 'w')
with timeframe as text:
for line in lines:
text.write(line.strip() + "+" + obj.name + ".ply" + "\n")
print("writing " + line.strip() + "+" + obj.name + ".ply")
# "~/Desktop/attractor/Wang-Sun/"
# "/Users/your-name/Desktop/attractor/Wang-Sun/"
# "C:/Users/your-name/Desktop/attractor/Wang-Sun/"
path = "/path/to/"
name = "wang-sun"
append_objects_to_sketchfab_timeframe(path, name)
Run

Export to .ply
import bpy
import os
def export_ply_all(path):
if os.path.isdir(path) is False:
# os.makedirs(path)
print("'path' is missing")
return 0
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_by_type(type='MESH')
objList = [obj.name for obj in bpy.context.selected_objects]
objList = sorted(objList)
for objects in objList:
obj = bpy.data.objects[objects]
_objects = objects.replace('.', '_')
bpy.ops.object.select_all(action='DESELECT')
obj.select=True
bpy.context.scene.objects.active = obj
obj.data.name = _objects
bpy.context.active_object.name = _objects
bpy.ops.export_mesh.ply(
filepath=path+_objects+".ply",
check_existing=True,
axis_forward='Y',
axis_up='Z',
filter_glob="*.ply",
use_mesh_modifiers=True,
use_normals=True,
use_uv_coords=True,
use_colors=True,
global_scale=1.0
)
# "~/Desktop/attractor/test/"
# "/Users/your-name/Desktop/attractor/test/"
# "C:/Users/your-name/Desktop/attractor/test/"
path = "/path/to/"
export_ply_all(path)
Run

Rendering of the Sketchfab is beautiful than my own rendering image…, that is easy to use for beginner 3D artist. It is the most attractive thing to me. Thank you for give me a place to publish my work.
I’d like to thank the Sketchfab Team & Community!
Find me on:


