Simple Blender Render: no longer render to intermediate directory

Simple Blender Render now no longer renders to an intermediate directory.
This not only simplifies the script, but it also opens the door for
selective re-running of individual tasks.

In the old situation, where the intermediate directory was renamed to
the desired name in the last task, rerunning tasks would fail because the
directory they expect to exist no longer exists. This is now resolved.
This commit is contained in:
Sybren A. Stüvel 2022-08-31 17:08:01 +02:00
parent f065cda830
commit 0afde53209
2 changed files with 22 additions and 42 deletions

View File

@ -89,11 +89,11 @@ func TestSimpleBlenderRenderHappy(t *testing.T) {
settings := sj.Settings.AdditionalProperties settings := sj.Settings.AdditionalProperties
// Tasks should have been created to render the frames: 1-3, 4-6, 7-9, 10, video-encoding, and cleanup // Tasks should have been created to render the frames: 1-3, 4-6, 7-9, 10, and video-encoding
assert.Len(t, aj.Tasks, 6) assert.Len(t, aj.Tasks, 5)
t0 := aj.Tasks[0] t0 := aj.Tasks[0]
expectCliArgs := []interface{}{ // They are strings, but Goja doesn't know that and will produce an []interface{}. expectCliArgs := []interface{}{ // They are strings, but Goja doesn't know that and will produce an []interface{}.
"--render-output", "/render/sprites/farm_output/promo/square_ellie/square_ellie.lighting_light_breakdown2__intermediate-2006-01-02_090405/######", "--render-output", "/render/sprites/farm_output/promo/square_ellie/square_ellie.lighting_light_breakdown2/######",
"--render-format", settings["format"].(string), "--render-format", settings["format"].(string),
"--render-frame", "1..3", "--render-frame", "1..3",
} }
@ -116,8 +116,8 @@ func TestSimpleBlenderRenderHappy(t *testing.T) {
assert.Equal(t, "frames-to-video", tVideo.Commands[0].Name) assert.Equal(t, "frames-to-video", tVideo.Commands[0].Name)
assert.EqualValues(t, AuthoredCommandParameters{ assert.EqualValues(t, AuthoredCommandParameters{
"exe": "ffmpeg", "exe": "ffmpeg",
"inputGlob": "/render/sprites/farm_output/promo/square_ellie/square_ellie.lighting_light_breakdown2__intermediate-2006-01-02_090405/*.png", "inputGlob": "/render/sprites/farm_output/promo/square_ellie/square_ellie.lighting_light_breakdown2/*.png",
"outputFile": "/render/sprites/farm_output/promo/square_ellie/square_ellie.lighting_light_breakdown2__intermediate-2006-01-02_090405/scene123-1-10.mp4", "outputFile": "/render/sprites/farm_output/promo/square_ellie/square_ellie.lighting_light_breakdown2/scene123-1-10.mp4",
"fps": int64(24), "fps": int64(24),
"args": expectedFramesToVideoArgs, "args": expectedFramesToVideoArgs,
}, tVideo.Commands[0].Parameters) }, tVideo.Commands[0].Parameters)
@ -173,12 +173,12 @@ func TestSimpleBlenderRenderWindowsPaths(t *testing.T) {
settings := sj.Settings.AdditionalProperties settings := sj.Settings.AdditionalProperties
// Tasks should have been created to render the frames: 1-3, 4-6, 7-9, 10, video-encoding, and cleanup // Tasks should have been created to render the frames: 1-3, 4-6, 7-9, 10, and video-encoding
assert.Len(t, aj.Tasks, 6) assert.Len(t, aj.Tasks, 5)
t0 := aj.Tasks[0] t0 := aj.Tasks[0]
expectCliArgs := []interface{}{ // They are strings, but Goja doesn't know that and will produce an []interface{}. expectCliArgs := []interface{}{ // They are strings, but Goja doesn't know that and will produce an []interface{}.
// The render output is constructed by the job compiler, and thus transforms to forward slashes. // The render output is constructed by the job compiler, and thus transforms to forward slashes.
"--render-output", "R:/sprites/farm_output/promo/square_ellie/square_ellie.lighting_light_breakdown2__intermediate-2006-01-02_090405/######", "--render-output", "R:/sprites/farm_output/promo/square_ellie/square_ellie.lighting_light_breakdown2/######",
"--render-format", settings["format"].(string), "--render-format", settings["format"].(string),
"--render-frame", "1..3", "--render-frame", "1..3",
} }
@ -201,8 +201,8 @@ func TestSimpleBlenderRenderWindowsPaths(t *testing.T) {
assert.Equal(t, "frames-to-video", tVideo.Commands[0].Name) assert.Equal(t, "frames-to-video", tVideo.Commands[0].Name)
assert.EqualValues(t, AuthoredCommandParameters{ assert.EqualValues(t, AuthoredCommandParameters{
"exe": "ffmpeg", "exe": "ffmpeg",
"inputGlob": "R:/sprites/farm_output/promo/square_ellie/square_ellie.lighting_light_breakdown2__intermediate-2006-01-02_090405/*.png", "inputGlob": "R:/sprites/farm_output/promo/square_ellie/square_ellie.lighting_light_breakdown2/*.png",
"outputFile": "R:/sprites/farm_output/promo/square_ellie/square_ellie.lighting_light_breakdown2__intermediate-2006-01-02_090405/scene123-1-10.mp4", "outputFile": "R:/sprites/farm_output/promo/square_ellie/square_ellie.lighting_light_breakdown2/scene123-1-10.mp4",
"fps": int64(24), "fps": int64(24),
"args": expectedFramesToVideoArgs, "args": expectedFramesToVideoArgs,
}, tVideo.Commands[0].Parameters) }, tVideo.Commands[0].Parameters)
@ -232,11 +232,11 @@ func TestSimpleBlenderRenderOutputPathFieldReplacement(t *testing.T) {
// The job compiler should have replaced the {timestamp} and {ext} fields. // The job compiler should have replaced the {timestamp} and {ext} fields.
assert.Equal(t, "/root/2006-01-02_090405/jobname/######", aj.Settings["render_output_path"]) assert.Equal(t, "/root/2006-01-02_090405/jobname/######", aj.Settings["render_output_path"])
// Tasks should have been created to render the frames: 1-3, 4-6, 7-9, 10, video-encoding, and cleanup // Tasks should have been created to render the frames: 1-3, 4-6, 7-9, 10, and video-encoding
assert.Len(t, aj.Tasks, 6) require.Len(t, aj.Tasks, 5)
t0 := aj.Tasks[0] t0 := aj.Tasks[0]
expectCliArgs := []interface{}{ // They are strings, but Goja doesn't know that and will produce an []interface{}. expectCliArgs := []interface{}{ // They are strings, but Goja doesn't know that and will produce an []interface{}.
"--render-output", "/root/2006-01-02_090405/jobname__intermediate-2006-01-02_090405/######", "--render-output", "/root/2006-01-02_090405/jobname/######",
"--render-format", sj.Settings.AdditionalProperties["format"].(string), "--render-format", sj.Settings.AdditionalProperties["format"].(string),
"--render-frame", "1..3", "--render-frame", "1..3",
} }
@ -251,8 +251,8 @@ func TestSimpleBlenderRenderOutputPathFieldReplacement(t *testing.T) {
tVideo := aj.Tasks[4] // This should be a video encoding task tVideo := aj.Tasks[4] // This should be a video encoding task
assert.EqualValues(t, AuthoredCommandParameters{ assert.EqualValues(t, AuthoredCommandParameters{
"exe": "ffmpeg", "exe": "ffmpeg",
"inputGlob": "/root/2006-01-02_090405/jobname__intermediate-2006-01-02_090405/*.png", "inputGlob": "/root/2006-01-02_090405/jobname/*.png",
"outputFile": "/root/2006-01-02_090405/jobname__intermediate-2006-01-02_090405/scene123-1-10.mp4", "outputFile": "/root/2006-01-02_090405/jobname/scene123-1-10.mp4",
"fps": int64(24), "fps": int64(24),
"args": expectedFramesToVideoArgs, "args": expectedFramesToVideoArgs,
}, tVideo.Commands[0].Parameters) }, tVideo.Commands[0].Parameters)

View File

@ -45,23 +45,22 @@ function compileJob(job) {
print("Blender Render job submitted"); print("Blender Render job submitted");
print("job: ", job); print("job: ", job);
if (videoFormats.indexOf(job.settings.format) >= 0) { const settings = job.settings;
throw `This job type only renders images, and not "${job.settings.format}"`; if (videoFormats.indexOf(settings.format) >= 0) {
throw `This job type only renders images, and not "${settings.format}"`;
} }
const renderOutput = renderOutputPath(job); const renderOutput = renderOutputPath(job);
job.settings.render_output_path = renderOutput;
const finalDir = path.dirname(renderOutput); // Make sure that when the job is investigated later, it shows the
const renderDir = intermediatePath(job, finalDir); // actually-used render output:
settings.render_output_path = renderOutput;
const settings = job.settings; const renderDir = path.dirname(renderOutput);
const renderTasks = authorRenderTasks(settings, renderDir, renderOutput); const renderTasks = authorRenderTasks(settings, renderDir, renderOutput);
const videoTask = authorCreateVideoTask(settings, renderDir); const videoTask = authorCreateVideoTask(settings, renderDir);
const cleanupTask = authorCleanupTask(finalDir, renderDir);
for (const rt of renderTasks) { for (const rt of renderTasks) {
cleanupTask.addDependency(rt);
job.addTask(rt); job.addTask(rt);
} }
if (videoTask) { if (videoTask) {
@ -69,10 +68,8 @@ function compileJob(job) {
for (const rt of renderTasks) { for (const rt of renderTasks) {
videoTask.addDependency(rt); videoTask.addDependency(rt);
} }
cleanupTask.addDependency(videoTask);
job.addTask(videoTask); job.addTask(videoTask);
} }
job.addTask(cleanupTask);
} }
// Do field replacement on the render output path. // Do field replacement on the render output path.
@ -91,13 +88,6 @@ function renderOutputPath(job) {
}); });
} }
// Determine the intermediate render output path.
function intermediatePath(job, finalDir) {
const basename = path.basename(finalDir);
const name = `${basename}__intermediate-${formatTimestampLocal(job.created)}`;
return path.join(path.dirname(finalDir), name);
}
function authorRenderTasks(settings, renderDir, renderOutput) { function authorRenderTasks(settings, renderDir, renderOutput) {
print("authorRenderTasks(", renderDir, renderOutput, ")"); print("authorRenderTasks(", renderDir, renderOutput, ")");
let renderTasks = []; let renderTasks = [];
@ -156,13 +146,3 @@ function authorCreateVideoTask(settings, renderDir) {
print(`Creating output video for ${settings.format}`); print(`Creating output video for ${settings.format}`);
return task; return task;
} }
function authorCleanupTask(finalDir, renderDir) {
const task = author.Task("move-to-final", "file-management");
const command = author.Command("move-directory", {
src: renderDir,
dest: finalDir,
});
task.addCommand(command);
return task;
}