EEVEE-Next: Add Max Displacement option

Add a Max Displacement option to Material settings, so frustum culling
can work correctly with vertex displacement.

Pull Request: https://projects.blender.org/blender/blender/pulls/114200
This commit is contained in:
Miguel Pozo
2023-11-07 15:28:07 +01:00
parent b2bdfe946e
commit b4316445a8
11 changed files with 105 additions and 19 deletions
+2 -1
View File
@@ -299,7 +299,8 @@ class EEVEE_NEXT_MATERIAL_PT_settings_surface(MaterialButtonsPanel, Panel):
col.prop(mat, "use_backface_culling", text="Camera")
col.prop(mat, "use_backface_culling_shadow", text="Shadow")
# TODO(fclem): Displacement option
layout.prop(mat, "max_vertex_displacement", text="Max Displacement")
layout.prop(mat, "use_transparent_shadow")
col = layout.column()
@@ -196,6 +196,7 @@ void Instance::object_sync(Object *ob)
OB_VOLUME,
OB_LAMP,
OB_LIGHTPROBE);
const bool is_drawable_type = is_renderable_type && !ELEM(ob->type, OB_LAMP, OB_LIGHTPROBE);
const int ob_visibility = DRW_object_visibility_in_active_context(ob);
const bool partsys_is_visible = (ob_visibility & OB_VISIBLE_PARTICLES) != 0 &&
(ob->type == OB_MESH);
@@ -208,15 +209,17 @@ void Instance::object_sync(Object *ob)
/* TODO cleanup. */
ObjectRef ob_ref = DRW_object_ref_get(ob);
ResourceHandle res_handle = manager->resource_handle(ob_ref);
ObjectHandle &ob_handle = sync.sync_object(ob);
ResourceHandle res_handle = {0};
if (is_drawable_type) {
res_handle = manager->resource_handle(ob_ref);
}
if (partsys_is_visible && ob != DRW_context_state_get()->object_edit) {
auto sync_hair =
[&](ObjectHandle hair_handle, ModifierData &md, ParticleSystem &particle_sys) {
ResourceHandle _res_handle = manager->resource_handle(float4x4(ob->object_to_world));
sync.sync_curves(ob, hair_handle, _res_handle, &md, &particle_sys);
sync.sync_curves(ob, hair_handle, _res_handle, ob_ref, &md, &particle_sys);
};
foreach_hair_particle_handle(ob, ob_handle, sync_hair);
}
@@ -238,7 +241,7 @@ void Instance::object_sync(Object *ob)
sync.sync_volume(ob, ob_handle, res_handle);
break;
case OB_CURVES:
sync.sync_curves(ob, ob_handle, res_handle);
sync.sync_curves(ob, ob_handle, res_handle, ob_ref);
break;
case OB_GPENCIL_LEGACY:
sync.sync_gpencil(ob, ob_handle, res_handle);
@@ -141,6 +141,7 @@ void SyncModule::sync_mesh(Object *ob,
}
bool is_alpha_blend = false;
float inflate_bounds = 0.0f;
for (auto i : material_array.gpu_materials.index_range()) {
GPUBatch *geom = mat_geom[i];
if (geom == nullptr) {
@@ -176,6 +177,14 @@ void SyncModule::sync_mesh(Object *ob,
::Material *mat = GPU_material_get_material(gpu_material);
inst_.cryptomatte.sync_material(mat);
if (GPU_material_has_displacement_output(gpu_material)) {
inflate_bounds = math::max(inflate_bounds, mat->inflate_bounds);
}
}
if (inflate_bounds != 0.0f) {
inst_.manager->update_handle_bounds(res_handle, ob_ref, inflate_bounds);
}
inst_.manager->extract_object_attributes(res_handle, ob_ref, material_array.gpu_materials);
@@ -202,18 +211,11 @@ bool SyncModule::sync_sculpt(Object *ob,
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 tile-map 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_alpha_blend = false;
float inflate_bounds = 0.0f;
for (SculptBatch &batch :
sculpt_batches_per_material_get(ob_ref.object, material_array.gpu_materials))
{
@@ -251,8 +253,21 @@ bool SyncModule::sync_sculpt(Object *ob,
GPUMaterial *gpu_material = material_array.gpu_materials[batch.material_slot];
::Material *mat = GPU_material_get_material(gpu_material);
inst_.cryptomatte.sync_material(mat);
if (GPU_material_has_displacement_output(gpu_material)) {
inflate_bounds = math::max(inflate_bounds, mat->inflate_bounds);
}
}
/* Use a valid bounding box. The PBVH module already does its own culling, but a valid */
/* bounding box is still needed for directional shadow tile-map 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;
half_extent += inflate_bounds;
inst_.manager->update_handle_bounds(res_handle, center, half_extent);
inst_.manager->extract_object_attributes(res_handle, ob_ref, material_array.gpu_materials);
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend);
@@ -270,7 +285,7 @@ bool SyncModule::sync_sculpt(Object *ob,
void SyncModule::sync_point_cloud(Object *ob,
ObjectHandle &ob_handle,
ResourceHandle res_handle,
const ObjectRef & /*ob_ref*/)
const ObjectRef &ob_ref)
{
const int material_slot = POINTCLOUD_MATERIAL_NR;
@@ -319,6 +334,11 @@ void SyncModule::sync_point_cloud(Object *ob,
inst_.cryptomatte.sync_material(mat);
bool is_alpha_blend = material.is_alpha_blend_transparent;
if (GPU_material_has_displacement_output(gpu_material) && mat->inflate_bounds != 0.0f) {
inst_.manager->update_handle_bounds(res_handle, ob_ref, mat->inflate_bounds);
}
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend);
}
@@ -494,6 +514,7 @@ void SyncModule::sync_gpencil(Object *ob, ObjectHandle &ob_handle, ResourceHandl
void SyncModule::sync_curves(Object *ob,
ObjectHandle &ob_handle,
ResourceHandle res_handle,
const ObjectRef &ob_ref,
ModifierData *modifier_data,
ParticleSystem *particle_sys)
{
@@ -552,6 +573,11 @@ void SyncModule::sync_curves(Object *ob,
inst_.cryptomatte.sync_material(mat);
bool is_alpha_blend = material.is_alpha_blend_transparent;
if (GPU_material_has_displacement_output(gpu_material) && mat->inflate_bounds != 0.0f) {
inst_.manager->update_handle_bounds(res_handle, ob_ref, mat->inflate_bounds);
}
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend);
}
@@ -161,6 +161,7 @@ class SyncModule {
void sync_curves(Object *ob,
ObjectHandle &ob_handle,
ResourceHandle res_handle,
const ObjectRef &ob_ref,
ModifierData *modifier_data = nullptr,
ParticleSystem *particle_sys = nullptr);
void sync_light_probe(Object *ob, ObjectHandle &ob_handle);
+26 -3
View File
@@ -119,7 +119,7 @@ class Manager {
/**
* Create a new resource handle for the given object.
*/
ResourceHandle resource_handle(const ObjectRef ref);
ResourceHandle resource_handle(const ObjectRef ref, float inflate_bounds = 0.0f);
/**
* Create a new resource handle for the given object, but optionally override model matrix and
* bounds.
@@ -142,6 +142,15 @@ class Manager {
const float3 &bounds_center,
const float3 &bounds_half_extent);
/** Update the bounds of an already created handle. */
void update_handle_bounds(ResourceHandle handle,
const ObjectRef ref,
float inflate_bounds = 0.0f);
/** Update the bounds of an already created handle. */
void update_handle_bounds(ResourceHandle handle,
const float3 &bounds_center,
const float3 &bounds_half_extent);
/**
* Populate additional per resource data on demand.
*/
@@ -206,11 +215,11 @@ class Manager {
void sync_layer_attributes();
};
inline ResourceHandle Manager::resource_handle(const ObjectRef ref)
inline ResourceHandle Manager::resource_handle(const ObjectRef ref, float inflate_bounds)
{
bool is_active_object = (ref.dupli_object ? ref.dupli_parent : ref.object) == object_active;
matrix_buf.current().get_or_resize(resource_len_).sync(*ref.object);
bounds_buf.current().get_or_resize(resource_len_).sync(*ref.object);
bounds_buf.current().get_or_resize(resource_len_).sync(*ref.object, inflate_bounds);
infos_buf.current().get_or_resize(resource_len_).sync(ref, is_active_object);
return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0);
}
@@ -255,6 +264,20 @@ inline ResourceHandle Manager::resource_handle(const float4x4 &model_matrix,
return ResourceHandle(resource_len_++, false);
}
inline void Manager::update_handle_bounds(ResourceHandle handle,
const ObjectRef ref,
float inflate_bounds)
{
bounds_buf.current()[handle.resource_index()].sync(*ref.object, inflate_bounds);
}
inline void Manager::update_handle_bounds(ResourceHandle handle,
const float3 &bounds_center,
const float3 &bounds_half_extent)
{
bounds_buf.current()[handle.resource_index()].sync(bounds_center, bounds_half_extent);
}
inline void Manager::extract_object_attributes(ResourceHandle handle,
const ObjectRef &ref,
Span<GPUMaterial *> materials)
+11 -1
View File
@@ -159,7 +159,7 @@ inline void ObjectBounds::sync()
bounding_sphere.w = -1.0f; /* Disable test. */
}
inline void ObjectBounds::sync(Object &ob)
inline void ObjectBounds::sync(Object &ob, float inflate_bounds)
{
const std::optional<BoundBox> bbox = BKE_object_boundbox_get(&ob);
if (!bbox) {
@@ -171,6 +171,16 @@ inline void ObjectBounds::sync(Object &ob)
*reinterpret_cast<float3 *>(&bounding_corners[2]) = bbox->vec[3];
*reinterpret_cast<float3 *>(&bounding_corners[3]) = bbox->vec[1];
bounding_sphere.w = 0.0f; /* Enable test. */
if (inflate_bounds != 0.0f) {
BLI_assert(inflate_bounds >= 0.0f);
float p = inflate_bounds;
float n = -inflate_bounds;
bounding_corners[0] += float4(n, n, n, 0.0f);
bounding_corners[1] += float4(p, n, n, 0.0f);
bounding_corners[2] += float4(n, p, n, 0.0f);
bounding_corners[3] += float4(n, n, p, 0.0f);
}
}
inline void ObjectBounds::sync(const float3 &center, const float3 &size)
@@ -204,7 +204,7 @@ struct ObjectBounds {
#if !defined(GPU_SHADER) && defined(__cplusplus)
void sync();
void sync(Object &ob);
void sync(Object &ob, float inflate_bounds = 0.0f);
void sync(const float3 &center, const float3 &size);
#endif
};
+1
View File
@@ -320,6 +320,7 @@ struct GPUUniformBuf *GPU_material_create_sss_profile_ubo(void);
bool GPU_material_has_surface_output(GPUMaterial *mat);
bool GPU_material_has_volume_output(GPUMaterial *mat);
bool GPU_material_has_displacement_output(GPUMaterial *mat);
void GPU_material_flag_set(GPUMaterial *mat, eGPUMaterialFlag flag);
bool GPU_material_flag_get(const GPUMaterial *mat, eGPUMaterialFlag flag);
@@ -130,6 +130,7 @@ struct GPUMaterial {
/** DEPRECATED: To remove. */
bool has_surface_output;
bool has_volume_output;
bool has_displacement_output;
/** DEPRECATED: To remove. */
GPUUniformBuf *sss_profile; /* UBO containing SSS profile. */
GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */
@@ -662,6 +663,7 @@ void GPU_material_output_displacement(GPUMaterial *material, GPUNodeLink *link)
{
if (!material->graph.outlink_displacement) {
material->graph.outlink_displacement = link;
material->has_displacement_output = true;
}
}
@@ -779,6 +781,11 @@ bool GPU_material_has_volume_output(GPUMaterial *mat)
return mat->has_volume_output;
}
bool GPU_material_has_displacement_output(GPUMaterial *mat)
{
return mat->has_displacement_output;
}
void GPU_material_flag_set(GPUMaterial *mat, eGPUMaterialFlag flag)
{
mat->flag |= flag;
@@ -221,6 +221,11 @@ typedef struct Material {
/* Volume. */
char volume_intersection_method;
/* Displacement*/
float inflate_bounds;
char _pad3[4];
/**
* Cached slots for texture painting, must be refreshed in
* refresh_texpaint_image_cache before using.
@@ -964,6 +964,15 @@ void RNA_def_material(BlenderRNA *brna)
"Determines which inner part of the mesh will produce volumetric effect");
RNA_def_property_update(prop, 0, "rna_Material_draw_update");
prop = RNA_def_property(srna, "max_vertex_displacement", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, nullptr, "inflate_bounds");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop,
"Max Vertex Displacement",
"The max distance a vertex can be displaced."
"Displacements over this threshold may cause visibility issues");
RNA_def_property_update(prop, 0, "rna_Material_draw_update");
/* For Preview Render */
prop = RNA_def_property(srna, "preview_render_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "pr_type");