Cycles microdisplacement: Move displacement options from mesh to material settings
authorMai Lavelle <mai.lavelle@gmail.com>
Tue, 2 Aug 2016 09:13:58 +0000 (05:13 -0400)
committerMai Lavelle <mai.lavelle@gmail.com>
Sun, 7 Aug 2016 18:15:20 +0000 (14:15 -0400)
Displacement is now a per material setting, which means old files will have to
be updated if they had used displacement. Cool side effect of this change is
material previews now show displacement.

Reviewed By: brecht

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

intern/cycles/blender/addon/properties.py
intern/cycles/blender/addon/ui.py
intern/cycles/blender/blender_mesh.cpp
intern/cycles/blender/blender_shader.cpp
intern/cycles/render/mesh.cpp
intern/cycles/render/mesh.h
intern/cycles/render/mesh_displace.cpp
intern/cycles/render/object.cpp
intern/cycles/render/shader.cpp
intern/cycles/render/shader.h

index 81204eb8ae0bfe1a2f82368fc750b862fb275c4b..8e82eac2b59d65e7329c7c08aafd703e958600a1 100644 (file)
@@ -775,6 +775,13 @@ class CyclesMaterialSettings(bpy.types.PropertyGroup):
                 default='LINEAR',
                 )
 
+        cls.displacement_method = EnumProperty(
+                name="Displacement Method",
+                description="Method to use for the displacement",
+                items=enum_displacement_methods,
+                default='BUMP',
+                )
+
     @classmethod
     def unregister(cls):
         del bpy.types.Material.cycles
@@ -952,13 +959,6 @@ class CyclesMeshSettings(bpy.types.PropertyGroup):
                 type=cls,
                 )
 
-        cls.displacement_method = EnumProperty(
-                name="Displacement Method",
-                description="Method to use for the displacement",
-                items=enum_displacement_methods,
-                default='BUMP',
-                )
-
     @classmethod
     def unregister(cls):
         del bpy.types.Mesh.cycles
index 42f7970769acd8f60f75cbfa02e0e24b4d9adb89..52872d2b83fa8c59d4ea866973143ad5aae627f1 100644 (file)
@@ -674,40 +674,6 @@ class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
             split.separator()
 
 
-class Cycles_PT_mesh_displacement(CyclesButtonsPanel, Panel):
-    bl_label = "Displacement"
-    bl_context = "data"
-
-    @classmethod
-    def poll(cls, context):
-        if CyclesButtonsPanel.poll(context):
-            if context.mesh or context.curve or context.meta_ball:
-                if context.scene.cycles.feature_set == 'EXPERIMENTAL':
-                    return True
-
-        return False
-
-    def draw(self, context):
-        layout = self.layout
-
-        mesh = context.mesh
-        curve = context.curve
-        mball = context.meta_ball
-
-        if mesh:
-            cdata = mesh.cycles
-        elif curve:
-            cdata = curve.cycles
-        elif mball:
-            cdata = mball.cycles
-
-        split = layout.split()
-
-        col = split.column()
-        sub = col.column(align=True)
-        sub.label(text="Displacement:")
-        sub.prop(cdata, "displacement_method", text="")
-
 class CyclesObject_PT_motion_blur(CyclesButtonsPanel, Panel):
     bl_label = "Motion Blur"
     bl_context = "object"
@@ -1219,6 +1185,11 @@ class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
         col.prop(cmat, "sample_as_light", text="Multiple Importance")
         col.prop(cmat, "use_transparent_shadow")
 
+        if context.scene.cycles.feature_set == 'EXPERIMENTAL':
+            col.separator()
+            col.label(text="Displacement:")
+            col.prop(cmat, "displacement_method", text="")
+
         col = split.column()
         col.label(text="Volume:")
         sub = col.column()
index b4c490c0d330c24dbf9733b0efa3674d005efdda..11aef55c277a76e7203645bb83a9752a7783d135 100644 (file)
@@ -1008,21 +1008,6 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
        }
        mesh->geometry_flags = requested_geometry_flags;
 
-       /* displacement method */
-       if(cmesh.data) {
-               const int method = get_enum(cmesh,
-                                           "displacement_method",
-                                           Mesh::DISPLACE_NUM_METHODS,
-                                           Mesh::DISPLACE_BUMP);
-
-               if(method == 0 || !experimental)
-                       mesh->displacement_method = Mesh::DISPLACE_BUMP;
-               else if(method == 1)
-                       mesh->displacement_method = Mesh::DISPLACE_TRUE;
-               else
-                       mesh->displacement_method = Mesh::DISPLACE_BOTH;
-       }
-
        /* fluid motion */
        sync_mesh_fluid_motion(b_ob, scene, mesh);
 
