* Add max diffuse/glossy/transmission bounces
* Add separate min/max for transparent depth
* Updated/added some presets that use these options
* Add ray visibility options for objects, to hide them from
  camera/diffuse/glossy/transmission/shadow rays
* Is singular ray output for light path node

Details here:
http://wiki.blender.org/index.php/Dev:2.5/Source/Render/Cycles/LightPaths
This commit is contained in:
Brecht Van Lommel 2011-09-01 15:53:36 +00:00
parent 1e741b3a52
commit df625253ac
35 changed files with 457 additions and 153 deletions

@ -255,8 +255,8 @@ static void xml_read_integrator(const XMLReadState& state, pugi::xml_node node)
{ {
Integrator *integrator = state.scene->integrator; Integrator *integrator = state.scene->integrator;
xml_read_int(&integrator->minbounce, node, "min_bounce"); xml_read_int(&integrator->min_bounce, node, "min_bounce");
xml_read_int(&integrator->maxbounce, node, "max_bounce"); xml_read_int(&integrator->max_bounce, node, "max_bounce");
xml_read_bool(&integrator->no_caustics, node, "no_caustics"); xml_read_bool(&integrator->no_caustics, node, "no_caustics");
xml_read_float(&integrator->blur_caustics, node, "blur_caustics"); xml_read_float(&integrator->blur_caustics, node, "blur_caustics");
} }

@ -33,6 +33,11 @@ class AddPresetIntegrator(AddPresetBase, Operator):
"cycles.max_bounces", "cycles.max_bounces",
"cycles.min_bounces", "cycles.min_bounces",
"cycles.no_caustics", "cycles.no_caustics",
"cycles.diffuse_bounces",
"cycles.glossy_bounces",
"cycles.transmission_bounces",
"cycles.transparent_min_bounces",
"cycles.transparent_max_bounces"
] ]
preset_subdir = "cycles/integrator" preset_subdir = "cycles/integrator"

@ -24,7 +24,7 @@ from cycles import enums
class CyclesRenderSettings(bpy.types.PropertyGroup): class CyclesRenderSettings(bpy.types.PropertyGroup):
@classmethod @classmethod
def register(cls): def register(cls):
bpy.types.Scene.cycles = PointerProperty(type=cls, name="Cycles Render Settings", description="Cycles Render Settings") bpy.types.Scene.cycles = PointerProperty(type=cls, name="Cycles Render Settings", description="Cycles render settings")
cls.device = EnumProperty(name="Device", description="Device to use for rendering", cls.device = EnumProperty(name="Device", description="Device to use for rendering",
items=enums.devices, default="CPU") items=enums.devices, default="CPU")
@ -39,18 +39,31 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
cls.preview_pause = BoolProperty(name="Pause Preview", description="Pause all viewport preview renders", cls.preview_pause = BoolProperty(name="Pause Preview", description="Pause all viewport preview renders",
default=False) default=False)
cls.min_bounces = IntProperty(name="Min Bounces", description="Minimum number of bounces",
default=3, min=0, max=1024)
cls.max_bounces = IntProperty(name="Max Bounces", description="Maximum number of bounces",
default=8, min=0, max=1024)
cls.no_caustics = BoolProperty(name="No Caustics", description="Leave out caustics, resulting in a darker image with less noise", cls.no_caustics = BoolProperty(name="No Caustics", description="Leave out caustics, resulting in a darker image with less noise",
default=False) default=False)
cls.blur_caustics = FloatProperty(name="Blur Caustics", description="Blur caustics to reduce noise", cls.blur_caustics = FloatProperty(name="Blur Caustics", description="Blur caustics to reduce noise",
default=0.0, min=0.0, max=1.0) default=0.0, min=0.0, max=1.0)
cls.exposure = FloatProperty(name="Exposure", description="Image brightness scale", cls.min_bounces = IntProperty(name="Min Bounces", description="Minimum number of bounces, setting this lower than the maximum enables probalistic path termination (faster but noisier)",
default=3, min=0, max=1024)
cls.max_bounces = IntProperty(name="Max Bounces", description="Total maximum number of bounces",
default=8, min=0, max=1024)
cls.diffuse_bounces = IntProperty(name="Diffuse Bounces", description="Maximum number of diffuse reflection bounces, bounded by total maximum",
default=1024, min=0, max=1024)
cls.glossy_bounces = IntProperty(name="Glossy Bounces", description="Maximum number of glossy reflection bounces, bounded by total maximum",
default=1024, min=0, max=1024)
cls.transmission_bounces = IntProperty(name="Transmission Bounces", description="Maximum number of transmission bounces, bounded by total maximum",
default=1024, min=0, max=1024)
cls.transparent_min_bounces = IntProperty(name="Transparent Min Bounces", description="Minimum number of transparent bounces, setting this lower than the maximum enables probalistic path termination (faster but noisier)",
default=8, min=0, max=1024)
cls.transparent_max_bounces = IntProperty(name="Transparent Max Bounces", description="Maximum number of transparent bounces",
default=8, min=0, max=1024)
cls.film_exposure = FloatProperty(name="Exposure", description="Image brightness scale",
default=1.0, min=0.0, max=10.0) default=1.0, min=0.0, max=10.0)
cls.transparent = BoolProperty(name="Transparent", description="World background is transparent", cls.film_transparent = BoolProperty(name="Transparent", description="World background is transparent",
default=False) default=False)
cls.filter_type = EnumProperty(name="Filter Type", description="Pixel filter type", cls.filter_type = EnumProperty(name="Filter Type", description="Pixel filter type",
@ -81,7 +94,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
class CyclesCameraSettings(bpy.types.PropertyGroup): class CyclesCameraSettings(bpy.types.PropertyGroup):
@classmethod @classmethod
def register(cls): def register(cls):
bpy.types.Camera.cycles = PointerProperty(type=cls, name="Cycles Camera Settings", description="Cycles Camera Settings") bpy.types.Camera.cycles = PointerProperty(type=cls, name="Cycles Camera Settings", description="Cycles camera settings")
cls.lens_radius = FloatProperty(name="Lens radius", description="Lens radius for depth of field", cls.lens_radius = FloatProperty(name="Lens radius", description="Lens radius for depth of field",
default=0.0, min=0.0, max=10.0) default=0.0, min=0.0, max=10.0)
@ -93,7 +106,7 @@ class CyclesCameraSettings(bpy.types.PropertyGroup):
class CyclesMaterialSettings(bpy.types.PropertyGroup): class CyclesMaterialSettings(bpy.types.PropertyGroup):
@classmethod @classmethod
def register(cls): def register(cls):
bpy.types.Material.cycles = PointerProperty(type=cls, name="Cycles Material Settings", description="Cycles Material Settings") bpy.types.Material.cycles = PointerProperty(type=cls, name="Cycles Material Settings", description="Cycles material settings")
@classmethod @classmethod
def unregister(cls): def unregister(cls):
@ -102,18 +115,33 @@ class CyclesMaterialSettings(bpy.types.PropertyGroup):
class CyclesWorldSettings(bpy.types.PropertyGroup): class CyclesWorldSettings(bpy.types.PropertyGroup):
@classmethod @classmethod
def register(cls): def register(cls):
bpy.types.World.cycles = PointerProperty(type=cls, name="Cycles World Settings", description="Cycles World Settings") bpy.types.World.cycles = PointerProperty(type=cls, name="Cycles World Settings", description="Cycles world settings")
@classmethod @classmethod
def unregister(cls): def unregister(cls):
del bpy.types.World.cycles del bpy.types.World.cycles
class CyclesVisibilitySettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
bpy.types.Object.cycles_visibility = PointerProperty(type=cls, name="Cycles Visibility Settings", description="Cycles visibility settings")
cls.camera = BoolProperty(name="Camera", description="Object visibility for camera rays", default=True)
cls.diffuse = BoolProperty(name="Diffuse", description="Object visibility for diffuse reflection rays", default=True)
cls.glossy = BoolProperty(name="Glossy", description="Object visibility for glossy reflection rays", default=True)
cls.transmission = BoolProperty(name="Transmission", description="Object visibility for transmission rays", default=True)
cls.shadow = BoolProperty(name="Shadow", description="Object visibility for shadow rays", default=True)
@classmethod
def unregister(cls):
del bpy.types.Object.cycles_visibility
class CyclesMeshSettings(bpy.types.PropertyGroup): class CyclesMeshSettings(bpy.types.PropertyGroup):
@classmethod @classmethod
def register(cls): def register(cls):
bpy.types.Mesh.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles Mesh Settings") bpy.types.Mesh.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles mesh settings")
bpy.types.Curve.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles Mesh Settings") bpy.types.Curve.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles mesh settings")
bpy.types.MetaBall.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles Mesh Settings") bpy.types.MetaBall.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles mesh settings")
cls.displacement_method = EnumProperty(name="Displacement Method", description="Method to use for the displacement", cls.displacement_method = EnumProperty(name="Displacement Method", description="Method to use for the displacement",
items=enums.displacement_methods, default="BUMP") items=enums.displacement_methods, default="BUMP")
@ -124,12 +152,15 @@ class CyclesMeshSettings(bpy.types.PropertyGroup):
@classmethod @classmethod
def unregister(cls): def unregister(cls):
del bpy.types.Mesh.cycles del bpy.types.Mesh.cycles
del bpy.types.Curve.cycles
del bpy.types.MetaBall.cycles
def register(): def register():
bpy.utils.register_class(CyclesRenderSettings) bpy.utils.register_class(CyclesRenderSettings)
bpy.utils.register_class(CyclesCameraSettings) bpy.utils.register_class(CyclesCameraSettings)
bpy.utils.register_class(CyclesMaterialSettings) bpy.utils.register_class(CyclesMaterialSettings)
bpy.utils.register_class(CyclesWorldSettings) bpy.utils.register_class(CyclesWorldSettings)
bpy.utils.register_class(CyclesVisibilitySettings)
bpy.utils.register_class(CyclesMeshSettings) bpy.utils.register_class(CyclesMeshSettings)
def unregister(): def unregister():
@ -138,4 +169,5 @@ def unregister():
bpy.utils.unregister_class(CyclesMaterialSettings) bpy.utils.unregister_class(CyclesMaterialSettings)
bpy.utils.unregister_class(CyclesWorldSettings) bpy.utils.unregister_class(CyclesWorldSettings)
bpy.utils.unregister_class(CyclesMeshSettings) bpy.utils.unregister_class(CyclesMeshSettings)
bpy.utils.unregister_class(CyclesVisibilitySettings)

