diff --git a/intern/cycles/blender/geometry.cpp b/intern/cycles/blender/geometry.cpp index 9afdad29138..a576f8b1813 100644 --- a/intern/cycles/blender/geometry.cpp +++ b/intern/cycles/blender/geometry.cpp @@ -32,7 +32,8 @@ static Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_parti } if (b_ob_info.object_data.is_a(&RNA_Volume) || - (b_ob_info.object_data == object_get_data(b_ob_info.real_object) && + (b_ob_info.object_data == + object_get_data(b_ob_info.real_object, b_ob_info.use_adaptive_subdivision) && object_fluid_gas_domain_find(b_ob_info.real_object))) { return Geometry::VOLUME; diff --git a/intern/cycles/blender/mesh.cpp b/intern/cycles/blender/mesh.cpp index af89d5c45b8..bdf2001cad0 100644 --- a/intern/cycles/blender/mesh.cpp +++ b/intern/cycles/blender/mesh.cpp @@ -1106,14 +1106,8 @@ void BlenderSync::sync_mesh(BObjectInfo &b_ob_info, Mesh *mesh) new_mesh.set_used_shaders(used_shaders); if (view_layer.use_surfaces) { - /* Adaptive subdivision setup. Not for baking since that requires - * exact mapping to the Blender mesh. */ - if (b_ob_info.real_object != b_bake_target) { - object_subdivision_to_mesh(b_ob_info.real_object, new_mesh, preview, experimental); - } - - /* For some reason, meshes do not need this... */ - BL::Mesh b_mesh = object_to_mesh(b_ob_info, new_mesh.get_subdivision_type()); + object_subdivision_to_mesh(b_ob_info.real_object, new_mesh, preview, use_adaptive_subdivision); + BL::Mesh b_mesh = object_to_mesh(b_ob_info); if (b_mesh) { /* Motion blur attribute is relative to seconds, we need it relative to frames. */ @@ -1189,7 +1183,7 @@ void BlenderSync::sync_mesh_motion(BObjectInfo &b_ob_info, Mesh *mesh, const int BL::Mesh b_mesh_rna(PointerRNA_NULL); if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) { /* get derived mesh */ - b_mesh_rna = object_to_mesh(b_ob_info, mesh->get_subdivision_type()); + b_mesh_rna = object_to_mesh(b_ob_info); } const std::string ob_name = b_ob_info.real_object.name(); diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp index 4af3f2e3007..a1e1e379ead 100644 --- a/intern/cycles/blender/object.cpp +++ b/intern/cycles/blender/object.cpp @@ -91,14 +91,14 @@ bool BlenderSync::object_can_have_geometry(BL::Object &b_ob) bool BlenderSync::object_is_light(BL::Object &b_ob) { - BL::ID b_ob_data = object_get_data(b_ob); + BL::ID b_ob_data = object_get_data(b_ob, true); return (b_ob_data && b_ob_data.is_a(&RNA_Light)); } bool BlenderSync::object_is_camera(BL::Object &b_ob) { - BL::ID b_ob_data = object_get_data(b_ob); + BL::ID b_ob_data = object_get_data(b_ob, true); return (b_ob_data && b_ob_data.is_a(&RNA_Camera)); } @@ -157,7 +157,11 @@ Object *BlenderSync::sync_object(BL::ViewLayer &b_view_layer, BL::Object b_ob = b_instance.object(); BL::Object b_parent = is_instance ? b_instance.parent() : b_instance.object(); BL::Object b_real_object = is_instance ? b_instance.instance_object() : b_ob; - BObjectInfo b_ob_info{b_ob, b_real_object, object_get_data(b_ob)}; + const bool use_adaptive_subdiv = object_subdivision_type( + b_real_object, preview, use_adaptive_subdivision) != + Mesh::SUBDIVISION_NONE; + BObjectInfo b_ob_info{ + b_ob, b_real_object, object_get_data(b_ob, use_adaptive_subdiv), use_adaptive_subdiv}; const bool motion = motion_time != 0.0f; /*const*/ Transform tfm = get_transform(b_ob.matrix_world()); int *persistent_id = nullptr; @@ -582,7 +586,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, BL::MeshSequenceCacheModifier b_mesh_cache(PointerRNA_NULL); /* Experimental as Blender does not have good support for procedurals at the moment. */ - if (experimental) { + if (use_experimental_procedural) { b_mesh_cache = object_mesh_cache_find(b_ob, &has_subdivision_modifier); use_procedural = b_mesh_cache && b_mesh_cache.cache_file().use_render_procedural(); } diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp index 6aca1d5015d..3473c7d1365 100644 --- a/intern/cycles/blender/sync.cpp +++ b/intern/cycles/blender/sync.cpp @@ -58,7 +58,6 @@ BlenderSync::BlenderSync(BL::RenderEngine &b_engine, world_recalc(false), scene(scene), preview(preview), - experimental(false), use_developer_ui(use_developer_ui), dicing_rate(1.0f), max_subdivisions(12), @@ -100,7 +99,7 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d /* Sync recalc flags from blender to cycles. Actual update is done separate, * so we can do it later on if doing it immediate is not suitable. */ - if (experimental) { + if (use_adaptive_subdivision) { /* Mark all meshes as needing to be exported again if dicing changed. */ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); bool dicing_prop_changed = false; @@ -177,10 +176,14 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d object_map.set_recalc(b_ob); } - if (updated_geometry || - (object_subdivision_type(b_ob, preview, experimental) != Mesh::SUBDIVISION_NONE)) - { - BL::ID const key = BKE_object_is_modified(b_ob) ? b_ob : object_get_data(b_ob); + const bool use_adaptive_subdiv = object_subdivision_type( + b_ob, preview, use_adaptive_subdivision) != + Mesh::SUBDIVISION_NONE; + + if (updated_geometry || use_adaptive_subdiv) { + BL::ID const key = BKE_object_is_modified(b_ob) ? + b_ob : + object_get_data(b_ob, use_adaptive_subdiv); geometry_map.set_recalc(key); /* Sync all contained geometry instances as well when the object changed.. */ @@ -314,7 +317,9 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, { PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - experimental = (get_enum(cscene, "feature_set") != 0); + /* No adaptive subdivision for baking, mesh needs to match Blender exactly. */ + use_adaptive_subdivision = (get_enum(cscene, "feature_set") != 0) && !b_bake_target; + use_experimental_procedural = (get_enum(cscene, "feature_set") != 0); Integrator *integrator = scene->integrator; diff --git a/intern/cycles/blender/sync.h b/intern/cycles/blender/sync.h index b4bdeeb9a4b..d1cc97402eb 100644 --- a/intern/cycles/blender/sync.h +++ b/intern/cycles/blender/sync.h @@ -240,7 +240,8 @@ class BlenderSync { Scene *scene; bool preview; - bool experimental; + bool use_experimental_procedural = false; + bool use_adaptive_subdivision = false; bool use_developer_ui; float dicing_rate; diff --git a/intern/cycles/blender/util.h b/intern/cycles/blender/util.h index d2ddbf8f466..45d154ccad5 100644 --- a/intern/cycles/blender/util.h +++ b/intern/cycles/blender/util.h @@ -28,11 +28,11 @@ CCL_NAMESPACE_BEGIN -static inline BL::ID object_get_data(const BL::Object &b_ob) +static inline BL::ID object_get_data(const BL::Object &b_ob, const bool use_adaptive_subdivision) { ::Object *object = reinterpret_cast<::Object *>(b_ob.ptr.data); - if (object->type == OB_MESH) { + if (!use_adaptive_subdivision && object->type == OB_MESH) { ::Mesh *mesh = static_cast<::Mesh *>(object->data); mesh = BKE_mesh_wrapper_ensure_subdivision(mesh); return BL::ID(RNA_id_pointer_create(&mesh->id)); @@ -55,20 +55,23 @@ struct BObjectInfo { * iterator is done. It might have a different type compared to object_get_data(real_object). */ BL::ID object_data; + /* Object will use adaptive subdivision. */ + bool use_adaptive_subdivision; + /* True when the current geometry is the data of the referenced object. False when it is a * geometry instance that does not have a 1-to-1 relationship with an object. */ bool is_real_object_data() const { - return object_get_data(const_cast(real_object)) == object_data; + return object_get_data(const_cast(real_object), use_adaptive_subdivision) == + object_data; } }; -static inline BL::Mesh object_copy_mesh_data(const BObjectInfo &b_ob_info, - const Mesh::SubdivisionType subdivision_type) +static inline BL::Mesh object_copy_mesh_data(const BObjectInfo &b_ob_info) { ::Object *object = static_cast<::Object *>(b_ob_info.real_object.ptr.data); ::Mesh *mesh = BKE_mesh_new_from_object( - nullptr, object, false, false, subdivision_type == Mesh::SUBDIVISION_NONE); + nullptr, object, false, false, !b_ob_info.use_adaptive_subdivision); return BL::Mesh(RNA_id_pointer_create(&mesh->id)); } @@ -78,32 +81,15 @@ BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_r void python_thread_state_save(void **python_thread_state); void python_thread_state_restore(void **python_thread_state); -static bool mesh_use_corner_normals(BL::Mesh &mesh, Mesh::SubdivisionType subdivision_type) +static bool mesh_use_corner_normals(const BObjectInfo &b_ob_info, BL::Mesh &mesh) { - return mesh && (subdivision_type == Mesh::SUBDIVISION_NONE) && + return mesh && !b_ob_info.use_adaptive_subdivision && (static_cast(mesh.ptr.data)->normals_domain(true) == blender::bke::MeshNormalDomain::Corner); } -static inline BL::Mesh object_to_mesh( - BObjectInfo &b_ob_info, Mesh::SubdivisionType subdivision_type = Mesh::SUBDIVISION_NONE) +static inline BL::Mesh object_to_mesh(BObjectInfo &b_ob_info) { - /* TODO: make this work with copy-on-evaluation, modifiers are already evaluated. */ -#if 0 - bool subsurf_mod_show_render = false; - bool subsurf_mod_show_viewport = false; - - if (subdivision_type != Mesh::SUBDIVISION_NONE) { - BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length() - 1]; - - subsurf_mod_show_render = subsurf_mod.show_render(); - subsurf_mod_show_viewport = subsurf_mod.show_viewport(); - - subsurf_mod.show_render(false); - subsurf_mod.show_viewport(false); - } -#endif - BL::Mesh mesh = (b_ob_info.object_data.is_a(&RNA_Mesh)) ? BL::Mesh(b_ob_info.object_data) : BL::Mesh(PointerRNA_NULL); @@ -113,40 +99,31 @@ static inline BL::Mesh object_to_mesh( if (mesh) { if (mesh.is_editmode()) { /* Flush edit-mesh to mesh, including all data layers. */ - mesh = object_copy_mesh_data(b_ob_info, subdivision_type); - use_corner_normals = mesh_use_corner_normals(mesh, subdivision_type); + mesh = object_copy_mesh_data(b_ob_info); + use_corner_normals = mesh_use_corner_normals(b_ob_info, mesh); } - else if (mesh_use_corner_normals(mesh, subdivision_type)) { + else if (mesh_use_corner_normals(b_ob_info, mesh)) { /* Make a copy to split faces. */ - mesh = object_copy_mesh_data(b_ob_info, subdivision_type); + mesh = object_copy_mesh_data(b_ob_info); use_corner_normals = true; } } else { - mesh = object_copy_mesh_data(b_ob_info, subdivision_type); - use_corner_normals = mesh_use_corner_normals(mesh, subdivision_type); + mesh = object_copy_mesh_data(b_ob_info); + use_corner_normals = mesh_use_corner_normals(b_ob_info, mesh); } } else { /* TODO: what to do about non-mesh geometry instances? */ - use_corner_normals = mesh_use_corner_normals(mesh, subdivision_type); + use_corner_normals = mesh_use_corner_normals(b_ob_info, mesh); } -#if 0 - if (subdivision_type != Mesh::SUBDIVISION_NONE) { - BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length() - 1]; - - subsurf_mod.show_render(subsurf_mod_show_render); - subsurf_mod.show_viewport(subsurf_mod_show_viewport); - } -#endif - if (mesh) { if (use_corner_normals) { mesh.split_faces(); } - if (subdivision_type == Mesh::SUBDIVISION_NONE) { + if (b_ob_info.use_adaptive_subdivision) { mesh.calc_loop_triangles(); } } @@ -161,7 +138,7 @@ static inline void free_object_to_mesh(BObjectInfo &b_ob_info, BL::Mesh &mesh) } /* Free mesh if we didn't just use the existing one. */ BL::Object object = b_ob_info.real_object; - if (object_get_data(object).ptr.data != mesh.ptr.data) { + if (object_get_data(object, b_ob_info.use_adaptive_subdivision).ptr.data != mesh.ptr.data) { BKE_id_free(nullptr, static_cast(mesh.ptr.data)); } } @@ -693,13 +670,11 @@ static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b return BL::MeshSequenceCacheModifier(PointerRNA_NULL); } -static BL::SubsurfModifier object_subdivision_modifier(BL::Object &b_ob, - const bool preview, - const bool experimental) +static BL::SubsurfModifier object_subdivision_modifier(BL::Object &b_ob, const bool preview) { PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles"); - if (cobj.data && !b_ob.modifiers.empty() && experimental) { + if (cobj.data && !b_ob.modifiers.empty()) { BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length() - 1]; const bool enabled = preview ? mod.show_viewport() : mod.show_render(); @@ -716,9 +691,13 @@ static BL::SubsurfModifier object_subdivision_modifier(BL::Object &b_ob, static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob, const bool preview, - const bool experimental) + const bool use_adaptive_subdivision) { - BL::SubsurfModifier subsurf = object_subdivision_modifier(b_ob, preview, experimental); + if (!use_adaptive_subdivision) { + return Mesh::SUBDIVISION_NONE; + } + + BL::SubsurfModifier subsurf = object_subdivision_modifier(b_ob, preview); if (subsurf) { if (subsurf.subdivision_type() == BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) { @@ -733,9 +712,14 @@ static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob, static inline void object_subdivision_to_mesh(BL::Object &b_ob, Mesh &mesh, const bool preview, - const bool experimental) + const bool use_adaptive_subdivision) { - BL::SubsurfModifier subsurf = object_subdivision_modifier(b_ob, preview, experimental); + if (!use_adaptive_subdivision) { + mesh.set_subdivision_type(Mesh::SUBDIVISION_NONE); + return; + } + + BL::SubsurfModifier subsurf = object_subdivision_modifier(b_ob, preview); if (!subsurf) { mesh.set_subdivision_type(Mesh::SUBDIVISION_NONE); diff --git a/source/blender/blenkernel/BKE_subdiv_modifier.hh b/source/blender/blenkernel/BKE_subdiv_modifier.hh index 67a9ed32208..ee0c474e93b 100644 --- a/source/blender/blenkernel/BKE_subdiv_modifier.hh +++ b/source/blender/blenkernel/BKE_subdiv_modifier.hh @@ -68,8 +68,9 @@ bool BKE_subsurf_modifier_has_split_normals(const SubsurfModifierData *smd, cons bool BKE_subsurf_modifier_force_disable_gpu_evaluation_for_mesh(const SubsurfModifierData *smd, const Mesh *mesh); /** - * \param skip_check_is_last: When true, we assume that the modifier passed is the last enabled - * modifier in the stack. + * Return true if GPU subdivision can be used for this modifier. It does not check if + * the modifier is in the right place in the modifier stack, only if the settings and + * GPU are compatible. */ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const SubsurfModifierData *smd, const Mesh *mesh); diff --git a/source/blender/modifiers/intern/MOD_subsurf.cc b/source/blender/modifiers/intern/MOD_subsurf.cc index 72c2fd2cccd..8c7f8bf133d 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.cc +++ b/source/blender/modifiers/intern/MOD_subsurf.cc @@ -210,13 +210,6 @@ static ModifierData *modifier_get_last_enabled_for_mode(const Scene *scene, return md; } -/** - * Return true if GPU subdivision evaluation is disabled by force due to incompatible mesh or - * modifier settings. This will only return true if GPU subdivision is enabled in the preferences - * and supported by the GPU. It is mainly useful for showing UI messages. - */ -bool BKE_subsurf_modifier_can_use_gpu_evaluation(const SubsurfModifierData *smd, const Mesh *mesh); - /* Modifier itself. */ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) diff --git a/tests/data b/tests/data index a61cf75cfcf..4bb5c44abd1 160000 --- a/tests/data +++ b/tests/data @@ -1 +1 @@ -Subproject commit a61cf75cfcfab3f6b8186410dfffdc4b98922aad +Subproject commit 4bb5c44abd165be08fd21fb0d327ff77f1b00858