index 2fe8ee90334dc5c7777a873e18cc06870b1c8a6c..534bc6cc8973ccac0ec9af4d9fe76c80ce0a9610 100644 (file)
@@ -64,6 +64,14 @@ static VolumeInterpolation get_volume_interpolation(PointerRNA& ptr)
                                             VOLUME_INTERPOLATION_LINEAR);
 }
 
+static DisplacementMethod get_displacement_method(PointerRNA& ptr)
+{
+       return (DisplacementMethod)get_enum(ptr,
+                                           "displacement_method",
+                                           DISPLACE_NUM_METHODS,
+                                           DISPLACE_BUMP);
+}
+
 static int validate_enum_value(int value, int num_values, int default_value)
 {
        if(value >= num_values) {
@@ -1182,6 +1190,7 @@ void BlenderSync::sync_materials(bool update_all)
                        shader->heterogeneous_volume = !get_boolean(cmat, "homogeneous_volume");
                        shader->volume_sampling_method = get_volume_sampling(cmat);
                        shader->volume_interpolation_method = get_volume_interpolation(cmat);
+                       shader->displacement_method = (experimental) ? get_displacement_method(cmat) : DISPLACE_BUMP;
 
                        shader->set_graph(graph);
                        shader->tag_update(scene);
index 0a8122199443d77c0bd3443ad2e34d882b8166f9..f90c19a11c867003f1a0c713383d279c463dcea0 100644 (file)
@@ -120,12 +120,6 @@ NODE_DEFINE(Mesh)
 {
        NodeType* type = NodeType::add("mesh", create);
 
-       static NodeEnum displacement_method_enum;
-       displacement_method_enum.insert("bump", DISPLACE_BUMP);
-       displacement_method_enum.insert("true", DISPLACE_TRUE);
-       displacement_method_enum.insert("both", DISPLACE_BOTH);
-       SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP);
-
        SOCKET_UINT(motion_steps, "Motion Steps", 3);
        SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false);
 
@@ -787,6 +781,17 @@ bool Mesh::has_motion_blur() const
                 curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)));
 }
 