@ -42,6 +42,7 @@ class CyclesButtonsPanel():
class CyclesRender_PT_integrator(CyclesButtonsPanel, Panel): class CyclesRender_PT_integrator(CyclesButtonsPanel, Panel):
bl_label = "Integrator" bl_label = "Integrator"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
@ -58,14 +59,28 @@ class CyclesRender_PT_integrator(CyclesButtonsPanel, Panel):
col = split.column() col = split.column()
sub = col.column(align=True) sub = col.column(align=True)
sub.prop(cscene, "passes", text="Render Passes") sub.label(text="Passes:")
sub.prop(cscene, "preview_passes") sub.prop(cscene, "passes", text="Render")
col.prop(cscene, "no_caustics") sub.prop(cscene, "preview_passes", text="Preview")
sub = col.column(align=True)
sub.label("Tranparency:")
sub.prop(cscene, "transparent_max_bounces", text="Max")
sub.prop(cscene, "transparent_min_bounces", text="Min")
sub.prop(cscene, "no_caustics")
col = split.column() col = split.column()
sub = col.column(align=True) sub = col.column(align=True)
sub.prop(cscene, "max_bounces") sub.label(text="Bounces:")
sub.prop(cscene, "min_bounces") sub.prop(cscene, "max_bounces", text="Max")
sub.prop(cscene, "min_bounces", text="Min")
sub = col.column(align=True)
sub.label(text="Light Paths:")
sub.prop(cscene, "diffuse_bounces", text="Diffuse")
sub.prop(cscene, "glossy_bounces", text="Glossy")
sub.prop(cscene, "transmission_bounces", text="Transmission")
#row = col.row() #row = col.row()
#row.prop(cscene, "blur_caustics") #row.prop(cscene, "blur_caustics")
@ -83,8 +98,8 @@ class CyclesRender_PT_film(CyclesButtonsPanel, Panel):
split = layout.split() split = layout.split()
col = split.column(); col = split.column();
col.prop(cscene, "exposure") col.prop(cscene, "film_exposure")
col.prop(cscene, "transparent") col.prop(cscene, "film_transparent")
col = split.column() col = split.column()
sub = col.column(align=True) sub = col.column(align=True)
@ -233,6 +248,33 @@ class Cycles_PT_mesh_displacement(CyclesButtonsPanel, Panel):
layout.prop(cdata, "use_subdivision"); layout.prop(cdata, "use_subdivision");
layout.prop(cdata, "dicing_rate"); layout.prop(cdata, "dicing_rate");
class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel):
bl_label = "Ray Visibility"
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
ob = context.object
return ob and ob.type in ('MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META') # todo: 'LAMP'
def draw(self, context):
layout = self.layout
ob = context.object
visibility = ob.cycles_visibility
split = layout.split()
col = split.column()
col.prop(visibility, "camera")
col.prop(visibility, "diffuse")
col.prop(visibility, "glossy")
col = split.column()
col.prop(visibility, "transmission")
col.prop(visibility, "shadow")
def find_node(material, nodetype): def find_node(material, nodetype):
if material and material.node_tree: if material and material.node_tree:
ntree = material.node_tree ntree = material.node_tree

@ -63,6 +63,20 @@ bool BlenderSync::object_is_light(BL::Object b_ob)
return (b_ob_data && b_ob_data.is_a(&RNA_Lamp)); return (b_ob_data && b_ob_data.is_a(&RNA_Lamp));
} }
static uint object_ray_visibility(BL::Object b_ob)
{
PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility");
uint flag = 0;
flag |= get_boolean(cvisibility, "camera")? PATH_RAY_CAMERA: 0;
flag |= get_boolean(cvisibility, "diffuse")? PATH_RAY_DIFFUSE: 0;
flag |= get_boolean(cvisibility, "glossy")? PATH_RAY_GLOSSY: 0;
flag |= get_boolean(cvisibility, "transmission")? PATH_RAY_TRANSMIT: 0;
flag |= get_boolean(cvisibility, "shadow")? PATH_RAY_SHADOW: 0;
return flag;
}
/* Light */ /* Light */
void BlenderSync::sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm) void BlenderSync::sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm)
@ -115,6 +129,11 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob,
if(object_map.sync(&object, b_ob, b_parent, key)) { if(object_map.sync(&object, b_ob, b_parent, key)) {
object->name = b_ob.name(); object->name = b_ob.name();
object->tfm = tfm; object->tfm = tfm;
object->visibility = object_ray_visibility(b_ob);
if(b_parent.ptr.data != b_ob.ptr.data)
object->visibility &= object_ray_visibility(b_parent);
object->tag_update(scene); object->tag_update(scene);
object_updated = true; object_updated = true;
} }

@ -599,7 +599,7 @@ void BlenderSync::sync_world()
} }
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
background->transparent = get_boolean(cscene, "transparent"); background->transparent = get_boolean(cscene, "film_transparent");
if(background->modified(prevbackground)) if(background->modified(prevbackground))
background->tag_update(scene); background->tag_update(scene);

@ -131,8 +131,16 @@ void BlenderSync::sync_integrator()
Integrator *integrator = scene->integrator; Integrator *integrator = scene->integrator;
Integrator previntegrator = *integrator; Integrator previntegrator = *integrator;
integrator->minbounce = get_int(cscene, "min_bounces"); integrator->min_bounce = get_int(cscene, "min_bounces");
integrator->maxbounce = get_int(cscene, "max_bounces"); integrator->max_bounce = get_int(cscene, "max_bounces");
integrator->max_diffuse_bounce = get_int(cscene, "diffuse_bounces");
integrator->max_glossy_bounce = get_int(cscene, "glossy_bounces");
integrator->max_transmission_bounce = get_int(cscene, "transmission_bounces");
integrator->transparent_max_bounce = get_int(cscene, "transparent_max_bounces");
integrator->transparent_min_bounce = get_int(cscene, "transparent_min_bounces");
integrator->no_caustics = get_boolean(cscene, "no_caustics"); integrator->no_caustics = get_boolean(cscene, "no_caustics");
integrator->blur_caustics = get_float(cscene, "blur_caustics"); integrator->blur_caustics = get_float(cscene, "blur_caustics");
@ -149,7 +157,7 @@ void BlenderSync::sync_film()
Film *film = scene->film; Film *film = scene->film;
Film prevfilm = *film; Film prevfilm = *film;
film->exposure = get_float(cscene, "exposure"); film->exposure = get_float(cscene, "film_exposure");
if(film->modified(prevfilm)) if(film->modified(prevfilm))
film->tag_update(scene); film->tag_update(scene);

