Spaces:
Running on Zero
Running on Zero
Download scripts/create_demo.py from cpuai/blender-render-studio: direct link, hf CLI and curl.
- Browser
- Download file 5.71 kB
-
https://huggingface.co/spaces/cpuai/blender-render-studio/resolve/main/scripts/create_demo.py
- Command line
-
hf download hf://spaces/cpuai/blender-render-studio/scripts/create_demo.py
-
curl -L -o create_demo.py https://huggingface.co/spaces/cpuai/blender-render-studio/resolve/main/scripts/create_demo.py
5.71 kB
| """生成无需外部贴图的演示场景。 | |
| blender --background --factory-startup --python scripts/create_demo.py -- --output demo.blend | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import math | |
| import sys | |
| from pathlib import Path | |
| import bpy | |
| from mathutils import Vector | |
| def material(name, color, metallic=0.0, roughness=0.4): | |
| value = bpy.data.materials.new(name) | |
| value.diffuse_color = (*color, 1) | |
| value.use_nodes = True | |
| shader = value.node_tree.nodes.get("Principled BSDF") | |
| shader.inputs["Base Color"].default_value = (*color, 1) | |
| shader.inputs["Metallic"].default_value = metallic | |
| shader.inputs["Roughness"].default_value = roughness | |
| return value | |
| def smooth(obj): | |
| for polygon in obj.data.polygons: | |
| polygon.use_smooth = True | |
| def aim(obj, target): | |
| obj.rotation_euler = (Vector(target) - obj.location).to_track_quat("-Z", "Y").to_euler() | |
| def area(name, location, energy, color, size, target=(0, 0, 1)): | |
| bpy.ops.object.light_add(type="AREA", location=location) | |
| obj = bpy.context.object | |
| obj.name = name | |
| obj.data.energy = energy | |
| obj.data.color = color | |
| obj.data.shape = "DISK" | |
| obj.data.size = size | |
| aim(obj, target) | |
| return obj | |
| def build(output: Path): | |
| bpy.ops.wm.read_factory_settings(use_empty=True) | |
| scene = bpy.context.scene | |
| scene.name = "Studio" | |
| scene.render.engine = "CYCLES" | |
| scene.cycles.samples = 64 | |
| scene.cycles.use_denoising = True | |
| scene.render.resolution_x = 960 | |
| scene.render.resolution_y = 540 | |
| scene.render.resolution_percentage = 100 | |
| scene.render.fps = 24 | |
| scene.frame_start = 1 | |
| scene.frame_end = 120 | |
| scene.render.image_settings.file_format = "PNG" | |
| scene.world = bpy.data.worlds.new("Studio World") | |
| scene.world.use_nodes = True | |
| scene.world.node_tree.nodes["Background"].inputs["Color"].default_value = (0.055, 0.085, 0.13, 1) | |
| scene.world.node_tree.nodes["Background"].inputs["Strength"].default_value = 0.3 | |
| try: | |
| scene.view_settings.view_transform = "AgX" | |
| except TypeError: | |
| pass | |
| jade = material("Jade ceramic", (0.05, 0.42, 0.32), metallic=0.24, roughness=0.2) | |
| gold = material("Champagne metal", (0.8, 0.55, 0.2), metallic=0.88, roughness=0.24) | |
| cream = material("Warm porcelain", (0.76, 0.68, 0.55), roughness=0.28) | |
| navy = material("Midnight plinth", (0.023, 0.054, 0.085), metallic=0.2, roughness=0.35) | |
| floor = material("Studio floor", (0.055, 0.085, 0.11), roughness=0.45) | |
| bpy.ops.mesh.primitive_plane_add(size=200) | |
| bpy.context.object.name = "Floor" | |
| bpy.context.object.data.materials.append(floor) | |
| bpy.ops.mesh.primitive_cylinder_add(vertices=96, radius=1.85, depth=0.32, location=(0, 0, 0.16)) | |
| plinth = bpy.context.object | |
| plinth.name = "Display plinth" | |
| plinth.data.materials.append(navy) | |
| bevel = plinth.modifiers.new("Soft edges", "BEVEL") | |
| bevel.width = 0.08 | |
| bevel.segments = 4 | |
| smooth(plinth) | |
| bpy.ops.mesh.primitive_monkey_add(location=(0.0, 0, 1.45)) | |
| hero = bpy.context.object | |
| hero.name = "Jade Suzanne" | |
| hero.rotation_euler.z = math.radians(-12) | |
| hero.data.materials.append(jade) | |
| subdivision = hero.modifiers.new("Sculpted surface", "SUBSURF") | |
| subdivision.levels = 2 | |
| subdivision.render_levels = 2 | |
| smooth(hero) | |
| bpy.ops.mesh.primitive_torus_add(major_segments=96, minor_segments=24, | |
| location=(0, 0.25, 1.6), rotation=(math.radians(76), 0.2, 0), | |
| major_radius=1.52, minor_radius=0.052) | |
| ring = bpy.context.object | |
| ring.name = "Golden orbit" | |
| ring.data.materials.append(gold) | |
| smooth(ring) | |
| for name, loc, radius, mat in [ | |
| ("Porcelain sphere", (1.23, -0.63, 0.63), 0.31, cream), | |
| ("Golden sphere", (-1.16, -0.67, 0.59), 0.27, gold), | |
| ("Small jade sphere", (0.7, 0.9, 0.5), 0.18, jade), | |
| ]: | |
| bpy.ops.mesh.primitive_uv_sphere_add(segments=48, ring_count=24, radius=radius, location=loc) | |
| obj = bpy.context.object | |
| obj.name = name | |
| obj.data.materials.append(mat) | |
| smooth(obj) | |
| area("Large warm key", (3, -4, 6), 1100, (1.0, 0.84, 0.67), 4) | |
| area("Soft cool fill", (-4, -1, 3), 800, (0.50, 0.76, 1.0), 3) | |
| area("Golden rim", (1, 4, 5), 1500, (1.0, 0.65, 0.28), 2.5) | |
| bpy.ops.object.empty_add(type="PLAIN_AXES", location=(0, 0, 1.12)) | |
| target = bpy.context.object | |
| target.name = "Camera target" | |
| bpy.ops.object.camera_add(location=(5.4, -7.5, 4.2)) | |
| camera = bpy.context.object | |
| camera.name = "OrbitCamera" | |
| camera.data.lens = 52 | |
| camera.data.dof.use_dof = True | |
| camera.data.dof.focus_object = target | |
| camera.data.dof.aperture_fstop = 6.3 | |
| aim(camera, target.location) | |
| track = camera.constraints.new("TRACK_TO") | |
| track.target = target | |
| track.track_axis = "TRACK_NEGATIVE_Z" | |
| track.up_axis = "UP_Y" | |
| scene.camera = camera | |
| # 逐帧记录相机位置,不使用驱动器或自动脚本。 | |
| for frame in range(1, 121): | |
| angle = math.radians(-68 + (frame - 1) * 70 / 119) | |
| camera.location = (8.9 * math.cos(angle), 8.9 * math.sin(angle), 4.0) | |
| camera.keyframe_insert(data_path="location", frame=frame) | |
| scene.frame_set(1) | |
| output.parent.mkdir(parents=True, exist_ok=True) | |
| bpy.ops.wm.save_as_mainfile(filepath=str(output.resolve()), check_existing=False) | |
| print(f"已创建演示场景:{output.resolve()}") | |
| if __name__ == "__main__": | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--output", default="demo.blend") | |
| args = parser.parse_args(sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []) | |
| build(Path(args.output)) | |