+bool Mesh::has_true_displacement() const
+{
+       foreach(Shader *shader, used_shaders) {
+               if(shader->has_displacement && shader->displacement_method != DISPLACE_BUMP) {
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 bool Mesh::need_build_bvh() const
 {
        return !transform_applied || has_surface_bssrdf;
@@ -1659,7 +1664,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
        bool old_need_object_flags_update = false;
        foreach(Mesh *mesh, scene->meshes) {
                if(mesh->need_update &&
-                  mesh->displacement_method != Mesh::DISPLACE_BUMP)
+                  mesh->has_true_displacement())
                {
                        true_displacement_used = true;
                        break;
index 2436d6aa23177182c45851d60d786b6a88624c6f..eff5c50e63505fb0d2432d1fe9ab0255eaf658cf 100644 (file)
@@ -116,15 +116,6 @@ public:
                float crease;
        };
 
-       /* Displacement */
-       enum DisplacementMethod {
-               DISPLACE_BUMP = 0,
-               DISPLACE_TRUE = 1,
-               DISPLACE_BOTH = 2,
-
-               DISPLACE_NUM_METHODS,
-       };
-
        enum SubdivisionType {
                SUBDIVISION_NONE,
                SUBDIVISION_LINEAR,
@@ -174,7 +165,6 @@ public:
        bool transform_applied;
        bool transform_negative_scaled;
        Transform transform_normal;
-       DisplacementMethod displacement_method;
 
        PackedPatchTable *patch_table;
 
@@ -245,6 +235,7 @@ public:
        void tag_update(Scene *scene, bool rebuild);
 
        bool has_motion_blur() const;
+       bool has_true_displacement() const;
 
        /* Check whether the mesh should have own BVH built separately. Briefly,
         * own BVH is needed for mesh, if:
index 95f46ff02a2b21ec80e51ca87f9af4ef525195e2..ef9cfedd4124209d28bf43748d6046a43652ec4b 100644 (file)
 
 CCL_NAMESPACE_BEGIN
 
+static float3 compute_face_normal(const Mesh::Triangle& t, float3 *verts)
+{
+       float3 v0 = verts[t.v[0]];
+       float3 v1 = verts[t.v[1]];
+       float3 v2 = verts[t.v[2]];
+
+       float3 norm = cross(v1 - v0, v2 - v0);
+       float normlen = len(norm);
+
+       if(normlen == 0.0f)
+               return make_float3(1.0f, 0.0f, 0.0f);
+
+       return norm / normlen;
+}
+
 bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress& progress)
 {
        /* verify if we have a displacement shader */
-       bool has_displacement = false;
-
-       if(mesh->displacement_method != Mesh::DISPLACE_BUMP) {
-               foreach(Shader *shader, mesh->used_shaders)
-                       if(shader->has_displacement)
-                               has_displacement = true;
-       }
-       
-       if(!has_displacement)
+       if(!mesh->has_true_displacement()) {
                return false;
+       }
 
        string msg = string_printf("Computing Displacement %s", mesh->name.c_str());
        progress.set_status("Updating Mesh", msg);
@@ -67,8 +75,9 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
                Shader *shader = (shader_index < mesh->used_shaders.size()) ?
                        mesh->used_shaders[shader_index] : scene->default_surface;
 
-               if(!shader->has_displacement)
+               if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) {
                        continue;
+               }
 
                for(int j = 0; j < 3; j++) {
                        if(done[t.v[j]])
@@ -153,8 +162,9 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
                Shader *shader = (shader_index < mesh->used_shaders.size()) ?
                        mesh->used_shaders[shader_index] : scene->default_surface;
 
-               if(!shader->has_displacement)
+               if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) {
                        continue;
+               }
 
                for(int j = 0; j < 3; j++) {
                        if(!done[t.v[j]]) {
@@ -178,9 +188,131 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
        mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
        mesh->add_face_normals();
 
-       if(mesh->displacement_method == Mesh::DISPLACE_TRUE) {
-               mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
-               mesh->add_vertex_normals();
+       bool need_recompute_vertex_normals = false;
+
+       foreach(Shader *shader, mesh->used_shaders) {
+               if(shader->has_displacement && shader->displacement_method == DISPLACE_TRUE) {
+                       need_recompute_vertex_normals = true;
+                       break;
+               }
+       }
+
+       if(need_recompute_vertex_normals) {
+               bool flip = mesh->transform_negative_scaled;
+               vector<bool> tri_has_true_disp(num_triangles, false);
+
+               for(size_t i = 0; i < num_triangles; i++) {
+                       int shader_index = mesh->shader[i];
+                       Shader *shader = (shader_index < mesh->used_shaders.size()) ?
+                               mesh->used_shaders[shader_index] : scene->default_surface;
+
+                       tri_has_true_disp[i] = shader->has_displacement && shader->displacement_method == DISPLACE_TRUE;
+               }
+
+               /* static vertex normals */
+
+               /* get attributes */
+               Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL);
+               Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
+
+               float3 *fN = attr_fN->data_float3();
+               float3 *vN = attr_vN->data_float3();
+
+               /* compute vertex normals */
+
+               /* zero vertex normals on triangles with true displacement */
+               for(size_t i = 0; i < num_triangles; i++) {
+                       if(tri_has_true_disp[i]) {
+                               for(size_t j = 0; j < 3; j++) {
+                                       vN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f);
+                               }
+                       }
+               }
+
+               /* add face normals to vertex normals */
+               for(size_t i = 0; i < num_triangles; i++) {
+                       if(tri_has_true_disp[i]) {
+                               for(size_t j = 0; j < 3; j++) {
+                                       vN[mesh->get_triangle(i).v[j]] += fN[i];
+                               }
+                       }
+               }
+
+               /* normalize vertex normals */
+               done.clear();
+               done.resize(num_verts, false);
+
+               for(size_t i = 0; i < num_triangles; i++) {
+                       if(tri_has_true_disp[i]) {
+                               for(size_t j = 0; j < 3; j++) {
+                                       int vert = mesh->get_triangle(i).v[j];
+
+                                       if(done[vert]) {
+                                               continue;
+                                       }
+
+                                       vN[vert] = normalize(vN[vert]);
+                                       if(flip)
+                                               vN[vert] = -vN[vert];
+
+                                       done[vert] = true;
+                               }
+                       }
+               }
+
+               /* motion vertex normals */
+               Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+               Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
+
+               if(mesh->has_motion_blur() && attr_mP && attr_mN) {
+                       for(int step = 0; step < mesh->motion_steps - 1; step++) {
+                               float3 *mP = attr_mP->data_float3() + step*mesh->verts.size();
+                               float3 *mN = attr_mN->data_float3() + step*mesh->verts.size();
+
+                               /* compute */
+
+                               /* zero vertex normals on triangles with true displacement */
+                               for(size_t i = 0; i < num_triangles; i++) {
+                                       if(tri_has_true_disp[i]) {
+                                               for(size_t j = 0; j < 3; j++) {
+                                                       mN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f);
+                                               }
+                                       }
+                               }
+
+                               /* add face normals to vertex normals */
+                               for(size_t i = 0; i < num_triangles; i++) {
+                                       if(tri_has_true_disp[i]) {
+                                               for(size_t j = 0; j < 3; j++) {
+                                                       float3 fN = compute_face_normal(mesh->get_triangle(i), mP);
+                                                       mN[mesh->get_triangle(i).v[j]] += fN;
+                                               }
+                                       }
+                               }
+
+                               /* normalize vertex normals */
+                               done.clear();
+                               done.resize(num_verts, false);
+
+                               for(size_t i = 0; i < num_triangles; i++) {
+                                       if(tri_has_true_disp[i]) {
+                                               for(size_t j = 0; j < 3; j++) {
+                                                       int vert = mesh->get_triangle(i).v[j];
+
+                                                       if(done[vert]) {
+                                                               continue;
+                                                       }
+
+                                                       mN[vert] = normalize(mN[vert]);
+                                                       if(flip)
+                                                               mN[vert] = -mN[vert];
+
+                                                       done[vert] = true;
+                                               }
+                                       }
+                               }
+                       }
+               }
        }
 
        return true;
index eeb44f4668571e5e3f4d8e2a8641ea3ab5a3ff40..28cc4fe58fa42ad53d980245f739254664e06171 100644 (file)
@@ -689,7 +689,7 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
                 * Could be solved by moving reference counter to Mesh.
                 */
                if((mesh_users[object->mesh] == 1 && !object->mesh->has_surface_bssrdf) &&
-                  object->mesh->displacement_method == Mesh::DISPLACE_BUMP)
+                  !object->mesh->has_true_displacement())
                {
                        if(!(motion_blur && object->use_motion)) {
                                if(!object->mesh->transform_applied) {
index 4cdb878df45df8572bd0ae72d3c6c34500bb28f3..d000cca5a4504118fb55fc9091ea18bf60eb438a 100644 (file)
@@ -150,6 +150,12 @@ NODE_DEFINE(Shader)
        volume_interpolation_method_enum.insert("cubic", VOLUME_INTERPOLATION_CUBIC);
        SOCKET_ENUM(volume_interpolation_method, "Volume Interpolation Method", volume_interpolation_method_enum, VOLUME_INTERPOLATION_LINEAR);
 
+       static NodeEnum displacement_method_enum;
+       displacement_method_enum.insert("bump", DISPLACE_BUMP);
+       displacement_method_enum.insert("true", DISPLACE_TRUE);
+       displacement_method_enum.insert("both", DISPLACE_BOTH);
+       SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP);
+
        return type;
 }
 
@@ -173,6 +179,8 @@ Shader::Shader()
        has_object_dependency = false;
        has_integrator_dependency = false;
 
+       displacement_method = DISPLACE_BUMP;
+
        id = -1;
        used = false;
 
@@ -310,7 +318,7 @@ int ShaderManager::get_shader_id(Shader *shader, Mesh *mesh, bool smooth)
        int id = shader->id*2;
        
        /* index depends bump since this setting is not in the shader */
-       if(mesh && mesh->displacement_method != Mesh::DISPLACE_TRUE)
+       if(mesh && shader->displacement_method != DISPLACE_TRUE)
                id += 1;
        /* smooth flag */
        if(smooth)
index dc57ed4e4eb4decd7caf74a684f540969b2e6a19..060ad7056bc33eab82410707af183bfe23ee0fd7 100644 (file)
@@ -66,6 +66,14 @@ enum VolumeInterpolation {
        VOLUME_NUM_INTERPOLATION,
 };
 
+enum DisplacementMethod {
+       DISPLACE_BUMP = 0,
+       DISPLACE_TRUE = 1,
+       DISPLACE_BOTH = 2,
+
+       DISPLACE_NUM_METHODS,
+};
+
 /* Shader describing the appearance of a Mesh, Light or Background.
  *
  * While there is only a single shader graph, it has three outputs: surface,
@@ -110,6 +118,9 @@ public:
        bool has_object_dependency;
        bool has_integrator_dependency;
 
+       /* displacement */
+       DisplacementMethod displacement_method;
+
        /* requested mesh attributes */
        AttributeRequestSet attributes;