EEVEE Next: Sculpt support

Add sculpt support to EEVEE Next.

It creates a new resource handle for sculpt object, since
BKE_object_boundbox_get returns a wrong (zeroed) bounding box.

This also adds a new `resource_handle` function to the `draw::Manager`
that works like the default one, but lets the caller optionally override the
object matrix and/or bounds.

Pull Request: https://projects.blender.org/blender/blender/pulls/110703
This commit is contained in:
Miguel Pozo 2023-08-04 16:38:04 +02:00
parent ada738ac7c
commit 41c83d6cfc
4 changed files with 109 additions and 1 deletions

View File

@ -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);

View File

@ -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, &center, &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;
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -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,

View File

@ -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);