forked from bartvdbraak/blender
Merge branch 'master' into blender2.8
This commit is contained in:
commit
046735d751
@ -672,10 +672,10 @@ function(SETUP_BLENDER_SORTED_LIBS)
|
|||||||
bf_intern_mikktspace
|
bf_intern_mikktspace
|
||||||
bf_intern_dualcon
|
bf_intern_dualcon
|
||||||
bf_intern_cycles
|
bf_intern_cycles
|
||||||
|
cycles_device
|
||||||
cycles_render
|
cycles_render
|
||||||
cycles_graph
|
cycles_graph
|
||||||
cycles_bvh
|
cycles_bvh
|
||||||
cycles_device
|
|
||||||
cycles_kernel
|
cycles_kernel
|
||||||
cycles_util
|
cycles_util
|
||||||
cycles_subd
|
cycles_subd
|
||||||
|
@ -257,7 +257,20 @@ def register_passes(engine, scene, srl):
|
|||||||
if crl.use_pass_volume_indirect: engine.register_pass(scene, srl, "VolumeInd", 3, "RGB", 'COLOR')
|
if crl.use_pass_volume_indirect: engine.register_pass(scene, srl, "VolumeInd", 3, "RGB", 'COLOR')
|
||||||
|
|
||||||
cscene = scene.cycles
|
cscene = scene.cycles
|
||||||
if crl.use_denoising and crl.denoising_store_passes and not cscene.use_progressive_refine:
|
|
||||||
|
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:
|
||||||
engine.register_pass(scene, srl, "Denoising Normal", 3, "XYZ", 'VECTOR')
|
engine.register_pass(scene, srl, "Denoising Normal", 3, "XYZ", 'VECTOR')
|
||||||
engine.register_pass(scene, srl, "Denoising Normal Variance", 3, "XYZ", 'VECTOR')
|
engine.register_pass(scene, srl, "Denoising Normal Variance", 3, "XYZ", 'VECTOR')
|
||||||
engine.register_pass(scene, srl, "Denoising Albedo", 3, "RGB", 'COLOR')
|
engine.register_pass(scene, srl, "Denoising Albedo", 3, "RGB", 'COLOR')
|
||||||
@ -266,9 +279,7 @@ def register_passes(engine, scene, srl):
|
|||||||
engine.register_pass(scene, srl, "Denoising Depth Variance", 1, "Z", 'VALUE')
|
engine.register_pass(scene, srl, "Denoising Depth Variance", 1, "Z", 'VALUE')
|
||||||
engine.register_pass(scene, srl, "Denoising Shadow A", 3, "XYV", 'VECTOR')
|
engine.register_pass(scene, srl, "Denoising Shadow A", 3, "XYV", 'VECTOR')
|
||||||
engine.register_pass(scene, srl, "Denoising Shadow B", 3, "XYV", 'VECTOR')
|
engine.register_pass(scene, srl, "Denoising Shadow B", 3, "XYV", 'VECTOR')
|
||||||
engine.register_pass(scene, srl, "Denoising Image", 3, "RGB", 'COLOR')
|
|
||||||
engine.register_pass(scene, srl, "Denoising Image Variance", 3, "RGB", 'COLOR')
|
engine.register_pass(scene, srl, "Denoising Image Variance", 3, "RGB", 'COLOR')
|
||||||
|
|
||||||
clean_options = ("denoising_diffuse_direct", "denoising_diffuse_indirect",
|
clean_options = ("denoising_diffuse_direct", "denoising_diffuse_indirect",
|
||||||
"denoising_glossy_direct", "denoising_glossy_indirect",
|
"denoising_glossy_direct", "denoising_glossy_indirect",
|
||||||
"denoising_transmission_direct", "denoising_transmission_indirect",
|
"denoising_transmission_direct", "denoising_transmission_indirect",
|
||||||
|
@ -1347,6 +1347,36 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
|
|||||||
default=False,
|
default=False,
|
||||||
update=update_render_passes,
|
update=update_render_passes,
|
||||||
)
|
)
|
||||||
|
use_pass_crypto_object: BoolProperty(
|
||||||
|
name="Cryptomatte Object",
|
||||||
|
description="Cryptomatte Object pass",
|
||||||
|
default=False,
|
||||||
|
update=update_render_passes,
|
||||||
|
)
|
||||||
|
use_pass_crypto_material: BoolProperty(
|
||||||
|
name="Cryptomatte Material",
|
||||||
|
description="Cryptomatte Material pass",
|
||||||
|
default=False,
|
||||||
|
update=update_render_passes,
|
||||||
|
)
|
||||||
|
use_pass_crypto_asset: BoolProperty(
|
||||||
|
name="Cryptomatte Asset",
|
||||||
|
description="Cryptomatte Asset pass",
|
||||||
|
default=False,
|
||||||
|
update=update_render_passes,
|
||||||
|
)
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
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
|
@classmethod
|
||||||
def register(cls):
|
def register(cls):
|
||||||
|
@ -817,6 +817,17 @@ class CYCLES_RENDER_PT_layer_passes(CyclesButtonsPanel, Panel):
|
|||||||
col.prop(cycles_view_layer, "pass_debug_bvh_intersections")
|
col.prop(cycles_view_layer, "pass_debug_bvh_intersections")
|
||||||
col.prop(cycles_view_layer, "pass_debug_ray_bounces")
|
col.prop(cycles_view_layer, "pass_debug_ray_bounces")
|
||||||
|
|
||||||
|
layout.label("Cryptomatte:")
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.prop(cycles_view_layer, "use_pass_crypto_object", text="Object", toggle=True)
|
||||||
|
row.prop(cycles_view_layer, "use_pass_crypto_material", text="Material", toggle=True)
|
||||||
|
row.prop(cycles_view_layer, "use_pass_crypto_asset", text="Asset", toggle=True)
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.prop(cycles_view_layer, "pass_crypto_depth")
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.active = use_cpu(context)
|
||||||
|
row.prop(cycles_view_layer, "pass_crypto_accurate", text="Accurate Mode")
|
||||||
|
|
||||||
|
|
||||||
class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel):
|
class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel):
|
||||||
bl_label = "Denoising"
|
bl_label = "Denoising"
|
||||||
|
@ -424,6 +424,23 @@ Object *BlenderSync::sync_object(BL::Depsgraph& b_depsgraph,
|
|||||||
object_updated = true;
|
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
|
/* object sync
|
||||||
* transform comparison should not be needed, but duplis don't work perfect
|
* 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 */
|
* in the depsgraph and may not signal changes, so this is a workaround */
|
||||||
|
@ -407,7 +407,7 @@ void BlenderSession::render(BL::Depsgraph& b_depsgraph_)
|
|||||||
BL::RenderLayer b_rlay = *b_single_rlay;
|
BL::RenderLayer b_rlay = *b_single_rlay;
|
||||||
|
|
||||||
/* add passes */
|
/* add passes */
|
||||||
array<Pass> passes = sync->sync_render_passes(b_rlay, b_view_layer, session_params);
|
vector<Pass> passes = sync->sync_render_passes(b_rlay, b_view_layer, session_params);
|
||||||
buffer_params.passes = passes;
|
buffer_params.passes = passes;
|
||||||
|
|
||||||
PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
|
PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
|
||||||
@ -711,7 +711,7 @@ void BlenderSession::do_write_update_render_result(BL::RenderResult& b_rr,
|
|||||||
bool read = false;
|
bool read = false;
|
||||||
if(pass_type != PASS_NONE) {
|
if(pass_type != PASS_NONE) {
|
||||||
/* copy pixels */
|
/* 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 {
|
else {
|
||||||
int denoising_offset = BlenderSync::get_denoising_pass(b_pass);
|
int denoising_offset = BlenderSync::get_denoising_pass(b_pass);
|
||||||
@ -730,7 +730,7 @@ void BlenderSession::do_write_update_render_result(BL::RenderResult& b_rr,
|
|||||||
else {
|
else {
|
||||||
/* copy combined pass */
|
/* copy combined pass */
|
||||||
BL::RenderPass b_combined_pass(b_rlay.passes.find_by_name("Combined", b_rview_name.c_str()));
|
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]);
|
b_combined_pass.rect(&pixels[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@
|
|||||||
|
|
||||||
CCL_NAMESPACE_BEGIN
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
static const char *cryptomatte_prefix = "Crypto";
|
||||||
|
|
||||||
/* Constructor */
|
/* Constructor */
|
||||||
|
|
||||||
BlenderSync::BlenderSync(BL::RenderEngine& b_engine,
|
BlenderSync::BlenderSync(BL::RenderEngine& b_engine,
|
||||||
@ -449,6 +451,9 @@ PassType BlenderSync::get_pass_type(BL::RenderPass& b_pass)
|
|||||||
MAP_PASS("Debug Ray Bounces", PASS_RAY_BOUNCES);
|
MAP_PASS("Debug Ray Bounces", PASS_RAY_BOUNCES);
|
||||||
#endif
|
#endif
|
||||||
MAP_PASS("Debug Render Time", PASS_RENDER_TIME);
|
MAP_PASS("Debug Render Time", PASS_RENDER_TIME);
|
||||||
|
if(string_startswith(name, cryptomatte_prefix)) {
|
||||||
|
return PASS_CRYPTOMATTE;
|
||||||
|
}
|
||||||
#undef MAP_PASS
|
#undef MAP_PASS
|
||||||
|
|
||||||
return PASS_NONE;
|
return PASS_NONE;
|
||||||
@ -457,6 +462,9 @@ PassType BlenderSync::get_pass_type(BL::RenderPass& b_pass)
|
|||||||
int BlenderSync::get_denoising_pass(BL::RenderPass& b_pass)
|
int BlenderSync::get_denoising_pass(BL::RenderPass& b_pass)
|
||||||
{
|
{
|
||||||
string name = b_pass.name();
|
string name = b_pass.name();
|
||||||
|
|
||||||
|
if(name == "Noisy Image") return DENOISING_PASS_COLOR;
|
||||||
|
|
||||||
if(name.substr(0, 10) != "Denoising ") {
|
if(name.substr(0, 10) != "Denoising ") {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -471,7 +479,6 @@ int BlenderSync::get_denoising_pass(BL::RenderPass& b_pass)
|
|||||||
MAP_PASS("Depth Variance", DENOISING_PASS_DEPTH_VAR);
|
MAP_PASS("Depth Variance", DENOISING_PASS_DEPTH_VAR);
|
||||||
MAP_PASS("Shadow A", DENOISING_PASS_SHADOW_A);
|
MAP_PASS("Shadow A", DENOISING_PASS_SHADOW_A);
|
||||||
MAP_PASS("Shadow B", DENOISING_PASS_SHADOW_B);
|
MAP_PASS("Shadow B", DENOISING_PASS_SHADOW_B);
|
||||||
MAP_PASS("Image", DENOISING_PASS_COLOR);
|
|
||||||
MAP_PASS("Image Variance", DENOISING_PASS_COLOR_VAR);
|
MAP_PASS("Image Variance", DENOISING_PASS_COLOR_VAR);
|
||||||
MAP_PASS("Clean", DENOISING_PASS_CLEAN);
|
MAP_PASS("Clean", DENOISING_PASS_CLEAN);
|
||||||
#undef MAP_PASS
|
#undef MAP_PASS
|
||||||
@ -479,11 +486,11 @@ int BlenderSync::get_denoising_pass(BL::RenderPass& b_pass)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
array<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay,
|
vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay,
|
||||||
BL::ViewLayer& b_view_layer,
|
BL::ViewLayer& b_view_layer,
|
||||||
const SessionParams &session_params)
|
const SessionParams &session_params)
|
||||||
{
|
{
|
||||||
array<Pass> passes;
|
vector<Pass> passes;
|
||||||
Pass::add(PASS_COMBINED, passes);
|
Pass::add(PASS_COMBINED, passes);
|
||||||
|
|
||||||
if(!session_params.device.advanced_shading) {
|
if(!session_params.device.advanced_shading) {
|
||||||
@ -505,20 +512,7 @@ array<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay,
|
|||||||
|
|
||||||
scene->film->denoising_flags = 0;
|
scene->film->denoising_flags = 0;
|
||||||
PointerRNA crp = RNA_pointer_get(&b_view_layer.ptr, "cycles");
|
PointerRNA crp = RNA_pointer_get(&b_view_layer.ptr, "cycles");
|
||||||
if(get_boolean(crp, "denoising_store_passes") &&
|
if(get_boolean(crp, "use_denoising")) {
|
||||||
get_boolean(crp, "use_denoising"))
|
|
||||||
{
|
|
||||||
b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str());
|
|
||||||
b_engine.add_pass("Denoising Normal Variance", 3, "XYZ", b_view_layer.name().c_str());
|
|
||||||
b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str());
|
|
||||||
b_engine.add_pass("Denoising Albedo Variance", 3, "RGB", b_view_layer.name().c_str());
|
|
||||||
b_engine.add_pass("Denoising Depth", 1, "Z", b_view_layer.name().c_str());
|
|
||||||
b_engine.add_pass("Denoising Depth Variance", 1, "Z", b_view_layer.name().c_str());
|
|
||||||
b_engine.add_pass("Denoising Shadow A", 3, "XYV", b_view_layer.name().c_str());
|
|
||||||
b_engine.add_pass("Denoising Shadow B", 3, "XYV", b_view_layer.name().c_str());
|
|
||||||
b_engine.add_pass("Denoising Image", 3, "RGB", b_view_layer.name().c_str());
|
|
||||||
b_engine.add_pass("Denoising Image Variance", 3, "RGB", b_view_layer.name().c_str());
|
|
||||||
|
|
||||||
#define MAP_OPTION(name, flag) if(!get_boolean(crp, name)) scene->film->denoising_flags |= flag;
|
#define MAP_OPTION(name, flag) if(!get_boolean(crp, name)) scene->film->denoising_flags |= flag;
|
||||||
MAP_OPTION("denoising_diffuse_direct", DENOISING_CLEAN_DIFFUSE_DIR);
|
MAP_OPTION("denoising_diffuse_direct", DENOISING_CLEAN_DIFFUSE_DIR);
|
||||||
MAP_OPTION("denoising_diffuse_indirect", DENOISING_CLEAN_DIFFUSE_IND);
|
MAP_OPTION("denoising_diffuse_indirect", DENOISING_CLEAN_DIFFUSE_IND);
|
||||||
@ -530,10 +524,23 @@ array<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay,
|
|||||||
MAP_OPTION("denoising_subsurface_indirect", DENOISING_CLEAN_SUBSURFACE_IND);
|
MAP_OPTION("denoising_subsurface_indirect", DENOISING_CLEAN_SUBSURFACE_IND);
|
||||||
#undef MAP_OPTION
|
#undef MAP_OPTION
|
||||||
|
|
||||||
|
b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str());
|
||||||
|
if(get_boolean(crp, "denoising_store_passes")) {
|
||||||
|
b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str());
|
||||||
|
b_engine.add_pass("Denoising Normal Variance", 3, "XYZ", b_view_layer.name().c_str());
|
||||||
|
b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str());
|
||||||
|
b_engine.add_pass("Denoising Albedo Variance", 3, "RGB", b_view_layer.name().c_str());
|
||||||
|
b_engine.add_pass("Denoising Depth", 1, "Z", b_view_layer.name().c_str());
|
||||||
|
b_engine.add_pass("Denoising Depth Variance", 1, "Z", b_view_layer.name().c_str());
|
||||||
|
b_engine.add_pass("Denoising Shadow A", 3, "XYV", b_view_layer.name().c_str());
|
||||||
|
b_engine.add_pass("Denoising Shadow B", 3, "XYV", b_view_layer.name().c_str());
|
||||||
|
b_engine.add_pass("Denoising Image Variance", 3, "RGB", b_view_layer.name().c_str());
|
||||||
|
|
||||||
if(scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES) {
|
if(scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES) {
|
||||||
b_engine.add_pass("Denoising Clean", 3, "RGB", b_view_layer.name().c_str());
|
b_engine.add_pass("Denoising Clean", 3, "RGB", b_view_layer.name().c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#ifdef __KERNEL_DEBUG__
|
#ifdef __KERNEL_DEBUG__
|
||||||
if(get_boolean(crp, "pass_debug_bvh_traversed_nodes")) {
|
if(get_boolean(crp, "pass_debug_bvh_traversed_nodes")) {
|
||||||
b_engine.add_pass("Debug BVH Traversed Nodes", 1, "X", b_view_layer.name().c_str());
|
b_engine.add_pass("Debug BVH Traversed Nodes", 1, "X", b_view_layer.name().c_str());
|
||||||
@ -565,6 +572,39 @@ array<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay,
|
|||||||
Pass::add(PASS_VOLUME_INDIRECT, passes);
|
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_view_layer.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_view_layer.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_view_layer.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;
|
return passes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ public:
|
|||||||
int width, int height,
|
int width, int height,
|
||||||
void **python_thread_state);
|
void **python_thread_state);
|
||||||
void sync_view_layer(BL::SpaceView3D& b_v3d, BL::ViewLayer& b_view_layer);
|
void sync_view_layer(BL::SpaceView3D& b_v3d, BL::ViewLayer& b_view_layer);
|
||||||
array<Pass> sync_render_passes(BL::RenderLayer& b_render_layer,
|
vector<Pass> sync_render_passes(BL::RenderLayer& b_render_layer,
|
||||||
BL::ViewLayer& b_view_layer,
|
BL::ViewLayer& b_view_layer,
|
||||||
const SessionParams &session_params);
|
const SessionParams &session_params);
|
||||||
void sync_integrator();
|
void sync_integrator();
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include "kernel/osl/osl_globals.h"
|
#include "kernel/osl/osl_globals.h"
|
||||||
|
|
||||||
#include "render/buffers.h"
|
#include "render/buffers.h"
|
||||||
|
#include "render/coverage.h"
|
||||||
|
|
||||||
#include "util/util_debug.h"
|
#include "util/util_debug.h"
|
||||||
#include "util/util_foreach.h"
|
#include "util/util_foreach.h"
|
||||||
@ -677,8 +678,15 @@ public:
|
|||||||
|
|
||||||
void path_trace(DeviceTask &task, RenderTile &tile, KernelGlobals *kg)
|
void path_trace(DeviceTask &task, RenderTile &tile, KernelGlobals *kg)
|
||||||
{
|
{
|
||||||
|
const bool use_coverage = kernel_data.film.cryptomatte_passes & CRYPT_ACCURATE;
|
||||||
|
|
||||||
scoped_timer timer(&tile.buffers->render_time);
|
scoped_timer timer(&tile.buffers->render_time);
|
||||||
|
|
||||||
|
Coverage coverage(kg, tile);
|
||||||
|
if(use_coverage) {
|
||||||
|
coverage.init_path_trace();
|
||||||
|
}
|
||||||
|
|
||||||
float *render_buffer = (float*)tile.buffer;
|
float *render_buffer = (float*)tile.buffer;
|
||||||
int start_sample = tile.start_sample;
|
int start_sample = tile.start_sample;
|
||||||
int end_sample = tile.start_sample + tile.num_samples;
|
int end_sample = tile.start_sample + tile.num_samples;
|
||||||
@ -691,6 +699,9 @@ public:
|
|||||||
|
|
||||||
for(int y = tile.y; y < tile.y + tile.h; y++) {
|
for(int y = tile.y; y < tile.y + tile.h; y++) {
|
||||||
for(int x = tile.x; x < tile.x + tile.w; x++) {
|
for(int x = tile.x; x < tile.x + tile.w; x++) {
|
||||||
|
if(use_coverage) {
|
||||||
|
coverage.init_pixel(x, y);
|
||||||
|
}
|
||||||
path_trace_kernel()(kg, render_buffer,
|
path_trace_kernel()(kg, render_buffer,
|
||||||
sample, x, y, tile.offset, tile.stride);
|
sample, x, y, tile.offset, tile.stride);
|
||||||
}
|
}
|
||||||
@ -700,6 +711,9 @@ public:
|
|||||||
|
|
||||||
task.update_progress(&tile, tile.w*tile.h);
|
task.update_progress(&tile, tile.w*tile.h);
|
||||||
}
|
}
|
||||||
|
if(use_coverage) {
|
||||||
|
coverage.finalize();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void denoise(DenoisingTask& denoising, RenderTile &tile)
|
void denoise(DenoisingTask& denoising, RenderTile &tile)
|
||||||
@ -760,7 +774,6 @@ public:
|
|||||||
}
|
}
|
||||||
else if(tile.task == RenderTile::DENOISE) {
|
else if(tile.task == RenderTile::DENOISE) {
|
||||||
denoise(denoising, tile);
|
denoise(denoising, tile);
|
||||||
|
|
||||||
task.update_progress(&tile, tile.w*tile.h);
|
task.update_progress(&tile, tile.w*tile.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +96,7 @@ set(SRC_HEADERS
|
|||||||
kernel_emission.h
|
kernel_emission.h
|
||||||
kernel_film.h
|
kernel_film.h
|
||||||
kernel_globals.h
|
kernel_globals.h
|
||||||
|
kernel_id_passes.h
|
||||||
kernel_jitter.h
|
kernel_jitter.h
|
||||||
kernel_light.h
|
kernel_light.h
|
||||||
kernel_math.h
|
kernel_math.h
|
||||||
|
@ -304,6 +304,24 @@ ccl_device int shader_pass_id(KernelGlobals *kg, const ShaderData *sd)
|
|||||||
return kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).pass_id;
|
return kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).pass_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Cryptomatte ID */
|
||||||
|
|
||||||
|
ccl_device_inline float object_cryptomatte_id(KernelGlobals *kg, int object)
|
||||||
|
{
|
||||||
|
if(object == OBJECT_NONE)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return kernel_tex_fetch(__objects, object).cryptomatte_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
ccl_device_inline float object_cryptomatte_asset_id(KernelGlobals *kg, int object)
|
||||||
|
{
|
||||||
|
if(object == OBJECT_NONE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return kernel_tex_fetch(__objects, object).cryptomatte_asset;
|
||||||
|
}
|
||||||
|
|
||||||
/* Particle data from which object was instanced */
|
/* Particle data from which object was instanced */
|
||||||
|
|
||||||
ccl_device_inline uint particle_index(KernelGlobals *kg, int particle)
|
ccl_device_inline uint particle_index(KernelGlobals *kg, int particle)
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#ifdef __KERNEL_CPU__
|
#ifdef __KERNEL_CPU__
|
||||||
# include "util/util_vector.h"
|
# include "util/util_vector.h"
|
||||||
|
# include "util/util_map.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __KERNEL_OPENCL__
|
#ifdef __KERNEL_OPENCL__
|
||||||
@ -42,6 +43,8 @@ struct OSLThreadData;
|
|||||||
struct OSLShadingSystem;
|
struct OSLShadingSystem;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
typedef unordered_map<float, float> CoverageMap;
|
||||||
|
|
||||||
struct Intersection;
|
struct Intersection;
|
||||||
struct VolumeStep;
|
struct VolumeStep;
|
||||||
|
|
||||||
@ -68,6 +71,11 @@ typedef struct KernelGlobals {
|
|||||||
VolumeStep *decoupled_volume_steps[2];
|
VolumeStep *decoupled_volume_steps[2];
|
||||||
int decoupled_volume_steps_index;
|
int decoupled_volume_steps_index;
|
||||||
|
|
||||||
|
/* A buffer for storing per-pixel coverage for Cryptomatte. */
|
||||||
|
CoverageMap *coverage_object;
|
||||||
|
CoverageMap *coverage_material;
|
||||||
|
CoverageMap *coverage_asset;
|
||||||
|
|
||||||
/* split kernel */
|
/* split kernel */
|
||||||
SplitData split_data;
|
SplitData split_data;
|
||||||
SplitParams split_param_data;
|
SplitParams split_param_data;
|
||||||
|
94
intern/cycles/kernel/kernel_id_passes.h
Normal file
94
intern/cycles/kernel/kernel_id_passes.h
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Blender Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
ccl_device_inline void kernel_write_id_slots(ccl_global float *buffer, int num_slots, float id, float weight)
|
||||||
|
{
|
||||||
|
kernel_assert(id != ID_NONE);
|
||||||
|
if(weight == 0.0f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int slot = 0; slot < num_slots; slot++) {
|
||||||
|
ccl_global float2 *id_buffer = (ccl_global float2*)buffer;
|
||||||
|
#ifdef __ATOMIC_PASS_WRITE__
|
||||||
|
/* If the loop reaches an empty slot, the ID isn't in any slot yet - so add it! */
|
||||||
|
if(id_buffer[slot].x == ID_NONE) {
|
||||||
|
/* Use an atomic to claim this slot.
|
||||||
|
* If a different thread got here first, try again from this slot on. */
|
||||||
|
float old_id = atomic_compare_and_swap_float(buffer+slot*2, ID_NONE, id);
|
||||||
|
if(old_id != ID_NONE && old_id != id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
atomic_add_and_fetch_float(buffer+slot*2+1, weight);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* If there already is a slot for that ID, add the weight.
|
||||||
|
* If no slot was found, add it to the last. */
|
||||||
|
else if(id_buffer[slot].x == id || slot == num_slots - 1) {
|
||||||
|
atomic_add_and_fetch_float(buffer+slot*2+1, weight);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#else /* __ATOMIC_PASS_WRITE__ */
|
||||||
|
/* If the loop reaches an empty slot, the ID isn't in any slot yet - so add it! */
|
||||||
|
if(id_buffer[slot].x == ID_NONE) {
|
||||||
|
id_buffer[slot].x = id;
|
||||||
|
id_buffer[slot].y = weight;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* If there already is a slot for that ID, add the weight.
|
||||||
|
* If no slot was found, add it to the last. */
|
||||||
|
else if(id_buffer[slot].x == id || slot == num_slots - 1) {
|
||||||
|
id_buffer[slot].y += weight;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif /* __ATOMIC_PASS_WRITE__ */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ccl_device_inline void kernel_sort_id_slots(ccl_global float *buffer, int num_slots)
|
||||||
|
{
|
||||||
|
ccl_global float2 *id_buffer = (ccl_global float2*)buffer;
|
||||||
|
for(int slot = 1; slot < num_slots; ++slot) {
|
||||||
|
if(id_buffer[slot].x == ID_NONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Since we're dealing with a tiny number of elements, insertion sort should be fine. */
|
||||||
|
int i = slot;
|
||||||
|
while(i > 0 && id_buffer[i].y > id_buffer[i - 1].y) {
|
||||||
|
float2 swap = id_buffer[i];
|
||||||
|
id_buffer[i] = id_buffer[i - 1];
|
||||||
|
id_buffer[i - 1] = swap;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __KERNEL_GPU__
|
||||||
|
/* post-sorting for Cryptomatte */
|
||||||
|
ccl_device void kernel_cryptomatte_post(KernelGlobals *kg, ccl_global float *buffer, uint sample, int x, int y, int offset, int stride)
|
||||||
|
{
|
||||||
|
if(sample - 1 == kernel_data.integrator.aa_samples) {
|
||||||
|
int index = offset + x + y * stride;
|
||||||
|
int pass_stride = kernel_data.film.pass_stride;
|
||||||
|
ccl_global float *cryptomatte_buffer = buffer + index * pass_stride + kernel_data.film.pass_cryptomatte;
|
||||||
|
kernel_sort_id_slots(cryptomatte_buffer, 2 * kernel_data.film.cryptomatte_depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
@ -187,7 +187,10 @@ ccl_device float2 regular_polygon_sample(float corners, float rotation, float u,
|
|||||||
ccl_device float3 ensure_valid_reflection(float3 Ng, float3 I, float3 N)
|
ccl_device float3 ensure_valid_reflection(float3 Ng, float3 I, float3 N)
|
||||||
{
|
{
|
||||||
float3 R = 2*dot(N, I)*N - I;
|
float3 R = 2*dot(N, I)*N - I;
|
||||||
if(dot(Ng, R) >= 0.05f) {
|
|
||||||
|
/* Reflection rays may always be at least as shallow as the incoming ray. */
|
||||||
|
float threshold = min(0.9f*dot(Ng, I), 0.01f);
|
||||||
|
if(dot(Ng, R) >= threshold) {
|
||||||
return N;
|
return N;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,22 +198,86 @@ ccl_device float3 ensure_valid_reflection(float3 Ng, float3 I, float3 N)
|
|||||||
* The X axis is found by normalizing the component of N that's orthogonal to Ng.
|
* The X axis is found by normalizing the component of N that's orthogonal to Ng.
|
||||||
* The Y axis isn't actually needed.
|
* The Y axis isn't actually needed.
|
||||||
*/
|
*/
|
||||||
float3 X = normalize(N - dot(N, Ng)*Ng);
|
float NdotNg = dot(N, Ng);
|
||||||
|
float3 X = normalize(N - NdotNg*Ng);
|
||||||
|
|
||||||
/* Calculate N.z and N.x in the local coordinate system. */
|
/* Calculate N.z and N.x in the local coordinate system.
|
||||||
float Iz = dot(I, Ng);
|
*
|
||||||
float Ix2 = sqr(dot(I, X)), Iz2 = sqr(Iz);
|
* The goal of this computation is to find a N' that is rotated towards Ng just enough
|
||||||
float Ix2Iz2 = Ix2 + Iz2;
|
* to lift R' above the threshold (here called t), therefore dot(R', Ng) = t.
|
||||||
|
*
|
||||||
|
* According to the standard reflection equation, this means that we want dot(2*dot(N', I)*N' - I, Ng) = t.
|
||||||
|
*
|
||||||
|
* Since the Z axis of our local coordinate system is Ng, dot(x, Ng) is just x.z, so we get 2*dot(N', I)*N'.z - I.z = t.
|
||||||
|
*
|
||||||
|
* The rotation is simple to express in the coordinate system we formed - since N lies in the X-Z-plane, we know that
|
||||||
|
* N' will also lie in the X-Z-plane, so N'.y = 0 and therefore dot(N', I) = N'.x*I.x + N'.z*I.z .
|
||||||
|
*
|
||||||
|
* Furthermore, we want N' to be normalized, so N'.x = sqrt(1 - N'.z^2).
|
||||||
|
*
|
||||||
|
* With these simplifications, we get the final equation 2*(sqrt(1 - N'.z^2)*I.x + N'.z*I.z)*N'.z - I.z = t.
|
||||||
|
*
|
||||||
|
* The only unknown here is N'.z, so we can solve for that.
|
||||||
|
*
|
||||||
|
* The equation has four solutions in general:
|
||||||
|
*
|
||||||
|
* N'.z = +-sqrt(0.5*(+-sqrt(I.x^2*(I.x^2 + I.z^2 - t^2)) + t*I.z + I.x^2 + I.z^2)/(I.x^2 + I.z^2))
|
||||||
|
* We can simplify this expression a bit by grouping terms:
|
||||||
|
*
|
||||||
|
* a = I.x^2 + I.z^2
|
||||||
|
* b = sqrt(I.x^2 * (a - t^2))
|
||||||
|
* c = I.z*t + a
|
||||||
|
* N'.z = +-sqrt(0.5*(+-b + c)/a)
|
||||||
|
*
|
||||||
|
* Two solutions can immediately be discarded because they're negative so N' would lie in the lower hemisphere.
|
||||||
|
*/
|
||||||
|
float Ix = dot(I, X), Iz = dot(I, Ng);
|
||||||
|
float Ix2 = sqr(Ix), Iz2 = sqr(Iz);
|
||||||
|
float a = Ix2 + Iz2;
|
||||||
|
|
||||||
float a = safe_sqrtf(Ix2*(Ix2Iz2 - sqr(0.05f)));
|
float b = safe_sqrtf(Ix2*(a - sqr(threshold)));
|
||||||
float b = Iz*0.05f + Ix2Iz2;
|
float c = Iz*threshold + a;
|
||||||
float c = (a + b > 0.0f)? (a + b) : (-a + b);
|
|
||||||
|
|
||||||
float Nz = safe_sqrtf(0.5f * c * (1.0f / Ix2Iz2));
|
/* Evaluate both solutions.
|
||||||
float Nx = safe_sqrtf(1.0f - sqr(Nz));
|
* In many cases one can be immediately discarded (if N'.z would be imaginary or larger than one), so check for that first.
|
||||||
|
* If no option is viable (might happen in extreme cases like N being in the wrong hemisphere), give up and return Ng. */
|
||||||
|
float fac = 0.5f/a;
|
||||||
|
float N1_z2 = fac*(b+c), N2_z2 = fac*(-b+c);
|
||||||
|
bool valid1 = (N1_z2 > 1e-5f) && (N1_z2 <= (1.0f + 1e-5f));
|
||||||
|
bool valid2 = (N2_z2 > 1e-5f) && (N2_z2 <= (1.0f + 1e-5f));
|
||||||
|
|
||||||
/* Transform back into global coordinates. */
|
float2 N_new;
|
||||||
return Nx*X + Nz*Ng;
|
if(valid1 && valid2) {
|
||||||
|
/* If both are possible, do the expensive reflection-based check. */
|
||||||
|
float2 N1 = make_float2(safe_sqrtf(1.0f - N1_z2), safe_sqrtf(N1_z2));
|
||||||
|
float2 N2 = make_float2(safe_sqrtf(1.0f - N2_z2), safe_sqrtf(N2_z2));
|
||||||
|
|
||||||
|
float R1 = 2*(N1.x*Ix + N1.y*Iz)*N1.y - Iz;
|
||||||
|
float R2 = 2*(N2.x*Ix + N2.y*Iz)*N2.y - Iz;
|
||||||
|
|
||||||
|
valid1 = (R1 >= 1e-5f);
|
||||||
|
valid2 = (R2 >= 1e-5f);
|
||||||
|
if(valid1 && valid2) {
|
||||||
|
/* If both solutions are valid, return the one with the shallower reflection since it will be closer to the input
|
||||||
|
* (if the original reflection wasn't shallow, we would not be in this part of the function). */
|
||||||
|
N_new = (R1 < R2)? N1 : N2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* If only one reflection is valid (= positive), pick that one. */
|
||||||
|
N_new = (R1 > R2)? N1 : N2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(valid1 || valid2) {
|
||||||
|
/* Only one solution passes the N'.z criterium, so pick that one. */
|
||||||
|
float Nz2 = valid1? N1_z2 : N2_z2;
|
||||||
|
N_new = make_float2(safe_sqrtf(1.0f - Nz2), safe_sqrtf(Nz2));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Ng;
|
||||||
|
}
|
||||||
|
|
||||||
|
return N_new.x*X + N_new.y*Ng;
|
||||||
}
|
}
|
||||||
|
|
||||||
CCL_NAMESPACE_END
|
CCL_NAMESPACE_END
|
||||||
|
@ -14,12 +14,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
CCL_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
#if defined(__SPLIT_KERNEL__) || defined(__KERNEL_CUDA__)
|
#if defined(__SPLIT_KERNEL__) || defined(__KERNEL_CUDA__)
|
||||||
#define __ATOMIC_PASS_WRITE__
|
#define __ATOMIC_PASS_WRITE__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "kernel/kernel_id_passes.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
ccl_device_inline void kernel_write_pass_float(ccl_global float *buffer, float value)
|
ccl_device_inline void kernel_write_pass_float(ccl_global float *buffer, float value)
|
||||||
{
|
{
|
||||||
ccl_global float *buf = buffer;
|
ccl_global float *buf = buffer;
|
||||||
@ -189,6 +191,23 @@ ccl_device_inline void kernel_write_debug_passes(KernelGlobals *kg,
|
|||||||
}
|
}
|
||||||
#endif /* __KERNEL_DEBUG__ */
|
#endif /* __KERNEL_DEBUG__ */
|
||||||
|
|
||||||
|
#ifdef __KERNEL_CPU__
|
||||||
|
#define WRITE_ID_SLOT(buffer, depth, id, matte_weight, name) kernel_write_id_pass_cpu(buffer, depth * 2, id, matte_weight, kg->coverage_##name)
|
||||||
|
ccl_device_inline size_t kernel_write_id_pass_cpu(float *buffer, size_t depth, float id, float matte_weight, CoverageMap *map)
|
||||||
|
{
|
||||||
|
if(map) {
|
||||||
|
(*map)[id] += matte_weight;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else /* __KERNEL_CPU__ */
|
||||||
|
#define WRITE_ID_SLOT(buffer, depth, id, matte_weight, name) kernel_write_id_slots_gpu(buffer, depth * 2, id, matte_weight)
|
||||||
|
ccl_device_inline size_t kernel_write_id_slots_gpu(ccl_global float *buffer, size_t depth, float id, float matte_weight)
|
||||||
|
{
|
||||||
|
#endif /* __KERNEL_CPU__ */
|
||||||
|
kernel_write_id_slots(buffer, depth, id, matte_weight);
|
||||||
|
return depth * 2;
|
||||||
|
}
|
||||||
|
|
||||||
ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global float *buffer, PathRadiance *L,
|
ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global float *buffer, PathRadiance *L,
|
||||||
ShaderData *sd, ccl_addr_space PathState *state, float3 throughput)
|
ShaderData *sd, ccl_addr_space PathState *state, float3 throughput)
|
||||||
{
|
{
|
||||||
@ -242,6 +261,26 @@ ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global fl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(kernel_data.film.cryptomatte_passes) {
|
||||||
|
const float matte_weight = average(throughput) * (1.0f - average(shader_bsdf_transparency(kg, sd)));
|
||||||
|
if(matte_weight > 0.0f) {
|
||||||
|
ccl_global float *cryptomatte_buffer = buffer + kernel_data.film.pass_cryptomatte;
|
||||||
|
if(kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) {
|
||||||
|
float id = object_cryptomatte_id(kg, sd->object);
|
||||||
|
cryptomatte_buffer += WRITE_ID_SLOT(cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight, object);
|
||||||
|
}
|
||||||
|
if(kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) {
|
||||||
|
float id = shader_cryptomatte_id(kg, sd->shader);
|
||||||
|
cryptomatte_buffer += WRITE_ID_SLOT(cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight, material);
|
||||||
|
}
|
||||||
|
if(kernel_data.film.cryptomatte_passes & CRYPT_ASSET) {
|
||||||
|
float id = object_cryptomatte_asset_id(kg, sd->object);
|
||||||
|
cryptomatte_buffer += WRITE_ID_SLOT(cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight, asset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(light_flag & PASSMASK_COMPONENT(DIFFUSE))
|
if(light_flag & PASSMASK_COMPONENT(DIFFUSE))
|
||||||
L->color_diffuse += shader_bsdf_diffuse(kg, sd)*throughput;
|
L->color_diffuse += shader_bsdf_diffuse(kg, sd)*throughput;
|
||||||
if(light_flag & PASSMASK_COMPONENT(GLOSSY))
|
if(light_flag & PASSMASK_COMPONENT(GLOSSY))
|
||||||
|
@ -1276,4 +1276,9 @@ ccl_device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect
|
|||||||
}
|
}
|
||||||
#endif /* __TRANSPARENT_SHADOWS__ */
|
#endif /* __TRANSPARENT_SHADOWS__ */
|
||||||
|
|
||||||
|
ccl_device float shader_cryptomatte_id(KernelGlobals *kg, int shader)
|
||||||
|
{
|
||||||
|
return kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).cryptomatte_id;
|
||||||
|
}
|
||||||
|
|
||||||
CCL_NAMESPACE_END
|
CCL_NAMESPACE_END
|
||||||
|
@ -53,6 +53,7 @@ CCL_NAMESPACE_BEGIN
|
|||||||
#define OBJECT_NONE (~0)
|
#define OBJECT_NONE (~0)
|
||||||
#define PRIM_NONE (~0)
|
#define PRIM_NONE (~0)
|
||||||
#define LAMP_NONE (~0)
|
#define LAMP_NONE (~0)
|
||||||
|
#define ID_NONE (0.0f)
|
||||||
|
|
||||||
#define VOLUME_STACK_SIZE 32
|
#define VOLUME_STACK_SIZE 32
|
||||||
|
|
||||||
@ -415,6 +416,7 @@ typedef enum PassType {
|
|||||||
PASS_RAY_BOUNCES,
|
PASS_RAY_BOUNCES,
|
||||||
#endif
|
#endif
|
||||||
PASS_RENDER_TIME,
|
PASS_RENDER_TIME,
|
||||||
|
PASS_CRYPTOMATTE,
|
||||||
PASS_CATEGORY_MAIN_END = 31,
|
PASS_CATEGORY_MAIN_END = 31,
|
||||||
|
|
||||||
PASS_MIST = 32,
|
PASS_MIST = 32,
|
||||||
@ -443,6 +445,14 @@ typedef enum PassType {
|
|||||||
|
|
||||||
#define PASS_ANY (~0)
|
#define PASS_ANY (~0)
|
||||||
|
|
||||||
|
typedef enum CryptomatteType {
|
||||||
|
CRYPT_NONE = 0,
|
||||||
|
CRYPT_OBJECT = (1 << 0),
|
||||||
|
CRYPT_MATERIAL = (1 << 1),
|
||||||
|
CRYPT_ASSET = (1 << 2),
|
||||||
|
CRYPT_ACCURATE = (1 << 3),
|
||||||
|
} CryptomatteType;
|
||||||
|
|
||||||
typedef enum DenoisingPassOffsets {
|
typedef enum DenoisingPassOffsets {
|
||||||
DENOISING_PASS_NORMAL = 0,
|
DENOISING_PASS_NORMAL = 0,
|
||||||
DENOISING_PASS_NORMAL_VAR = 3,
|
DENOISING_PASS_NORMAL_VAR = 3,
|
||||||
@ -1260,6 +1270,9 @@ typedef struct KernelFilm {
|
|||||||
int pass_shadow;
|
int pass_shadow;
|
||||||
float pass_shadow_scale;
|
float pass_shadow_scale;
|
||||||
int filter_table_offset;
|
int filter_table_offset;
|
||||||
|
int cryptomatte_passes;
|
||||||
|
int cryptomatte_depth;
|
||||||
|
int pass_cryptomatte;
|
||||||
|
|
||||||
int pass_mist;
|
int pass_mist;
|
||||||
float mist_start;
|
float mist_start;
|
||||||
@ -1270,7 +1283,7 @@ typedef struct KernelFilm {
|
|||||||
int pass_denoising_clean;
|
int pass_denoising_clean;
|
||||||
int denoising_flags;
|
int denoising_flags;
|
||||||
|
|
||||||
int pad1, pad2, pad3;
|
int pad1, pad2;
|
||||||
|
|
||||||
/* XYZ to rendering color space transform. float4 instead of float3 to
|
/* XYZ to rendering color space transform. float4 instead of float3 to
|
||||||
* ensure consistent padding/alignment across devices. */
|
* ensure consistent padding/alignment across devices. */
|
||||||
@ -1460,7 +1473,11 @@ typedef struct KernelObject {
|
|||||||
uint patch_map_offset;
|
uint patch_map_offset;
|
||||||
uint attribute_map_offset;
|
uint attribute_map_offset;
|
||||||
uint motion_offset;
|
uint motion_offset;
|
||||||
uint pad;
|
uint pad1;
|
||||||
|
|
||||||
|
float cryptomatte_object;
|
||||||
|
float cryptomatte_asset;
|
||||||
|
float pad2, pad3;
|
||||||
} KernelObject;
|
} KernelObject;
|
||||||
static_assert_align(KernelObject, 16);
|
static_assert_align(KernelObject, 16);
|
||||||
|
|
||||||
@ -1540,7 +1557,7 @@ static_assert_align(KernelParticle, 16);
|
|||||||
|
|
||||||
typedef struct KernelShader {
|
typedef struct KernelShader {
|
||||||
float constant_emission[3];
|
float constant_emission[3];
|
||||||
float pad1;
|
float cryptomatte_id;
|
||||||
int flags;
|
int flags;
|
||||||
int pass_id;
|
int pass_id;
|
||||||
int pad2, pad3;
|
int pad2, pad3;
|
||||||
|
@ -40,14 +40,21 @@ CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_MAX_REGISTERS)
|
|||||||
kernel_cuda_path_trace(WorkTile *tile, uint total_work_size)
|
kernel_cuda_path_trace(WorkTile *tile, uint total_work_size)
|
||||||
{
|
{
|
||||||
int work_index = ccl_global_id(0);
|
int work_index = ccl_global_id(0);
|
||||||
|
bool thread_is_active = work_index < total_work_size;
|
||||||
if(work_index < total_work_size) {
|
|
||||||
uint x, y, sample;
|
uint x, y, sample;
|
||||||
|
KernelGlobals kg;
|
||||||
|
if(thread_is_active) {
|
||||||
get_work_pixel(tile, work_index, &x, &y, &sample);
|
get_work_pixel(tile, work_index, &x, &y, &sample);
|
||||||
|
|
||||||
KernelGlobals kg;
|
|
||||||
kernel_path_trace(&kg, tile->buffer, sample, x, y, tile->offset, tile->stride);
|
kernel_path_trace(&kg, tile->buffer, sample, x, y, tile->offset, tile->stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(kernel_data.film.cryptomatte_passes) {
|
||||||
|
__syncthreads();
|
||||||
|
if(thread_is_active) {
|
||||||
|
kernel_cryptomatte_post(&kg, tile->buffer, sample, x, y, tile->offset, tile->stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __BRANCHED_PATH__
|
#ifdef __BRANCHED_PATH__
|
||||||
@ -56,14 +63,21 @@ CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_BRANCHED_MAX_REGISTERS)
|
|||||||
kernel_cuda_branched_path_trace(WorkTile *tile, uint total_work_size)
|
kernel_cuda_branched_path_trace(WorkTile *tile, uint total_work_size)
|
||||||
{
|
{
|
||||||
int work_index = ccl_global_id(0);
|
int work_index = ccl_global_id(0);
|
||||||
|
bool thread_is_active = work_index < total_work_size;
|
||||||
if(work_index < total_work_size) {
|
|
||||||
uint x, y, sample;
|
uint x, y, sample;
|
||||||
|
KernelGlobals kg;
|
||||||
|
if(thread_is_active) {
|
||||||
get_work_pixel(tile, work_index, &x, &y, &sample);
|
get_work_pixel(tile, work_index, &x, &y, &sample);
|
||||||
|
|
||||||
KernelGlobals kg;
|
|
||||||
kernel_branched_path_trace(&kg, tile->buffer, sample, x, y, tile->offset, tile->stride);
|
kernel_branched_path_trace(&kg, tile->buffer, sample, x, y, tile->offset, tile->stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(kernel_data.film.cryptomatte_passes) {
|
||||||
|
__syncthreads();
|
||||||
|
if(thread_is_active) {
|
||||||
|
kernel_cryptomatte_post(&kg, tile->buffer, sample, x, y, tile->offset, tile->stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -66,10 +66,18 @@ __kernel void kernel_ocl_path_trace(
|
|||||||
|
|
||||||
int x = sx + ccl_global_id(0);
|
int x = sx + ccl_global_id(0);
|
||||||
int y = sy + ccl_global_id(1);
|
int y = sy + ccl_global_id(1);
|
||||||
|
bool thread_is_active = x < sx + sw && y < sy + sh;
|
||||||
if(x < sx + sw && y < sy + sh)
|
if(thread_is_active) {
|
||||||
kernel_path_trace(kg, buffer, sample, x, y, offset, stride);
|
kernel_path_trace(kg, buffer, sample, x, y, offset, stride);
|
||||||
}
|
}
|
||||||
|
if(kernel_data.film.cryptomatte_passes) {
|
||||||
|
/* Make sure no thread is writing to the buffers. */
|
||||||
|
ccl_barrier(CCL_LOCAL_MEM_FENCE);
|
||||||
|
if(thread_is_active) {
|
||||||
|
kernel_cryptomatte_post(kg, buffer, sample, x, y, offset, stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else /* __COMPILE_ONLY_MEGAKERNEL__ */
|
#else /* __COMPILE_ONLY_MEGAKERNEL__ */
|
||||||
|
|
||||||
|
@ -884,6 +884,23 @@ bool OSLRenderServices::has_userdata(ustring name, TypeDesc type, OSL::ShaderGlo
|
|||||||
return false; /* never called by OSL */
|
return false; /* never called by OSL */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(ustring filename)
|
||||||
|
{
|
||||||
|
if (filename.length() && filename[0] == '@') {
|
||||||
|
/* Dummy, we don't use texture handles for builtin textures but need
|
||||||
|
* to tell the OSL runtime optimizer that this is a valid texture. */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return texturesys()->get_texture_handle(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OSLRenderServices::good(TextureSystem::TextureHandle *texture_handle)
|
||||||
|
{
|
||||||
|
return texturesys()->good(texture_handle);
|
||||||
|
}
|
||||||
|
|
||||||
bool OSLRenderServices::texture(ustring filename,
|
bool OSLRenderServices::texture(ustring filename,
|
||||||
TextureHandle *texture_handle,
|
TextureHandle *texture_handle,
|
||||||
TexturePerthread *texture_thread_info,
|
TexturePerthread *texture_thread_info,
|
||||||
@ -894,7 +911,8 @@ bool OSLRenderServices::texture(ustring filename,
|
|||||||
int nchannels,
|
int nchannels,
|
||||||
float *result,
|
float *result,
|
||||||
float *dresultds,
|
float *dresultds,
|
||||||
float *dresultdt)
|
float *dresultdt,
|
||||||
|
ustring *errormessage)
|
||||||
{
|
{
|
||||||
OSL::TextureSystem *ts = osl_ts;
|
OSL::TextureSystem *ts = osl_ts;
|
||||||
ShaderData *sd = (ShaderData *)(sg->renderstate);
|
ShaderData *sd = (ShaderData *)(sg->renderstate);
|
||||||
@ -1156,8 +1174,14 @@ bool OSLRenderServices::get_texture_info(OSL::ShaderGlobals *sg, ustring filenam
|
|||||||
TypeDesc datatype, void *data)
|
TypeDesc datatype, void *data)
|
||||||
{
|
{
|
||||||
OSL::TextureSystem *ts = osl_ts;
|
OSL::TextureSystem *ts = osl_ts;
|
||||||
|
if (filename.length() && filename[0] == '@') {
|
||||||
|
/* Special builtin textures. */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
return ts->get_texture_info(filename, subimage, dataname, datatype, data);
|
return ts->get_texture_info(filename, subimage, dataname, datatype, data);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int OSLRenderServices::pointcloud_search(OSL::ShaderGlobals *sg, ustring filename, const OSL::Vec3 ¢er,
|
int OSLRenderServices::pointcloud_search(OSL::ShaderGlobals *sg, ustring filename, const OSL::Vec3 ¢er,
|
||||||
float radius, int max_points, bool sort,
|
float radius, int max_points, bool sort,
|
||||||
|
@ -93,6 +93,10 @@ public:
|
|||||||
bool getmessage(OSL::ShaderGlobals *sg, ustring source, ustring name,
|
bool getmessage(OSL::ShaderGlobals *sg, ustring source, ustring name,
|
||||||
TypeDesc type, void *val, bool derivatives);
|
TypeDesc type, void *val, bool derivatives);
|
||||||
|
|
||||||
|
TextureSystem::TextureHandle *get_texture_handle(ustring filename);
|
||||||
|
|
||||||
|
bool good(TextureSystem::TextureHandle *texture_handle);
|
||||||
|
|
||||||
bool texture(ustring filename,
|
bool texture(ustring filename,
|
||||||
TextureSystem::TextureHandle *texture_handle,
|
TextureSystem::TextureHandle *texture_handle,
|
||||||
TexturePerthread *texture_thread_info,
|
TexturePerthread *texture_thread_info,
|
||||||
@ -103,7 +107,8 @@ public:
|
|||||||
int nchannels,
|
int nchannels,
|
||||||
float *result,
|
float *result,
|
||||||
float *dresultds,
|
float *dresultds,
|
||||||
float *dresultdt);
|
float *dresultdt,
|
||||||
|
ustring *errormessage);
|
||||||
|
|
||||||
bool texture3d(ustring filename,
|
bool texture3d(ustring filename,
|
||||||
TextureHandle *texture_handle,
|
TextureHandle *texture_handle,
|
||||||
|
@ -284,33 +284,63 @@ point rotate (point p, float angle, point a, point b)
|
|||||||
|
|
||||||
normal ensure_valid_reflection(normal Ng, vector I, normal N)
|
normal ensure_valid_reflection(normal Ng, vector I, normal N)
|
||||||
{
|
{
|
||||||
|
/* The implementation here mirrors the one in kernel_montecarlo.h,
|
||||||
|
* check there for an explanation of the algorithm. */
|
||||||
|
|
||||||
float sqr(float x) { return x*x; }
|
float sqr(float x) { return x*x; }
|
||||||
|
|
||||||
vector R = 2*dot(N, I)*N - I;
|
vector R = 2*dot(N, I)*N - I;
|
||||||
if (dot(Ng, R) >= 0.05) {
|
|
||||||
|
float threshold = min(0.9*dot(Ng, I), 0.01);
|
||||||
|
if(dot(Ng, R) >= threshold) {
|
||||||
return N;
|
return N;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Form coordinate system with Ng as the Z axis and N inside the X-Z-plane.
|
float NdotNg = dot(N, Ng);
|
||||||
* The X axis is found by normalizing the component of N that's orthogonal to Ng.
|
vector X = normalize(N - NdotNg*Ng);
|
||||||
* The Y axis isn't actually needed.
|
|
||||||
*/
|
|
||||||
vector X = normalize(N - dot(N, Ng)*Ng);
|
|
||||||
|
|
||||||
/* Calculate N.z and N.x in the local coordinate system. */
|
|
||||||
float Ix = dot(I, X), Iz = dot(I, Ng);
|
float Ix = dot(I, X), Iz = dot(I, Ng);
|
||||||
float Ix2 = sqr(dot(I, X)), Iz2 = sqr(dot(I, Ng));
|
float Ix2 = sqr(Ix), Iz2 = sqr(Iz);
|
||||||
float Ix2Iz2 = Ix2 + Iz2;
|
float a = Ix2 + Iz2;
|
||||||
|
|
||||||
float a = sqrt(Ix2*(Ix2Iz2 - sqr(0.05)));
|
float b = sqrt(Ix2*(a - sqr(threshold)));
|
||||||
float b = Iz*0.05 + Ix2Iz2;
|
float c = Iz*threshold + a;
|
||||||
float c = (a + b > 0.0)? (a + b) : (-a + b);
|
|
||||||
|
|
||||||
float Nz = sqrt(0.5 * c * (1.0 / Ix2Iz2));
|
float fac = 0.5/a;
|
||||||
float Nx = sqrt(1.0 - sqr(Nz));
|
float N1_z2 = fac*(b+c), N2_z2 = fac*(-b+c);
|
||||||
|
int valid1 = (N1_z2 > 1e-5) && (N1_z2 <= (1.0 + 1e-5));
|
||||||
|
int valid2 = (N2_z2 > 1e-5) && (N2_z2 <= (1.0 + 1e-5));
|
||||||
|
|
||||||
/* Transform back into global coordinates. */
|
float N_new_x, N_new_z;
|
||||||
return Nx*X + Nz*Ng;
|
if(valid1 && valid2) {
|
||||||
|
float N1_x = sqrt(1.0 - N1_z2), N1_z = sqrt(N1_z2);
|
||||||
|
float N2_x = sqrt(1.0 - N2_z2), N2_z = sqrt(N2_z2);
|
||||||
|
|
||||||
|
float R1 = 2*(N1_x*Ix + N1_z*Iz)*N1_z - Iz;
|
||||||
|
float R2 = 2*(N2_x*Ix + N2_z*Iz)*N2_z - Iz;
|
||||||
|
|
||||||
|
valid1 = (R1 >= 1e-5);
|
||||||
|
valid2 = (R2 >= 1e-5);
|
||||||
|
if(valid1 && valid2) {
|
||||||
|
N_new_x = (R1 < R2)? N1_x : N2_x;
|
||||||
|
N_new_z = (R1 < R2)? N1_z : N2_z;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
N_new_x = (R1 > R2)? N1_x : N2_x;
|
||||||
|
N_new_z = (R1 > R2)? N1_z : N2_z;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(valid1 || valid2) {
|
||||||
|
float Nz2 = valid1? N1_z2 : N2_z2;
|
||||||
|
N_new_x = sqrt(1.0 - Nz2);
|
||||||
|
N_new_z = sqrt(Nz2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Ng;
|
||||||
|
}
|
||||||
|
|
||||||
|
return N_new_x*X + N_new_z*Ng;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -80,8 +80,10 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg,
|
|||||||
PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
|
PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
|
||||||
ccl_global Ray *ray = &kernel_split_state.ray[ray_index];
|
ccl_global Ray *ray = &kernel_split_state.ray[ray_index];
|
||||||
ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index];
|
ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index];
|
||||||
|
bool ray_was_updated = false;
|
||||||
|
|
||||||
if(IS_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER)) {
|
if(IS_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER)) {
|
||||||
|
ray_was_updated = true;
|
||||||
uint sample = state->sample;
|
uint sample = state->sample;
|
||||||
uint buffer_offset = kernel_split_state.buffer_offset[ray_index];
|
uint buffer_offset = kernel_split_state.buffer_offset[ray_index];
|
||||||
ccl_global float *buffer = kernel_split_params.tile.buffer + buffer_offset;
|
ccl_global float *buffer = kernel_split_params.tile.buffer + buffer_offset;
|
||||||
@ -92,6 +94,17 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg,
|
|||||||
ASSIGN_RAY_STATE(ray_state, ray_index, RAY_TO_REGENERATE);
|
ASSIGN_RAY_STATE(ray_state, ray_index, RAY_TO_REGENERATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(kernel_data.film.cryptomatte_passes) {
|
||||||
|
/* Make sure no thread is writing to the buffers. */
|
||||||
|
ccl_barrier(CCL_LOCAL_MEM_FENCE);
|
||||||
|
if(ray_was_updated && state->sample - 1 == kernel_data.integrator.aa_samples) {
|
||||||
|
uint buffer_offset = kernel_split_state.buffer_offset[ray_index];
|
||||||
|
ccl_global float *buffer = kernel_split_params.tile.buffer + buffer_offset;
|
||||||
|
ccl_global float *cryptomatte_buffer = buffer + kernel_data.film.pass_cryptomatte;
|
||||||
|
kernel_sort_id_slots(cryptomatte_buffer, 2 * kernel_data.film.cryptomatte_depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(IS_STATE(ray_state, ray_index, RAY_TO_REGENERATE)) {
|
if(IS_STATE(ray_state, ray_index, RAY_TO_REGENERATE)) {
|
||||||
/* We have completed current work; So get next work */
|
/* We have completed current work; So get next work */
|
||||||
ccl_global uint *work_pools = kernel_split_params.work_pools;
|
ccl_global uint *work_pools = kernel_split_params.work_pools;
|
||||||
|
@ -15,6 +15,7 @@ set(SRC
|
|||||||
buffers.cpp
|
buffers.cpp
|
||||||
camera.cpp
|
camera.cpp
|
||||||
constant_fold.cpp
|
constant_fold.cpp
|
||||||
|
coverage.cpp
|
||||||
film.cpp
|
film.cpp
|
||||||
graph.cpp
|
graph.cpp
|
||||||
image.cpp
|
image.cpp
|
||||||
@ -46,6 +47,7 @@ set(SRC_HEADERS
|
|||||||
buffers.h
|
buffers.h
|
||||||
camera.h
|
camera.h
|
||||||
constant_fold.h
|
constant_fold.h
|
||||||
|
coverage.h
|
||||||
film.h
|
film.h
|
||||||
graph.h
|
graph.h
|
||||||
image.h
|
image.h
|
||||||
|
@ -160,11 +160,12 @@ bool RenderBuffers::get_denoising_pass_rect(int offset, float exposure, int samp
|
|||||||
(offset == DENOISING_PASS_DEPTH_VAR) ||
|
(offset == DENOISING_PASS_DEPTH_VAR) ||
|
||||||
(offset == DENOISING_PASS_COLOR_VAR);
|
(offset == DENOISING_PASS_COLOR_VAR);
|
||||||
|
|
||||||
|
float scale_exposure = scale;
|
||||||
if(offset == DENOISING_PASS_COLOR || offset == DENOISING_PASS_CLEAN) {
|
if(offset == DENOISING_PASS_COLOR || offset == DENOISING_PASS_CLEAN) {
|
||||||
scale *= exposure;
|
scale_exposure *= exposure;
|
||||||
}
|
}
|
||||||
else if(offset == DENOISING_PASS_COLOR_VAR) {
|
else if(offset == DENOISING_PASS_COLOR_VAR) {
|
||||||
scale *= exposure*exposure;
|
scale_exposure *= exposure*exposure;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += params.get_denoising_offset();
|
offset += params.get_denoising_offset();
|
||||||
@ -181,14 +182,14 @@ bool RenderBuffers::get_denoising_pass_rect(int offset, float exposure, int samp
|
|||||||
|
|
||||||
if(components == 1) {
|
if(components == 1) {
|
||||||
for(int i = 0; i < size; i++, mean += pass_stride, var += pass_stride, pixels++) {
|
for(int i = 0; i < size; i++, mean += pass_stride, var += pass_stride, pixels++) {
|
||||||
pixels[0] = max(0.0f, var[0] - mean[0]*mean[0]*invsample)*scale;
|
pixels[0] = max(0.0f, var[0] - mean[0]*mean[0]*invsample)*scale_exposure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(components == 3) {
|
else if(components == 3) {
|
||||||
for(int i = 0; i < size; i++, mean += pass_stride, var += pass_stride, pixels += 3) {
|
for(int i = 0; i < size; i++, mean += pass_stride, var += pass_stride, pixels += 3) {
|
||||||
pixels[0] = max(0.0f, var[0] - mean[0]*mean[0]*invsample)*scale;
|
pixels[0] = max(0.0f, var[0] - mean[0]*mean[0]*invsample)*scale_exposure;
|
||||||
pixels[1] = max(0.0f, var[1] - mean[1]*mean[1]*invsample)*scale;
|
pixels[1] = max(0.0f, var[1] - mean[1]*mean[1]*invsample)*scale_exposure;
|
||||||
pixels[2] = max(0.0f, var[2] - mean[2]*mean[2]*invsample)*scale;
|
pixels[2] = max(0.0f, var[2] - mean[2]*mean[2]*invsample)*scale_exposure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -200,14 +201,28 @@ bool RenderBuffers::get_denoising_pass_rect(int offset, float exposure, int samp
|
|||||||
|
|
||||||
if(components == 1) {
|
if(components == 1) {
|
||||||
for(int i = 0; i < size; i++, in += pass_stride, pixels++) {
|
for(int i = 0; i < size; i++, in += pass_stride, pixels++) {
|
||||||
pixels[0] = in[0]*scale;
|
pixels[0] = in[0]*scale_exposure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(components == 3) {
|
else if(components == 3) {
|
||||||
for(int i = 0; i < size; i++, in += pass_stride, pixels += 3) {
|
for(int i = 0; i < size; i++, in += pass_stride, pixels += 3) {
|
||||||
pixels[0] = in[0]*scale;
|
pixels[0] = in[0]*scale_exposure;
|
||||||
pixels[1] = in[1]*scale;
|
pixels[1] = in[1]*scale_exposure;
|
||||||
pixels[2] = in[2]*scale;
|
pixels[2] = in[2]*scale_exposure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(components == 4) {
|
||||||
|
assert(offset == DENOISING_PASS_COLOR);
|
||||||
|
|
||||||
|
/* Since the alpha channel is not involved in denoising, output the Combined alpha channel. */
|
||||||
|
assert(params.passes[0].type == PASS_COMBINED);
|
||||||
|
float *in_combined = buffer.data();
|
||||||
|
|
||||||
|
for(int i = 0; i < size; i++, in += pass_stride, in_combined += pass_stride, pixels += 4) {
|
||||||
|
pixels[0] = in[0]*scale_exposure;
|
||||||
|
pixels[1] = in[1]*scale_exposure;
|
||||||
|
pixels[2] = in[2]*scale_exposure;
|
||||||
|
pixels[3] = saturate(in_combined[3]*scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -218,7 +233,7 @@ bool RenderBuffers::get_denoising_pass_rect(int offset, float exposure, int samp
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int components, float *pixels)
|
bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int components, float *pixels, const string &name)
|
||||||
{
|
{
|
||||||
if(buffer.data() == NULL) {
|
if(buffer.data() == NULL) {
|
||||||
return false;
|
return false;
|
||||||
@ -234,6 +249,14 @@ bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tell Cryptomatte passes apart by their name. */
|
||||||
|
if(pass.type == PASS_CRYPTOMATTE) {
|
||||||
|
if(pass.name != name) {
|
||||||
|
pass_offset += pass.components;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float *in = buffer.data() + pass_offset;
|
float *in = buffer.data() + pass_offset;
|
||||||
int pass_stride = params.get_passes_size();
|
int pass_stride = params.get_passes_size();
|
||||||
|
|
||||||
@ -370,6 +393,17 @@ bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int
|
|||||||
pixels[3] = f.w*invw;
|
pixels[3] = f.w*invw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(type == PASS_CRYPTOMATTE) {
|
||||||
|
for(int i = 0; i < size; i++, in += pass_stride, pixels += 4) {
|
||||||
|
float4 f = make_float4(in[0], in[1], in[2], in[3]);
|
||||||
|
/* x and z contain integer IDs, don't rescale them.
|
||||||
|
y and w contain matte weights, they get scaled. */
|
||||||
|
pixels[0] = f.x;
|
||||||
|
pixels[1] = f.y * scale;
|
||||||
|
pixels[2] = f.z;
|
||||||
|
pixels[3] = f.w * scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
for(int i = 0; i < size; i++, in += pass_stride, pixels += 4) {
|
for(int i = 0; i < size; i++, in += pass_stride, pixels += 4) {
|
||||||
float4 f = make_float4(in[0], in[1], in[2], in[3]);
|
float4 f = make_float4(in[0], in[1], in[2], in[3]);
|
||||||
|
@ -50,7 +50,7 @@ public:
|
|||||||
int full_height;
|
int full_height;
|
||||||
|
|
||||||
/* passes */
|
/* passes */
|
||||||
array<Pass> passes;
|
vector<Pass> passes;
|
||||||
bool denoising_data_pass;
|
bool denoising_data_pass;
|
||||||
/* If only some light path types should be denoised, an additional pass is needed. */
|
/* If only some light path types should be denoised, an additional pass is needed. */
|
||||||
bool denoising_clean_pass;
|
bool denoising_clean_pass;
|
||||||
@ -84,7 +84,7 @@ public:
|
|||||||
void zero();
|
void zero();
|
||||||
|
|
||||||
bool copy_from_device();
|
bool copy_from_device();
|
||||||
bool get_pass_rect(PassType type, float exposure, int sample, int components, float *pixels);
|
bool get_pass_rect(PassType type, float exposure, int sample, int components, float *pixels, const string &name);
|
||||||
bool get_denoising_pass_rect(int offset, float exposure, int sample, int components, float *pixels);
|
bool get_denoising_pass_rect(int offset, float exposure, int sample, int components, float *pixels);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
143
intern/cycles/render/coverage.cpp
Normal file
143
intern/cycles/render/coverage.cpp
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Blender Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "render/coverage.h"
|
||||||
|
#include "kernel/kernel_compat_cpu.h"
|
||||||
|
#include "kernel/split/kernel_split_data.h"
|
||||||
|
#include "kernel/kernel_globals.h"
|
||||||
|
#include "kernel/kernel_id_passes.h"
|
||||||
|
#include "kernel/kernel_types.h"
|
||||||
|
#include "util/util_map.h"
|
||||||
|
#include "util/util_vector.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
static bool crypomatte_comp(const pair<float, float>& i, const pair<float, float> j) { return i.first > j.first; }
|
||||||
|
|
||||||
|
void Coverage::finalize()
|
||||||
|
{
|
||||||
|
int pass_offset = 0;
|
||||||
|
if(kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) {
|
||||||
|
finalize_buffer(coverage_object, pass_offset);
|
||||||
|
pass_offset += kernel_data.film.cryptomatte_depth * 4;
|
||||||
|
}
|
||||||
|
if(kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) {
|
||||||
|
finalize_buffer(coverage_material, pass_offset);
|
||||||
|
pass_offset += kernel_data.film.cryptomatte_depth * 4;
|
||||||
|
}
|
||||||
|
if(kernel_data.film.cryptomatte_passes & CRYPT_ASSET) {
|
||||||
|
finalize_buffer(coverage_asset, pass_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Coverage::init_path_trace()
|
||||||
|
{
|
||||||
|
kg->coverage_object = kg->coverage_material = kg->coverage_asset = NULL;
|
||||||
|
|
||||||
|
if(kernel_data.film.cryptomatte_passes & CRYPT_ACCURATE) {
|
||||||
|
if(kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) {
|
||||||
|
coverage_object.clear();
|
||||||
|
coverage_object.resize(tile.w * tile.h);
|
||||||
|
}
|
||||||
|
if(kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) {
|
||||||
|
coverage_material.clear();
|
||||||
|
coverage_material.resize(tile.w * tile.h);
|
||||||
|
}
|
||||||
|
if(kernel_data.film.cryptomatte_passes & CRYPT_ASSET) {
|
||||||
|
coverage_asset.clear();
|
||||||
|
coverage_asset.resize(tile.w * tile.h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Coverage::init_pixel(int x, int y)
|
||||||
|
{
|
||||||
|
if(kernel_data.film.cryptomatte_passes & CRYPT_ACCURATE) {
|
||||||
|
const int pixel_index = tile.w * (y - tile.y) + x - tile.x;
|
||||||
|
if(kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) {
|
||||||
|
kg->coverage_object = &coverage_object[pixel_index];
|
||||||
|
}
|
||||||
|
if(kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) {
|
||||||
|
kg->coverage_material = &coverage_material[pixel_index];
|
||||||
|
}
|
||||||
|
if(kernel_data.film.cryptomatte_passes & CRYPT_ASSET) {
|
||||||
|
kg->coverage_asset = &coverage_asset[pixel_index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Coverage::finalize_buffer(vector<CoverageMap> & coverage, const int pass_offset)
|
||||||
|
{
|
||||||
|
if(kernel_data.film.cryptomatte_passes & CRYPT_ACCURATE) {
|
||||||
|
flatten_buffer(coverage, pass_offset);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sort_buffer(pass_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Coverage::flatten_buffer(vector<CoverageMap> &coverage, const int pass_offset)
|
||||||
|
{
|
||||||
|
/* Sort the coverage map and write it to the output */
|
||||||
|
int pixel_index = 0;
|
||||||
|
int pass_stride = tile.buffers->params.get_passes_size();
|
||||||
|
for(int y = 0; y < tile.h; ++y) {
|
||||||
|
for(int x = 0; x < tile.w; ++x) {
|
||||||
|
const CoverageMap& pixel = coverage[pixel_index];
|
||||||
|
if(!pixel.empty()) {
|
||||||
|
/* buffer offset */
|
||||||
|
int index = x + y * tile.stride;
|
||||||
|
float *buffer = (float*)tile.buffer + index*pass_stride;
|
||||||
|
|
||||||
|
/* sort the cryptomatte pixel */
|
||||||
|
vector<pair<float, float> > sorted_pixel;
|
||||||
|
for(CoverageMap::const_iterator it = pixel.begin(); it != pixel.end(); ++it) {
|
||||||
|
sorted_pixel.push_back(std::make_pair(it->second, it->first));
|
||||||
|
}
|
||||||
|
sort(sorted_pixel.begin(), sorted_pixel.end(), crypomatte_comp);
|
||||||
|
int num_slots = 2 * (kernel_data.film.cryptomatte_depth);
|
||||||
|
if(sorted_pixel.size() > num_slots) {
|
||||||
|
float leftover = 0.0f;
|
||||||
|
for(vector<pair<float, float> >::iterator it = sorted_pixel.begin()+num_slots; it != sorted_pixel.end(); ++it) {
|
||||||
|
leftover += it->first;
|
||||||
|
}
|
||||||
|
sorted_pixel[num_slots-1].first += leftover;
|
||||||
|
}
|
||||||
|
int limit = min(num_slots, sorted_pixel.size());
|
||||||
|
for(int i = 0; i < limit; ++i) {
|
||||||
|
kernel_write_id_slots(buffer + kernel_data.film.pass_cryptomatte + pass_offset, 2 * (kernel_data.film.cryptomatte_depth), sorted_pixel[i].second, sorted_pixel[i].first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++pixel_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Coverage::sort_buffer(const int pass_offset)
|
||||||
|
{
|
||||||
|
/* Sort the coverage map and write it to the output */
|
||||||
|
int pass_stride = tile.buffers->params.get_passes_size();
|
||||||
|
for(int y = 0; y < tile.h; ++y) {
|
||||||
|
for(int x = 0; x < tile.w; ++x) {
|
||||||
|
/* buffer offset */
|
||||||
|
int index = x + y*tile.stride;
|
||||||
|
float *buffer = (float*)tile.buffer + index*pass_stride;
|
||||||
|
kernel_sort_id_slots(buffer + kernel_data.film.pass_cryptomatte + pass_offset, 2 * (kernel_data.film.cryptomatte_depth));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
49
intern/cycles/render/coverage.h
Normal file
49
intern/cycles/render/coverage.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Blender Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "render/buffers.h"
|
||||||
|
#include "kernel/kernel_compat_cpu.h"
|
||||||
|
#include "kernel/split/kernel_split_data.h"
|
||||||
|
#include "kernel/kernel_globals.h"
|
||||||
|
#include "util/util_map.h"
|
||||||
|
#include "util/util_vector.h"
|
||||||
|
|
||||||
|
#ifndef __COVERAGE_H__
|
||||||
|
#define __COVERAGE_H__
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class Coverage {
|
||||||
|
public:
|
||||||
|
Coverage(KernelGlobals *kg_, RenderTile &tile_) : kg(kg_), tile(tile_) { }
|
||||||
|
void init_path_trace();
|
||||||
|
void init_pixel(int x, int y);
|
||||||
|
void finalize();
|
||||||
|
private:
|
||||||
|
vector<CoverageMap>coverage_object;
|
||||||
|
vector<CoverageMap>coverage_material;
|
||||||
|
vector<CoverageMap>coverage_asset;
|
||||||
|
KernelGlobals *kg;
|
||||||
|
RenderTile &tile;
|
||||||
|
void finalize_buffer(vector<CoverageMap>&coverage, const int pass_offset);
|
||||||
|
void flatten_buffer(vector<CoverageMap>&coverage, const int pass_offset);
|
||||||
|
void sort_buffer(const int pass_offset);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __COVERAGE_H__ */
|
@ -38,11 +38,14 @@ static bool compare_pass_order(const Pass& a, const Pass& b)
|
|||||||
return (a.components > b.components);
|
return (a.components > b.components);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pass::add(PassType type, array<Pass>& passes)
|
void Pass::add(PassType type, vector<Pass>& passes, const char *name)
|
||||||
{
|
{
|
||||||
for(size_t i = 0; i < passes.size(); i++)
|
for(size_t i = 0; i < passes.size(); i++) {
|
||||||
if(passes[i].type == type)
|
if(passes[i].type == type &&
|
||||||
|
(name ? (passes[i].name == name) : passes[i].name.empty())) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Pass pass;
|
Pass pass;
|
||||||
|
|
||||||
@ -50,6 +53,9 @@ void Pass::add(PassType type, array<Pass>& passes)
|
|||||||
pass.filter = true;
|
pass.filter = true;
|
||||||
pass.exposure = false;
|
pass.exposure = false;
|
||||||
pass.divide_type = PASS_NONE;
|
pass.divide_type = PASS_NONE;
|
||||||
|
if(name) {
|
||||||
|
pass.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case PASS_NONE:
|
case PASS_NONE:
|
||||||
@ -155,13 +161,15 @@ void Pass::add(PassType type, array<Pass>& passes)
|
|||||||
pass.components = 4;
|
pass.components = 4;
|
||||||
pass.exposure = true;
|
pass.exposure = true;
|
||||||
break;
|
break;
|
||||||
|
case PASS_CRYPTOMATTE:
|
||||||
|
pass.components = 4;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
passes.push_back_slow(pass);
|
passes.push_back(pass);
|
||||||
|
|
||||||
/* order from by components, to ensure alignment so passes with size 4
|
/* order from by components, to ensure alignment so passes with size 4
|
||||||
* come first and then passes with size 1 */
|
* come first and then passes with size 1 */
|
||||||
@ -171,19 +179,19 @@ void Pass::add(PassType type, array<Pass>& passes)
|
|||||||
Pass::add(pass.divide_type, passes);
|
Pass::add(pass.divide_type, passes);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Pass::equals(const array<Pass>& A, const array<Pass>& B)
|
bool Pass::equals(const vector<Pass>& A, const vector<Pass>& B)
|
||||||
{
|
{
|
||||||
if(A.size() != B.size())
|
if(A.size() != B.size())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for(int i = 0; i < A.size(); i++)
|
for(int i = 0; i < A.size(); i++)
|
||||||
if(A[i].type != B[i].type)
|
if(A[i].type != B[i].type || A[i].name != B[i].name)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Pass::contains(const array<Pass>& passes, PassType type)
|
bool Pass::contains(const vector<Pass>& passes, PassType type)
|
||||||
{
|
{
|
||||||
for(size_t i = 0; i < passes.size(); i++)
|
for(size_t i = 0; i < passes.size(); i++)
|
||||||
if(passes[i].type == type)
|
if(passes[i].type == type)
|
||||||
@ -290,6 +298,7 @@ Film::Film()
|
|||||||
|
|
||||||
use_light_visibility = false;
|
use_light_visibility = false;
|
||||||
filter_table_offset = TABLE_OFFSET_INVALID;
|
filter_table_offset = TABLE_OFFSET_INVALID;
|
||||||
|
cryptomatte_passes = CRYPT_NONE;
|
||||||
|
|
||||||
need_update = true;
|
need_update = true;
|
||||||
}
|
}
|
||||||
@ -314,6 +323,8 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
|||||||
kfilm->pass_stride = 0;
|
kfilm->pass_stride = 0;
|
||||||
kfilm->use_light_pass = use_light_visibility || use_sample_clamp;
|
kfilm->use_light_pass = use_light_visibility || use_sample_clamp;
|
||||||
|
|
||||||
|
bool have_cryptomatte = false;
|
||||||
|
|
||||||
for(size_t i = 0; i < passes.size(); i++) {
|
for(size_t i = 0; i < passes.size(); i++) {
|
||||||
Pass& pass = passes[i];
|
Pass& pass = passes[i];
|
||||||
|
|
||||||
@ -434,7 +445,10 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
|||||||
#endif
|
#endif
|
||||||
case PASS_RENDER_TIME:
|
case PASS_RENDER_TIME:
|
||||||
break;
|
break;
|
||||||
|
case PASS_CRYPTOMATTE:
|
||||||
|
kfilm->pass_cryptomatte = have_cryptomatte ? min(kfilm->pass_cryptomatte, kfilm->pass_stride) : kfilm->pass_stride;
|
||||||
|
have_cryptomatte = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
@ -471,6 +485,9 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
|||||||
kfilm->mist_inv_depth = (mist_depth > 0.0f)? 1.0f/mist_depth: 0.0f;
|
kfilm->mist_inv_depth = (mist_depth > 0.0f)? 1.0f/mist_depth: 0.0f;
|
||||||
kfilm->mist_falloff = mist_falloff;
|
kfilm->mist_falloff = mist_falloff;
|
||||||
|
|
||||||
|
kfilm->cryptomatte_passes = cryptomatte_passes;
|
||||||
|
kfilm->cryptomatte_depth = cryptomatte_depth;
|
||||||
|
|
||||||
pass_stride = kfilm->pass_stride;
|
pass_stride = kfilm->pass_stride;
|
||||||
denoising_data_offset = kfilm->pass_denoising_data;
|
denoising_data_offset = kfilm->pass_denoising_data;
|
||||||
denoising_clean_offset = kfilm->pass_denoising_clean;
|
denoising_clean_offset = kfilm->pass_denoising_clean;
|
||||||
@ -490,7 +507,7 @@ bool Film::modified(const Film& film)
|
|||||||
return !Node::equals(film) || !Pass::equals(passes, film.passes);
|
return !Node::equals(film) || !Pass::equals(passes, film.passes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Film::tag_passes_update(Scene *scene, const array<Pass>& passes_)
|
void Film::tag_passes_update(Scene *scene, const vector<Pass>& passes_)
|
||||||
{
|
{
|
||||||
if(Pass::contains(passes, PASS_UV) != Pass::contains(passes_, PASS_UV)) {
|
if(Pass::contains(passes, PASS_UV) != Pass::contains(passes_, PASS_UV)) {
|
||||||
scene->mesh_manager->tag_update(scene);
|
scene->mesh_manager->tag_update(scene);
|
||||||
|
@ -45,10 +45,11 @@ public:
|
|||||||
bool filter;
|
bool filter;
|
||||||
bool exposure;
|
bool exposure;
|
||||||
PassType divide_type;
|
PassType divide_type;
|
||||||
|
string name;
|
||||||
|
|
||||||
static void add(PassType type, array<Pass>& passes);
|
static void add(PassType type, vector<Pass>& passes, const char* name = NULL);
|
||||||
static bool equals(const array<Pass>& A, const array<Pass>& B);
|
static bool equals(const vector<Pass>& A, const vector<Pass>& B);
|
||||||
static bool contains(const array<Pass>& passes, PassType);
|
static bool contains(const vector<Pass>& passes, PassType);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Film : public Node {
|
class Film : public Node {
|
||||||
@ -56,7 +57,7 @@ public:
|
|||||||
NODE_DECLARE
|
NODE_DECLARE
|
||||||
|
|
||||||
float exposure;
|
float exposure;
|
||||||
array<Pass> passes;
|
vector<Pass> passes;
|
||||||
bool denoising_data_pass;
|
bool denoising_data_pass;
|
||||||
bool denoising_clean_pass;
|
bool denoising_clean_pass;
|
||||||
int denoising_flags;
|
int denoising_flags;
|
||||||
@ -76,6 +77,8 @@ public:
|
|||||||
|
|
||||||
bool use_light_visibility;
|
bool use_light_visibility;
|
||||||
bool use_sample_clamp;
|
bool use_sample_clamp;
|
||||||
|
CryptomatteType cryptomatte_passes;
|
||||||
|
int cryptomatte_depth;
|
||||||
|
|
||||||
bool need_update;
|
bool need_update;
|
||||||
|
|
||||||
@ -86,7 +89,7 @@ public:
|
|||||||
void device_free(Device *device, DeviceScene *dscene, Scene *scene);
|
void device_free(Device *device, DeviceScene *dscene, Scene *scene);
|
||||||
|
|
||||||
bool modified(const Film& film);
|
bool modified(const Film& film);
|
||||||
void tag_passes_update(Scene *scene, const array<Pass>& passes_);
|
void tag_passes_update(Scene *scene, const vector<Pass>& passes_);
|
||||||
void tag_update(Scene *scene);
|
void tag_update(Scene *scene);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "util/util_map.h"
|
#include "util/util_map.h"
|
||||||
#include "util/util_progress.h"
|
#include "util/util_progress.h"
|
||||||
#include "util/util_vector.h"
|
#include "util/util_vector.h"
|
||||||
|
#include "util/util_murmurhash.h"
|
||||||
|
|
||||||
#include "subd/subd_patch_table.h"
|
#include "subd/subd_patch_table.h"
|
||||||
|
|
||||||
@ -483,6 +484,10 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
|
|||||||
kobject.numverts = mesh->verts.size();
|
kobject.numverts = mesh->verts.size();
|
||||||
kobject.patch_map_offset = 0;
|
kobject.patch_map_offset = 0;
|
||||||
kobject.attribute_map_offset = 0;
|
kobject.attribute_map_offset = 0;
|
||||||
|
uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0);
|
||||||
|
uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0);
|
||||||
|
kobject.cryptomatte_object = util_hash_to_float(hash_name);
|
||||||
|
kobject.cryptomatte_asset = util_hash_to_float(hash_asset);
|
||||||
|
|
||||||
/* Object flag. */
|
/* Object flag. */
|
||||||
if(ob->use_holdout) {
|
if(ob->use_holdout) {
|
||||||
|
@ -48,6 +48,7 @@ public:
|
|||||||
BoundBox bounds;
|
BoundBox bounds;
|
||||||
uint random_id;
|
uint random_id;
|
||||||
int pass_id;
|
int pass_id;
|
||||||
|
ustring asset_name;
|
||||||
vector<ParamValue> attributes;
|
vector<ParamValue> attributes;
|
||||||
uint visibility;
|
uint visibility;
|
||||||
array<Transform> motion;
|
array<Transform> motion;
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "render/tables.h"
|
#include "render/tables.h"
|
||||||
|
|
||||||
#include "util/util_foreach.h"
|
#include "util/util_foreach.h"
|
||||||
|
#include "util/util_murmurhash.h"
|
||||||
|
|
||||||
#ifdef WITH_OCIO
|
#ifdef WITH_OCIO
|
||||||
# include <OpenColorIO/OpenColorIO.h>
|
# include <OpenColorIO/OpenColorIO.h>
|
||||||
@ -524,12 +525,15 @@ void ShaderManager::device_update_common(Device *device,
|
|||||||
if(shader->is_constant_emission(&constant_emission))
|
if(shader->is_constant_emission(&constant_emission))
|
||||||
flag |= SD_HAS_CONSTANT_EMISSION;
|
flag |= SD_HAS_CONSTANT_EMISSION;
|
||||||
|
|
||||||
|
uint32_t cryptomatte_id = util_murmur_hash3(shader->name.c_str(), shader->name.length(), 0);
|
||||||
|
|
||||||
/* regular shader */
|
/* regular shader */
|
||||||
kshader->flags = flag;
|
kshader->flags = flag;
|
||||||
kshader->pass_id = shader->pass_id;
|
kshader->pass_id = shader->pass_id;
|
||||||
kshader->constant_emission[0] = constant_emission.x;
|
kshader->constant_emission[0] = constant_emission.x;
|
||||||
kshader->constant_emission[1] = constant_emission.y;
|
kshader->constant_emission[1] = constant_emission.y;
|
||||||
kshader->constant_emission[2] = constant_emission.z;
|
kshader->constant_emission[2] = constant_emission.z;
|
||||||
|
kshader->cryptomatte_id = util_hash_to_float(cryptomatte_id);
|
||||||
kshader++;
|
kshader++;
|
||||||
|
|
||||||
has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
|
has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
|
||||||
|
@ -15,6 +15,7 @@ set(SRC
|
|||||||
util_logging.cpp
|
util_logging.cpp
|
||||||
util_math_cdf.cpp
|
util_math_cdf.cpp
|
||||||
util_md5.cpp
|
util_md5.cpp
|
||||||
|
util_murmurhash.cpp
|
||||||
util_path.cpp
|
util_path.cpp
|
||||||
util_string.cpp
|
util_string.cpp
|
||||||
util_simd.cpp
|
util_simd.cpp
|
||||||
@ -64,6 +65,7 @@ set(SRC_HEADERS
|
|||||||
util_math_int4.h
|
util_math_int4.h
|
||||||
util_math_matrix.h
|
util_math_matrix.h
|
||||||
util_md5.h
|
util_md5.h
|
||||||
|
util_murmurhash.h
|
||||||
util_opengl.h
|
util_opengl.h
|
||||||
util_optimization.h
|
util_optimization.h
|
||||||
util_param.h
|
util_param.h
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "atomic_ops.h"
|
#include "atomic_ops.h"
|
||||||
|
|
||||||
#define atomic_add_and_fetch_float(p, x) atomic_add_and_fetch_fl((p), (x))
|
#define atomic_add_and_fetch_float(p, x) atomic_add_and_fetch_fl((p), (x))
|
||||||
|
#define atomic_compare_and_swap_float(p, old_val, new_val) atomic_cas_float((p), (old_val), (new_val))
|
||||||
|
|
||||||
#define atomic_fetch_and_inc_uint32(p) atomic_fetch_and_add_uint32((p), 1)
|
#define atomic_fetch_and_inc_uint32(p) atomic_fetch_and_add_uint32((p), 1)
|
||||||
#define atomic_fetch_and_dec_uint32(p) atomic_fetch_and_add_uint32((p), -1)
|
#define atomic_fetch_and_dec_uint32(p) atomic_fetch_and_add_uint32((p), -1)
|
||||||
@ -57,6 +58,20 @@ ccl_device_inline float atomic_add_and_fetch_float(volatile ccl_global float *so
|
|||||||
return new_value.float_value;
|
return new_value.float_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ccl_device_inline float atomic_compare_and_swap_float(volatile ccl_global float *dest,
|
||||||
|
const float old_val, const float new_val)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
unsigned int int_value;
|
||||||
|
float float_value;
|
||||||
|
} new_value, prev_value, result;
|
||||||
|
prev_value.float_value = old_val;
|
||||||
|
new_value.float_value = new_val;
|
||||||
|
result.int_value = atomic_cmpxchg((volatile ccl_global unsigned int *)dest,
|
||||||
|
prev_value.int_value, new_value.int_value);
|
||||||
|
return result.float_value;
|
||||||
|
}
|
||||||
|
|
||||||
#define atomic_fetch_and_add_uint32(p, x) atomic_add((p), (x))
|
#define atomic_fetch_and_add_uint32(p, x) atomic_add((p), (x))
|
||||||
#define atomic_fetch_and_inc_uint32(p) atomic_inc((p))
|
#define atomic_fetch_and_inc_uint32(p) atomic_inc((p))
|
||||||
#define atomic_fetch_and_dec_uint32(p) atomic_dec((p))
|
#define atomic_fetch_and_dec_uint32(p) atomic_dec((p))
|
||||||
@ -75,6 +90,19 @@ ccl_device_inline float atomic_add_and_fetch_float(volatile ccl_global float *so
|
|||||||
#define atomic_fetch_and_inc_uint32(p) atomic_fetch_and_add_uint32((p), 1)
|
#define atomic_fetch_and_inc_uint32(p) atomic_fetch_and_add_uint32((p), 1)
|
||||||
#define atomic_fetch_and_dec_uint32(p) atomic_fetch_and_sub_uint32((p), 1)
|
#define atomic_fetch_and_dec_uint32(p) atomic_fetch_and_sub_uint32((p), 1)
|
||||||
|
|
||||||
|
ccl_device_inline float atomic_compare_and_swap_float(volatile float *dest,
|
||||||
|
const float old_val, const float new_val)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
unsigned int int_value;
|
||||||
|
float float_value;
|
||||||
|
} new_value, prev_value, result;
|
||||||
|
prev_value.float_value = old_val;
|
||||||
|
new_value.float_value = new_val;
|
||||||
|
result.int_value = atomicCAS((unsigned int *)dest, prev_value.int_value,new_value.int_value);
|
||||||
|
return result.float_value;
|
||||||
|
}
|
||||||
|
|
||||||
#define CCL_LOCAL_MEM_FENCE
|
#define CCL_LOCAL_MEM_FENCE
|
||||||
#define ccl_barrier(flags) __syncthreads()
|
#define ccl_barrier(flags) __syncthreads()
|
||||||
|
|
||||||
|
127
intern/cycles/util/util_murmurhash.cpp
Normal file
127
intern/cycles/util/util_murmurhash.cpp
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Blender Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This is taken from alShaders/Cryptomatte/MurmurHash3.h:
|
||||||
|
*
|
||||||
|
* MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||||
|
* domain. The author hereby disclaims copyright to this source code.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "util/util_algorithm.h"
|
||||||
|
#include "util/util_murmurhash.h"
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# define ROTL32(x,y) _rotl(x,y)
|
||||||
|
# define ROTL64(x,y) _rotl64(x,y)
|
||||||
|
# define BIG_CONSTANT(x) (x)
|
||||||
|
#else
|
||||||
|
ccl_device_inline uint32_t rotl32(uint32_t x, int8_t r)
|
||||||
|
{
|
||||||
|
return (x << r) | (x >> (32 - r));
|
||||||
|
}
|
||||||
|
# define ROTL32(x,y) rotl32(x,y)
|
||||||
|
# define BIG_CONSTANT(x) (x##LLU)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/* Block read - if your platform needs to do endian-swapping or can only
|
||||||
|
* handle aligned reads, do the conversion here. */
|
||||||
|
ccl_device_inline uint32_t mm_hash_getblock32(const uint32_t *p, int i)
|
||||||
|
{
|
||||||
|
return p[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finalization mix - force all bits of a hash block to avalanche */
|
||||||
|
ccl_device_inline uint32_t mm_hash_fmix32 ( uint32_t h )
|
||||||
|
{
|
||||||
|
h ^= h >> 16;
|
||||||
|
h *= 0x85ebca6b;
|
||||||
|
h ^= h >> 13;
|
||||||
|
h *= 0xc2b2ae35;
|
||||||
|
h ^= h >> 16;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t util_murmur_hash3(const void *key, int len, uint32_t seed)
|
||||||
|
{
|
||||||
|
const uint8_t * data = (const uint8_t*)key;
|
||||||
|
const int nblocks = len / 4;
|
||||||
|
|
||||||
|
uint32_t h1 = seed;
|
||||||
|
|
||||||
|
const uint32_t c1 = 0xcc9e2d51;
|
||||||
|
const uint32_t c2 = 0x1b873593;
|
||||||
|
|
||||||
|
const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
|
||||||
|
|
||||||
|
for(int i = -nblocks; i; i++) {
|
||||||
|
uint32_t k1 = mm_hash_getblock32(blocks,i);
|
||||||
|
|
||||||
|
k1 *= c1;
|
||||||
|
k1 = ROTL32(k1,15);
|
||||||
|
k1 *= c2;
|
||||||
|
|
||||||
|
h1 ^= k1;
|
||||||
|
h1 = ROTL32(h1,13);
|
||||||
|
h1 = h1 * 5 + 0xe6546b64;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *tail = (const uint8_t*)(data + nblocks*4);
|
||||||
|
|
||||||
|
uint32_t k1 = 0;
|
||||||
|
|
||||||
|
switch(len & 3) {
|
||||||
|
case 3:
|
||||||
|
k1 ^= tail[2] << 16;
|
||||||
|
ATTR_FALLTHROUGH;
|
||||||
|
case 2:
|
||||||
|
k1 ^= tail[1] << 8;
|
||||||
|
ATTR_FALLTHROUGH;
|
||||||
|
case 1:
|
||||||
|
k1 ^= tail[0];
|
||||||
|
k1 *= c1;
|
||||||
|
k1 = ROTL32(k1,15);
|
||||||
|
k1 *= c2;
|
||||||
|
h1 ^= k1;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 ^= len;
|
||||||
|
h1 = mm_hash_fmix32(h1);
|
||||||
|
return h1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is taken from the cryptomatte specification 1.0 */
|
||||||
|
float util_hash_to_float(uint32_t hash)
|
||||||
|
{
|
||||||
|
uint32_t mantissa = hash & (( 1 << 23) - 1);
|
||||||
|
uint32_t exponent = (hash >> 23) & ((1 << 8) - 1);
|
||||||
|
exponent = max(exponent, (uint32_t) 1);
|
||||||
|
exponent = min(exponent, (uint32_t) 254);
|
||||||
|
exponent = exponent << 23;
|
||||||
|
uint32_t sign = (hash >> 31);
|
||||||
|
sign = sign << 31;
|
||||||
|
uint32_t float_bits = sign | exponent | mantissa;
|
||||||
|
float f;
|
||||||
|
memcpy(&f, &float_bits, sizeof(uint32_t));
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
30
intern/cycles/util/util_murmurhash.h
Normal file
30
intern/cycles/util/util_murmurhash.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Blender Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __UTIL_MURMURHASH_H__
|
||||||
|
#define __UTIL_MURMURHASH_H__
|
||||||
|
|
||||||
|
#include "util/util_types.h"
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
uint32_t util_murmur_hash3(const void *key, int len, uint32_t seed);
|
||||||
|
float util_hash_to_float(uint32_t hash);
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __UTIL_MURMURHASH_H__ */
|
@ -1 +1 @@
|
|||||||
Subproject commit 2e14c2aa69726b472f8758f62ad839eddaf63bfe
|
Subproject commit 6c3a46dc113de870a03191e4c0685238b0823acd
|
@ -1 +1 @@
|
|||||||
Subproject commit 311b03bd2ce4c5b3c3fc5e2b58a4ee1a629ea6a9
|
Subproject commit 15b25a42783d1e516b5298d70b582fae2559ae17
|
@ -603,6 +603,8 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
|
|||||||
/* not sure if this is right, but seems to give the relevant mnts */
|
/* not sure if this is right, but seems to give the relevant mnts */
|
||||||
if (!STREQLEN(mnt->mnt_fsname, "/dev", 4))
|
if (!STREQLEN(mnt->mnt_fsname, "/dev", 4))
|
||||||
continue;
|
continue;
|
||||||
|
if (STREQLEN(mnt->mnt_fsname, "/dev/loop", 9))
|
||||||
|
continue;
|
||||||
|
|
||||||
len = strlen(mnt->mnt_dir);
|
len = strlen(mnt->mnt_dir);
|
||||||
if (len && mnt->mnt_dir[len - 1] != '/') {
|
if (len && mnt->mnt_dir[len - 1] != '/') {
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 5162393c104d6d5f0314183a084875fff68f28bb
|
Subproject commit 11656ebaf7f912cdb1b5eb39c5d0a3b5d492c1aa
|
Loading…
Reference in New Issue
Block a user