blender, python, らせん階段、色

改良点はわずかですが、色つけて回転軸を変えてカメラ注目点を変えました。
動画1秒はtwitterで[この動画](https://mobile.twitter.com/naohiko7/status/1328308708959404043)です。
![bph38color.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690216/d24b05b7-a66e-a811-0ec8-7136b163d565.png)


```python3
# nh38 == 5階建ラセン。2020.11.14--2020.11.16
import bpy
import math
import random
# ========= DELETE ALL mesh, light, camera, みな削除する2行 =========
for item in bpy.data.objects:
	bpy.data.objects.remove(item)
#================== building helix 
s_per_floor = 36 #s_per_floor: number of steps in each floor . example 12,18,36,... 
#floors = 3 # floors==== number of floors (stories) 
floors = 5 # floors==== number of floors (stories)
floorheight = 3  # floorheight : height of each floor (meter)
xc = 0 # center x of helix
yc = 0 # center y of  helix
zc = 0 # center z
radius1 = 5 

stepheight = floorheight / s_per_floor
totalsteps = floors * s_per_floor
for i in range(totalsteps):
    x1 = math.cos(6.28 * i / s_per_floor )*radius1 + xc
    y1 = math.sin(6.28 * i / s_per_floor )*radius1 + yc
    z1 = i *  stepheight +zc
    bpy.ops.mesh.primitive_cube_add(size=1, enter_editmode=False, align='WORLD', location=(x1, y1, z1), scale=(1, 1, 1), rotation=(0, 0, (6.28 * i / s_per_floor )))
    obj = bpy.context.view_layer.objects.active
    mat = bpy.data.materials.new('Cube')
    r1=0.15+ 0.8*random.random()
    g1=0.07+ 0.3*random.random()
    b1=0.01+ 0.05*random.random()
    mat.diffuse_color = (r1, g1, b1, 0) #====== random BROWN COLOR
    obj.data.materials.append(mat)
#=========================

# Add a plane for ground  ==================
bpy.ops.mesh.primitive_plane_add(size=200.0, align='WORLD', location=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0) )
matp = bpy.data.materials.new('Plane')
matp.diffuse_color = (0.4, 0.2, 0.01, 0) 
obj.data.materials.append(matp)

# ==== world - surface - background (背景) 
bpy.data.worlds["World"].node_tree.nodes["Background"].inputs[0].default_value = (0.01, 0.15, 0.25, 1)
bpy.data.worlds["World"].node_tree.nodes["Background"].inputs[1].default_value = 0.7        
# ================== background 

# ============== "light" spot1, spot2, spot3
# create light datablock, set attributes
#light_data = bpy.data.lights.new(name="light_spot1", type='SPOT')
light_data = bpy.data.lights.new(name="light_spot1", type='SUN')
light_data.energy = 5
# create new object with our light datablock
light_object1 = bpy.data.objects.new(name="light_spot1", object_data=light_data)
# link light object
bpy.context.collection.objects.link(light_object1)
# make it active 
bpy.context.view_layer.objects.active = light_object1
#change location
light_object1.location = (5, -10, 50)
light_object1.delta_rotation_euler = (1.3, 0, 0.3) #ゼロゼロゼロで真下を向く。
# update scene, if needed
dg = bpy.context.evaluated_depsgraph_get() 
dg.update()

light_data = bpy.data.lights.new(name="light_spot2", type='SPOT')
light_data.energy = 20000
# create new object with our light datablock
light_object2 = bpy.data.objects.new(name="light_spot2", object_data=light_data)
# link light object
bpy.context.collection.objects.link(light_object2)
# make it active 
bpy.context.view_layer.objects.active = light_object2
#change location
light_object2.location = (5, 5, 17)
light_object2.delta_rotation_euler = (0.1, 0, 0.3) #ゼロゼロゼロで真下を向く。
# update scene, if needed
dg = bpy.context.evaluated_depsgraph_get() 
dg.update()

light_data = bpy.data.lights.new(name="light_spot3", type='SPOT')
light_data.energy = 20000
# create new object with our light datablock
light_object3 = bpy.data.objects.new(name="light_spot3", object_data=light_data)
# link light object
bpy.context.collection.objects.link(light_object3)
# make it active 
bpy.context.view_layer.objects.active = light_object3
#change location
light_object3.location = (-5, 5, 20)
light_object3.delta_rotation_euler = (0.1, 0, 0.3) #ゼロゼロゼロで真下を向く。
# update scene, if needed
dg = bpy.context.evaluated_depsgraph_get() 
dg.update()
# ================ end of light

#  ================== = camera movement START

bpy.ops.object.empty_add(type='PLAIN_AXES', radius=1.0, align='WORLD', location=(0, 0, 5))
bpy.context.active_object.name = 'empty_target' # === camera is looking at 'empty_target'

bpy.ops.curve.primitive_bezier_circle_add(enter_editmode=False, align='WORLD', location=(0, 0, 25))
bpy.context.object.scale[0] = 30
bpy.context.object.scale[1] = 30
bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0,0,0))
bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=(0,0,0), rotation=(0, 0, 0))

bpy.data.objects['Empty'].select_set(True)
bpy.data.objects['Camera'].select_set(True)

bpy.context.view_layer.objects.active = bpy.data.objects['Empty']
bpy.ops.object.parent_set(type='OBJECT')

bpy.data.objects['Camera'].select_set(False)
bpy.data.objects['Empty'].select_set(True)

bpy.ops.object.constraint_add(type='FOLLOW_PATH')
bpy.context.object.constraints["Follow Path"].target = bpy.data.objects["BezierCircle"]

bpy.context.object.constraints["Follow Path"].use_curve_follow = True
bpy.context.object.constraints["Follow Path"].use_fixed_location = True

bpy.data.objects['Empty'].select_set(False)
bpy.data.objects['Camera'].select_set(True)

bpy.ops.object.constraint_add(type='TRACK_TO')

#bpy.context.object.constraints["Track To"].target = bpy.data.objects["Cube.016"]
bpy.context.object.constraints["Track To"].target = bpy.data.objects['empty_target']
bpy.context.object.constraints["Track To"].up_axis = 'UP_Y'
bpy.context.object.constraints["Track To"].track_axis = 'TRACK_NEGATIVE_Z'  #5m00sec
#Camera Keyframe #(Insert keyframe to object's Offset Factor Python API - stack exchange)
bpy.data.objects['Camera'].select_set(False)
bpy.data.objects['Empty'].select_set(True)
bpy.context.scene.frame_current = 1
bpy.context.object.constraints["Follow Path"].offset_factor = 0
ob = bpy.context.object
# ob.constraints['Follow Path']
# bpy.data.objects['Empty'].constraints["Follow Path"]
# [bpy.data.objects['Empty'].constraints["Follow Path"]]
con = ob.constraints.get("Follow Path")
con.offset_factor = 0.0
con.keyframe_insert("offset_factor", frame=1)
con.offset_factor = 0.25
con.keyframe_insert("offset_factor", frame=8)
con.offset_factor = 0.50
con.keyframe_insert("offset_factor", frame=16)
con.offset_factor = 0.75
con.keyframe_insert("offset_factor", frame=23)
con.offset_factor = 0.99
con.keyframe_insert("offset_factor", frame=30)
# ==== END of camera movement
```