@ -84,6 +84,7 @@ bool BVH::cache_read(CacheData& key)
value.read(pack.nodes); value.read(pack.nodes);
value.read(pack.object_node); value.read(pack.object_node);
value.read(pack.tri_woop); value.read(pack.tri_woop);
value.read(pack.prim_visibility);
value.read(pack.prim_index); value.read(pack.prim_index);
value.read(pack.prim_object); value.read(pack.prim_object);
value.read(pack.is_leaf); value.read(pack.is_leaf);
@ -103,6 +104,7 @@ void BVH::cache_write(CacheData& key)
value.add(pack.nodes); value.add(pack.nodes);
value.add(pack.object_node); value.add(pack.object_node);
value.add(pack.tri_woop); value.add(pack.tri_woop);
value.add(pack.prim_visibility);
value.add(pack.prim_index); value.add(pack.prim_index);
value.add(pack.prim_object); value.add(pack.prim_object);
value.add(pack.is_leaf); value.add(pack.is_leaf);
@ -236,6 +238,8 @@ void BVH::pack_triangles()
pack.tri_woop.clear(); pack.tri_woop.clear();
pack.tri_woop.resize(tidx_size * nsize); pack.tri_woop.resize(tidx_size * nsize);
pack.prim_visibility.clear();
pack.prim_visibility.resize(tidx_size);
for(unsigned int i = 0; i < tidx_size; i++) { for(unsigned int i = 0; i < tidx_size; i++) {
if(pack.prim_index[i] != -1) { if(pack.prim_index[i] != -1) {
@ -243,6 +247,10 @@ void BVH::pack_triangles()
pack_triangle(i, woop); pack_triangle(i, woop);
memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3); memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
int tob = pack.prim_object[i];
Object *ob = objects[tob];
pack.prim_visibility[i] = ob->visibility;
} }
} }
} }
@ -292,12 +300,14 @@ void BVH::pack_instances(size_t nodes_size)
pack.prim_index.resize(prim_index_size); pack.prim_index.resize(prim_index_size);
pack.prim_object.resize(prim_index_size); pack.prim_object.resize(prim_index_size);
pack.prim_visibility.resize(prim_index_size);
pack.tri_woop.resize(tri_woop_size); pack.tri_woop.resize(tri_woop_size);
pack.nodes.resize(nodes_size); pack.nodes.resize(nodes_size);
pack.object_node.resize(objects.size()); pack.object_node.resize(objects.size());
int *pack_prim_index = &pack.prim_index[0]; int *pack_prim_index = &pack.prim_index[0];
int *pack_prim_object = &pack.prim_object[0]; int *pack_prim_object = &pack.prim_object[0];
uint *pack_prim_visibility = &pack.prim_visibility[0];
float4 *pack_tri_woop = &pack.tri_woop[0]; float4 *pack_tri_woop = &pack.tri_woop[0];
int4 *pack_nodes = &pack.nodes[0]; int4 *pack_nodes = &pack.nodes[0];
@ -327,9 +337,11 @@ void BVH::pack_instances(size_t nodes_size)
{ {
size_t bvh_prim_index_size = bvh->pack.prim_index.size(); size_t bvh_prim_index_size = bvh->pack.prim_index.size();
int *bvh_prim_index = &bvh->pack.prim_index[0]; int *bvh_prim_index = &bvh->pack.prim_index[0];
uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
for(size_t i = 0; i < bvh_prim_index_size; i++) { for(size_t i = 0; i < bvh_prim_index_size; i++) {
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset; pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i] + mesh_tri_offset;
pack_prim_object[pack_prim_index_offset] = 0; // unused for instances pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
pack_prim_index_offset++; pack_prim_index_offset++;
} }
@ -394,25 +406,25 @@ void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
{ {
if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1) if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1)
/* object */ /* object */
pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, ~(leaf->m_lo), 0); pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, ~(leaf->m_lo), 0, leaf->m_visibility, leaf->m_visibility);
else else
/* triangle */ /* triangle */
pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, leaf->m_lo, leaf->m_hi); pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, leaf->m_lo, leaf->m_hi, leaf->m_visibility, leaf->m_visibility);
} }
void RegularBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1) void RegularBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1)
{ {
pack_node(e.idx, e0.node->m_bounds, e1.node->m_bounds, e0.encodeIdx(), e1.encodeIdx()); pack_node(e.idx, e0.node->m_bounds, e1.node->m_bounds, e0.encodeIdx(), e1.encodeIdx(), e0.node->m_visibility, e1.node->m_visibility);
} }
void RegularBVH::pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1) void RegularBVH::pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1, uint visibility0, uint visibility1)
{ {
int4 data[BVH_NODE_SIZE] = int4 data[BVH_NODE_SIZE] =
{ {
make_int4(__float_as_int(b0.min.x), __float_as_int(b0.max.x), __float_as_int(b0.min.y), __float_as_int(b0.max.y)), make_int4(__float_as_int(b0.min.x), __float_as_int(b0.max.x), __float_as_int(b0.min.y), __float_as_int(b0.max.y)),
make_int4(__float_as_int(b1.min.x), __float_as_int(b1.max.x), __float_as_int(b1.min.y), __float_as_int(b1.max.y)), make_int4(__float_as_int(b1.min.x), __float_as_int(b1.max.x), __float_as_int(b1.min.y), __float_as_int(b1.max.y)),
make_int4(__float_as_int(b0.min.z), __float_as_int(b0.max.z), __float_as_int(b1.min.z), __float_as_int(b1.max.z)), make_int4(__float_as_int(b0.min.z), __float_as_int(b0.max.z), __float_as_int(b1.min.z), __float_as_int(b1.max.z)),
make_int4(c0, c1, 0, 0) make_int4(c0, c1, visibility0, visibility1)
}; };
memcpy(&pack.nodes[idx * BVH_NODE_SIZE], data, sizeof(int4)*BVH_NODE_SIZE); memcpy(&pack.nodes[idx * BVH_NODE_SIZE], data, sizeof(int4)*BVH_NODE_SIZE);
@ -467,10 +479,11 @@ void RegularBVH::refit_nodes()
assert(!params.top_level); assert(!params.top_level);
BoundBox bbox; BoundBox bbox;
refit_node(0, (pack.is_leaf[0])? true: false, bbox); uint visibility = 0;
refit_node(0, (pack.is_leaf[0])? true: false, bbox, visibility);
} }
void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox) void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
{ {
int4 *data = &pack.nodes[idx*4]; int4 *data = &pack.nodes[idx*4];
@ -499,21 +512,25 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox)
bbox.grow(vpos[vidx[1]]); bbox.grow(vpos[vidx[1]]);
bbox.grow(vpos[vidx[2]]); bbox.grow(vpos[vidx[2]]);
} }
visibility |= ob->visibility;
} }
pack_node(idx, bbox, bbox, c0, c1); pack_node(idx, bbox, bbox, c0, c1, visibility, visibility);
} }
else { else {
/* refit inner node, set bbox from children */ /* refit inner node, set bbox from children */
BoundBox bbox0, bbox1; BoundBox bbox0, bbox1;
uint visibility0 = 0, visibility1 = 0;
refit_node((c0 < 0)? -c0-1: c0, (c0 < 0), bbox0); refit_node((c0 < 0)? -c0-1: c0, (c0 < 0), bbox0, visibility0);
refit_node((c1 < 0)? -c1-1: c1, (c1 < 0), bbox1); refit_node((c1 < 0)? -c1-1: c1, (c1 < 0), bbox1, visibility1);
pack_node(idx, bbox0, bbox1, c0, c1, visibility0, visibility1);
bbox.grow(bbox0); bbox.grow(bbox0);
bbox.grow(bbox1); bbox.grow(bbox1);
visibility = visibility0|visibility1;
pack_node(idx, bbox0, bbox1, c0, c1);
} }
} }
@ -523,6 +540,8 @@ QBVH::QBVH(const BVHParams& params_, const vector<Object*>& objects_)
: BVH(params_, objects_) : BVH(params_, objects_)
{ {
params.use_qbvh = true; params.use_qbvh = true;
/* todo: use visibility */
} }
void QBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf) void QBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)

