Cycles: option to make background visible through glass transparent.
authorLukas Stockner <lukas.stockner@freenet.de>
Thu, 11 Jan 2018 19:03:31 +0000 (20:03 +0100)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Fri, 12 Jan 2018 00:34:28 +0000 (01:34 +0100)
This can be enabled in the Film panel, with an option to control the
transmisison roughness below which glass becomes transparent.

Differential Revision: https://developer.blender.org/D2904

intern/cycles/blender/addon/properties.py
intern/cycles/blender/addon/ui.py
intern/cycles/blender/blender_shader.cpp
intern/cycles/kernel/closure/bsdf.h
intern/cycles/kernel/kernel_accumulate.h
intern/cycles/kernel/kernel_passes.h
intern/cycles/kernel/kernel_path.h
intern/cycles/kernel/kernel_path_state.h
intern/cycles/kernel/kernel_types.h
intern/cycles/render/background.cpp
intern/cycles/render/background.h

index 263d90d..7410cc3 100644 (file)
@@ -413,9 +413,20 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
                 )
         cls.film_transparent = BoolProperty(
                 name="Transparent",
-                description="World background is transparent with premultiplied alpha",
+                description="World background is transparent, for compositing the render over another background",
                 default=False,
                 )
+        cls.film_transparent_glass = BoolProperty(
+                name="Transparent Glass",
+                description="Render transmissive surfaces as transparent, for compositing glass over another background",
+                default=False,
+                )
+        cls.film_transparent_roughness = FloatProperty(
+                name="Transparent Roughness Threshold",
+                description="For transparent transmission, keep surfaces with roughness above the threshold opaque",
+                min=0.0, max=1.0,
+                default=0.1,
+                )
 
         # Really annoyingly, we have to keep it around for a few releases,
         # otherwise forward compatibility breaks in really bad manner: CRASH!
index 5bb0ea1..5d58ecc 100644 (file)
@@ -367,14 +367,21 @@ class CYCLES_RENDER_PT_film(CyclesButtonsPanel, Panel):
 
         col = split.column()
         col.prop(cscene, "film_exposure")
-        col.prop(cscene, "film_transparent")
-
-        col = split.column()
+        col.separator()
         sub = col.column(align=True)
         sub.prop(cscene, "pixel_filter_type", text="")
         if cscene.pixel_filter_type != 'BOX':
             sub.prop(cscene, "filter_width", text="Width")
 
+        col = split.column()
+        col.prop(cscene, "film_transparent")
+        sub = col.row()
+        sub.prop(cscene, "film_transparent_glass", text="Transparent Glass")
+        sub.active = cscene.film_transparent
+        sub = col.row()
+        sub.prop(cscene, "film_transparent_roughness", text="Roughness Threshold")
+        sub.active = cscene.film_transparent and cscene.film_transparent_glass
+
 
 class CYCLES_RENDER_PT_performance(CyclesButtonsPanel, Panel):
     bl_label = "Performance"
index a90e0d3..67845bb 100644 (file)
@@ -1333,6 +1333,15 @@ void BlenderSync::sync_world(bool update_all)
        else
                background->transparent = b_scene.render().alpha_mode() == BL::RenderSettings::alpha_mode_TRANSPARENT;
 
+       if(background->transparent) {
+               background->transparent_glass = get_boolean(cscene, "film_transparent_glass");
+               background->transparent_roughness_threshold = get_float(cscene, "film_transparent_roughness");
+       }
+       else {
+               background->transparent_glass = false;
+               background->transparent_roughness_threshold = 0.0f;
+       }
+
        background->use_shader = render_layer.use_background_shader;
        background->use_ao = background->use_ao && render_layer.use_background_ao;
 
index e457302..6f0bdb3 100644 (file)
@@ -38,7 +38,7 @@ CCL_NAMESPACE_BEGIN
 
 /* Returns the square of the roughness of the closure if it has roughness,
  * 0 for singular closures and 1 otherwise. */
