Distributed rendering of single images #104327
@ -3,21 +3,142 @@ const JOB_TYPE = {
|
||||
description: "Distributed rendering of a single image.",
|
||||
settings: [
|
||||
// Settings for artists to determine:
|
||||
{ key: "tile_size_x", type: "int32", default: 64, description: "Tile size in pixels for the X axis" },
|
||||
{ key: "tile_size_y", type: "int32", default: 64, description: "Tile size in pixels for the Y axis" },
|
||||
{
|
||||
key: "tile_size_x",
|
||||
type: "int32",
|
||||
default: 64,
|
||||
description: "Tile size in pixels for the X axis"
|
||||
},
|
||||
{
|
||||
key: "tile_size_y",
|
||||
type: "int32",
|
||||
default: 64,
|
||||
description: "Tile size in pixels for the Y axis"
|
||||
},
|
||||
|
||||
// render_output_root + add_path_components determine the value of render_output_path.
|
||||
{ key: "render_output_root", type: "string", subtype: "dir_path", required: true, visible: "submission",
|
||||
description: "Base directory of where render output is stored. Will have some job-specific parts appended to it"},
|
||||
{ key: "add_path_components", type: "int32", required: true, default: 0, propargs: {min: 0, max: 32}, visible: "submission",
|
||||
description: "Number of path components of the current blend file to use in the render output path"},
|
||||
{ key: "render_output_path", type: "string", subtype: "file_path", editable: false,
|
||||
{
|
||||
key: "render_output_root",
|
||||
type: "string",
|
||||
subtype: "dir_path",
|
||||
required: true,
|
||||
visible: "submission",
|
||||
description: "Base directory of where render output is stored. Will have some job-specific parts appended to it"
|
||||
},
|
||||
{
|
||||
key: "add_path_components",
|
||||
type: "int32",
|
||||
required: true,
|
||||
default: 0,
|
||||
propargs: {min: 0, max: 32},
|
||||
visible: "submission",
|
||||
description: "Number of path components of the current blend file to use in the render output path"
|
||||
},
|
||||
{
|
||||
key: "render_output_path", type: "string", subtype: "file_path", editable: false,
|
||||
eval: "str(Path(abspath(settings.render_output_root), last_n_dir_parts(settings.add_path_components), jobname, '{timestamp}', '######'))",
|
||||
description: "Final file path of where render output will be saved"},
|
||||
description: "Final file path of where render output will be saved"
|
||||
},
|
||||
|
||||
// Automatically evaluated settings:
|
||||
{
|
||||
key: "blendfile",
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Path of the Blend file to render",
|
||||
visible: "web"
|
||||
},
|
||||
{
|
||||
key: "format",
|
||||
type: "string",
|
||||
required: true,
|
||||
eval: "C.scene.render.image_settings.file_format",
|
||||
visible: "web"
|
||||
},
|
||||
{
|
||||
key: "image_file_extension",
|
||||
type: "string",
|
||||
required: true,
|
||||
eval: "C.scene.render.file_extension",
|
||||
visible: "hidden",
|
||||
description: "File extension used when rendering images"
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
function compileJob(job) {
|
||||
print("Single Image Render job submitted");
|
||||
print("job: ", job);
|
||||
|
||||
const settings = job.settings;
|
||||
const renderOutput = renderOutputPath(job);
|
||||
|
||||
// Make sure that when the job is investigated later, it shows the
|
||||
// actually-used render output:
|
||||
settings.render_output_path = renderOutput;
|
||||
|
||||
const renderDir = path.dirname(renderOutput);
|
||||
const renderTasks = authorRenderTasks(settings, renderDir, renderOutput);
|
||||
}
|
||||
|
||||
// Do field replacement on the render output path.
|
||||
function renderOutputPath(job) {
|
||||
let path = job.settings.render_output_path;
|
||||
if (!path) {
|
||||
throw "no render_output_path setting!";
|
||||
}
|
||||
return path.replace(/{([^}]+)}/g, (match, group0) => {
|
||||
switch (group0) {
|
||||
case "timestamp":
|
||||
return formatTimestampLocal(job.created);
|
||||
default:
|
||||
return match;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function calcBorders(tileSizeX, tileSizeY, width, height) {
|
||||
borders = [];
|
||||
for (let y = 0; y < height; y += tileSizeY) {
|
||||
for (let x = 0; x < width; x += tileSizeX) {
|
||||
borders.push([x, y, Math.min(x + tileSizeX, width), Math.min(y + tileSizeY, height)]);
|
||||
}
|
||||
}
|
||||
print("borders: ", borders);
|
||||
return borders;
|
||||
}
|
||||
|
||||
function authorRenderTasks(settings, renderDir, renderOutput) {
|
||||
print("authorRenderTasks(", renderDir, renderOutput, ")");
|
||||
let renderTasks = [];
|
||||
render = C.scene.render;
|
||||
let borders = calcBorders(settings.tile_size_x, settings.tile_size_y, render.resolution_x, render.resolution_y);
|
||||
for (border of borders) {
|
||||
const task = author.Task(`render-${border[0]}-${border[1]}`, "blender");
|
||||
let pythonExpr = `import bpy
|
||||
|
||||
render = bpy.context.scene.render
|
||||
render.image_settings.file_format = 'OPEN_EXR_MULTILAYER'
|
||||
render.use_compositing = False
|
||||
|
||||
render.border_min_x = ${border[0]} // settings.resolution_x
|
||||
render.border_min_y = ${border[1]} // settings.resolution_y
|
||||
render.border_max_x = ${border[2]} // settings.resolution_x
|
||||
render.border_max_y = ${border[3]} // settings.resolution_y
|
||||
render.use_border = True`
|
||||
const command = author.Command("blender-render", {
|
||||
exe: "{blender}",
|
||||
exeArgs: "{blenderArgs}",
|
||||
argsBefore: [],
|
||||
blendfile: settings.blendfile,
|
||||
args: [
|
||||
"--render-output", path.join(renderDir, path.basename(renderOutput)),
|
||||
"--render-format", settings.format,
|
||||
"--python-expr", pythonExpr
|
||||
]
|
||||
});
|
||||
task.addCommand(command);
|
||||
renderTasks.push(task);
|
||||
}
|
||||
return renderTasks;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user