Cycles: Expose volume voxel data interpolation to the interface
authorSergey Sharybin <sergey.vfx@gmail.com>
Wed, 22 Oct 2014 13:23:45 +0000 (19:23 +0600)
committerSergey Sharybin <sergey.vfx@gmail.com>
Wed, 22 Oct 2014 13:53:06 +0000 (19:53 +0600)
It is per-material setting which could be found under the Volume settings
in the material and world context buttons.

There could still be some code-wise improvements, like using variable-size
macro for interp3d instead of having interp3d_ex to which you can pass the
interpolation method.

intern/cycles/blender/addon/properties.py
intern/cycles/blender/addon/ui.py
intern/cycles/blender/blender_shader.cpp
intern/cycles/kernel/geom/geom_volume.h
intern/cycles/kernel/kernel_compat_cpu.h
intern/cycles/kernel/kernel_types.h
intern/cycles/render/shader.cpp
intern/cycles/render/shader.h

index 597ac1a9ce0d02dbe04f126e125b565298e4505b..05a6f70d42338d33d8dc572f59d9c9c27f039363 100644 (file)
@@ -114,6 +114,11 @@ enum_volume_sampling = (
     ('MULTIPLE_IMPORTANCE', "Multiple Importance", "Combine distance and equi-angular sampling for volumes where neither method is ideal"),
     )
 
+enum_volume_interpolation = (
+    ('LINEAR', "Linear", "Good smoothness and speed"),
+    ('CUBIC', 'Cubic', 'Smoothed high quality interpolation, but slower')
+    )
+
 
 class CyclesRenderSettings(bpy.types.PropertyGroup):
     @classmethod
@@ -617,6 +622,13 @@ class CyclesMaterialSettings(bpy.types.PropertyGroup):
                 default='DISTANCE',
                 )
 
+        cls.volume_interpolation = EnumProperty(
+                name="Volume Interpolation",
+                description="Interpolation method to use for volumes",
+                items=enum_volume_interpolation,
+                default='LINEAR',
+                )
+
     @classmethod
     def unregister(cls):
         del bpy.types.Material.cycles
@@ -693,6 +705,13 @@ class CyclesWorldSettings(bpy.types.PropertyGroup):
                 default='EQUIANGULAR',
                 )
 
+        cls.volume_interpolation = EnumProperty(
+                name="Volume Interpolation",
+                description="Interpolation method to use for volumes",
+                items=enum_volume_interpolation,
+                default='LINEAR',
+                )
+
     @classmethod
     def unregister(cls):
         del bpy.types.World.cycles
index 8743aa445be20c2a5af89ddc22ea0d61441e89c0..6a08b47b01f2e11165371267598031eb61284e3f 100644 (file)
@@ -936,6 +936,7 @@ class CyclesWorld_PT_settings(CyclesButtonsPanel, Panel):
         sub = col.column()
         sub.active = use_cpu(context)
         sub.prop(cworld, "volume_sampling", text="")
+        sub.prop(cworld, "volume_interpolation", text="")
         col.prop(cworld, "homogeneous_volume", text="Homogeneous")
 
 
@@ -1040,6 +1041,7 @@ class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
         sub = col.column()
         sub.active = use_cpu(context)
         sub.prop(cmat, "volume_sampling", text="")
+        col.prop(cmat, "volume_interpolation", text="")
         col.prop(cmat, "homogeneous_volume", text="Homogeneous")
 
 
index 33c7bf5f8591ecac6cbbc4f6622edac924366e6a..97f2ecc1a6c3a3170ccec0ee8ae99319a90f31a3 100644 (file)
@@ -1015,6 +1015,7 @@ void BlenderSync::sync_materials(bool update_all)
                        shader->use_transparent_shadow = get_boolean(cmat, "use_transparent_shadow");
                        shader->heterogeneous_volume = !get_boolean(cmat, "homogeneous_volume");
                        shader->volume_sampling_method = RNA_enum_get(&cmat, "volume_sampling");
+                       shader->volume_interpolation_method = RNA_enum_get(&cmat, "volume_interpolation");
 
                        shader->set_graph(graph);
                        shader->tag_update(scene);
@@ -1045,6 +1046,7 @@ void BlenderSync::sync_world(bool update_all)
                        PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
                        shader->heterogeneous_volume = !get_boolean(cworld, "homogeneous_volume");
                        shader->volume_sampling_method = RNA_enum_get(&cworld, "volume_sampling");
