Cycles: Added Cryptomatte output.
This allows for extra output passes that encode automatic object and material masks for the entire scene. It is an implementation of the Cryptomatte standard as introduced by Psyop. A good future extension would be to add a manifest to the export and to do plenty of testing to ensure that it is fully compatible with other renderers and compositing programs that use Cryptomatte. Internally, it adds the ability for Cycles to have several passes of the same type that are distinguished by their name. Differential Revision: https://developer.blender.org/D3538
This commit is contained in:
@@ -254,6 +254,17 @@ def register_passes(engine, scene, srl):
|
||||
if crl.use_pass_volume_indirect: engine.register_pass(scene, srl, "VolumeInd", 3, "RGB", 'COLOR')
|
||||
|
||||
cscene = scene.cycles
|
||||
|
||||
if crl.use_pass_crypto_object:
|
||||
for i in range(0, crl.pass_crypto_depth, 2):
|
||||
engine.register_pass(scene, srl, "CryptoObject" + '{:02d}'.format(i), 4, "RGBA", 'COLOR')
|
||||
if crl.use_pass_crypto_material:
|
||||
for i in range(0, crl.pass_crypto_depth, 2):
|
||||
engine.register_pass(scene, srl, "CryptoMaterial" + '{:02d}'.format(i), 4, "RGBA", 'COLOR')
|
||||
if srl.cycles.use_pass_crypto_asset:
|
||||
for i in range(0, srl.cycles.pass_crypto_depth, 2):
|
||||
engine.register_pass(scene, srl, "CryptoAsset" + '{:02d}'.format(i), 4, "RGBA", 'COLOR')
|
||||
|
||||
if crl.use_denoising:
|
||||
engine.register_pass(scene, srl, "Noisy Image", 3, "RGBA", 'COLOR')
|
||||
if crl.denoising_store_passes:
|
||||
|
||||
@@ -1339,7 +1339,36 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
|
||||
default=False,
|
||||
update=update_render_passes,
|
||||
)
|
||||
|
||||
cls.use_pass_crypto_object = BoolProperty(
|
||||
name="Cryptomatte Object",
|
||||
description="Cryptomatte Object pass",
|
||||
default=False,
|
||||
update=update_render_passes,
|
||||
)
|
||||
cls.use_pass_crypto_material = BoolProperty(
|
||||
name="Cryptomatte Material",
|
||||
description="Cryptomatte Material pass",
|
||||
default=False,
|
||||
update=update_render_passes,
|
||||
)
|
||||
cls.use_pass_crypto_asset = BoolProperty(
|
||||
name="Cryptomatte Asset",
|
||||
description="Cryptomatte Asset pass",
|
||||
default=False,
|
||||
update=update_render_passes,
|
||||
)
|
||||
cls.pass_crypto_depth = IntProperty(
|
||||
name="Cryptomatte Levels",
|
||||
description="Describes how many unique IDs per pixel are written to Cryptomatte",
|
||||
default=6, min=2, max=16, step=2,
|
||||
update=update_render_passes,
|
||||
)
|
||||
cls.pass_crypto_accurate = BoolProperty(
|
||||
name="Cryptomatte Accurate",
|
||||
description="Gerenate a more accurate Cryptomatte pass, CPU only, may render slower and use more memory",
|
||||
default=True,
|
||||
update=update_render_passes,
|
||||
)
|
||||
@classmethod
|
||||
def unregister(cls):
|
||||
del bpy.types.SceneRenderLayer.cycles
|
||||
|
||||
@@ -563,6 +563,17 @@ class CYCLES_RENDER_PT_layer_passes(CyclesButtonsPanel, Panel):
|
||||
col.prop(crl, "pass_debug_bvh_intersections")
|
||||
col.prop(crl, "pass_debug_ray_bounces")
|
||||
|
||||
crl = rl.cycles
|
||||
layout.label("Cryptomatte:")
|
||||
row = layout.row(align=True)
|
||||
row.prop(crl, "use_pass_crypto_object", text="Object", toggle=True)
|
||||
row.prop(crl, "use_pass_crypto_material", text="Material", toggle=True)
|
||||
row.prop(crl, "use_pass_crypto_asset", text="Asset", toggle=True)
|
||||
row = layout.row(align=True)
|
||||
row.prop(crl, "pass_crypto_depth")
|
||||
row = layout.row(align=True)
|
||||
row.active = use_cpu(context)
|
||||
row.prop(crl, "pass_crypto_accurate", text="Accurate Mode")
|
||||
|
||||
class CYCLES_RENDER_PT_views(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Views"
|
||||
|
||||
@@ -384,6 +384,23 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
|
||||
object_updated = true;
|
||||
}
|
||||
|
||||
/* sync the asset name for Cryptomatte */
|
||||
BL::Object parent = b_ob.parent();
|
||||
ustring parent_name;
|
||||
if(parent) {
|
||||
while(parent.parent()) {
|
||||
parent = parent.parent();
|
||||
}
|
||||
parent_name = parent.name();
|
||||
}
|
||||
else {
|
||||
parent_name = b_ob.name();
|
||||
}
|
||||
if(object->asset_name != parent_name) {
|
||||
object->asset_name = parent_name;
|
||||
object_updated = true;
|
||||
}
|
||||
|
||||
/* object sync
|
||||
* transform comparison should not be needed, but duplis don't work perfect
|
||||
* in the depsgraph and may not signal changes, so this is a workaround */
|
||||
|
||||
@@ -405,7 +405,7 @@ void BlenderSession::render()
|
||||
BL::RenderLayer b_rlay = *b_single_rlay;
|
||||
|
||||
/* add passes */
|
||||
array<Pass> passes = sync->sync_render_passes(b_rlay, *b_layer_iter, session_params);
|
||||
vector<Pass> passes = sync->sync_render_passes(b_rlay, *b_layer_iter, session_params);
|
||||
buffer_params.passes = passes;
|
||||
|
||||
PointerRNA crl = RNA_pointer_get(&b_layer_iter->ptr, "cycles");
|
||||
@@ -700,7 +700,7 @@ void BlenderSession::do_write_update_render_result(BL::RenderResult& b_rr,
|
||||
bool read = false;
|
||||
if(pass_type != PASS_NONE) {
|
||||
/* copy pixels */
|
||||
read = buffers->get_pass_rect(pass_type, exposure, sample, components, &pixels[0]);
|
||||
read = buffers->get_pass_rect(pass_type, exposure, sample, components, &pixels[0], b_pass.name());
|
||||
}
|
||||
else {
|
||||
int denoising_offset = BlenderSync::get_denoising_pass(b_pass);
|
||||
@@ -719,7 +719,7 @@ void BlenderSession::do_write_update_render_result(BL::RenderResult& b_rr,
|
||||
else {
|
||||
/* copy combined pass */
|
||||
BL::RenderPass b_combined_pass(b_rlay.passes.find_by_name("Combined", b_rview_name.c_str()));
|
||||
if(buffers->get_pass_rect(PASS_COMBINED, exposure, sample, 4, &pixels[0]))
|
||||
if(buffers->get_pass_rect(PASS_COMBINED, exposure, sample, 4, &pixels[0], "Combined"))
|
||||
b_combined_pass.rect(&pixels[0]);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
static const char *cryptomatte_prefix = "Crypto";
|
||||
|
||||
/* Constructor */
|
||||
|
||||
BlenderSync::BlenderSync(BL::RenderEngine& b_engine,
|
||||
@@ -517,6 +519,9 @@ PassType BlenderSync::get_pass_type(BL::RenderPass& b_pass)
|
||||
MAP_PASS("Debug Ray Bounces", PASS_RAY_BOUNCES);
|
||||
#endif
|
||||
MAP_PASS("Debug Render Time", PASS_RENDER_TIME);
|
||||
if(string_startswith(name, cryptomatte_prefix)) {
|
||||
return PASS_CRYPTOMATTE;
|
||||
}
|
||||
#undef MAP_PASS
|
||||
|
||||
return PASS_NONE;
|
||||
@@ -549,11 +554,11 @@ int BlenderSync::get_denoising_pass(BL::RenderPass& b_pass)
|
||||
return -1;
|
||||
}
|
||||
|
||||
array<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay,
|
||||
BL::SceneRenderLayer& b_srlay,
|
||||
const SessionParams &session_params)
|
||||
vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay,
|
||||
BL::SceneRenderLayer& b_srlay,
|
||||
const SessionParams &session_params)
|
||||
{
|
||||
array<Pass> passes;
|
||||
vector<Pass> passes;
|
||||
Pass::add(PASS_COMBINED, passes);
|
||||
|
||||
if(!session_params.device.advanced_shading) {
|
||||
@@ -636,6 +641,39 @@ array<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay,
|
||||
Pass::add(PASS_VOLUME_INDIRECT, passes);
|
||||
}
|
||||
|
||||
/* Cryptomatte stores two ID/weight pairs per RGBA layer.
|
||||
* User facing paramter is the number of pairs. */
|
||||
int crypto_depth = min(16, get_int(crp, "pass_crypto_depth")) / 2;
|
||||
scene->film->cryptomatte_depth = crypto_depth;
|
||||
scene->film->cryptomatte_passes = CRYPT_NONE;
|
||||
if(get_boolean(crp, "use_pass_crypto_object")) {
|
||||
for(int i = 0; i < crypto_depth; ++i) {
|
||||
string passname = cryptomatte_prefix + string_printf("Object%02d", i);
|
||||
b_engine.add_pass(passname.c_str(), 4, "RGBA", b_srlay.name().c_str());
|
||||
Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str());
|
||||
}
|
||||
scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_OBJECT);
|
||||
}
|
||||
if(get_boolean(crp, "use_pass_crypto_material")) {
|
||||
for(int i = 0; i < crypto_depth; ++i) {
|
||||
string passname = cryptomatte_prefix + string_printf("Material%02d", i);
|
||||
b_engine.add_pass(passname.c_str(), 4, "RGBA", b_srlay.name().c_str());
|
||||
Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str());
|
||||
}
|
||||
scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_MATERIAL);
|
||||
}
|
||||
if(get_boolean(crp, "use_pass_crypto_asset")) {
|
||||
for(int i = 0; i < crypto_depth; ++i) {
|
||||
string passname = cryptomatte_prefix + string_printf("Asset%02d", i);
|
||||
b_engine.add_pass(passname.c_str(), 4, "RGBA", b_srlay.name().c_str());
|
||||
Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str());
|
||||
}
|
||||
scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_ASSET);
|
||||
}
|
||||
if(get_boolean(crp, "pass_crypto_accurate") && scene->film->cryptomatte_passes != CRYPT_NONE) {
|
||||
scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_ACCURATE);
|
||||
}
|
||||
|
||||
return passes;
|
||||
}
|
||||
|
||||
|
||||
@@ -66,9 +66,9 @@ public:
|
||||
void **python_thread_state,
|
||||
const char *layer = 0);
|
||||
void sync_render_layers(BL::SpaceView3D& b_v3d, const char *layer);
|
||||
array<Pass> sync_render_passes(BL::RenderLayer& b_rlay,
|
||||
BL::SceneRenderLayer& b_srlay,
|
||||
const SessionParams &session_params);
|
||||
vector<Pass> sync_render_passes(BL::RenderLayer& b_rlay,
|
||||
BL::SceneRenderLayer& b_srlay,
|
||||
const SessionParams &session_params);
|
||||
void sync_integrator();
|
||||
void sync_camera(BL::RenderSettings& b_render,
|
||||
BL::Object& b_override,
|
||||
|
||||
Reference in New Issue
Block a user