# Stage 38 (read-only): clay render, to settle whether the remaining speckle is GEOMETRY or PAINT. # # blender --background --python 38_clay.py -- # # The lane README's own advice: a clay render drops the material, and it is the only reliable way # to tell a mesh defect from a painted one. Several dead ends here came from mistaking painted # shadow for a dent and vice versa. Same cameras as 09_beauty so the frames line up. import bpy, sys, math, os from mathutils import Vector, Euler argv = sys.argv[sys.argv.index("--") + 1:] BLEND, OUT = argv[0], os.path.abspath(argv[1]) os.makedirs(OUT, exist_ok=True) bpy.ops.wm.open_mainfile(filepath=BLEND) for o in list(bpy.data.objects): if o.type in ('LIGHT', 'CAMERA'): bpy.data.objects.remove(o, do_unlink=True) ob = max([o for o in bpy.data.objects if o.type == 'MESH'], key=lambda o: len(o.data.vertices)) clay = bpy.data.materials.new("clay") clay.use_nodes = True bsdf = clay.node_tree.nodes["Principled BSDF"] bsdf.inputs["Base Color"].default_value = (0.62, 0.62, 0.62, 1) bsdf.inputs["Roughness"].default_value = 0.55 if "Metallic" in bsdf.inputs: bsdf.inputs["Metallic"].default_value = 0.0 clay.use_backface_culling = False ob.data.materials.clear() ob.data.materials.append(clay) sc = bpy.context.scene sc.render.engine = 'BLENDER_EEVEE' sc.render.resolution_x = sc.render.resolution_y = 1200 wd = bpy.data.worlds.new("w") wd.use_nodes = True wd.node_tree.nodes["Background"].inputs[0].default_value = (0.20, 0.20, 0.22, 1) sc.world = wd def sun(rot, e): ld = bpy.data.lights.new("s", 'SUN') ld.energy = e ld.use_shadow = False lo = bpy.data.objects.new("s", ld) lo.rotation_euler = rot bpy.context.collection.objects.link(lo) sun(Euler((math.radians(55), 0, math.radians(-35))), 2.6) sun(Euler((math.radians(120), 0, math.radians(150))), 1.1) sun(Euler((math.radians(85), 0, math.radians(35))), 0.9) cam = bpy.data.cameras.new("c") cam.lens = 70 cob = bpy.data.objects.new("c", cam) bpy.context.collection.objects.link(cob) sc.camera = cob for name, loc, rot in [ ("full_front", Vector((0.0, -2.05, 0.50)), Euler((math.radians(90), 0, 0))), ("chest", Vector((0.0, -0.85, 0.70)), Euler((math.radians(90), 0, 0))), ("hip", Vector((0.0, -0.85, 0.46)), Euler((math.radians(90), 0, 0))), ("thigh", Vector((0.0, -0.70, 0.33)), Euler((math.radians(90), 0, 0))), ]: cob.location = loc cob.rotation_euler = rot sc.render.filepath = os.path.join(OUT, f"{name}.png") bpy.ops.render.render(write_still=True) print(f"clay {name}", flush=True) print("CLAY_DONE")