-ccl_device_inline float bsdf_get_roughness_sqr(const ShaderClosure *sc)
+ccl_device_inline float bsdf_get_roughness_squared(const ShaderClosure *sc)
 {
        if(CLOSURE_IS_BSDF_SINGULAR(sc->type)) {
                return 0.0f;
@@ -173,6 +173,17 @@ ccl_device_forceinline int bsdf_sample(KernelGlobals *kg,
                        break;
        }
 
+       /* Test if BSDF sample should be treated as transparent for background. */
+       if(label & LABEL_TRANSMIT) {
+               float threshold_squared = kernel_data.background.transparent_roughness_squared_threshold;
+
+               if(threshold_squared >= 0.0f) {
+                       if(bsdf_get_roughness_squared(sc) <= threshold_squared) {
+                               label |= LABEL_TRANSMIT_TRANSPARENT;
+                       }
+               }
+       }
+
        return label;
 }
 
index 7c1b2a0..c0f281c 100644 (file)
@@ -455,7 +455,7 @@ ccl_device_inline void path_radiance_accum_background(
 
 #ifdef __PASSES__
        if(L->use_light_pass) {
-               if(state->bounce == 0)
+               if(state->flag & PATH_RAY_TRANSPARENT_BACKGROUND)
                        L->background += throughput*value;
                else if(state->bounce == 1)
                        L->direct_emission += throughput*value;
index 29451b6..1933d69 100644 (file)
@@ -140,7 +140,7 @@ ccl_device_inline void kernel_update_denoising_features(KernelGlobals *kg,
                /* All closures contribute to the normal feature, but only diffuse-like ones to the albedo. */
                normal += sc->N * sc->sample_weight;
                sum_weight += sc->sample_weight;
-               if(bsdf_get_roughness_sqr(sc) > sqr(0.075f)) {
+               if(bsdf_get_roughness_squared(sc) > sqr(0.075f)) {
                        albedo += sc->weight;
                        sum_nonspecular_weight += sc->sample_weight;
                }
index c2421c1..1e98bca 100644 (file)
@@ -136,7 +136,7 @@ ccl_device_forceinline void kernel_path_background(
        PathRadiance *L)
 {
        /* eval background shader if nothing hit */
-       if(kernel_data.background.transparent && (state->flag & PATH_RAY_CAMERA)) {
+       if(kernel_data.background.transparent && (state->flag & PATH_RAY_TRANSPARENT_BACKGROUND)) {
                L->transparent += average(throughput);
 
 #ifdef __PASSES__
@@ -280,7 +280,7 @@ ccl_device_forceinline bool kernel_path_shader_apply(
 {
 #ifdef __SHADOW_TRICKS__
        if((sd->object_flag & SD_OBJECT_SHADOW_CATCHER)) {
-               if(state->flag & PATH_RAY_CAMERA) {
+               if(state->flag & PATH_RAY_TRANSPARENT_BACKGROUND) {
                        state->flag |= (PATH_RAY_SHADOW_CATCHER |
                                                   PATH_RAY_STORE_SHADOW_INFO);
 
@@ -302,7 +302,7 @@ ccl_device_forceinline bool kernel_path_shader_apply(
 #ifdef __HOLDOUT__
        if(((sd->flag & SD_HOLDOUT) ||
                (sd->object_flag & SD_OBJECT_HOLDOUT_MASK)) &&
-          (state->flag & PATH_RAY_CAMERA))
+          (state->flag & PATH_RAY_TRANSPARENT_BACKGROUND))
        {
                if(kernel_data.background.transparent) {
                        float3 holdout_weight;
index eccee54..505eed1 100644 (file)
@@ -23,7 +23,7 @@ ccl_device_inline void path_state_init(KernelGlobals *kg,
                                        int sample,
                                        ccl_addr_space Ray *ray)
 {
-       state->flag = PATH_RAY_CAMERA|PATH_RAY_MIS_SKIP;
+       state->flag = PATH_RAY_CAMERA|PATH_RAY_MIS_SKIP|PATH_RAY_TRANSPARENT_BACKGROUND;
 
        state->rng_hash = rng_hash;
        state->rng_offset = PRNG_BASE_NUM;
@@ -86,12 +86,13 @@ ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathSta
        }
 
        state->bounce++;
+       state->flag &= ~(PATH_RAY_ALL_VISIBILITY|PATH_RAY_MIS_SKIP);
 
 #ifdef __VOLUME__
        if(label & LABEL_VOLUME_SCATTER) {
                /* volume scatter */
                state->flag |= PATH_RAY_VOLUME_SCATTER;
-               state->flag &= ~(PATH_RAY_REFLECT|PATH_RAY_TRANSMIT|PATH_RAY_CAMERA|PATH_RAY_TRANSPARENT|PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP);
+               state->flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND;
 
                state->volume_bounce++;
        }
@@ -101,7 +102,7 @@ ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathSta
                /* surface reflection/transmission */
                if(label & LABEL_REFLECT) {
                        state->flag |= PATH_RAY_REFLECT;
-                       state->flag &= ~(PATH_RAY_TRANSMIT|PATH_RAY_VOLUME_SCATTER|PATH_RAY_CAMERA|PATH_RAY_TRANSPARENT);
+                       state->flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND;
 
                        if(label & LABEL_DIFFUSE)
                                state->diffuse_bounce++;
@@ -112,7 +113,10 @@ ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathSta
                        kernel_assert(label & LABEL_TRANSMIT);
 
                        state->flag |= PATH_RAY_TRANSMIT;
-                       state->flag &= ~(PATH_RAY_REFLECT|PATH_RAY_VOLUME_SCATTER|PATH_RAY_CAMERA|PATH_RAY_TRANSPARENT);
+
+                       if(!(label & LABEL_TRANSMIT_TRANSPARENT)) {
+                               state->flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND;
+                       }
 
                        state->transmission_bounce++;
                }
@@ -120,17 +124,13 @@ ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathSta
                /* diffuse/glossy/singular */
                if(label & LABEL_DIFFUSE) {
                        state->flag |= PATH_RAY_DIFFUSE|PATH_RAY_DIFFUSE_ANCESTOR;
-                       state->flag &= ~(PATH_RAY_GLOSSY|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP);
                }
                else if(label & LABEL_GLOSSY) {
                        state->flag |= PATH_RAY_GLOSSY;
-                       state->flag &= ~(PATH_RAY_DIFFUSE|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP);
                }
                else {
                        kernel_assert(label & LABEL_SINGULAR);
-
                        state->flag |= PATH_RAY_GLOSSY|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP;
-                       state->flag &= ~PATH_RAY_DIFFUSE;
                }
        }
 
index b052d66..4f65578 100644 (file)
@@ -346,11 +346,12 @@ enum PathRayFlag {
 
        PATH_RAY_ALL_VISIBILITY = ((1 << 14)-1),
 
-       PATH_RAY_MIS_SKIP            = (1 << 15),
-       PATH_RAY_DIFFUSE_ANCESTOR    = (1 << 16),
-       PATH_RAY_SINGLE_PASS_DONE    = (1 << 17),
-       PATH_RAY_SHADOW_CATCHER      = (1 << 18),
-       PATH_RAY_STORE_SHADOW_INFO   = (1 << 19),
+       PATH_RAY_MIS_SKIP               = (1 << 15),
+       PATH_RAY_DIFFUSE_ANCESTOR       = (1 << 16),
+       PATH_RAY_SINGLE_PASS_DONE       = (1 << 17),
+       PATH_RAY_SHADOW_CATCHER         = (1 << 18),
+       PATH_RAY_STORE_SHADOW_INFO      = (1 << 19),
+       PATH_RAY_TRANSPARENT_BACKGROUND = (1 << 20),
 };
 
 /* Closure Label */
@@ -364,6 +365,7 @@ typedef enum ClosureLabel {
        LABEL_SINGULAR = 16,
        LABEL_TRANSPARENT = 32,
        LABEL_VOLUME_SCATTER = 64,
+       LABEL_TRANSMIT_TRANSPARENT = 128,
 } ClosureLabel;
 
 /* Render Passes */
@@ -1259,7 +1261,7 @@ typedef struct KernelBackground {
        int surface_shader;
        int volume_shader;
        int transparent;
-       int pad;
+       float transparent_roughness_squared_threshold;
 
        /* ambient occlusion */
        float ao_factor;
index 3ed9673..df3b65b 100644 (file)
@@ -38,7 +38,10 @@ NODE_DEFINE(Background)
        SOCKET_BOOLEAN(use_shader, "Use Shader", true);
        SOCKET_BOOLEAN(use_ao, "Use AO", false);
        SOCKET_UINT(visibility, "Visibility", PATH_RAY_ALL_VISIBILITY);
+
        SOCKET_BOOLEAN(transparent, "Transparent", false);
+       SOCKET_BOOLEAN(transparent_glass, "Transparent Glass", false);
+       SOCKET_FLOAT(transparent_roughness_threshold, "Transparent Roughness Threshold", 0.0f);
 
        SOCKET_NODE(shader, "Shader", &Shader::node_type);
 
@@ -81,6 +84,15 @@ void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene
        kbackground->transparent = transparent;
        kbackground->surface_shader = scene->shader_manager->get_shader_id(bg_shader);
 
+       if(transparent && transparent_glass) {
+               /* Square twice, once for principled BSDF convention, and once for
+                * faster comparison in kernel with anisotropic roughness. */
+               kbackground->transparent_roughness_squared_threshold = sqr(sqr(transparent_roughness_threshold));
+       }
+       else {
+               kbackground->transparent_roughness_squared_threshold = -1.0f;
+       }
+
        if(bg_shader->has_volume)
                kbackground->volume_shader = kbackground->surface_shader;
        else
index db20b6e..145c05f 100644 (file)
@@ -42,6 +42,9 @@ public:
        Shader *shader;
 
        bool transparent;
+       bool transparent_glass;
+       float transparent_roughness_threshold;
+
        bool need_update;
 
        Background();