import bpy import math from mathutils import Vector # DSH Director Toolkit: "Cyclopean Porcelain / 独眼玄瓷" script demo. # Three-beat short: reveal -> gaze -> levitation. scene = bpy.context.scene scene.render.engine = 'BLENDER_EEVEE' scene.render.resolution_x = 720 scene.render.resolution_y = 720 scene.render.resolution_percentage = 100 scene.render.fps = 30 scene.frame_start = 1 scene.frame_end = 180 scene.render.image_settings.file_format = 'PNG' scene.render.filepath = '/tmp/dsh-director-toolkit/frames/frame_' scene.render.film_transparent = False scene.world.color = (0.001, 0.002, 0.004) def mat_principled(name, base, metallic=0.0, roughness=0.4, transmission=0.0, emission=None, emission_strength=0.0): mat = bpy.data.materials.new(name) mat.diffuse_color = (*base, 1) mat.use_nodes = True bsdf = mat.node_tree.nodes.get('Principled BSDF') bsdf.inputs['Base Color'].default_value = (*base, 1) bsdf.inputs['Metallic'].default_value = metallic bsdf.inputs['Roughness'].default_value = roughness if 'Transmission Weight' in bsdf.inputs: bsdf.inputs['Transmission Weight'].default_value = transmission if emission: bsdf.inputs['Emission Color'].default_value = (*emission, 1) bsdf.inputs['Emission Strength'].default_value = emission_strength return mat ceramic = mat_principled('Ceramic SSS · #E8F0F0', (0.78, 0.91, 0.91), roughness=0.17, transmission=0.36, emission=(0.03, 0.13, 0.15), emission_strength=0.10) ceramic.node_tree.nodes['Principled BSDF'].inputs['Subsurface Weight'].default_value = 0.28 eye = mat_principled('Glass Eye · cyan core', (0.02, 0.18, 0.23), roughness=0.015, transmission=0.75, emission=(0.02, 0.75, 0.9), emission_strength=2.8) plinth_mat = mat_principled('Matte Black Plinth', (0.005, 0.008, 0.012), roughness=0.78) iris_mat = mat_principled('Iris Cyan', (0.0, 0.25, 0.32), metallic=0.1, roughness=0.12, emission=(0.0, 0.8, 1.0), emission_strength=1.7) white = mat_principled('Title White', (0.8, 0.95, 0.96), emission=(0.5, 0.9, 1.0), emission_strength=0.5) def add_uv(name, loc, scale, material, segments=64, rings=32): bpy.ops.mesh.primitive_uv_sphere_add(segments=segments, ring_count=rings, location=loc) obj = bpy.context.object obj.name = name obj.scale = scale bpy.ops.object.transform_apply(location=False, rotation=False, scale=True) obj.data.materials.append(material) bpy.ops.object.shade_smooth() return obj def add_cylinder(name, loc, radius, depth, material, bevel=0.04): bpy.ops.mesh.primitive_cylinder_add(vertices=96, radius=radius, depth=depth, location=loc) obj = bpy.context.object obj.name = name obj.data.materials.append(material) bevel_mod = obj.modifiers.new('soft edge', 'BEVEL') bevel_mod.width = bevel bevel_mod.segments = 5 bpy.context.view_layer.objects.active = obj bpy.ops.object.shade_smooth() return obj # Plinth and creature. plinth = add_cylinder('Black Plinth · 0.6m', (0, 0, 0.3), 0.72, 0.6, plinth_mat, 0.06) body = add_uv('Cyclopean Porcelain Creature · 1.2m', (0, 0, 1.42), (0.52, 0.40, 0.78), ceramic) body.scale.y = 0.86 body.rotation_euler[2] = math.radians(-3) # Tapered neck/shoulder silhouette. shoulder = add_uv('Shoulder volume', (0, 0.01, 1.08), (0.58, 0.42, 0.28), ceramic) shoulder.scale.z = 0.80 # Oversized eye, iris and pupil. eye_glass = add_uv('Single glass eye · 0.4m', (0, -0.36, 1.55), (0.24, 0.105, 0.24), eye) iris = add_uv('Cyan iris', (0, -0.462, 1.55), (0.135, 0.025, 0.135), iris_mat, 48, 24) pupil = add_uv('Dark pupil', (0, -0.49, 1.55), (0.052, 0.018, 0.09), plinth_mat, 32, 16) catch = add_uv('Eye catchlight', (-0.065, -0.515, 1.64), (0.024, 0.008, 0.032), white, 24, 12) # Cyan rim and warm top fill. Ratio is intentionally close to v4 model brief: 16:1. bpy.ops.object.light_add(type='AREA', location=(1.8, 1.4, 2.5)) rim = bpy.context.object rim.name = 'CYAN RIM · 800W' rim.data.energy = 800 rim.data.shape = 'RECTANGLE' rim.data.size = 0.10 rim.data.size_y = 1.2 rim.data.color = (0.0, 0.85, 1.0) rim.rotation_euler = (math.radians(25), 0, math.radians(145)) bpy.ops.object.light_add(type='AREA', location=(-0.7, -0.4, 3.4)) top = bpy.context.object top.name = 'WARM TOP FILL · 50W' top.data.energy = 50 top.data.shape = 'DISK' top.data.size = 1.2 top.data.color = (1.0, 0.28, 0.10) top.rotation_euler = (0, 0, math.radians(180)) # Camera: 50mm, low front, push-in from 3.5m to 3.0m, then rise 5cm. bpy.ops.object.camera_add(location=(0, -3.5, 1.48)) camera = bpy.context.object camera.name = 'Hero Camera · 50mm' camera.data.lens = 50 camera.data.sensor_width = 36 scene.camera = camera def track(obj, target): obj.rotation_euler = (Vector(target) - obj.location).to_track_quat('-Z', 'Y').to_euler() track(camera, (0, 0, 1.45)) camera.keyframe_insert(data_path='location', frame=1) camera.keyframe_insert(data_path='rotation_euler', frame=1) camera.location.y = -3.0 camera.keyframe_insert(data_path='location', frame=90) camera.location.z += 0.05 camera.keyframe_insert(data_path='location', frame=180) # Story animation: reveal in first third, gaze/turn in second, breathing hover in final third. body.keyframe_insert(data_path='location', frame=1) body.keyframe_insert(data_path='rotation_euler', frame=1) body.location.z += 0.05 body.keyframe_insert(data_path='location', frame=30) body.rotation_euler[2] = math.radians(-15) body.keyframe_insert(data_path='rotation_euler', frame=90) body.location.z += 0.035 body.rotation_euler[2] = math.radians(-13) body.keyframe_insert(data_path='location', frame=130) body.location.z -= 0.085 body.rotation_euler[2] = math.radians(-3) body.keyframe_insert(data_path='location', frame=180) body.keyframe_insert(data_path='rotation_euler', frame=180) # Keep the eye fixed to camera visually by a tracking constraint. for obj in (eye_glass, iris, pupil, catch): con = obj.constraints.new(type='TRACK_TO') con.target = camera con.track_axis = 'TRACK_NEGATIVE_Y' con.up_axis = 'UP_Z' # Title cards as 3D text, fading into the scene as the camera arrives. def add_text(name, body_text, loc, size, material, align='CENTER'): bpy.ops.object.text_add(location=loc, rotation=(math.radians(90), 0, 0)) obj = bpy.context.object obj.name = name obj.data.body = body_text obj.data.align_x = align obj.data.size = size obj.data.extrude = 0.002 obj.data.bevel_depth = 0.001 obj.data.materials.append(material) return obj title = add_text('Title Card', 'CYCLOPEAN PORCELAIN', (-0.0, 0.25, 0.12), 0.11, white) title.data.align_x = 'CENTER' title.hide_render = True subtitle = add_text('Subtitle Card', 'DSH 3D DIRECTOR / DEEPSEEK V4 PRO', (0.0, 0.25, 0.03), 0.035, iris_mat) subtitle.hide_render = True # Render config and compositor glow. scene.view_settings.look = 'AgX - Medium High Contrast' scene.render.image_settings.file_format = 'PNG' scene.render.filepath = '/tmp/dsh-director-toolkit/frames/frame_' scene.render.fps = 30 bpy.ops.wm.save_as_mainfile(filepath='/tmp/dsh-director-toolkit/cyclopean-porcelain.blend') bpy.ops.render.render(animation=True)