EEVEE-Next: Jittered Shadow Transparency
Smooth transparent shadows by jittering their opacity threshold every sample. Always enabled on final renders, optionally enabled in the viewport with `scene.eevee.shadow_jittered_transparency`. Pull Request: https://projects.blender.org/blender/blender/pulls/119480
This commit is contained in:
parent
0c8b96d1e0
commit
881fd2dbd5
|
@ -727,6 +727,9 @@ class RENDER_PT_eevee_next_shadows(RenderButtonsPanel, Panel):
|
||||||
col = layout.column()
|
col = layout.column()
|
||||||
col.prop(props, "shadow_normal_bias", text="Normal Bias")
|
col.prop(props, "shadow_normal_bias", text="Normal Bias")
|
||||||
|
|
||||||
|
col = layout.column()
|
||||||
|
col.prop(props, "use_shadow_jittered_viewport", text="Jittered Transparency (Viewport)")
|
||||||
|
|
||||||
|
|
||||||
class RENDER_PT_eevee_sampling(RenderButtonsPanel, Panel):
|
class RENDER_PT_eevee_sampling(RenderButtonsPanel, Panel):
|
||||||
bl_label = "Sampling"
|
bl_label = "Sampling"
|
||||||
|
|
|
@ -356,6 +356,10 @@ Material &MaterialModule::material_sync(Object *ob,
|
||||||
mat.is_alpha_blend_transparent = use_forward_pipeline &&
|
mat.is_alpha_blend_transparent = use_forward_pipeline &&
|
||||||
GPU_material_flag_get(mat.shading.gpumat,
|
GPU_material_flag_get(mat.shading.gpumat,
|
||||||
GPU_MATFLAG_TRANSPARENT);
|
GPU_MATFLAG_TRANSPARENT);
|
||||||
|
mat.has_transparent_shadows = blender_mat->blend_flag & MA_BL_TRANSPARENT_SHADOW &&
|
||||||
|
GPU_material_flag_get(mat.shading.gpumat,
|
||||||
|
GPU_MATFLAG_TRANSPARENT);
|
||||||
|
|
||||||
return mat;
|
return mat;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -291,6 +291,7 @@ struct MaterialPass {
|
||||||
|
|
||||||
struct Material {
|
struct Material {
|
||||||
bool is_alpha_blend_transparent;
|
bool is_alpha_blend_transparent;
|
||||||
|
bool has_transparent_shadows;
|
||||||
bool has_surface;
|
bool has_surface;
|
||||||
bool has_volume;
|
bool has_volume;
|
||||||
MaterialPass shadow;
|
MaterialPass shadow;
|
||||||
|
|
|
@ -742,6 +742,9 @@ void ShadowModule::init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jittered_transparency_ = !inst_.is_viewport() ||
|
||||||
|
scene.eevee.flag & SCE_EEVEE_SHADOW_JITTERED_VIEWPORT;
|
||||||
|
|
||||||
data_.ray_count = clamp_i(inst_.scene->eevee.shadow_ray_count, 1, SHADOW_MAX_RAY);
|
data_.ray_count = clamp_i(inst_.scene->eevee.shadow_ray_count, 1, SHADOW_MAX_RAY);
|
||||||
data_.step_count = clamp_i(inst_.scene->eevee.shadow_step_count, 1, SHADOW_MAX_STEP);
|
data_.step_count = clamp_i(inst_.scene->eevee.shadow_step_count, 1, SHADOW_MAX_STEP);
|
||||||
data_.normal_bias = max_ff(inst_.scene->eevee.shadow_normal_bias, 0.0f);
|
data_.normal_bias = max_ff(inst_.scene->eevee.shadow_normal_bias, 0.0f);
|
||||||
|
@ -824,6 +827,8 @@ void ShadowModule::begin_sync()
|
||||||
past_casters_updated_.clear();
|
past_casters_updated_.clear();
|
||||||
curr_casters_updated_.clear();
|
curr_casters_updated_.clear();
|
||||||
curr_casters_.clear();
|
curr_casters_.clear();
|
||||||
|
jittered_transparent_casters_.clear();
|
||||||
|
update_casters_ = true;
|
||||||
|
|
||||||
{
|
{
|
||||||
Manager &manager = *inst_.manager;
|
Manager &manager = *inst_.manager;
|
||||||
|
@ -897,7 +902,8 @@ void ShadowModule::begin_sync()
|
||||||
void ShadowModule::sync_object(const Object *ob,
|
void ShadowModule::sync_object(const Object *ob,
|
||||||
const ObjectHandle &handle,
|
const ObjectHandle &handle,
|
||||||
const ResourceHandle &resource_handle,
|
const ResourceHandle &resource_handle,
|
||||||
bool is_alpha_blend)
|
bool is_alpha_blend,
|
||||||
|
bool has_transparent_shadows)
|
||||||
{
|
{
|
||||||
bool is_shadow_caster = !(ob->visibility_flag & OB_HIDE_SHADOW);
|
bool is_shadow_caster = !(ob->visibility_flag & OB_HIDE_SHADOW);
|
||||||
if (!is_shadow_caster && !is_alpha_blend) {
|
if (!is_shadow_caster && !is_alpha_blend) {
|
||||||
|
@ -907,12 +913,19 @@ void ShadowModule::sync_object(const Object *ob,
|
||||||
ShadowObject &shadow_ob = objects_.lookup_or_add_default(handle.object_key);
|
ShadowObject &shadow_ob = objects_.lookup_or_add_default(handle.object_key);
|
||||||
shadow_ob.used = true;
|
shadow_ob.used = true;
|
||||||
const bool is_initialized = shadow_ob.resource_handle.raw != 0;
|
const bool is_initialized = shadow_ob.resource_handle.raw != 0;
|
||||||
if ((handle.recalc != 0 || !is_initialized) && is_shadow_caster) {
|
const bool has_jittered_transparency = has_transparent_shadows && jittered_transparency_;
|
||||||
if (shadow_ob.resource_handle.raw != 0) {
|
if (is_shadow_caster && (handle.recalc || !is_initialized || has_jittered_transparency)) {
|
||||||
|
if (handle.recalc && is_initialized) {
|
||||||
past_casters_updated_.append(shadow_ob.resource_handle.raw);
|
past_casters_updated_.append(shadow_ob.resource_handle.raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_jittered_transparency) {
|
||||||
|
jittered_transparent_casters_.append(resource_handle.raw);
|
||||||
|
}
|
||||||
|
else {
|
||||||
curr_casters_updated_.append(resource_handle.raw);
|
curr_casters_updated_.append(resource_handle.raw);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
shadow_ob.resource_handle = resource_handle;
|
shadow_ob.resource_handle = resource_handle;
|
||||||
|
|
||||||
if (is_shadow_caster) {
|
if (is_shadow_caster) {
|
||||||
|
@ -973,6 +986,7 @@ void ShadowModule::end_sync()
|
||||||
}
|
}
|
||||||
past_casters_updated_.push_update();
|
past_casters_updated_.push_update();
|
||||||
curr_casters_updated_.push_update();
|
curr_casters_updated_.push_update();
|
||||||
|
jittered_transparent_casters_.push_update();
|
||||||
|
|
||||||
curr_casters_.push_update();
|
curr_casters_.push_update();
|
||||||
|
|
||||||
|
@ -1080,6 +1094,22 @@ void ShadowModule::end_sync()
|
||||||
pass.barrier(GPU_BARRIER_SHADER_STORAGE);
|
pass.barrier(GPU_BARRIER_SHADER_STORAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Mark for update all shadow pages touching a jittered transparency shadow caster. */
|
||||||
|
PassSimple &pass = jittered_transparent_caster_update_ps_;
|
||||||
|
pass.init();
|
||||||
|
if (jittered_transparent_casters_.size() > 0) {
|
||||||
|
pass.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_UPDATE));
|
||||||
|
pass.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_data);
|
||||||
|
pass.bind_ssbo("tiles_buf", tilemap_pool.tiles_data);
|
||||||
|
pass.bind_ssbo("bounds_buf", &manager.bounds_buf.current());
|
||||||
|
pass.bind_ssbo("resource_ids_buf", jittered_transparent_casters_);
|
||||||
|
pass.dispatch(
|
||||||
|
int3(jittered_transparent_casters_.size(), 1, tilemap_pool.tilemaps_data.size()));
|
||||||
|
pass.barrier(GPU_BARRIER_SHADER_STORAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Non volume usage tagging happens between these two steps.
|
/* Non volume usage tagging happens between these two steps.
|
||||||
* (Setup at begin_sync) */
|
* (Setup at begin_sync) */
|
||||||
|
|
||||||
|
@ -1339,7 +1369,7 @@ void ShadowModule::set_view(View &view, GPUTexture *depth_tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
inst_.hiz_buffer.update();
|
inst_.hiz_buffer.update();
|
||||||
bool update_casters = true;
|
bool first_loop = true;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
DRW_stats_group_start("Shadow");
|
DRW_stats_group_start("Shadow");
|
||||||
|
@ -1347,12 +1377,15 @@ void ShadowModule::set_view(View &view, GPUTexture *depth_tx)
|
||||||
GPU_uniformbuf_clear_to_zero(shadow_multi_view_.matrices_ubo_get());
|
GPU_uniformbuf_clear_to_zero(shadow_multi_view_.matrices_ubo_get());
|
||||||
|
|
||||||
inst_.manager->submit(tilemap_setup_ps_, view);
|
inst_.manager->submit(tilemap_setup_ps_, view);
|
||||||
if (assign_if_different(update_casters, false)) {
|
if (assign_if_different(update_casters_, false)) {
|
||||||
/* Run caster update only once. */
|
/* Run caster update only once. */
|
||||||
/* TODO(fclem): There is an optimization opportunity here where we can
|
/* TODO(fclem): There is an optimization opportunity here where we can
|
||||||
* test casters only against the static tilemaps instead of all of them. */
|
* test casters only against the static tilemaps instead of all of them. */
|
||||||
inst_.manager->submit(caster_update_ps_, view);
|
inst_.manager->submit(caster_update_ps_, view);
|
||||||
}
|
}
|
||||||
|
if (assign_if_different(first_loop, false)) {
|
||||||
|
inst_.manager->submit(jittered_transparent_caster_update_ps_, view);
|
||||||
|
}
|
||||||
inst_.manager->submit(tilemap_usage_ps_, view);
|
inst_.manager->submit(tilemap_usage_ps_, view);
|
||||||
inst_.manager->submit(tilemap_update_ps_, view);
|
inst_.manager->submit(tilemap_update_ps_, view);
|
||||||
|
|
||||||
|
|
|
@ -213,6 +213,11 @@ class ShadowModule {
|
||||||
/** Map of shadow casters to track deletion & update of intersected shadows. */
|
/** Map of shadow casters to track deletion & update of intersected shadows. */
|
||||||
Map<ObjectKey, ShadowObject> objects_;
|
Map<ObjectKey, ShadowObject> objects_;
|
||||||
|
|
||||||
|
/* Used to call caster_update_ps_ only once per sync (Initialized on begin_sync). */
|
||||||
|
bool update_casters_ = false;
|
||||||
|
|
||||||
|
bool jittered_transparency_ = false;
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/** \name Tile-map Management
|
/** \name Tile-map Management
|
||||||
* \{ */
|
* \{ */
|
||||||
|
@ -229,9 +234,11 @@ class ShadowModule {
|
||||||
Framebuffer usage_tag_fb;
|
Framebuffer usage_tag_fb;
|
||||||
|
|
||||||
PassSimple caster_update_ps_ = {"CasterUpdate"};
|
PassSimple caster_update_ps_ = {"CasterUpdate"};
|
||||||
|
PassSimple jittered_transparent_caster_update_ps_ = {"TransparentCasterUpdate"};
|
||||||
/** List of Resource IDs (to get bounds) for tagging passes. */
|
/** List of Resource IDs (to get bounds) for tagging passes. */
|
||||||
StorageVectorBuffer<uint, 128> past_casters_updated_ = {"PastCastersUpdated"};
|
StorageVectorBuffer<uint, 128> past_casters_updated_ = {"PastCastersUpdated"};
|
||||||
StorageVectorBuffer<uint, 128> curr_casters_updated_ = {"CurrCastersUpdated"};
|
StorageVectorBuffer<uint, 128> curr_casters_updated_ = {"CurrCastersUpdated"};
|
||||||
|
StorageVectorBuffer<uint, 128> jittered_transparent_casters_ = {"JitteredTransparentCasters"};
|
||||||
/** List of Resource IDs (to get bounds) for getting minimum clip-maps bounds. */
|
/** List of Resource IDs (to get bounds) for getting minimum clip-maps bounds. */
|
||||||
StorageVectorBuffer<uint, 128> curr_casters_ = {"CurrCasters"};
|
StorageVectorBuffer<uint, 128> curr_casters_ = {"CurrCasters"};
|
||||||
|
|
||||||
|
@ -332,7 +339,8 @@ class ShadowModule {
|
||||||
void sync_object(const Object *ob,
|
void sync_object(const Object *ob,
|
||||||
const ObjectHandle &handle,
|
const ObjectHandle &handle,
|
||||||
const ResourceHandle &resource_handle,
|
const ResourceHandle &resource_handle,
|
||||||
bool is_alpha_blend);
|
bool is_alpha_blend,
|
||||||
|
bool has_transparent_shadows);
|
||||||
void end_sync();
|
void end_sync();
|
||||||
|
|
||||||
void set_lights_data();
|
void set_lights_data();
|
||||||
|
|
|
@ -114,6 +114,7 @@ void SyncModule::sync_mesh(Object *ob,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_alpha_blend = false;
|
bool is_alpha_blend = false;
|
||||||
|
bool has_transparent_shadows = false;
|
||||||
float inflate_bounds = 0.0f;
|
float inflate_bounds = 0.0f;
|
||||||
for (auto i : material_array.gpu_materials.index_range()) {
|
for (auto i : material_array.gpu_materials.index_range()) {
|
||||||
GPUBatch *geom = mat_geom[i];
|
GPUBatch *geom = mat_geom[i];
|
||||||
|
@ -147,6 +148,7 @@ void SyncModule::sync_mesh(Object *ob,
|
||||||
geometry_call(material.reflection_probe_shading.sub_pass, geom, res_handle);
|
geometry_call(material.reflection_probe_shading.sub_pass, geom, res_handle);
|
||||||
|
|
||||||
is_alpha_blend = is_alpha_blend || material.is_alpha_blend_transparent;
|
is_alpha_blend = is_alpha_blend || material.is_alpha_blend_transparent;
|
||||||
|
has_transparent_shadows = has_transparent_shadows || material.has_transparent_shadows;
|
||||||
|
|
||||||
::Material *mat = GPU_material_get_material(gpu_material);
|
::Material *mat = GPU_material_get_material(gpu_material);
|
||||||
inst_.cryptomatte.sync_material(mat);
|
inst_.cryptomatte.sync_material(mat);
|
||||||
|
@ -162,7 +164,7 @@ void SyncModule::sync_mesh(Object *ob,
|
||||||
|
|
||||||
inst_.manager->extract_object_attributes(res_handle, ob_ref, material_array.gpu_materials);
|
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);
|
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend, has_transparent_shadows);
|
||||||
inst_.cryptomatte.sync_object(ob, res_handle);
|
inst_.cryptomatte.sync_object(ob, res_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,6 +194,7 @@ bool SyncModule::sync_sculpt(Object *ob,
|
||||||
MaterialArray &material_array = inst_.materials.material_array_get(ob, has_motion);
|
MaterialArray &material_array = inst_.materials.material_array_get(ob, has_motion);
|
||||||
|
|
||||||
bool is_alpha_blend = false;
|
bool is_alpha_blend = false;
|
||||||
|
bool has_transparent_shadows = false;
|
||||||
float inflate_bounds = 0.0f;
|
float inflate_bounds = 0.0f;
|
||||||
for (SculptBatch &batch :
|
for (SculptBatch &batch :
|
||||||
sculpt_batches_per_material_get(ob_ref.object, material_array.gpu_materials))
|
sculpt_batches_per_material_get(ob_ref.object, material_array.gpu_materials))
|
||||||
|
@ -226,6 +229,7 @@ bool SyncModule::sync_sculpt(Object *ob,
|
||||||
geometry_call(material.reflection_probe_shading.sub_pass, geom, res_handle);
|
geometry_call(material.reflection_probe_shading.sub_pass, geom, res_handle);
|
||||||
|
|
||||||
is_alpha_blend = is_alpha_blend || material.is_alpha_blend_transparent;
|
is_alpha_blend = is_alpha_blend || material.is_alpha_blend_transparent;
|
||||||
|
has_transparent_shadows = has_transparent_shadows || material.has_transparent_shadows;
|
||||||
|
|
||||||
GPUMaterial *gpu_material = material_array.gpu_materials[batch.material_slot];
|
GPUMaterial *gpu_material = material_array.gpu_materials[batch.material_slot];
|
||||||
::Material *mat = GPU_material_get_material(gpu_material);
|
::Material *mat = GPU_material_get_material(gpu_material);
|
||||||
|
@ -245,7 +249,7 @@ bool SyncModule::sync_sculpt(Object *ob,
|
||||||
|
|
||||||
inst_.manager->extract_object_attributes(res_handle, ob_ref, material_array.gpu_materials);
|
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);
|
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend, has_transparent_shadows);
|
||||||
inst_.cryptomatte.sync_object(ob, res_handle);
|
inst_.cryptomatte.sync_object(ob, res_handle);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -308,13 +312,15 @@ void SyncModule::sync_point_cloud(Object *ob,
|
||||||
::Material *mat = GPU_material_get_material(gpu_material);
|
::Material *mat = GPU_material_get_material(gpu_material);
|
||||||
inst_.cryptomatte.sync_material(mat);
|
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) {
|
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_.manager->update_handle_bounds(res_handle, ob_ref, mat->inflate_bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend);
|
inst_.shadows.sync_object(ob,
|
||||||
|
ob_handle,
|
||||||
|
res_handle,
|
||||||
|
material.is_alpha_blend_transparent,
|
||||||
|
material.has_transparent_shadows);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
@ -486,7 +492,8 @@ void SyncModule::sync_gpencil(Object *ob, ObjectHandle &ob_handle, ResourceHandl
|
||||||
gpencil_drawcall_flush(iter);
|
gpencil_drawcall_flush(iter);
|
||||||
|
|
||||||
bool is_alpha_blend = true; /* TODO material.is_alpha_blend. */
|
bool is_alpha_blend = true; /* TODO material.is_alpha_blend. */
|
||||||
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend);
|
bool has_transparent_shadows = true; /* TODO material.has_transparent_shadows. */
|
||||||
|
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend, has_transparent_shadows);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
@ -560,13 +567,15 @@ void SyncModule::sync_curves(Object *ob,
|
||||||
::Material *mat = GPU_material_get_material(gpu_material);
|
::Material *mat = GPU_material_get_material(gpu_material);
|
||||||
inst_.cryptomatte.sync_material(mat);
|
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) {
|
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_.manager->update_handle_bounds(res_handle, ob_ref, mat->inflate_bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend);
|
inst_.shadows.sync_object(ob,
|
||||||
|
ob_handle,
|
||||||
|
res_handle,
|
||||||
|
material.is_alpha_blend_transparent,
|
||||||
|
material.has_transparent_shadows);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
|
@ -31,7 +31,8 @@ void main()
|
||||||
nodetree_surface(0.0);
|
nodetree_surface(0.0);
|
||||||
|
|
||||||
float noise_offset = sampling_rng_1D_get(SAMPLING_TRANSPARENCY);
|
float noise_offset = sampling_rng_1D_get(SAMPLING_TRANSPARENCY);
|
||||||
float random_threshold = transparency_hashed_alpha_threshold(1.0, noise_offset, g_data.P);
|
float random_threshold = transparency_hashed_alpha_threshold(
|
||||||
|
uniform_buf.pipeline.alpha_hash_scale, noise_offset, g_data.P);
|
||||||
|
|
||||||
float transparency = average(g_transmittance);
|
float transparency = average(g_transmittance);
|
||||||
if (transparency > random_threshold) {
|
if (transparency > random_threshold) {
|
||||||
|
|
|
@ -2887,6 +2887,7 @@ enum {
|
||||||
SCE_EEVEE_DOF_JITTER = (1 << 23),
|
SCE_EEVEE_DOF_JITTER = (1 << 23),
|
||||||
SCE_EEVEE_SHADOW_ENABLED = (1 << 24),
|
SCE_EEVEE_SHADOW_ENABLED = (1 << 24),
|
||||||
SCE_EEVEE_RAYTRACE_OPTIONS_SPLIT = (1 << 25),
|
SCE_EEVEE_RAYTRACE_OPTIONS_SPLIT = (1 << 25),
|
||||||
|
SCE_EEVEE_SHADOW_JITTERED_VIEWPORT = (1 << 26),
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum RaytraceEEVEE_Flag {
|
typedef enum RaytraceEEVEE_Flag {
|
||||||
|
|
|
@ -8038,6 +8038,14 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
|
||||||
prop, "Tracing Method", "Select the tracing method used to find scene-ray intersections");
|
prop, "Tracing Method", "Select the tracing method used to find scene-ray intersections");
|
||||||
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr);
|
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr);
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "use_shadow_jittered_viewport", PROP_BOOLEAN, PROP_NONE);
|
||||||
|
RNA_def_property_boolean_sdna(prop, nullptr, "flag", SCE_EEVEE_SHADOW_JITTERED_VIEWPORT);
|
||||||
|
RNA_def_property_ui_text(prop,
|
||||||
|
"Jittered Shadows (Viewport)",
|
||||||
|
"Enable jittered shadows on the viewport. (Jittered shadows are always "
|
||||||
|
"enabled for final renders)");
|
||||||
|
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr);
|
||||||
|
|
||||||
/* Volumetrics */
|
/* Volumetrics */
|
||||||
prop = RNA_def_property(srna, "volumetric_start", PROP_FLOAT, PROP_DISTANCE);
|
prop = RNA_def_property(srna, "volumetric_start", PROP_FLOAT, PROP_DISTANCE);
|
||||||
RNA_def_property_ui_text(prop, "Start", "Start distance of the volumetric effect");
|
RNA_def_property_ui_text(prop, "Start", "Start distance of the volumetric effect");
|
||||||
|
|
Loading…
Reference in New Issue