+                       shader->volume_interpolation_method = RNA_enum_get(&cworld, "volume_interpolation");
                }
                else if(b_world) {
                        ShaderNode *closure, *out;
index 33a20494966d63b7d49d13d7aac878515a2e3728..3cb6d168f809eacf0376de0a88b6a43e75f6f811 100644 (file)
@@ -52,7 +52,11 @@ ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd,
 #ifdef __KERNEL_GPU__
        float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
 #else
-       float4 r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
+       float4 r;
+       if(sd->flag & SD_VOLUME_CUBIC)
+               r = kernel_tex_image_interp_3d_ex(id, P.x, P.y, P.z, INTERPOLATION_CUBIC);
+       else
+               r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
 #endif
 
        if(dx) *dx = 0.0f;
@@ -68,7 +72,11 @@ ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *s
 #ifdef __KERNEL_GPU__
        float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
 #else
-       float4 r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
+       float4 r;
+       if(sd->flag & SD_VOLUME_CUBIC)
+               r = kernel_tex_image_interp_3d_ex(id, P.x, P.y, P.z, INTERPOLATION_CUBIC);
+       else
+               r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
 #endif
 
        if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
index e00caf5a720fb9d3579a48508c06fa4f62768fc1..37cba03ff9751743ed8d30875f51e11dc7cdaf73 100644 (file)
@@ -150,6 +150,13 @@ template<typename T> struct texture_image  {
        }
 
        ccl_always_inline float4 interp_3d(float x, float y, float z, bool periodic = false)
+       {
+               return interp_3d_ex(x, y, z, interpolation, periodic);
+       }
+
+       ccl_always_inline float4 interp_3d_ex(float x, float y, float z,
+                                             int interpolation = INTERPOLATION_LINEAR,
+                                             bool periodic = false)
        {
                if(UNLIKELY(!data))
                        return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
@@ -331,6 +338,7 @@ typedef texture_image<uchar4> texture_image_uchar4;
 #define kernel_tex_lookup(tex, t, offset, size) (kg->tex.lookup(t, offset, size))
 #define kernel_tex_image_interp(tex, x, y) ((tex < MAX_FLOAT_IMAGES) ? kg->texture_float_images[tex].interp(x, y) : kg->texture_byte_images[tex - MAX_FLOAT_IMAGES].interp(x, y))
 #define kernel_tex_image_interp_3d(tex, x, y, z) ((tex < MAX_FLOAT_IMAGES) ? kg->texture_float_images[tex].interp_3d(x, y, z) : kg->texture_byte_images[tex - MAX_FLOAT_IMAGES].interp_3d(x, y, z))
+#define kernel_tex_image_interp_3d_ex(tex, x, y, z, interpolation) ((tex < MAX_FLOAT_IMAGES) ? kg->texture_float_images[tex].interp_3d_ex(x, y, z, interpolation) : kg->texture_byte_images[tex - MAX_FLOAT_IMAGES].interp_3d_ex(x, y, z, interpolation))
 
 #define kernel_data (kg->__data)
 
index ca1210f2d8032f517819c1c417d268669d0cf349..e49a6c6669ef6318c92021a532dd7c38f0cef36b 100644 (file)
@@ -616,18 +616,20 @@ enum ShaderDataFlag {
        SD_HAS_BSSRDF_BUMP = 65536,                     /* bssrdf normal uses bump */
        SD_VOLUME_EQUIANGULAR = 131072,         /* use equiangular sampling */
        SD_VOLUME_MIS = 262144,                         /* use multiple importance sampling */
+       SD_VOLUME_CUBIC = 524288,
 
        SD_SHADER_FLAGS = (SD_USE_MIS|SD_HAS_TRANSPARENT_SHADOW|SD_HAS_VOLUME|
                           SD_HAS_ONLY_VOLUME|SD_HETEROGENEOUS_VOLUME|
-                                          SD_HAS_BSSRDF_BUMP|SD_VOLUME_EQUIANGULAR|SD_VOLUME_MIS),
+                          SD_HAS_BSSRDF_BUMP|SD_VOLUME_EQUIANGULAR|SD_VOLUME_MIS|
+                          SD_VOLUME_CUBIC),
 
        /* object flags */
-       SD_HOLDOUT_MASK = 524288,                       /* holdout for camera rays */
-       SD_OBJECT_MOTION = 1048576,                     /* has object motion blur */
-       SD_TRANSFORM_APPLIED = 2097152,         /* vertices have transform applied */
-       SD_NEGATIVE_SCALE_APPLIED = 4194304,    /* vertices have negative scale applied */
-       SD_OBJECT_HAS_VOLUME = 8388608,         /* object has a volume shader */
-       SD_OBJECT_INTERSECTS_VOLUME = 16777216, /* object intersects AABB of an object with volume shader */
+       SD_HOLDOUT_MASK = 1048576,                      /* holdout for camera rays */
+       SD_OBJECT_MOTION = 2097152,                     /* has object motion blur */
+       SD_TRANSFORM_APPLIED = 4194304,         /* vertices have transform applied */
+       SD_NEGATIVE_SCALE_APPLIED = 8388608,    /* vertices have negative scale applied */
+       SD_OBJECT_HAS_VOLUME = 16777216,                /* object has a volume shader */
+       SD_OBJECT_INTERSECTS_VOLUME = 33554432, /* object intersects AABB of an object with volume shader */
 
        SD_OBJECT_FLAGS = (SD_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_TRANSFORM_APPLIED|
                           SD_NEGATIVE_SCALE_APPLIED|SD_OBJECT_HAS_VOLUME|
index d8925852c2177ecff66359c2da96b3be1569ed00..b960dfa3861e546f4dff2bcf1aa1eb8388a5b8c4 100644 (file)
@@ -139,6 +139,7 @@ Shader::Shader()
        use_transparent_shadow = true;
        heterogeneous_volume = true;
        volume_sampling_method = 0;
+       volume_interpolation_method = 0;
 
        has_surface = false;
        has_surface_transparent = false;
@@ -356,6 +357,8 @@ void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Sc
                        flag |= SD_VOLUME_EQUIANGULAR;
                if(shader->volume_sampling_method == 2)
                        flag |= SD_VOLUME_MIS;
+               if(shader->volume_interpolation_method == 1)
+                       flag |= SD_VOLUME_CUBIC;
 
                /* regular shader */
                shader_flag[i++] = flag;
index 368496fd188a9b50c2091be24b2db6888f79118a..0eef62a1c615b2d036c3d7b6489139a517be11b8 100644 (file)
@@ -69,6 +69,7 @@ public:
        bool use_transparent_shadow;
        bool heterogeneous_volume;
        int volume_sampling_method;
+       int volume_interpolation_method;
 
        /* synchronization */
        bool need_update;