Cycles: Make adaptive subdivision a non-experimental feature
* Add adaptive subdivision properties natively on the subdivision surface modifier, so that other engines may reuse them in the future. This also resolve issues where they would not get copied properly. * Remove "Feature Set" option in the render properties, this was the last experimental one. * Add space choice between "Pixel" and "Object". The latter is new and can be used for object space dicing that works with instances. Instead of a pixel size an object space edge length is specified. * Add object space subdivision test. Ref #53901 Pull Request: https://projects.blender.org/blender/blender/pulls/146723
This commit is contained in:
committed by
Brecht Van Lommel
parent
2a1a658492
commit
689f182792
@@ -33,17 +33,6 @@ enum_devices = (
|
||||
"Use GPU compute device for rendering, configured in the system tab in the user preferences"),
|
||||
)
|
||||
|
||||
enum_feature_set = (
|
||||
('SUPPORTED',
|
||||
"Supported",
|
||||
"Only use finished and supported features"),
|
||||
('EXPERIMENTAL',
|
||||
"Experimental",
|
||||
"Use experimental and incomplete features that might be broken or change in the future",
|
||||
'ERROR',
|
||||
1),
|
||||
)
|
||||
|
||||
enum_bvh_layouts = (
|
||||
('BVH2', "BVH2", "", 1),
|
||||
('EMBREE', "Embree", "", 4),
|
||||
@@ -395,13 +384,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
items=enum_devices,
|
||||
default='CPU',
|
||||
)
|
||||
feature_set: EnumProperty(
|
||||
name="Feature Set",
|
||||
description="Feature set to use for rendering",
|
||||
items=enum_feature_set,
|
||||
default='SUPPORTED',
|
||||
update=update_render_engine,
|
||||
)
|
||||
shading_system: BoolProperty(
|
||||
name="Open Shading Language",
|
||||
description="Use Open Shading Language",
|
||||
@@ -806,22 +788,20 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
|
||||
dicing_rate: FloatProperty(
|
||||
name="Dicing Rate",
|
||||
description="Size of a micropolygon in pixels",
|
||||
description="Multiplier for per object adaptive subdivision size",
|
||||
min=0.1, max=1000.0, soft_min=0.5,
|
||||
default=1.0,
|
||||
subtype='PIXEL'
|
||||
)
|
||||
preview_dicing_rate: FloatProperty(
|
||||
name="Viewport Dicing Rate",
|
||||
description="Size of a micropolygon in pixels during preview render",
|
||||
description="Multiplier for per object adaptive subdivision size in the viewport",
|
||||
min=0.1, max=1000.0, soft_min=0.5,
|
||||
default=8.0,
|
||||
subtype='PIXEL'
|
||||
)
|
||||
|
||||
max_subdivisions: IntProperty(
|
||||
name="Max Subdivisions",
|
||||
description="Stop subdividing when this level is reached even if the dice rate would produce finer tessellation",
|
||||
description="Stop subdividing when this level is reached even if the dicing rate would produce finer tessellation",
|
||||
min=0,
|
||||
max=16,
|
||||
default=12,
|
||||
@@ -1378,19 +1358,6 @@ class CyclesObjectSettings(bpy.types.PropertyGroup):
|
||||
default=False,
|
||||
)
|
||||
|
||||
use_adaptive_subdivision: BoolProperty(
|
||||
name="Use Adaptive Subdivision",
|
||||
description="Use adaptive render time subdivision",
|
||||
default=False,
|
||||
)
|
||||
|
||||
dicing_rate: FloatProperty(
|
||||
name="Dicing Scale",
|
||||
description="Multiplier for scene dicing rate (located in the Subdivision panel)",
|
||||
min=0.1, max=1000.0, soft_min=0.5,
|
||||
default=1.0,
|
||||
)
|
||||
|
||||
shadow_terminator_offset: FloatProperty(
|
||||
name="Shadow Terminator Shading Offset",
|
||||
description="Push the shadow terminator towards the light to hide artifacts on low poly geometry",
|
||||
|
||||
@@ -524,10 +524,6 @@ class CYCLES_RENDER_PT_subdivision(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Subdivision"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.scene.render.engine == 'CYCLES') and (context.scene.cycles.feature_set == 'EXPERIMENTAL')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
@@ -2450,9 +2446,6 @@ def draw_device(self, context):
|
||||
from . import engine
|
||||
cscene = scene.cycles
|
||||
|
||||
col = layout.column()
|
||||
col.prop(cscene, "feature_set")
|
||||
|
||||
col = layout.column()
|
||||
col.active = show_device_active(context)
|
||||
col.prop(cscene, "device")
|
||||
|
||||
@@ -834,9 +834,20 @@ static void create_subd_mesh(Scene *scene,
|
||||
}
|
||||
|
||||
/* Set subd parameters. */
|
||||
PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
|
||||
const float subd_dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate);
|
||||
Mesh::SubdivisionAdaptiveSpace space = Mesh::SUBDIVISION_ADAPTIVE_SPACE_PIXEL;
|
||||
switch (subsurf_mod.adaptive_space()) {
|
||||
case BL::SubsurfModifier::adaptive_space_OBJECT:
|
||||
space = Mesh::SUBDIVISION_ADAPTIVE_SPACE_OBJECT;
|
||||
break;
|
||||
case BL::SubsurfModifier::adaptive_space_PIXEL:
|
||||
space = Mesh::SUBDIVISION_ADAPTIVE_SPACE_PIXEL;
|
||||
break;
|
||||
}
|
||||
const float subd_dicing_rate = (space == Mesh::SUBDIVISION_ADAPTIVE_SPACE_PIXEL) ?
|
||||
max(0.1f, subsurf_mod.adaptive_pixel_size() * dicing_rate) :
|
||||
subsurf_mod.adaptive_object_edge_length() * dicing_rate;
|
||||
|
||||
mesh->set_subd_adaptive_space(space);
|
||||
mesh->set_subd_dicing_rate(subd_dicing_rate);
|
||||
mesh->set_subd_max_level(max_subdivisions);
|
||||
mesh->set_subd_objecttoworld(get_transform(b_ob.matrix_world()));
|
||||
|
||||
@@ -337,8 +337,7 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer,
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
|
||||
/* No adaptive subdivision for baking, mesh needs to match Blender exactly. */
|
||||
use_adaptive_subdivision = (get_enum(cscene, "feature_set") != 0) && !b_bake_target;
|
||||
use_experimental_procedural = (get_enum(cscene, "feature_set") != 0);
|
||||
use_adaptive_subdivision = !b_bake_target;
|
||||
|
||||
Integrator *integrator = scene->integrator;
|
||||
|
||||
@@ -936,9 +935,6 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
|
||||
params.temp_dir = b_engine.temporary_directory();
|
||||
}
|
||||
|
||||
/* feature set */
|
||||
params.experimental = (get_enum(cscene, "feature_set") != 0);
|
||||
|
||||
/* Headless and background rendering. */
|
||||
params.headless = BlenderSession::headless;
|
||||
params.background = background;
|
||||
|
||||
@@ -241,7 +241,6 @@ class BlenderSync {
|
||||
|
||||
Scene *scene;
|
||||
bool preview;
|
||||
bool use_experimental_procedural = false;
|
||||
bool use_adaptive_subdivision = false;
|
||||
bool use_developer_ui;
|
||||
|
||||
|
||||
@@ -667,17 +667,15 @@ static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b
|
||||
|
||||
static BL::SubsurfModifier object_subdivision_modifier(BL::Object &b_ob, const bool preview)
|
||||
{
|
||||
PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
|
||||
|
||||
if (cobj.data && !b_ob.modifiers.empty()) {
|
||||
if (!b_ob.modifiers.empty()) {
|
||||
BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length() - 1];
|
||||
const bool enabled = preview ? mod.show_viewport() : mod.show_render();
|
||||
|
||||
if (enabled && mod.type() == BL::Modifier::type_SUBSURF &&
|
||||
RNA_boolean_get(&cobj, "use_adaptive_subdivision"))
|
||||
{
|
||||
if (enabled && mod.type() == BL::Modifier::type_SUBSURF) {
|
||||
BL::SubsurfModifier subsurf(mod);
|
||||
return subsurf;
|
||||
if (subsurf.use_adaptive_subdivision()) {
|
||||
return subsurf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -805,8 +805,10 @@ void GeometryManager::device_update(Device *device,
|
||||
SubdParams subd_params(mesh);
|
||||
subd_params.dicing_rate = mesh->get_subd_dicing_rate();
|
||||
subd_params.max_level = mesh->get_subd_max_level();
|
||||
subd_params.objecttoworld = mesh->get_subd_objecttoworld();
|
||||
subd_params.camera = dicing_camera;
|
||||
if (mesh->get_subd_adaptive_space() == Mesh::SUBDIVISION_ADAPTIVE_SPACE_PIXEL) {
|
||||
subd_params.objecttoworld = mesh->get_subd_objecttoworld();
|
||||
subd_params.camera = dicing_camera;
|
||||
}
|
||||
|
||||
mesh->tessellate(subd_params);
|
||||
}
|
||||
|
||||
@@ -305,6 +305,14 @@ NODE_DEFINE(Mesh)
|
||||
SOCKET_INT_ARRAY(subd_ptex_offset, "Subdivision Face PTex Offset", array<int>());
|
||||
|
||||
/* Subdivisions parameters */
|
||||
static NodeEnum subd_adaptive_space_enum;
|
||||
subd_adaptive_space_enum.insert("pixel", SUBDIVISION_ADAPTIVE_SPACE_PIXEL);
|
||||
subd_adaptive_space_enum.insert("object", SUBDIVISION_ADAPTIVE_SPACE_OBJECT);
|
||||
|
||||
SOCKET_ENUM(subd_adaptive_space,
|
||||
"Subdivision Adaptive Space",
|
||||
subd_adaptive_space_enum,
|
||||
SUBDIVISION_ADAPTIVE_SPACE_PIXEL);
|
||||
SOCKET_FLOAT(subd_dicing_rate, "Subdivision Dicing Rate", 1.0f)
|
||||
SOCKET_INT(subd_max_level, "Max Subdivision Level", 1);
|
||||
SOCKET_TRANSFORM(subd_objecttoworld, "Subdivision Object Transform", transform_identity());
|
||||
@@ -316,7 +324,8 @@ bool Mesh::need_tesselation()
|
||||
{
|
||||
return (subdivision_type != SUBDIVISION_NONE) &&
|
||||
(verts_is_modified() || subd_dicing_rate_is_modified() ||
|
||||
subd_objecttoworld_is_modified() || subd_max_level_is_modified());
|
||||
subd_adaptive_space_is_modified() || subd_objecttoworld_is_modified() ||
|
||||
subd_max_level_is_modified());
|
||||
}
|
||||
|
||||
Mesh::Mesh(const NodeType *node_type, Type geom_type_)
|
||||
|
||||
@@ -135,6 +135,11 @@ class Mesh : public Geometry {
|
||||
SUBDIVISION_FVAR_LINEAR_ALL,
|
||||
};
|
||||
|
||||
enum SubdivisionAdaptiveSpace {
|
||||
SUBDIVISION_ADAPTIVE_SPACE_PIXEL,
|
||||
SUBDIVISION_ADAPTIVE_SPACE_OBJECT,
|
||||
};
|
||||
|
||||
NODE_SOCKET_API(SubdivisionType, subdivision_type)
|
||||
NODE_SOCKET_API(SubdivisionBoundaryInterpolation, subdivision_boundary_interpolation)
|
||||
NODE_SOCKET_API(SubdivisionFVarInterpolation, subdivision_fvar_interpolation)
|
||||
@@ -161,6 +166,7 @@ class Mesh : public Geometry {
|
||||
NODE_SOCKET_API_ARRAY(array<float>, subd_vert_creases_weight)
|
||||
|
||||
/* Subdivisions parameters */
|
||||
NODE_SOCKET_API(SubdivisionAdaptiveSpace, subd_adaptive_space)
|
||||
NODE_SOCKET_API(float, subd_dicing_rate)
|
||||
NODE_SOCKET_API(int, subd_max_level)
|
||||
NODE_SOCKET_API(Transform, subd_objecttoworld)
|
||||
|
||||
@@ -44,7 +44,6 @@ class SessionParams {
|
||||
bool headless;
|
||||
bool background;
|
||||
|
||||
bool experimental;
|
||||
int samples;
|
||||
bool use_sample_subset;
|
||||
int sample_subset_offset;
|
||||
@@ -73,7 +72,6 @@ class SessionParams {
|
||||
headless = false;
|
||||
background = false;
|
||||
|
||||
experimental = false;
|
||||
samples = 1024;
|
||||
use_sample_subset = false;
|
||||
sample_subset_offset = 0;
|
||||
@@ -97,10 +95,10 @@ class SessionParams {
|
||||
/* Modified means we have to recreate the session, any parameter changes
|
||||
* that can be handled by an existing Session are omitted. */
|
||||
return !(device == params.device && headless == params.headless &&
|
||||
background == params.background && experimental == params.experimental &&
|
||||
pixel_size == params.pixel_size && threads == params.threads &&
|
||||
use_profiling == params.use_profiling && shadingsystem == params.shadingsystem &&
|
||||
use_auto_tile == params.use_auto_tile && tile_size == params.tile_size);
|
||||
background == params.background && pixel_size == params.pixel_size &&
|
||||
threads == params.threads && use_profiling == params.use_profiling &&
|
||||
shadingsystem == params.shadingsystem && use_auto_tile == params.use_auto_tile &&
|
||||
tile_size == params.tile_size);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 91
|
||||
#define BLENDER_FILE_SUBVERSION 92
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
||||
@@ -220,14 +220,6 @@ bool BKE_scene_uses_cycles(const Scene *scene);
|
||||
|
||||
bool BKE_scene_uses_shader_previews(const Scene *scene);
|
||||
|
||||
/**
|
||||
* Return whether the Cycles experimental feature is enabled. It is invalid to call without first
|
||||
* ensuring that Cycles is the active render engine (e.g. with #BKE_scene_uses_cycles).
|
||||
*
|
||||
* \note We cannot use `const` as RNA_id_pointer_create is not using a const ID.
|
||||
*/
|
||||
bool BKE_scene_uses_cycles_experimental_features(Scene *scene);
|
||||
|
||||
void BKE_scene_copy_data_eevee(Scene *sce_dst, const Scene *sce_src);
|
||||
|
||||
void BKE_scene_disable_color_management(Scene *scene);
|
||||
|
||||
@@ -2801,20 +2801,6 @@ enum eCyclesFeatureSet {
|
||||
CYCLES_FEATURES_EXPERIMENTAL = 1,
|
||||
};
|
||||
|
||||
bool BKE_scene_uses_cycles_experimental_features(Scene *scene)
|
||||
{
|
||||
BLI_assert(BKE_scene_uses_cycles(scene));
|
||||
PointerRNA scene_ptr = RNA_id_pointer_create(&scene->id);
|
||||
PointerRNA cycles_ptr = RNA_pointer_get(&scene_ptr, "cycles");
|
||||
|
||||
if (RNA_pointer_is_null(&cycles_ptr)) {
|
||||
/* The pointer only exists if Cycles is enabled. */
|
||||
return false;
|
||||
}
|
||||
|
||||
return RNA_enum_get(&cycles_ptr, "feature_set") == CYCLES_FEATURES_EXPERIMENTAL;
|
||||
}
|
||||
|
||||
void BKE_scene_base_flag_to_objects(const Scene *scene, ViewLayer *view_layer)
|
||||
{
|
||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||
|
||||
@@ -2658,6 +2658,44 @@ static void sequencer_remove_listbase_pointers(Scene &scene)
|
||||
blender::seq::meta_stack_set(&scene, last_meta_stack->parent_strip);
|
||||
}
|
||||
|
||||
static void do_version_adaptive_subdivision(Main *bmain)
|
||||
{
|
||||
/* Move cycles properties natively into subdivision surface modifier. */
|
||||
bool experimental_features = false;
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
IDProperty *idprop = version_cycles_properties_from_ID(&scene->id);
|
||||
if (idprop) {
|
||||
experimental_features |= version_cycles_property_boolean(idprop, "feature_set", false);
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Object *, object, &bmain->objects) {
|
||||
bool use_adaptive_subdivision = false;
|
||||
float dicing_rate = 1.0f;
|
||||
|
||||
IDProperty *idprop = version_cycles_properties_from_ID(&object->id);
|
||||
if (idprop) {
|
||||
if (experimental_features) {
|
||||
use_adaptive_subdivision = version_cycles_property_boolean(
|
||||
idprop, "use_adaptive_subdivision", false);
|
||||
}
|
||||
dicing_rate = version_cycles_property_float(idprop, "dicing_rate", 1.0f);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
|
||||
if (md->type == eModifierType_Subsurf) {
|
||||
SubsurfModifierData *smd = (SubsurfModifierData *)md;
|
||||
if (use_adaptive_subdivision) {
|
||||
smd->flags |= eSubsurfModifierFlag_UseAdaptiveSubdivision;
|
||||
smd->adaptive_space = SUBSURF_ADAPTIVE_SPACE_PIXEL;
|
||||
smd->adaptive_pixel_size = dicing_rate;
|
||||
smd->adaptive_object_edge_length = 0.01f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void blo_do_versions_500(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||
{
|
||||
using namespace blender;
|
||||
@@ -3625,6 +3663,10 @@ void blo_do_versions_500(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 92)) {
|
||||
do_version_adaptive_subdivision(bmain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
|
||||
|
||||
@@ -615,6 +615,9 @@
|
||||
.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, \
|
||||
.quality = 3, \
|
||||
.boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL, \
|
||||
.adaptive_space = SUBSURF_ADAPTIVE_SPACE_PIXEL, \
|
||||
.adaptive_pixel_size = 1.0f, \
|
||||
.adaptive_object_edge_length = 0.01f, \
|
||||
}
|
||||
|
||||
#define _DNA_DEFAULT_SurfaceModifierData \
|
||||
|
||||
@@ -234,8 +234,14 @@ typedef enum {
|
||||
eSubsurfModifierFlag_UseCrease = (1 << 4),
|
||||
eSubsurfModifierFlag_UseCustomNormals = (1 << 5),
|
||||
eSubsurfModifierFlag_UseRecursiveSubdivision = (1 << 6),
|
||||
eSubsurfModifierFlag_UseAdaptiveSubdivision = (1 << 7),
|
||||
} SubsurfModifierFlag;
|
||||
|
||||
typedef enum {
|
||||
SUBSURF_ADAPTIVE_SPACE_PIXEL = 0,
|
||||
SUBSURF_ADAPTIVE_SPACE_OBJECT = 1,
|
||||
} eSubsurfAdaptiveSpace;
|
||||
|
||||
typedef enum {
|
||||
SUBSURF_TYPE_CATMULL_CLARK = 0,
|
||||
SUBSURF_TYPE_SIMPLE = 1,
|
||||
@@ -268,7 +274,11 @@ typedef struct SubsurfModifierData {
|
||||
short quality;
|
||||
/** #eSubsurfBoundarySmooth. */
|
||||
short boundary_smooth;
|
||||
char _pad[2];
|
||||
/* Adaptive subdivision. */
|
||||
/** #eSubsurfAdaptiveSpace */
|
||||
short adaptive_space;
|
||||
float adaptive_pixel_size;
|
||||
float adaptive_object_edge_length;
|
||||
} SubsurfModifierData;
|
||||
|
||||
typedef struct LatticeModifierData {
|
||||
|
||||
@@ -2451,6 +2451,21 @@ static void rna_def_modifier_subsurf(BlenderRNA *brna)
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem prop_adaptive_space_items[] = {
|
||||
{SUBSURF_ADAPTIVE_SPACE_PIXEL,
|
||||
"PIXEL",
|
||||
0,
|
||||
"Pixel",
|
||||
"Subdivide polygons to reach a specified pixel size on screen"},
|
||||
{SUBSURF_ADAPTIVE_SPACE_OBJECT,
|
||||
"OBJECT",
|
||||
0,
|
||||
"Object",
|
||||
"Subdivide to reach a specified edge length in object space. This is required to use "
|
||||
"adaptive subdivision for instanced meshes"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
@@ -2510,6 +2525,32 @@ static void rna_def_modifier_subsurf(BlenderRNA *brna)
|
||||
"levels of subdivision (smoothest possible shape)");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_adaptive_subdivision", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(
|
||||
prop, nullptr, "flags", eSubsurfModifierFlag_UseAdaptiveSubdivision);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Use Adaptive Subdivision", "Adaptively subdivide mesh based on camera distance");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "adaptive_space", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, prop_adaptive_space_items);
|
||||
RNA_def_property_ui_text(prop, "Adaptive Space", "How to adaptively subdivide the mesh");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "adaptive_pixel_size", PROP_FLOAT, PROP_PIXEL);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Pixel Size", "Target polygon pixel size for adaptive subdivision");
|
||||
RNA_def_property_range(prop, 0.1f, 1000.0f);
|
||||
RNA_def_property_ui_range(prop, 0.5f, 1000.0f, 10, 3);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "adaptive_object_edge_length", PROP_FLOAT, PROP_DISTANCE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Edge Length", "Target object space edge length for adaptive subdivision");
|
||||
RNA_def_property_range(prop, 0.0001f, 1000.0f);
|
||||
RNA_def_property_ui_range(prop, 0.001f, 1000.0f, 10, 3);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
rna_def_modifier_panel_open_prop(srna, "open_adaptive_subdivision_panel", 0);
|
||||
rna_def_modifier_panel_open_prop(srna, "open_advanced_panel", 1);
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "DNA_defaults.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
@@ -315,7 +316,6 @@ static void deform_matrices(ModifierData *md,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_CYCLES
|
||||
static bool get_show_adaptive_options(const bContext *C, Panel *panel)
|
||||
{
|
||||
/* Don't show adaptive options if cycles isn't the active engine. */
|
||||
@@ -331,15 +331,8 @@ static bool get_show_adaptive_options(const bContext *C, Panel *panel)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Don't show adaptive options if the cycles experimental feature set is disabled. */
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
if (!BKE_scene_uses_cycles_experimental_features(scene)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void panel_draw(const bContext *C, Panel *panel)
|
||||
{
|
||||
@@ -348,27 +341,6 @@ static void panel_draw(const bContext *C, Panel *panel)
|
||||
PointerRNA ob_ptr;
|
||||
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
|
||||
|
||||
/* Only test for adaptive subdivision if built with cycles. */
|
||||
bool show_adaptive_options = false;
|
||||
bool ob_use_adaptive_subdivision = false;
|
||||
PointerRNA cycles_ptr = {};
|
||||
PointerRNA ob_cycles_ptr = {};
|
||||
#ifdef WITH_CYCLES
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
PointerRNA scene_ptr = RNA_id_pointer_create(&scene->id);
|
||||
if (BKE_scene_uses_cycles(scene)) {
|
||||
cycles_ptr = RNA_pointer_get(&scene_ptr, "cycles");
|
||||
ob_cycles_ptr = RNA_pointer_get(&ob_ptr, "cycles");
|
||||
if (!RNA_pointer_is_null(&ob_cycles_ptr)) {
|
||||
show_adaptive_options = get_show_adaptive_options(C, panel);
|
||||
ob_use_adaptive_subdivision = show_adaptive_options &&
|
||||
RNA_boolean_get(&ob_cycles_ptr, "use_adaptive_subdivision");
|
||||
}
|
||||
}
|
||||
#else
|
||||
UNUSED_VARS(C);
|
||||
#endif
|
||||
|
||||
layout->prop(ptr, "subdivision_type", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
|
||||
|
||||
layout->use_property_split_set(true);
|
||||
@@ -402,31 +374,47 @@ static void panel_draw(const bContext *C, Panel *panel)
|
||||
}
|
||||
}
|
||||
|
||||
if (show_adaptive_options) {
|
||||
if (get_show_adaptive_options(C, panel)) {
|
||||
PanelLayout adaptive_panel = layout->panel_prop_with_bool_header(
|
||||
C,
|
||||
ptr,
|
||||
"open_adaptive_subdivision_panel",
|
||||
&ob_cycles_ptr,
|
||||
ptr,
|
||||
"use_adaptive_subdivision",
|
||||
IFACE_("Adaptive Subdivision"));
|
||||
if (adaptive_panel.body) {
|
||||
adaptive_panel.body->active_set(ob_use_adaptive_subdivision);
|
||||
adaptive_panel.body->prop(
|
||||
&ob_cycles_ptr, "dicing_rate", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
PointerRNA scene_ptr = RNA_id_pointer_create(&scene->id);
|
||||
PointerRNA cycles_ptr = RNA_pointer_get(&scene_ptr, "cycles");
|
||||
const float render_rate = RNA_float_get(&cycles_ptr, "dicing_rate");
|
||||
const float preview_rate = RNA_float_get(&cycles_ptr, "preview_dicing_rate");
|
||||
std::string render_str, preview_str;
|
||||
|
||||
float render = std::max(RNA_float_get(&cycles_ptr, "dicing_rate") *
|
||||
RNA_float_get(&ob_cycles_ptr, "dicing_rate"),
|
||||
0.1f);
|
||||
float preview = std::max(RNA_float_get(&cycles_ptr, "preview_dicing_rate") *
|
||||
RNA_float_get(&ob_cycles_ptr, "dicing_rate"),
|
||||
0.1f);
|
||||
adaptive_panel.body->active_set(smd->flags & eSubsurfModifierFlag_UseAdaptiveSubdivision);
|
||||
adaptive_panel.body->prop(ptr, "adaptive_space", UI_ITEM_NONE, IFACE_("Space"), ICON_NONE);
|
||||
if (smd->adaptive_space == SUBSURF_ADAPTIVE_SPACE_OBJECT) {
|
||||
adaptive_panel.body->prop(
|
||||
ptr, "adaptive_object_edge_length", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
preview_str = fmt::format("{:.5g}", preview_rate * smd->adaptive_object_edge_length);
|
||||
render_str = fmt::format("{:.5g}", render_rate * smd->adaptive_object_edge_length);
|
||||
}
|
||||
else {
|
||||
adaptive_panel.body->prop(
|
||||
ptr, "adaptive_pixel_size", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
preview_str = fmt::format("{:.2f} px",
|
||||
std::max(preview_rate * smd->adaptive_pixel_size, 0.1f));
|
||||
render_str = fmt::format("{:.2f} px",
|
||||
std::max(render_rate * smd->adaptive_pixel_size, 0.1f));
|
||||
}
|
||||
|
||||
uiLayout *split = &adaptive_panel.body->split(0.4f, false);
|
||||
split->column(true).label("", ICON_NONE);
|
||||
uiLayout *col = &split->column(true);
|
||||
col->label(fmt::format(fmt::runtime(RPT_("Viewport {:.2f} px")), preview), ICON_NONE);
|
||||
col->label(fmt::format(fmt::runtime(RPT_("Render {:.2f} px")), render), ICON_NONE);
|
||||
col->alignment_set(blender::ui::LayoutAlign::Right);
|
||||
col->label(IFACE_("Viewport"), ICON_NONE);
|
||||
col->label(IFACE_("Render"), ICON_NONE);
|
||||
col = &split->column(true);
|
||||
col->label(preview_str, ICON_NONE);
|
||||
col->label(render_str, ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,7 +426,8 @@ static void panel_draw(const bContext *C, Panel *panel)
|
||||
advanced_layout->prop(ptr, "use_limit_surface", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
uiLayout *col = &advanced_layout->column(true);
|
||||
col->active_set(ob_use_adaptive_subdivision || RNA_boolean_get(ptr, "use_limit_surface"));
|
||||
col->active_set((smd->flags & eSubsurfModifierFlag_UseAdaptiveSubdivision) ||
|
||||
RNA_boolean_get(ptr, "use_limit_surface"));
|
||||
col->prop(ptr, "quality", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
advanced_layout->prop(ptr, "uv_smooth", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
BIN
tests/files/render/displacement/cycles_renders/object_dicing.png
(Stored with Git LFS)
Normal file
BIN
tests/files/render/displacement/cycles_renders/object_dicing.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
tests/files/render/displacement/eevee_renders/object_dicing.png
(Stored with Git LFS)
Normal file
BIN
tests/files/render/displacement/eevee_renders/object_dicing.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
tests/files/render/displacement/object_dicing.blend
(Stored with Git LFS)
Normal file
BIN
tests/files/render/displacement/object_dicing.blend
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
tests/files/render/displacement/storm_hydra_renders/object_dicing.png
(Stored with Git LFS)
Normal file
BIN
tests/files/render/displacement/storm_hydra_renders/object_dicing.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
tests/files/render/displacement/storm_usd_renders/object_dicing.png
(Stored with Git LFS)
Normal file
BIN
tests/files/render/displacement/storm_usd_renders/object_dicing.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
tests/files/render/displacement/workbench_renders/object_dicing.png
(Stored with Git LFS)
Normal file
BIN
tests/files/render/displacement/workbench_renders/object_dicing.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Reference in New Issue
Block a user