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:
@@ -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, ¢er, &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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ¢er, 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 ¢er, const float3 &size);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user