Cleanup: export particle hair as a separate Cycles object
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Sun, 2 Feb 2020 12:09:18 +0000 (13:09 +0100)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Fri, 7 Feb 2020 11:18:15 +0000 (12:18 +0100)
intern/cycles/blender/blender_curves.cpp
intern/cycles/blender/blender_mesh.cpp
intern/cycles/blender/blender_object.cpp
intern/cycles/blender/blender_sync.cpp
intern/cycles/blender/blender_sync.h
intern/cycles/blender/blender_util.h

index 78db1d5c832820109fe9bb58d879f6eead24f9f5..755214f422c0cbd05839e0bd6373da71f6d8c03e 100644 (file)
@@ -964,7 +964,29 @@ void BlenderSync::sync_curve_settings()
     curve_system_manager->tag_update(scene);
 }
 
-void BlenderSync::sync_curves(
+bool BlenderSync::object_has_particle_hair(BL::Object b_ob)
+{
+  /* Test if the object has a particle modifier with hair. */
+  BL::Object::modifiers_iterator b_mod;
+  for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
+    if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) &&
+        (preview ? b_mod->show_viewport() : b_mod->show_render())) {
+      BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
+      BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
+      BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+
+      if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
+          (b_part.type() == BL::ParticleSettings::type_HAIR)) {
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+/* Old particle hair. */
+void BlenderSync::sync_particle_hair(
     Mesh *mesh, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step)
 {
   if (!motion) {
index b18f9a37948cc0ae779d3c73e76dfd8242849bff..d3dac3c615142dd9eac64516c1f5892f232d5d01 100644 (file)
@@ -967,12 +967,12 @@ Mesh *BlenderSync::sync_mesh(BL::Depsgraph &b_depsgraph,
                              BL::Object &b_ob,
                              BL::Object &b_ob_instance,
                              bool object_updated,
-                             bool show_self,
-                             bool show_particles)
+                             bool use_particle_hair)
 {
   /* test if we can instance or if the object is modified */
   BL::ID b_ob_data = b_ob.data();
-  BL::ID key = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data;
+  BL::ID b_key_id = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data;
+  MeshKey key(b_key_id.ptr.data, use_particle_hair);
   BL::Material material_override = view_layer.material_override;
 
   /* find shader indices */
@@ -1006,7 +1006,7 @@ Mesh *BlenderSync::sync_mesh(BL::Depsgraph &b_depsgraph,
   }
   Mesh *mesh;
 
-  if (!mesh_map.sync(&mesh, key)) {
+  if (!mesh_map.sync(&mesh, b_key_id, key)) {
     /* if transform was applied to mesh, need full update */
     if (object_updated && mesh->transform_applied)
       ;
@@ -1078,7 +1078,7 @@ Mesh *BlenderSync::sync_mesh(BL::Depsgraph &b_depsgraph,
 
     if (b_mesh) {
       /* Sync mesh itself. */
-      if (view_layer.use_surfaces && show_self) {
+      if (view_layer.use_surfaces && !use_particle_hair) {
         if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE)
           create_subd_mesh(scene, mesh, b_ob, b_mesh, used_shaders, dicing_rate, max_subdivisions);
         else
@@ -1088,9 +1088,9 @@ Mesh *BlenderSync::sync_mesh(BL::Depsgraph &b_depsgraph,
       }
 
       /* Sync hair curves. */
-      if (view_layer.use_hair && show_particles &&
+      if (view_layer.use_hair && use_particle_hair &&
           mesh->subdivision_type == Mesh::SUBDIVISION_NONE) {
-        sync_curves(mesh, b_mesh, b_ob, false);
+        sync_particle_hair(mesh, b_mesh, b_ob, false);
       }
 
       free_object_to_mesh(b_data, b_ob, b_mesh);
@@ -1099,7 +1099,9 @@ Mesh *BlenderSync::sync_mesh(BL::Depsgraph &b_depsgraph,
   mesh->geometry_flags = requested_geometry_flags;
 
   /* mesh fluid motion mantaflow */
-  sync_mesh_fluid_motion(b_ob, scene, mesh);
+  if (!use_particle_hair) {
+    sync_mesh_fluid_motion(b_ob, scene, mesh);
+  }
 
   /* tag update */
   bool rebuild = (oldtriangles != mesh->triangles) || (oldsubd_faces != mesh->subd_faces) ||
@@ -1258,7 +1260,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph &b_depsgraph,
 
   /* hair motion */
   if (numkeys)
-    sync_curves(mesh, b_mesh, b_ob, true, motion_step);
+    sync_particle_hair(mesh, b_mesh, b_ob, true, motion_step);
 
   /* free derived mesh */
   free_object_to_mesh(b_data, b_ob, b_mesh);
index 6981412bb88d6d2364e5a79eafc1d5f6022fe618..c397a95fa71f852dc296713a71a0c24638b0d9f2 100644 (file)
@@ -115,7 +115,7 @@ void BlenderSync::sync_light(BL::Object &b_parent,
 {
   /* test if we need to sync */
   Light *light;
-  ObjectKey key(b_parent, persistent_id, b_ob_instance);
+  ObjectKey key(b_parent, persistent_id, b_ob_instance, false);
   BL::Light b_light(b_ob.data());
 
   /* Update if either object or light data changed. */
@@ -254,7 +254,7 @@ void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal)
     if (sample_as_light || use_portal) {
       /* test if we need to sync */
       Light *light;
-      ObjectKey key(b_world, 0, b_world);
+      ObjectKey key(b_world, 0, b_world, false);
 
       if (light_map.sync(&light, b_world, b_world, key) || world_recalc ||
           b_world.ptr.data != world_map) {
@@ -295,8 +295,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
                                  BL::ViewLayer &b_view_layer,
                                  BL::DepsgraphObjectInstance &b_instance,
                                  float motion_time,
-                                 bool show_self,
-                                 bool show_particles,
+                                 bool use_particle_hair,
                                  bool show_lights,
                                  BlenderObjectCulling &culling,
                                  bool *use_portal)
@@ -378,7 +377,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
   }
 
   /* key to lookup object */
-  ObjectKey key(b_parent, persistent_id, b_ob_instance);
+  ObjectKey key(b_parent, persistent_id, b_ob_instance, use_particle_hair);
   Object *object;
 
   /* motion vector case */
@@ -407,8 +406,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
     object_updated = true;
 
   /* mesh sync */
-  object->mesh = sync_mesh(
-      b_depsgraph, b_ob, b_ob_instance, object_updated, show_self, show_particles);
+  object->mesh = sync_mesh(b_depsgraph, b_ob, b_ob_instance, object_updated, use_particle_hair);
 
   /* special case not tracked by object update flags */
 
@@ -552,22 +550,34 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
     BL::DepsgraphObjectInstance b_instance = *b_instance_iter;
     BL::Object b_ob = b_instance.object();
 
-    /* load per-object culling data */
+    /* Viewport visibility. */
+    const bool show_in_viewport = !b_v3d || b_ob.visible_in_viewport_get(b_v3d);
+    if (show_in_viewport == false) {
+      continue;
+    }
+
+    /* Load per-object culling data. */
     culling.init_object(scene, b_ob);
 
-    /* test if object needs to be hidden */
-    const bool show_self = b_instance.show_self();
-    const bool show_particles = b_instance.show_particles();
-    const bool show_in_viewport = !b_v3d || b_ob.visible_in_viewport_get(b_v3d);
+    /* Object itself. */
+    if (b_instance.show_self()) {
+      sync_object(b_depsgraph,
+                  b_view_layer,
+                  b_instance,
+                  motion_time,
+                  false,
+                  show_lights,
+                  culling,
+                  &use_portal);
+    }
 
-    if (show_in_viewport && (show_self || show_particles)) {
-      /* object itself */
+    /* Particle hair as separate object. */
+    if (b_instance.show_particles() && object_has_particle_hair(b_ob)) {
       sync_object(b_depsgraph,
                   b_view_layer,
                   b_instance,
                   motion_time,
-                  show_self,
-                  show_particles,
+                  true,
                   show_lights,
                   culling,
                   &use_portal);
index 20dbe23cdb7623a1ec91c4829435e95ce31a1f92..bb8a132ebb7860f18e39c3467051dc5aef389364 100644 (file)
@@ -108,10 +108,12 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
     }
 
     if (dicing_prop_changed) {
-      for (const pair<void *, Mesh *> &iter : mesh_map.key_to_scene_data()) {
+      for (const pair<MeshKey, Mesh *> &iter : mesh_map.key_to_scene_data()) {
         Mesh *mesh = iter.second;
         if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE) {
-          mesh_map.set_recalc(iter.first);
+          PointerRNA id_ptr;
+          RNA_id_pointer_create((::ID *)iter.first.id, &id_ptr);
+          mesh_map.set_recalc(BL::ID(id_ptr));
         }
       }
     }
index a80f484fb924d06af590bfda6b53bf703b82afe5..07dccdc5a73bc566f804fabb718eb2031c7c8e39 100644 (file)
@@ -127,16 +127,15 @@ class BlenderSync {
                   BL::Object &b_ob,
                   BL::Object &b_ob_instance,
                   bool object_updated,
-                  bool show_self,
-                  bool show_particles);
-  void sync_curves(
+                  bool use_particle_hair);
+  bool object_has_particle_hair(BL::Object b_ob);
+  void sync_particle_hair(
       Mesh *mesh, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step = 0);
   Object *sync_object(BL::Depsgraph &b_depsgraph,
                       BL::ViewLayer &b_view_layer,
                       BL::DepsgraphObjectInstance &b_instance,
                       float motion_time,
-                      bool show_self,
-                      bool show_particles,
+                      bool use_particle_hair,
                       bool show_lights,
                       BlenderObjectCulling &culling,
                       bool *use_portal);
@@ -179,7 +178,7 @@ class BlenderSync {
 
   id_map<void *, Shader> shader_map;
   id_map<ObjectKey, Object> object_map;
-  id_map<void *, Mesh> mesh_map;
+  id_map<MeshKey, Mesh> mesh_map;
   id_map<ObjectKey, Light> light_map;
   id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
   set<Mesh *> mesh_synced;
index bea30a20b8cd37b6fd32ae15290b13610d8e5718..6d6dd75db6b7cfb6daffee7eea83ba38e62e2717 100644 (file)
@@ -625,6 +625,11 @@ template<typename K, typename T> class id_map {
     return sync(r_data, id, id, id.ptr.owner_id);
   }
 
+  bool sync(T **r_data, const BL::ID &id, const K &key)
+  {
+    return sync(r_data, id, id, key);
+  }
+
   bool sync(T **r_data, const BL::ID &id, const BL::ID &parent, const K &key)
   {
     T *data = find(key);
@@ -639,8 +644,9 @@ template<typename K, typename T> class id_map {
     }
     else {
       recalc = (b_recalc.find(id.ptr.data) != b_recalc.end());
-      if (parent.ptr.data)
+      if (parent.ptr.data && parent.ptr.data != id.ptr.data) {
         recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end());
+      }
     }
 
     used(data);
@@ -725,9 +731,10 @@ struct ObjectKey {
   void *parent;
   int id[OBJECT_PERSISTENT_ID_SIZE];
   void *ob;
+  bool use_particle_hair;
 
-  ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_)
-      : parent(parent_), ob(ob_)
+  ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_, bool use_particle_hair_)
+      : parent(parent_), ob(ob_), use_particle_hair(use_particle_hair_)
   {
     if (id_)
       memcpy(id, id_, sizeof(id));
@@ -741,10 +748,42 @@ struct ObjectKey {
       return true;
     }
     else if (ob == k.ob) {
-      if (parent < k.parent)
+      if (parent < k.parent) {
+        return true;
+      }
+      else if (parent == k.parent) {
+        if (use_particle_hair < k.use_particle_hair) {
+          return true;
+        }
+        else if (use_particle_hair == k.use_particle_hair) {
+          return memcmp(id, k.id, sizeof(id)) < 0;
+        }
+      }
+    }
+
+    return false;
+  }
+};
+
+/* Mesh Key */
+
+struct MeshKey {
+  void *id;
+  bool use_particle_hair;
+
+  MeshKey(void *id, bool use_particle_hair) : id(id), use_particle_hair(use_particle_hair)
+  {
+  }
+
+  bool operator<(const MeshKey &k) const
+  {
+    if (id < k.id) {
+      return true;
+    }
+    else if (id == k.id) {
+      if (use_particle_hair < k.use_particle_hair) {
         return true;
-      else if (parent == k.parent)
-        return memcmp(id, k.id, sizeof(id)) < 0;
+      }
     }
 
     return false;