"""Print Blender render-result/pass APIs without writing project assets.""" import bpy bpy.ops.mesh.primitive_cube_add() scene = bpy.context.scene scene.view_layers[0].use_pass_z = True scene.view_layers[0].use_pass_normal = True print("SCENE_COMPOSITOR_ATTRS", [name for name in dir(scene) if "composit" in name.lower() or "node" in name.lower()]) scene.use_nodes = True tree = scene.compositing_node_group if tree is None: tree = bpy.data.node_groups.new("SpriteForge compositor", "CompositorNodeTree") scene.compositing_node_group = tree print("COMPOSITOR_TREE", tree, "NODE_TYPES", [node.bl_idname for node in tree.nodes]) file_node = tree.nodes.new("CompositorNodeOutputFile") print("FILE_NODE_ATTRS", [name for name in dir(file_node) if "file" in name.lower() or "slot" in name.lower() or "item" in name.lower()]) print("FILE_NODE_PROPS", [prop.identifier for prop in file_node.bl_rna.properties]) print("FILE_ITEMS_ATTRS", [name for name in dir(file_node.file_output_items) if not name.startswith("__")]) print("FILE_ITEMS_NEW_DOC", file_node.file_output_items.new.__doc__) print("FILE_FORMATS", file_node.format.bl_rna.properties["file_format"].enum_items.keys()) render_node = tree.nodes.new("CompositorNodeRLayers") scene.view_layers[0].update_render_passes() print("RENDER_OUTPUTS", [socket.name for socket in render_node.outputs]) file_node.format.file_format = "OPEN_EXR_MULTILAYER" file_node.directory = bpy.app.tempdir file_node.file_name = "spriteforge-passes" file_node.file_output_items.clear() for socket_type, name in (("RGBA", "Image"), ("FLOAT", "Depth"), ("VECTOR", "Normal")): file_node.file_output_items.new(socket_type, name) tree.links.new(render_node.outputs[name], file_node.inputs[name]) print("OUTPUT_INPUTS", [(socket.name, socket.bl_idname) for socket in file_node.inputs]) print("OUTPUT_ITEM_PROPS", [[prop.identifier for prop in item.bl_rna.properties] for item in file_node.file_output_items]) scene.render.engine = "BLENDER_EEVEE" scene.render.resolution_x = 8 scene.render.resolution_y = 8 scene.render.resolution_percentage = 100 camera_data = bpy.data.cameras.new("camera") camera = bpy.data.objects.new("camera", camera_data) scene.collection.objects.link(camera) camera.location = (3, -3, 2) camera.rotation_euler = ((0, 0, 0)) camera.rotation_euler = ((0, 0, 0)) camera.rotation_euler = ((bpy.context.object.location-camera.location).to_track_quat("-Z", "Y").to_euler()) scene.camera = camera scene.render.image_settings.file_format = "PNG" scene.render.filepath = bpy.app.tempdir + "spriteforge-pass-api.exr" bpy.ops.render.render(write_still=True) result = bpy.data.images.get("Render Result") print("RESULT_ATTRS", [name for name in dir(result) if "layer" in name.lower() or "pass" in name.lower() or "slot" in name.lower()]) print("RESULT_TYPE", type(result), "SIZE", tuple(result.size), "PIXELS", len(result.pixels)) print("VIEW_LAYER_ATTRS", [name for name in dir(scene.view_layers[0]) if "pass" in name.lower()]) try: import OpenImageIO print("OPENIMAGEIO", OpenImageIO.VERSION_STRING) source = OpenImageIO.ImageInput.open(bpy.app.tempdir + "spriteforge-passes.exr") index = 0 while source.seek_subimage(index, 0): spec = source.spec() print("SUBIMAGE", index, spec.width, spec.height, list(spec.channelnames)) index += 1 source.close() except Exception as error: print("OPENIMAGEIO_MISSING", repr(error))