@ -51,6 +51,8 @@ struct PackedBVH {
array<int> object_node; array<int> object_node;
/* precomputed triangle intersection data, one triangle is 4x float4 */ /* precomputed triangle intersection data, one triangle is 4x float4 */
array<float4> tri_woop; array<float4> tri_woop;
/* visibility visibilitys for primitives */
array<uint> prim_visibility;
/* mapping from BVH primitive index to true primitive index, as primitives /* mapping from BVH primitive index to true primitive index, as primitives
may be duplicated due to spatial splits. -1 for instances. */ may be duplicated due to spatial splits. -1 for instances. */
array<int> prim_index; array<int> prim_index;
@ -121,11 +123,11 @@ protected:
void pack_nodes(const array<int>& prims, const BVHNode *root); void pack_nodes(const array<int>& prims, const BVHNode *root);
void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf); void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf);
void pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1); void pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1);
void pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1); void pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1, uint visibility0, uint visibility1);
/* refit */ /* refit */
void refit_nodes(); void refit_nodes();
void refit_node(int idx, bool leaf, BoundBox& bbox); void refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility);
}; };
/* QBVH /* QBVH

@ -218,12 +218,13 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const Reference *ref, int num)
{ {
if(num == 0) { if(num == 0) {
BoundBox bounds; BoundBox bounds;
return new LeafNode(bounds, 0, 0); return new LeafNode(bounds, 0, 0, 0);
} }
else if(num == 1) { else if(num == 1) {
prim_index.push_back(ref[0].prim_index); prim_index.push_back(ref[0].prim_index);
prim_object.push_back(ref[0].prim_object); prim_object.push_back(ref[0].prim_object);
return new LeafNode(ref[0].bounds, prim_index.size()-1, prim_index.size()); uint visibility = objects[ref[0].prim_object]->visibility;
return new LeafNode(ref[0].bounds, visibility, prim_index.size()-1, prim_index.size());
} }
else { else {
int mid = num/2; int mid = num/2;
@ -244,12 +245,14 @@ BVHNode* BVHBuild::create_leaf_node(const NodeSpec& spec)
vector<int>& p_object = prim_object; vector<int>& p_object = prim_object;
BoundBox bounds; BoundBox bounds;
int num = 0; int num = 0;
uint visibility = 0;
for(int i = 0; i < spec.num; i++) { for(int i = 0; i < spec.num; i++) {
if(references.back().prim_index != -1) { if(references.back().prim_index != -1) {
p_index.push_back(references.back().prim_index); p_index.push_back(references.back().prim_index);
p_object.push_back(references.back().prim_object); p_object.push_back(references.back().prim_object);
bounds.grow(references.back().bounds); bounds.grow(references.back().bounds);
visibility |= objects[references.back().prim_object]->visibility;
references.pop_back(); references.pop_back();
num++; num++;
} }
@ -258,7 +261,7 @@ BVHNode* BVHBuild::create_leaf_node(const NodeSpec& spec)
BVHNode *leaf = NULL; BVHNode *leaf = NULL;
if(num > 0) { if(num > 0) {
leaf = new LeafNode(bounds, p_index.size() - num, p_index.size()); leaf = new LeafNode(bounds, visibility, p_index.size() - num, p_index.size());
if(num == spec.num) if(num == spec.num)
return leaf; return leaf;

@ -52,6 +52,7 @@ public:
float getArea() const { return m_bounds.area(); } float getArea() const { return m_bounds.area(); }
BoundBox m_bounds; BoundBox m_bounds;
uint m_visibility;
// Subtree functions // Subtree functions
int getSubtreeSize(BVH_STAT stat=BVH_STAT_NODE_COUNT) const; int getSubtreeSize(BVH_STAT stat=BVH_STAT_NODE_COUNT) const;
@ -65,6 +66,7 @@ public:
InnerNode(const BoundBox& bounds, BVHNode* child0, BVHNode* child1) InnerNode(const BoundBox& bounds, BVHNode* child0, BVHNode* child1)
{ {
m_bounds = bounds; m_bounds = bounds;
m_visibility = child0->m_visibility|child1->m_visibility;
children[0] = child0; children[0] = child0;
children[1] = child1; children[1] = child1;
} }
@ -80,9 +82,10 @@ public:
class LeafNode : public BVHNode class LeafNode : public BVHNode
{ {
public: public:
LeafNode(const BoundBox& bounds, int lo, int hi) LeafNode(const BoundBox& bounds, uint visibility, int lo, int hi)
{ {
m_bounds = bounds; m_bounds = bounds;
m_visibility = visibility;
m_lo = lo; m_lo = lo;
m_hi = hi; m_hi = hi;
} }

@ -89,6 +89,10 @@ void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t
kg->__tri_woop.data = (float4*)mem; kg->__tri_woop.data = (float4*)mem;
kg->__tri_woop.width = width; kg->__tri_woop.width = width;
} }
else if(strcmp(name, "__prim_visibility") == 0) {
kg->__prim_visibility.data = (uint*)mem;
kg->__prim_visibility.width = width;
}
else if(strcmp(name, "__prim_index") == 0) { else if(strcmp(name, "__prim_index") == 0) {
kg->__prim_index.data = (uint*)mem; kg->__prim_index.data = (uint*)mem;
kg->__prim_index.width = width; kg->__prim_index.width = width;

@ -78,7 +78,7 @@ __device_inline void bvh_instance_pop(KernelGlobals *kg, int object, const Ray *
__device_inline void bvh_node_intersect(KernelGlobals *kg, __device_inline void bvh_node_intersect(KernelGlobals *kg,
bool *traverseChild0, bool *traverseChild1, bool *traverseChild0, bool *traverseChild1,
bool *closestChild1, int *nodeAddr0, int *nodeAddr1, bool *closestChild1, int *nodeAddr0, int *nodeAddr1,
float3 P, float3 idir, float t, int nodeAddr) float3 P, float3 idir, float t, uint visibility, int nodeAddr)
{ {
/* fetch node data */ /* fetch node data */
float4 n0xy = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0); float4 n0xy = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
@ -111,8 +111,14 @@ __device_inline void bvh_node_intersect(KernelGlobals *kg,
float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
/* decide which nodes to traverse next */ /* decide which nodes to traverse next */
#ifdef __VISIBILITY_FLAG__
/* this visibility test gives a 5% performance hit, how to solve? */
*traverseChild0 = (c0max >= c0min) && (__float_as_int(cnodes.z) & visibility);
*traverseChild1 = (c1max >= c1min) && (__float_as_int(cnodes.w) & visibility);
#else
*traverseChild0 = (c0max >= c0min); *traverseChild0 = (c0max >= c0min);
*traverseChild1 = (c1max >= c1min); *traverseChild1 = (c1max >= c1min);
#endif
*nodeAddr0 = __float_as_int(cnodes.x); *nodeAddr0 = __float_as_int(cnodes.x);
*nodeAddr1 = __float_as_int(cnodes.y); *nodeAddr1 = __float_as_int(cnodes.y);
@ -121,7 +127,8 @@ __device_inline void bvh_node_intersect(KernelGlobals *kg,
} }
/* Sven Woop's algorithm */ /* Sven Woop's algorithm */
__device_inline void bvh_triangle_intersect(KernelGlobals *kg, Intersection *isect, float3 P, float3 idir, int object, int triAddr) __device_inline void bvh_triangle_intersect(KernelGlobals *kg, Intersection *isect,
float3 P, float3 idir, uint visibility, int object, int triAddr)
{ {
/* compute and check intersection t-value */ /* compute and check intersection t-value */
float4 v00 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0); float4 v00 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0);
@ -146,18 +153,25 @@ __device_inline void bvh_triangle_intersect(KernelGlobals *kg, Intersection *ise
float v = Oy + t*Dy; float v = Oy + t*Dy;
if(v >= 0.0f && u + v <= 1.0f) { if(v >= 0.0f && u + v <= 1.0f) {
/* record intersection */ #ifdef __VISIBILITY_FLAG__
isect->prim = triAddr; /* visibility flag test. we do it here under the assumption
isect->object = object; that most triangles are culled by node flags */
isect->u = u; if(kernel_tex_fetch(__prim_visibility, triAddr) & visibility)
isect->v = v; #endif
isect->t = t; {
/* record intersection */
isect->prim = triAddr;
isect->object = object;
isect->u = u;
isect->v = v;
isect->t = t;
}
} }
} }
} }
} }
__device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const bool isshadowray, Intersection *isect) __device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect)
{ {
/* traversal stack in CUDA thread-local memory */ /* traversal stack in CUDA thread-local memory */
int traversalStack[BVH_STACK_SIZE]; int traversalStack[BVH_STACK_SIZE];
@ -191,7 +205,7 @@ __device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const bo
bvh_node_intersect(kg, &traverseChild0, &traverseChild1, bvh_node_intersect(kg, &traverseChild0, &traverseChild1,
&closestChild1, &nodeAddr, &nodeAddrChild1, &closestChild1, &nodeAddr, &nodeAddrChild1,
P, idir, isect->t, nodeAddr); P, idir, isect->t, visibility, nodeAddr);
if(traverseChild0 != traverseChild1) { if(traverseChild0 != traverseChild1) {
/* one child was intersected */ /* one child was intersected */
@ -236,10 +250,10 @@ __device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const bo
/* triangle intersection */ /* triangle intersection */
while(primAddr < primAddr2) { while(primAddr < primAddr2) {
/* intersect ray against triangle */ /* intersect ray against triangle */
bvh_triangle_intersect(kg, isect, P, idir, object, primAddr); bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
/* shadow ray early termination */ /* shadow ray early termination */
if(isshadowray && isect->prim != ~0) if(visibility == PATH_RAY_SHADOW && isect->prim != ~0)
return true; return true;
primAddr++; primAddr++;

@ -58,51 +58,108 @@ __device float3 path_terminate_modified_throughput(KernelGlobals *kg, __global f
} }
#endif #endif
__device float path_terminate_probability(KernelGlobals *kg, int bounce, const float3 throughput) typedef struct PathState {
{ uint flag;
if(bounce >= kernel_data.integrator.maxbounce) int bounce;
return 0.0f;
else if(bounce <= kernel_data.integrator.minbounce)
return 1.0f;
return average(throughput); int diffuse_bounce;
int glossy_bounce;
int transmission_bounce;
int transparent_bounce;
} PathState;
__device_inline void path_state_init(PathState *state)
{
state->flag = PATH_RAY_CAMERA|PATH_RAY_SINGULAR;
state->bounce = 0;
state->diffuse_bounce = 0;
state->glossy_bounce = 0;
state->transmission_bounce = 0;
state->transparent_bounce = 0;
} }
__device int path_flag_from_label(int path_flag, int label) __device_inline void path_state_next(PathState *state, int label)
{ {
/* reflect/transmit */ /* ray through transparent keeps same flags from previous ray and is
not counted as a regular bounce, transparent has separate max */
if(label & LABEL_TRANSPARENT) {
state->flag |= PATH_RAY_TRANSPARENT;
state->transparent_bounce++;
return;
}
state->bounce++;
/* reflection/transmission */
if(label & LABEL_REFLECT) { if(label & LABEL_REFLECT) {
path_flag |= PATH_RAY_REFLECT; state->flag |= PATH_RAY_REFLECT;
path_flag &= ~PATH_RAY_TRANSMIT; state->flag &= ~(PATH_RAY_TRANSMIT|PATH_RAY_CAMERA|PATH_RAY_TRANSPARENT);
if(label & LABEL_DIFFUSE)
state->diffuse_bounce++;
else
state->glossy_bounce++;
} }
else { else {
kernel_assert(label & LABEL_TRANSMIT); kernel_assert(label & LABEL_TRANSMIT);
path_flag |= PATH_RAY_TRANSMIT; state->flag |= PATH_RAY_TRANSMIT;
path_flag &= ~PATH_RAY_REFLECT; state->flag &= ~(PATH_RAY_REFLECT|PATH_RAY_CAMERA|PATH_RAY_TRANSPARENT);
state->transmission_bounce++;
} }
/* diffuse/glossy/singular */ /* diffuse/glossy/singular */
if(label & LABEL_DIFFUSE) { if(label & LABEL_DIFFUSE) {
path_flag |= PATH_RAY_DIFFUSE; state->flag |= PATH_RAY_DIFFUSE;
path_flag &= ~(PATH_RAY_GLOSSY|PATH_RAY_SINGULAR); state->flag &= ~(PATH_RAY_GLOSSY|PATH_RAY_SINGULAR);
} }
else if(label & LABEL_GLOSSY) { else if(label & LABEL_GLOSSY) {
path_flag |= PATH_RAY_GLOSSY; state->flag |= PATH_RAY_GLOSSY;
path_flag &= ~(PATH_RAY_DIFFUSE|PATH_RAY_SINGULAR); state->flag &= ~(PATH_RAY_DIFFUSE|PATH_RAY_SINGULAR);
} }
else { else {
kernel_assert(label & (LABEL_SINGULAR|LABEL_STRAIGHT)); kernel_assert(label & LABEL_SINGULAR);
path_flag |= PATH_RAY_SINGULAR; state->flag |= PATH_RAY_GLOSSY|PATH_RAY_SINGULAR;
path_flag &= ~(PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY); state->flag &= ~PATH_RAY_DIFFUSE;
} }
}
/* ray through transparent is still camera ray */
if(!(label & LABEL_STRAIGHT)) __device_inline uint path_state_ray_visibility(PathState *state)
path_flag &= ~PATH_RAY_CAMERA; {
uint flag = state->flag;
return path_flag;
/* for visibility, diffuse/glossy are for reflection only */
if(flag & PATH_RAY_TRANSMIT)
flag &= ~(PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY);
return flag;
}
__device_inline float path_state_terminate_probability(KernelGlobals *kg, PathState *state, const float3 throughput)
{
if(state->flag & PATH_RAY_TRANSPARENT) {
/* transparent rays treated separately */
if(state->transparent_bounce >= kernel_data.integrator.transparent_max_bounce)
return 0.0f;
else if(state->transparent_bounce <= kernel_data.integrator.transparent_min_bounce)
return 1.0f;
}
else {
/* other rays */
if((state->bounce >= kernel_data.integrator.max_bounce) ||
(state->diffuse_bounce >= kernel_data.integrator.max_diffuse_bounce) ||
(state->glossy_bounce >= kernel_data.integrator.max_glossy_bounce) ||
(state->transmission_bounce >= kernel_data.integrator.max_transmission_bounce))
return 0.0f;
else if(state->bounce <= kernel_data.integrator.min_bounce)
return 1.0f;
}
/* probalistic termination */
return average(throughput);
} }
__device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int pass, Ray ray, float3 throughput) __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int pass, Ray ray, float3 throughput)
@ -114,24 +171,27 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int pass, Ray
#ifdef __EMISSION__ #ifdef __EMISSION__
float ray_pdf = 0.0f; float ray_pdf = 0.0f;
#endif #endif
int path_flag = PATH_RAY_CAMERA|PATH_RAY_SINGULAR; PathState state;
int rng_offset = PRNG_BASE_NUM; int rng_offset = PRNG_BASE_NUM;
path_state_init(&state);
/* path iteration */ /* path iteration */
for(int bounce = 0; ; bounce++, rng_offset += PRNG_BOUNCE_NUM) { for(;; rng_offset += PRNG_BOUNCE_NUM) {
/* intersect scene */ /* intersect scene */
Intersection isect; Intersection isect;
uint visibility = path_state_ray_visibility(&state);
if(!scene_intersect(kg, &ray, false, &isect)) { if(!scene_intersect(kg, &ray, visibility, &isect)) {
/* eval background shader if nothing hit */ /* eval background shader if nothing hit */
if(kernel_data.background.transparent && (path_flag & PATH_RAY_CAMERA)) { if(kernel_data.background.transparent && (state.flag & PATH_RAY_CAMERA)) {
Ltransparent += average(throughput); Ltransparent += average(throughput);
} }
else { else {
#ifdef __BACKGROUND__ #ifdef __BACKGROUND__
ShaderData sd; ShaderData sd;
shader_setup_from_background(kg, &sd, &ray); shader_setup_from_background(kg, &sd, &ray);
L += throughput*shader_eval_background(kg, &sd, path_flag); L += throughput*shader_eval_background(kg, &sd, state.flag);
shader_release(kg, &sd); shader_release(kg, &sd);
#else #else
L += make_float3(0.8f, 0.8f, 0.8f); L += make_float3(0.8f, 0.8f, 0.8f);
@ -145,10 +205,10 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int pass, Ray
ShaderData sd; ShaderData sd;
shader_setup_from_ray(kg, &sd, &isect, &ray); shader_setup_from_ray(kg, &sd, &isect, &ray);
float rbsdf = path_rng(kg, rng, pass, rng_offset + PRNG_BSDF); float rbsdf = path_rng(kg, rng, pass, rng_offset + PRNG_BSDF);
shader_eval_surface(kg, &sd, rbsdf, path_flag); shader_eval_surface(kg, &sd, rbsdf, state.flag);
#ifdef __HOLDOUT__ #ifdef __HOLDOUT__
if((sd.flag & SD_HOLDOUT) && (path_flag & PATH_RAY_CAMERA)) { if((sd.flag & SD_HOLDOUT) && (state.flag & PATH_RAY_CAMERA)) {
float3 holdout_weight = shader_holdout_eval(kg, &sd); float3 holdout_weight = shader_holdout_eval(kg, &sd);
if(kernel_data.background.transparent) if(kernel_data.background.transparent)
@ -160,11 +220,25 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int pass, Ray
/* emission */ /* emission */
if(kernel_data.integrator.use_emission) { if(kernel_data.integrator.use_emission) {
if(sd.flag & SD_EMISSION) if(sd.flag & SD_EMISSION)
L += throughput*indirect_emission(kg, &sd, isect.t, path_flag, ray_pdf); L += throughput*indirect_emission(kg, &sd, isect.t, state.flag, ray_pdf);
}
#endif
/* path termination. this is a strange place to put the termination, it's
mainly due to the mixed in MIS that we use. gives too many unneeded
shader evaluations, only need emission if we are going to terminate */
float probability = path_state_terminate_probability(kg, &state, throughput);
float terminate = path_rng(kg, rng, pass, rng_offset + PRNG_TERMINATE);
if(terminate >= probability)
break;
throughput /= probability;
#ifdef __EMISSION__
if(kernel_data.integrator.use_emission) {
/* sample illumination from lights to find path contribution */ /* sample illumination from lights to find path contribution */
if((sd.flag & SD_BSDF_HAS_EVAL) && if(sd.flag & SD_BSDF_HAS_EVAL) {
bounce != kernel_data.integrator.maxbounce) {
float light_t = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT); float light_t = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT);
float light_o = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT_F); float light_o = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT_F);
float light_u = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT_U); float light_u = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT_U);
@ -173,9 +247,11 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int pass, Ray
Ray light_ray; Ray light_ray;
float3 light_L; float3 light_L;
/* todo: use visbility flag to skip lights */
if(direct_emission(kg, &sd, light_t, light_o, light_u, light_v, &light_ray, &light_L)) { if(direct_emission(kg, &sd, light_t, light_o, light_u, light_v, &light_ray, &light_L)) {
/* trace shadow ray */ /* trace shadow ray */
if(!scene_intersect(kg, &light_ray, true, &isect)) if(!scene_intersect(kg, &light_ray, PATH_RAY_SHADOW, &isect))
L += throughput*light_L; L += throughput*light_L;
} }
} }
@ -183,10 +259,8 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int pass, Ray
#endif #endif
/* no BSDF? we can stop here */ /* no BSDF? we can stop here */
if(!(sd.flag & SD_BSDF)) { if(!(sd.flag & SD_BSDF))
path_flag &= ~PATH_RAY_CAMERA;
break; break;
}
/* sample BSDF */ /* sample BSDF */
float bsdf_pdf; float bsdf_pdf;
@ -202,10 +276,8 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int pass, Ray
shader_release(kg, &sd); shader_release(kg, &sd);
if(bsdf_pdf == 0.0f || is_zero(bsdf_eval)) { if(bsdf_pdf == 0.0f || is_zero(bsdf_eval))
path_flag &= ~PATH_RAY_CAMERA;
break; break;
}
/* modify throughput */ /* modify throughput */
throughput *= bsdf_eval/bsdf_pdf; throughput *= bsdf_eval/bsdf_pdf;
@ -215,18 +287,8 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int pass, Ray
ray_pdf = bsdf_pdf; ray_pdf = bsdf_pdf;
#endif #endif
path_flag = path_flag_from_label(path_flag, label); /* update path state */
path_state_next(&state, label);
/* path termination */
float probability = path_terminate_probability(kg, bounce, throughput);
float terminate = path_rng(kg, rng, pass, rng_offset + PRNG_TERMINATE);
if(terminate >= probability) {
path_flag &= ~PATH_RAY_CAMERA;
break;
}
throughput /= probability;
/* setup ray */ /* setup ray */
ray.P = ray_offset(sd.P, (label & LABEL_TRANSMIT)? -sd.Ng: sd.Ng); ray.P = ray_offset(sd.P, (label & LABEL_TRANSMIT)? -sd.Ng: sd.Ng);

@ -11,6 +11,7 @@
/* bvh */ /* bvh */
KERNEL_TEX(float4, texture_float4, __bvh_nodes) KERNEL_TEX(float4, texture_float4, __bvh_nodes)
KERNEL_TEX(float4, texture_float4, __tri_woop) KERNEL_TEX(float4, texture_float4, __tri_woop)
KERNEL_TEX(uint, texture_uint, __prim_visibility)
KERNEL_TEX(uint, texture_uint, __prim_index) KERNEL_TEX(uint, texture_uint, __prim_index)
KERNEL_TEX(uint, texture_uint, __prim_object) KERNEL_TEX(uint, texture_uint, __prim_object)
KERNEL_TEX(uint, texture_uint, __object_node) KERNEL_TEX(uint, texture_uint, __object_node)

@ -34,11 +34,14 @@ CCL_NAMESPACE_BEGIN
#define __BACKGROUND__ #define __BACKGROUND__
#define __EMISSION__ #define __EMISSION__
#define __CAUSTICS_TRICKS__ #define __CAUSTICS_TRICKS__
#define __VISIBILITY_FLAG__
#ifndef __KERNEL_OPENCL__ #ifndef __KERNEL_OPENCL__
#define __SVM__ #define __SVM__
#define __TEXTURES__ #define __TEXTURES__
#define __HOLDOUT__ #define __HOLDOUT__
#endif #endif
#define __RAY_DIFFERENTIALS__ #define __RAY_DIFFERENTIALS__
#define __CAMERA_CLIPPING__ #define __CAMERA_CLIPPING__
#define __INTERSECTION_REFINE__ #define __INTERSECTION_REFINE__
@ -76,7 +79,8 @@ enum PathRayFlag {
PATH_RAY_TRANSMIT = 8, PATH_RAY_TRANSMIT = 8,
PATH_RAY_DIFFUSE = 16, PATH_RAY_DIFFUSE = 16,
PATH_RAY_GLOSSY = 32, PATH_RAY_GLOSSY = 32,
PATH_RAY_SINGULAR = 64 PATH_RAY_SINGULAR = 64,
PATH_RAY_TRANSPARENT = 128
}; };
/* Bidirectional Path Tracing */ /* Bidirectional Path Tracing */
@ -115,7 +119,7 @@ typedef enum ClosureLabel {
LABEL_DIFFUSE = 128, LABEL_DIFFUSE = 128,
LABEL_GLOSSY = 256, LABEL_GLOSSY = 256,
LABEL_SINGULAR = 512, LABEL_SINGULAR = 512,
LABEL_STRAIGHT = 1024, LABEL_TRANSPARENT = 1024,
LABEL_STOP = 2048 LABEL_STOP = 2048
} ClosureLabel; } ClosureLabel;
@ -351,9 +355,18 @@ typedef struct KernelIntegrator {
float pdf_triangles; float pdf_triangles;
float pdf_lights; float pdf_lights;
/* path tracing */ /* bounces */
int minbounce; int min_bounce;
int maxbounce; int max_bounce;
int max_diffuse_bounce;
int max_glossy_bounce;
int max_transmission_bounce;
/* transparent */
int transparent_min_bounce;
int transparent_max_bounce;
int transparent_shadows;
/* caustics */ /* caustics */
int no_caustics; int no_caustics;

@ -23,6 +23,7 @@ shader node_light_path(
output float IsShadowRay = 0.0, output float IsShadowRay = 0.0,
output float IsDiffuseRay = 0.0, output float IsDiffuseRay = 0.0,
output float IsGlossyRay = 0.0, output float IsGlossyRay = 0.0,
output float IsSingularRay = 0.0,
output float IsReflectionRay = 0.0, output float IsReflectionRay = 0.0,
output float IsTransmissionRay = 0.0) output float IsTransmissionRay = 0.0)
{ {
@ -30,6 +31,7 @@ shader node_light_path(
IsShadowRay = raytype("shadow"); IsShadowRay = raytype("shadow");
IsDiffuseRay = raytype("diffuse"); IsDiffuseRay = raytype("diffuse");
IsGlossyRay = raytype("glossy"); IsGlossyRay = raytype("glossy");
IsSingularRay = raytype("singular");
IsReflectionRay = raytype("reflection"); IsReflectionRay = raytype("reflection");
IsTransmissionRay = raytype("refraction"); IsTransmissionRay = raytype("refraction");
} }

@ -89,7 +89,7 @@ static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd,
globals->surfacearea = (sd->object == ~0)? 1.0f: object_surface_area(kg, sd->object); globals->surfacearea = (sd->object == ~0)? 1.0f: object_surface_area(kg, sd->object);
/* booleans */ /* booleans */
globals->raytype = path_flag; globals->raytype = path_flag; /* todo: add our own ray types */
globals->backfacing = (sd->flag & SD_BACKFACING); globals->backfacing = (sd->flag & SD_BACKFACING);
/* don't know yet if we need this */ /* don't know yet if we need this */
@ -437,7 +437,7 @@ int OSLShader::bsdf_sample(const ShaderData *sd, float randu, float randv, float
else if(uscattering == OSL::Labels::SINGULAR) else if(uscattering == OSL::Labels::SINGULAR)
label |= LABEL_SINGULAR; label |= LABEL_SINGULAR;
else else
label |= LABEL_STRAIGHT; label |= LABEL_TRANSPARENT;
/* eval + pdf */ /* eval + pdf */
eval *= flat->weight; eval *= flat->weight;

@ -70,7 +70,7 @@ __device int bsdf_transparent_sample(const ShaderData *sd, float randu, float ra
#endif #endif
*pdf = 1; *pdf = 1;
*eval = make_float3(1, 1, 1); *eval = make_float3(1, 1, 1);
return LABEL_TRANSMIT|LABEL_STRAIGHT; return LABEL_TRANSMIT|LABEL_TRANSPARENT;
} }
CCL_NAMESPACE_END CCL_NAMESPACE_END

@ -29,6 +29,7 @@ __device void svm_node_light_path(ShaderData *sd, float *stack, uint type, uint
case NODE_LP_shadow: info = (path_flag & PATH_RAY_SHADOW)? 1.0f: 0.0f; break; case NODE_LP_shadow: info = (path_flag & PATH_RAY_SHADOW)? 1.0f: 0.0f; break;
case NODE_LP_diffuse: info = (path_flag & PATH_RAY_DIFFUSE)? 1.0f: 0.0f; break; case NODE_LP_diffuse: info = (path_flag & PATH_RAY_DIFFUSE)? 1.0f: 0.0f; break;
case NODE_LP_glossy: info = (path_flag & PATH_RAY_GLOSSY)? 1.0f: 0.0f; break; case NODE_LP_glossy: info = (path_flag & PATH_RAY_GLOSSY)? 1.0f: 0.0f; break;
case NODE_LP_singular: info = (path_flag & PATH_RAY_SINGULAR)? 1.0f: 0.0f; break;
case NODE_LP_reflection: info = (path_flag & PATH_RAY_REFLECT)? 1.0f: 0.0f; break; case NODE_LP_reflection: info = (path_flag & PATH_RAY_REFLECT)? 1.0f: 0.0f; break;
case NODE_LP_transmission: info = (path_flag & PATH_RAY_TRANSMIT)? 1.0f: 0.0f; break; case NODE_LP_transmission: info = (path_flag & PATH_RAY_TRANSMIT)? 1.0f: 0.0f; break;
case NODE_LP_backfacing: info = (sd->flag & SD_BACKFACING)? 1.0f: 0.0f; break; case NODE_LP_backfacing: info = (sd->flag & SD_BACKFACING)? 1.0f: 0.0f; break;

@ -209,22 +209,5 @@ __device float psnoise(float3 p, float3 pperiod)
return perlin_periodic(p.x, p.y, p.z, pperiod); return perlin_periodic(p.x, p.y, p.z, pperiod);
} }
/* turbulence */
__device_noinline float turbulence(float3 P, int oct, bool hard)
{
float amp = 1.0f, fscale = 1.0f, sum = 0.0f;
int i;
for(i=0; i<=oct; i++, amp *= 0.5f, fscale *= 2.0f) {
float t = noise(fscale*P);
if(hard) t = fabsf(2.0f*t - 1.0f);
sum += t * amp;
}
sum *= ((float)(1<<oct)/(float)((1<<(oct+1))-1));
return sum;
}
CCL_NAMESPACE_END CCL_NAMESPACE_END

@ -42,7 +42,7 @@ __device float voronoi_distance(NodeDistanceMetric distance_metric, float3 d, fl
/* Voronoi / Worley like */ /* Voronoi / Worley like */
__device void voronoi(float3 p, NodeDistanceMetric distance_metric, float e, float da[4], float3 pa[4]) __device_noinline void voronoi(float3 p, NodeDistanceMetric distance_metric, float e, float da[4], float3 pa[4])
{ {
/* returns distances in da and point coords in pa */ /* returns distances in da and point coords in pa */
int xx, yy, zz, xi, yi, zi; int xx, yy, zz, xi, yi, zi;
@ -213,7 +213,7 @@ __device float noise_wave(NodeWaveType wave, float a)
/* Turbulence */ /* Turbulence */
__device float noise_turbulence(float3 p, NodeNoiseBasis basis, int octaves, int hard) __device_noinline float noise_turbulence(float3 p, NodeNoiseBasis basis, int octaves, int hard)
{ {
float fscale = 1.0f; float fscale = 1.0f;
float amp = 1.0f; float amp = 1.0f;

@ -104,6 +104,7 @@ typedef enum NodeLightPath {
NODE_LP_shadow, NODE_LP_shadow,
NODE_LP_diffuse, NODE_LP_diffuse,
NODE_LP_glossy, NODE_LP_glossy,
NODE_LP_singular,
NODE_LP_reflection, NODE_LP_reflection,
NODE_LP_transmission, NODE_LP_transmission,
NODE_LP_backfacing NODE_LP_backfacing

@ -25,8 +25,19 @@ CCL_NAMESPACE_BEGIN
Integrator::Integrator() Integrator::Integrator()
{ {
minbounce = 2; min_bounce = 2;
maxbounce = 7; max_bounce = 7;
max_diffuse_bounce = max_bounce;
max_glossy_bounce = max_bounce;
max_transmission_bounce = max_bounce;
probalistic_termination = true;
transparent_min_bounce = min_bounce;
transparent_max_bounce = max_bounce;
transparent_probalistic = true;
transparent_shadows = false;
no_caustics = false; no_caustics = false;
blur_caustics = 0.0f; blur_caustics = 0.0f;
@ -47,13 +58,29 @@ void Integrator::device_update(Device *device, DeviceScene *dscene)
KernelIntegrator *kintegrator = &dscene->data.integrator; KernelIntegrator *kintegrator = &dscene->data.integrator;
/* integrator parameters */ /* integrator parameters */
kintegrator->minbounce = minbounce + 1; kintegrator->max_bounce = max_bounce + 1;
kintegrator->maxbounce = maxbounce + 1; if(probalistic_termination)
kintegrator->min_bounce = min_bounce + 1;
else
kintegrator->min_bounce = kintegrator->max_bounce;
kintegrator->max_diffuse_bounce = max_diffuse_bounce + 1;
kintegrator->max_glossy_bounce = max_glossy_bounce + 1;
kintegrator->max_transmission_bounce = max_transmission_bounce + 1;
kintegrator->transparent_max_bounce = transparent_max_bounce + 1;
if(transparent_probalistic)
kintegrator->transparent_min_bounce = transparent_min_bounce + 1;
else
kintegrator->transparent_min_bounce = kintegrator->transparent_max_bounce;
kintegrator->transparent_shadows = transparent_shadows;
kintegrator->no_caustics = no_caustics; kintegrator->no_caustics = no_caustics;
kintegrator->blur_caustics = blur_caustics; kintegrator->blur_caustics = blur_caustics;
/* sobol directions table */ /* sobol directions table */
int dimensions = PRNG_BASE_NUM + (maxbounce + 2)*PRNG_BOUNCE_NUM; int dimensions = PRNG_BASE_NUM + (max_bounce + 2)*PRNG_BOUNCE_NUM;
uint *directions = dscene->sobol_directions.resize(SOBOL_BITS*dimensions); uint *directions = dscene->sobol_directions.resize(SOBOL_BITS*dimensions);
sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions); sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions);
@ -71,8 +98,16 @@ void Integrator::device_free(Device *device, DeviceScene *dscene)
bool Integrator::modified(const Integrator& integrator) bool Integrator::modified(const Integrator& integrator)
{ {
return !(minbounce == integrator.minbounce && return !(min_bounce == integrator.min_bounce &&
maxbounce == integrator.maxbounce && max_bounce == integrator.max_bounce &&
max_diffuse_bounce == integrator.max_diffuse_bounce &&
max_glossy_bounce == integrator.max_glossy_bounce &&
max_transmission_bounce == integrator.max_transmission_bounce &&
probalistic_termination == integrator.probalistic_termination &&
transparent_min_bounce == integrator.transparent_min_bounce &&
transparent_max_bounce == integrator.transparent_max_bounce &&
transparent_probalistic == integrator.transparent_probalistic &&
transparent_shadows == integrator.transparent_shadows &&
no_caustics == integrator.no_caustics && no_caustics == integrator.no_caustics &&
blur_caustics == integrator.blur_caustics); blur_caustics == integrator.blur_caustics);
} }

@ -27,8 +27,19 @@ class Scene;
class Integrator { class Integrator {
public: public:
int minbounce; int min_bounce;
int maxbounce; int max_bounce;
int max_diffuse_bounce;
int max_glossy_bounce;
int max_transmission_bounce;
bool probalistic_termination;
int transparent_min_bounce;
int transparent_max_bounce;
bool transparent_probalistic;
bool transparent_shadows;
bool no_caustics; bool no_caustics;
float blur_caustics; float blur_caustics;
bool need_update; bool need_update;

@ -576,6 +576,10 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
dscene->tri_woop.reference(&pack.tri_woop[0], pack.tri_woop.size()); dscene->tri_woop.reference(&pack.tri_woop[0], pack.tri_woop.size());
device->tex_alloc("__tri_woop", dscene->tri_woop); device->tex_alloc("__tri_woop", dscene->tri_woop);
} }
if(pack.prim_visibility.size()) {
dscene->prim_visibility.reference((uint*)&pack.prim_visibility[0], pack.prim_visibility.size());
device->tex_alloc("__prim_visibility", dscene->prim_visibility);
}
if(pack.prim_index.size()) { if(pack.prim_index.size()) {
dscene->prim_index.reference((uint*)&pack.prim_index[0], pack.prim_index.size()); dscene->prim_index.reference((uint*)&pack.prim_index[0], pack.prim_index.size());
device->tex_alloc("__prim_index", dscene->prim_index); device->tex_alloc("__prim_index", dscene->prim_index);
@ -686,6 +690,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
device->tex_free(dscene->bvh_nodes); device->tex_free(dscene->bvh_nodes);
device->tex_free(dscene->object_node); device->tex_free(dscene->object_node);
device->tex_free(dscene->tri_woop); device->tex_free(dscene->tri_woop);
device->tex_free(dscene->prim_visibility);
device->tex_free(dscene->prim_index); device->tex_free(dscene->prim_index);
device->tex_free(dscene->prim_object); device->tex_free(dscene->prim_object);
device->tex_free(dscene->tri_normal); device->tex_free(dscene->tri_normal);
@ -699,6 +704,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
dscene->bvh_nodes.clear(); dscene->bvh_nodes.clear();
dscene->object_node.clear(); dscene->object_node.clear();
dscene->tri_woop.clear(); dscene->tri_woop.clear();
dscene->prim_visibility.clear();
dscene->prim_index.clear(); dscene->prim_index.clear();
dscene->prim_object.clear(); dscene->prim_object.clear();
dscene->tri_normal.clear(); dscene->tri_normal.clear();

@ -1117,7 +1117,7 @@ GlassBsdfNode::GlassBsdfNode()
{ {
distribution = ustring("Sharp"); distribution = ustring("Sharp");
add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f); add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
add_input("Fresnel", SHADER_SOCKET_FLOAT, 0.3f); add_input("Fresnel", SHADER_SOCKET_FLOAT, 0.3f);
} }
@ -1490,8 +1490,8 @@ LightPathNode::LightPathNode()
add_output("Is Shadow Ray", SHADER_SOCKET_FLOAT); add_output("Is Shadow Ray", SHADER_SOCKET_FLOAT);
add_output("Is Diffuse Ray", SHADER_SOCKET_FLOAT); add_output("Is Diffuse Ray", SHADER_SOCKET_FLOAT);
add_output("Is Glossy Ray", SHADER_SOCKET_FLOAT); add_output("Is Glossy Ray", SHADER_SOCKET_FLOAT);
add_output("Is Reflection Ray", SHADER_SOCKET_FLOAT);
add_output("Is Transmission Ray", SHADER_SOCKET_FLOAT); add_output("Is Transmission Ray", SHADER_SOCKET_FLOAT);
add_output("Is Singular Ray", SHADER_SOCKET_FLOAT);
} }
void LightPathNode::compile(SVMCompiler& compiler) void LightPathNode::compile(SVMCompiler& compiler)
@ -1522,12 +1522,19 @@ void LightPathNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_glossy, out->stack_offset); compiler.add_node(NODE_LIGHT_PATH, NODE_LP_glossy, out->stack_offset);
} }
out = output("Is Singular Ray");
if(!out->links.empty()) {
compiler.stack_assign(out);
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_singular, out->stack_offset);
}
out = output("Is Reflection Ray"); out = output("Is Reflection Ray");
if(!out->links.empty()) { if(!out->links.empty()) {
compiler.stack_assign(out); compiler.stack_assign(out);
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_reflection, out->stack_offset); compiler.add_node(NODE_LIGHT_PATH, NODE_LP_reflection, out->stack_offset);
} }
out = output("Is Transmission Ray"); out = output("Is Transmission Ray");
if(!out->links.empty()) { if(!out->links.empty()) {
compiler.stack_assign(out); compiler.stack_assign(out);

@ -33,6 +33,7 @@ Object::Object()
name = ""; name = "";
mesh = NULL; mesh = NULL;
tfm = transform_identity(); tfm = transform_identity();
visibility = ~0;
} }
Object::~Object() Object::~Object()

@ -42,6 +42,7 @@ public:
BoundBox bounds; BoundBox bounds;
ustring name; ustring name;
vector<ParamValue> attributes; vector<ParamValue> attributes;
uint visibility;
Object(); Object();
~Object(); ~Object();

@ -57,6 +57,7 @@ public:
device_vector<float4> bvh_nodes; device_vector<float4> bvh_nodes;
device_vector<uint> object_node; device_vector<uint> object_node;
device_vector<float4> tri_woop; device_vector<float4> tri_woop;
device_vector<uint> prim_visibility;
device_vector<uint> prim_index; device_vector<uint> prim_index;
device_vector<uint> prim_object; device_vector<uint> prim_object;

@ -1,6 +1,11 @@
import bpy import bpy
cycles = bpy.context.scene.cycles cycles = bpy.context.scene.cycles
cycles.max_bounces = 0 cycles.max_bounces = 8
cycles.min_bounces = 0 cycles.min_bounces = 8
cycles.no_caustics = False cycles.no_caustics = True
cycles.diffuse_bounces = 0
cycles.glossy_bounces = 1
cycles.transmission_bounces = 2
cycles.transparent_min_bounces = 8
cycles.transparent_max_bounces = 8

@ -0,0 +1,11 @@
import bpy
cycles = bpy.context.scene.cycles
cycles.max_bounces = 1024
cycles.min_bounces = 3
cycles.no_caustics = False
cycles.diffuse_bounces = 1024
cycles.glossy_bounces = 1024
cycles.transmission_bounces = 1024
cycles.transparent_min_bounces = 8
cycles.transparent_max_bounces = 1024

@ -0,0 +1,11 @@
import bpy
cycles = bpy.context.scene.cycles
cycles.max_bounces = 8
cycles.min_bounces = 3
cycles.no_caustics = True
cycles.diffuse_bounces = 1
cycles.glossy_bounces = 4
cycles.transmission_bounces = 8
cycles.transparent_min_bounces = 8
cycles.transparent_max_bounces = 8

@ -33,7 +33,7 @@
static bNodeSocketType sh_node_bsdf_glass_in[]= { static bNodeSocketType sh_node_bsdf_glass_in[]= {
{ SOCK_RGBA, 1, "Color", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, { SOCK_RGBA, 1, "Color", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
{ SOCK_VALUE, 1, "Roughness", 0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { SOCK_VALUE, 1, "Roughness", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_VALUE, 1, "Fresnel", 0.3f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { SOCK_VALUE, 1, "Fresnel", 0.3f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ -1, 0, "" } { -1, 0, "" }
}; };

@ -36,6 +36,7 @@ static bNodeSocketType sh_node_light_path_out[]= {
{ SOCK_VALUE, 0, "Is Shadow Ray", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { SOCK_VALUE, 0, "Is Shadow Ray", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_VALUE, 0, "Is Diffuse Ray", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { SOCK_VALUE, 0, "Is Diffuse Ray", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_VALUE, 0, "Is Glossy Ray", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { SOCK_VALUE, 0, "Is Glossy Ray", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_VALUE, 0, "Is Singular Ray", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_VALUE, 0, "Is Reflection Ray", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { SOCK_VALUE, 0, "Is Reflection Ray", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_VALUE, 0, "Is Transmission Ray", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { SOCK_VALUE, 0, "Is Transmission Ray", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ -1, 0, "" } { -1, 0, "" }