diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index 5dee4aff7e3..1a108dfd69f 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -213,7 +213,9 @@ void Instance::object_sync(Object *ob) lights.sync_light(ob, ob_handle); break; case OB_MESH: - sync.sync_mesh(ob, ob_handle, res_handle, ob_ref); + if (!sync.sync_sculpt(ob, ob_handle, res_handle, ob_ref)) { + sync.sync_mesh(ob, ob_handle, res_handle, ob_ref); + } break; case OB_POINTCLOUD: sync.sync_point_cloud(ob, ob_handle, res_handle, ob_ref); diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.cc b/source/blender/draw/engines/eevee_next/eevee_sync.cc index 608643739cc..b574c2ac862 100644 --- a/source/blender/draw/engines/eevee_next/eevee_sync.cc +++ b/source/blender/draw/engines/eevee_next/eevee_sync.cc @@ -12,6 +12,8 @@ #include "BKE_gpencil_legacy.h" #include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_pbvh_api.hh" #include "DEG_depsgraph_query.h" #include "DNA_curves_types.h" #include "DNA_gpencil_legacy_types.h" @@ -19,6 +21,7 @@ #include "DNA_particle_types.h" #include "draw_common.hh" +#include "draw_sculpt.hh" #include "eevee_instance.hh" @@ -154,6 +157,75 @@ void SyncModule::sync_mesh(Object *ob, inst_.cryptomatte.sync_object(ob, res_handle); } +bool SyncModule::sync_sculpt(Object *ob, + ObjectHandle &ob_handle, + ResourceHandle res_handle, + const ObjectRef &ob_ref) +{ + bool pbvh_draw = BKE_sculptsession_use_pbvh_draw(ob, inst_.rv3d) && !DRW_state_is_image_render(); + /* Needed for mesh cache validation, to prevent two copies of + * of vertex color arrays from being sent to the GPU (e.g. + * when switching from eevee to workbench). + */ + if (ob_ref.object->sculpt && ob_ref.object->sculpt->pbvh) { + BKE_pbvh_is_drawing_set(ob_ref.object->sculpt->pbvh, pbvh_draw); + } + + if (!pbvh_draw) { + return false; + } + + /* Use a valid bounding box. The PBVH module already does its own culling, + * but a valid bounding box is still needed for directional shadow tilemap bounds computation. */ + float3 min, max; + BKE_pbvh_bounding_box(ob_ref.object->sculpt->pbvh, min, max); + float3 center = (min + max) * 0.5; + float3 half_extent = max - center; + res_handle = inst_.manager->resource_handle(ob_ref, nullptr, ¢er, &half_extent); + + bool has_motion = false; + MaterialArray &material_array = inst_.materials.material_array_get(ob, has_motion); + + bool is_shadow_caster = false; + bool is_alpha_blend = false; + bool do_probe_sync = inst_.do_probe_sync(); + for (SculptBatch &batch : + sculpt_batches_per_material_get(ob_ref.object, material_array.gpu_materials)) + { + GPUBatch *geom = batch.batch; + if (geom == nullptr) { + continue; + } + + Material &material = material_array.materials[batch.material_slot]; + + geometry_call(material.shading.sub_pass, geom, res_handle); + geometry_call(material.prepass.sub_pass, geom, res_handle); + geometry_call(material.shadow.sub_pass, geom, res_handle); + + /* TODO(Miguel Pozo): Is this needed ? */ + geometry_call(material.capture.sub_pass, geom, res_handle); + if (do_probe_sync) { + geometry_call(material.probe_prepass.sub_pass, geom, res_handle); + geometry_call(material.probe_shading.sub_pass, geom, res_handle); + } + + is_shadow_caster = is_shadow_caster || material.shadow.sub_pass != nullptr; + is_alpha_blend = is_alpha_blend || material.is_alpha_blend_transparent; + + GPUMaterial *gpu_material = material_array.gpu_materials[batch.material_slot]; + ::Material *mat = GPU_material_get_material(gpu_material); + inst_.cryptomatte.sync_material(mat); + } + + inst_.manager->extract_object_attributes(res_handle, ob_ref, material_array.gpu_materials); + + inst_.shadows.sync_object(ob_handle, res_handle, is_shadow_caster, is_alpha_blend); + inst_.cryptomatte.sync_object(ob, res_handle); + + return true; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.hh b/source/blender/draw/engines/eevee_next/eevee_sync.hh index 2291f7e3412..5f9e179a48a 100644 --- a/source/blender/draw/engines/eevee_next/eevee_sync.hh +++ b/source/blender/draw/engines/eevee_next/eevee_sync.hh @@ -167,6 +167,10 @@ class SyncModule { ObjectHandle &ob_handle, ResourceHandle res_handle, const ObjectRef &ob_ref); + bool sync_sculpt(Object *ob, + ObjectHandle &ob_handle, + ResourceHandle res_handle, + const ObjectRef &ob_ref); void sync_point_cloud(Object *ob, ObjectHandle &ob_handle, ResourceHandle res_handle, diff --git a/source/blender/draw/intern/draw_manager.hh b/source/blender/draw/intern/draw_manager.hh index 717a73ab993..8c9d71560d7 100644 --- a/source/blender/draw/intern/draw_manager.hh +++ b/source/blender/draw/intern/draw_manager.hh @@ -120,6 +120,14 @@ class Manager { * Create a new resource handle for the given object. */ ResourceHandle resource_handle(const ObjectRef ref); + /** + * Create a new resource handle for the given object, but optionally override model matrix and + * bounds. + */ + ResourceHandle resource_handle(const ObjectRef ref, + const float4x4 *model_matrix, + const float3 *bounds_center, + const float3 *bounds_half_extent); /** * Get resource id for a loose matrix. The draw-calls for this resource handle won't be culled * and there won't be any associated object info / bounds. Assumes correct handedness / winding. @@ -207,6 +215,28 @@ inline ResourceHandle Manager::resource_handle(const ObjectRef ref) return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0); } +inline ResourceHandle Manager::resource_handle(const ObjectRef ref, + const float4x4 *model_matrix, + const float3 *bounds_center, + const float3 *bounds_half_extent) +{ + bool is_active_object = (ref.dupli_object ? ref.dupli_parent : ref.object) == object_active; + if (model_matrix) { + matrix_buf.current().get_or_resize(resource_len_).sync(*model_matrix); + } + else { + matrix_buf.current().get_or_resize(resource_len_).sync(*ref.object); + } + if (bounds_center && bounds_half_extent) { + bounds_buf.current().get_or_resize(resource_len_).sync(*bounds_center, *bounds_half_extent); + } + else { + bounds_buf.current().get_or_resize(resource_len_).sync(*ref.object); + } + infos_buf.current().get_or_resize(resource_len_).sync(ref, is_active_object); + return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0); +} + inline ResourceHandle Manager::resource_handle(const float4x4 &model_matrix) { matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix);