Volumes: support lower resolution in viewport

The adds a new option to simplify volumes in the viewport.
The setting can be found in the Simplify panel in the render properties.

Volume objects use OpenVDB grids, which are sparse. For rendering,
we have to convert sparse grids to dense grids (for now). Those require
significantly more memory. Therefore, it's often a good idea to reduce
the resolution of volumes in the viewport.

Reviewers: brecht

Differential Revision: https://developer.blender.org/D9040

Ref T73201.
This commit is contained in:
Jacques Lucke
2020-10-01 17:58:43 +02:00
parent 5b8503425a
commit 365bf103d1
10 changed files with 221 additions and 152 deletions

View File

@@ -2082,6 +2082,7 @@ class CYCLES_RENDER_PT_simplify_viewport(CyclesButtonsPanel, Panel):
col.prop(rd, "simplify_child_particles", text="Child Particles") col.prop(rd, "simplify_child_particles", text="Child Particles")
col.prop(cscene, "texture_limit", text="Texture Limit") col.prop(cscene, "texture_limit", text="Texture Limit")
col.prop(cscene, "ao_bounces", text="AO Bounces") col.prop(cscene, "ao_bounces", text="AO Bounces")
col.prop(rd, "simplify_volumes", text="Volume Resolution")
class CYCLES_RENDER_PT_simplify_render(CyclesButtonsPanel, Panel): class CYCLES_RENDER_PT_simplify_render(CyclesButtonsPanel, Panel):

View File

@@ -656,6 +656,9 @@ class RENDER_PT_simplify_viewport(RenderButtonsPanel, Panel):
col = flow.column() col = flow.column()
col.prop(rd, "simplify_child_particles", text="Max Child Particles") col.prop(rd, "simplify_child_particles", text="Max Child Particles")
col = flow.column()
col.prop(rd, "simplify_volumes", text="Volume Resolution")
class RENDER_PT_simplify_render(RenderButtonsPanel, Panel): class RENDER_PT_simplify_render(RenderButtonsPanel, Panel):
bl_label = "Render" bl_label = "Render"

View File

@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */ /* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION #define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 6 #define BLENDER_FILE_SUBVERSION 7
/* Minimum Blender version that supports reading file written with the current /* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file * version. Older Blender versions will test this and show a warning if the file

View File

@@ -34,19 +34,19 @@ struct VolumeGrid;
/* Dense Voxels */ /* Dense Voxels */
bool BKE_volume_grid_dense_bounds(const struct Volume *volume, typedef struct DenseFloatVolumeGrid {
VolumeGridType type;
int resolution[3];
float texture_to_object[4][4];
int channels;
float *voxels;
} DenseFloatVolumeGrid;
bool BKE_volume_grid_dense_floats(const struct Volume *volume,
struct VolumeGrid *volume_grid, struct VolumeGrid *volume_grid,
int64_t min[3], const float resolution_factor,
int64_t max[3]); DenseFloatVolumeGrid *r_dense_grid);
void BKE_volume_grid_dense_transform_matrix(const struct VolumeGrid *volume_grid, void BKE_volume_dense_float_grid_clear(DenseFloatVolumeGrid *dense_grid);
const int64_t min[3],
const int64_t max[3],
float matrix[4][4]);
void BKE_volume_grid_dense_voxels(const struct Volume *volume,
struct VolumeGrid *volume_grid,
const int64_t min[3],
const int64_t max[3],
float *voxels);
/* Wireframe */ /* Wireframe */

View File

@@ -34,136 +34,181 @@
#ifdef WITH_OPENVDB #ifdef WITH_OPENVDB
# include <openvdb/openvdb.h> # include <openvdb/openvdb.h>
# include <openvdb/tools/Dense.h> # include <openvdb/tools/Dense.h>
# include <openvdb/tools/GridTransformer.h>
#endif #endif
/* Dense Voxels */ /* Dense Voxels */
bool BKE_volume_grid_dense_bounds(const Volume *volume,
VolumeGrid *volume_grid,
int64_t min[3],
int64_t max[3])
{
#ifdef WITH_OPENVDB #ifdef WITH_OPENVDB
openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
openvdb::CoordBBox bbox = grid->evalActiveVoxelBoundingBox(); /**
if (!bbox.empty()) { * Returns a grid of the same type as the input, but with more/less resolution. If
/* OpenVDB bbox is inclusive, so add 1 to convert. */ * resolution_factor is 1/2, the resolution on each axis is halved. The transform of the returned
min[0] = bbox.min().x(); * grid is adjusted to match the original grid. */
min[1] = bbox.min().y(); template<typename GridType>
min[2] = bbox.min().z(); static typename GridType::Ptr create_grid_with_changed_resolution(
max[0] = bbox.max().x() + 1; const openvdb::GridBase &old_grid, const float resolution_factor)
max[1] = bbox.max().y() + 1; {
max[2] = bbox.max().z() + 1; BLI_assert(resolution_factor > 0.0f);
return true; BLI_assert(old_grid.isType<GridType>());
openvdb::Mat4R xform;
xform.setToScale(openvdb::Vec3d(resolution_factor));
openvdb::tools::GridTransformer transformer{xform};
typename GridType::Ptr new_grid = GridType::create();
transformer.transformGrid<openvdb::tools::BoxSampler>(static_cast<const GridType &>(old_grid),
*new_grid);
new_grid->transform() = old_grid.transform();
new_grid->transform().preScale(1.0f / resolution_factor);
return new_grid;
}
static openvdb::GridBase::Ptr create_grid_with_changed_resolution(
const VolumeGridType grid_type,
const openvdb::GridBase &old_grid,
const float resolution_factor)
{
switch (grid_type) {
case VOLUME_GRID_BOOLEAN:
return create_grid_with_changed_resolution<openvdb::BoolGrid>(old_grid, resolution_factor);
case VOLUME_GRID_FLOAT:
return create_grid_with_changed_resolution<openvdb::FloatGrid>(old_grid, resolution_factor);
case VOLUME_GRID_DOUBLE:
return create_grid_with_changed_resolution<openvdb::DoubleGrid>(old_grid, resolution_factor);
case VOLUME_GRID_INT:
return create_grid_with_changed_resolution<openvdb::Int32Grid>(old_grid, resolution_factor);
case VOLUME_GRID_INT64:
return create_grid_with_changed_resolution<openvdb::Int64Grid>(old_grid, resolution_factor);
case VOLUME_GRID_MASK:
return create_grid_with_changed_resolution<openvdb::MaskGrid>(old_grid, resolution_factor);
case VOLUME_GRID_VECTOR_FLOAT:
return create_grid_with_changed_resolution<openvdb::Vec3fGrid>(old_grid, resolution_factor);
case VOLUME_GRID_VECTOR_DOUBLE:
return create_grid_with_changed_resolution<openvdb::Vec3dGrid>(old_grid, resolution_factor);
case VOLUME_GRID_VECTOR_INT:
return create_grid_with_changed_resolution<openvdb::Vec3IGrid>(old_grid, resolution_factor);
case VOLUME_GRID_STRING:
case VOLUME_GRID_POINTS:
case VOLUME_GRID_UNKNOWN:
/* Can't do this. */
break;
} }
#else return {};
UNUSED_VARS(volume, volume_grid); }
template<typename GridType, typename VoxelType>
static void extract_dense_voxels(const openvdb::GridBase &grid,
const openvdb::CoordBBox bbox,
VoxelType *r_voxels)
{
BLI_assert(grid.isType<GridType>());
openvdb::tools::Dense<VoxelType, openvdb::tools::LayoutXYZ> dense(bbox, r_voxels);
openvdb::tools::copyToDense(static_cast<const GridType &>(grid), dense);
}
static void extract_dense_float_voxels(const VolumeGridType grid_type,
const openvdb::GridBase &grid,
const openvdb::CoordBBox &bbox,
float *r_voxels)
{
switch (grid_type) {
case VOLUME_GRID_BOOLEAN:
return extract_dense_voxels<openvdb::BoolGrid, float>(grid, bbox, r_voxels);
case VOLUME_GRID_FLOAT:
return extract_dense_voxels<openvdb::FloatGrid, float>(grid, bbox, r_voxels);
case VOLUME_GRID_DOUBLE:
return extract_dense_voxels<openvdb::DoubleGrid, float>(grid, bbox, r_voxels);
case VOLUME_GRID_INT:
return extract_dense_voxels<openvdb::Int32Grid, float>(grid, bbox, r_voxels);
case VOLUME_GRID_INT64:
return extract_dense_voxels<openvdb::Int64Grid, float>(grid, bbox, r_voxels);
case VOLUME_GRID_MASK:
return extract_dense_voxels<openvdb::MaskGrid, float>(grid, bbox, r_voxels);
case VOLUME_GRID_VECTOR_FLOAT:
return extract_dense_voxels<openvdb::Vec3fGrid, openvdb::Vec3f>(
grid, bbox, reinterpret_cast<openvdb::Vec3f *>(r_voxels));
case VOLUME_GRID_VECTOR_DOUBLE:
return extract_dense_voxels<openvdb::Vec3dGrid, openvdb::Vec3f>(
grid, bbox, reinterpret_cast<openvdb::Vec3f *>(r_voxels));
case VOLUME_GRID_VECTOR_INT:
return extract_dense_voxels<openvdb::Vec3IGrid, openvdb::Vec3f>(
grid, bbox, reinterpret_cast<openvdb::Vec3f *>(r_voxels));
case VOLUME_GRID_STRING:
case VOLUME_GRID_POINTS:
case VOLUME_GRID_UNKNOWN:
/* Zero channels to copy. */
break;
}
return;
}
static void create_texture_to_object_matrix(const openvdb::Mat4d &grid_transform,
const openvdb::CoordBBox &bbox,
float r_texture_to_object[4][4])
{
float index_to_object[4][4];
memcpy(index_to_object, openvdb::Mat4s(grid_transform).asPointer(), sizeof(index_to_object));
float texture_to_index[4][4];
const openvdb::Vec3f loc = bbox.min().asVec3s();
const openvdb::Vec3f size = bbox.dim().asVec3s();
size_to_mat4(texture_to_index, size.asV());
copy_v3_v3(texture_to_index[3], loc.asV());
mul_m4_m4m4(r_texture_to_object, index_to_object, texture_to_index);
}
#endif #endif
min[0] = 0; bool BKE_volume_grid_dense_floats(const Volume *volume,
min[1] = 0; VolumeGrid *volume_grid,
min[2] = 0; const float resolution_factor,
max[0] = 0; DenseFloatVolumeGrid *r_dense_grid)
max[1] = 0; {
max[2] = 0; #ifdef WITH_OPENVDB
const VolumeGridType grid_type = BKE_volume_grid_type(volume_grid);
openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
if (resolution_factor != 1.0f) {
grid = create_grid_with_changed_resolution(grid_type, *grid, resolution_factor);
}
const openvdb::CoordBBox bbox = grid->evalActiveVoxelBoundingBox();
if (bbox.empty()) {
return false;
}
const openvdb::Vec3i resolution = bbox.dim().asVec3i();
const int64_t num_voxels = static_cast<int64_t>(resolution[0]) *
static_cast<int64_t>(resolution[1]) *
static_cast<int64_t>(resolution[2]);
const int channels = BKE_volume_grid_channels(volume_grid);
const int elem_size = sizeof(float) * channels;
float *voxels = static_cast<float *>(MEM_malloc_arrayN(num_voxels, elem_size, __func__));
if (voxels == NULL) {
return false;
}
extract_dense_float_voxels(grid_type, *grid, bbox, voxels);
create_texture_to_object_matrix(grid->transform().baseMap()->getAffineMap()->getMat4(),
bbox,
r_dense_grid->texture_to_object);
r_dense_grid->voxels = voxels;
r_dense_grid->channels = channels;
copy_v3_v3_int(r_dense_grid->resolution, resolution.asV());
return true;
#endif
UNUSED_VARS(volume, volume_grid, resolution_factor, r_dense_grid);
return false; return false;
} }
/* Transform matrix from unit cube to object space, for 3D texture sampling. */ void BKE_volume_dense_float_grid_clear(DenseFloatVolumeGrid *dense_grid)
void BKE_volume_grid_dense_transform_matrix(const VolumeGrid *volume_grid,
const int64_t min[3],
const int64_t max[3],
float mat[4][4])
{ {
#ifdef WITH_OPENVDB if (dense_grid->voxels != NULL) {
float index_to_world[4][4]; MEM_freeN(dense_grid->voxels);
BKE_volume_grid_transform_matrix(volume_grid, index_to_world);
float texture_to_index[4][4];
float loc[3] = {(float)min[0], (float)min[1], (float)min[2]};
float size[3] = {(float)(max[0] - min[0]), (float)(max[1] - min[1]), (float)(max[2] - min[2])};
size_to_mat4(texture_to_index, size);
copy_v3_v3(texture_to_index[3], loc);
mul_m4_m4m4(mat, index_to_world, texture_to_index);
#else
UNUSED_VARS(volume_grid, min, max);
unit_m4(mat);
#endif
}
void BKE_volume_grid_dense_voxels(const Volume *volume,
VolumeGrid *volume_grid,
const int64_t min[3],
const int64_t max[3],
float *voxels)
{
#ifdef WITH_OPENVDB
openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
/* Convert to OpenVDB inclusive bbox with -1. */
openvdb::CoordBBox bbox(min[0], min[1], min[2], max[0] - 1, max[1] - 1, max[2] - 1);
switch (BKE_volume_grid_type(volume_grid)) {
case VOLUME_GRID_BOOLEAN: {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, voxels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::BoolGrid>(grid), dense);
break;
}
case VOLUME_GRID_FLOAT: {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, voxels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid), dense);
break;
}
case VOLUME_GRID_DOUBLE: {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, voxels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::DoubleGrid>(grid), dense);
break;
}
case VOLUME_GRID_INT: {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, voxels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Int32Grid>(grid), dense);
break;
}
case VOLUME_GRID_INT64: {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, voxels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Int64Grid>(grid), dense);
break;
}
case VOLUME_GRID_MASK: {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, voxels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::MaskGrid>(grid), dense);
break;
}
case VOLUME_GRID_VECTOR_FLOAT: {
openvdb::tools::Dense<openvdb::Vec3f, openvdb::tools::LayoutXYZ> dense(
bbox, (openvdb::Vec3f *)voxels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Vec3fGrid>(grid), dense);
break;
}
case VOLUME_GRID_VECTOR_DOUBLE: {
openvdb::tools::Dense<openvdb::Vec3f, openvdb::tools::LayoutXYZ> dense(
bbox, (openvdb::Vec3f *)voxels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Vec3dGrid>(grid), dense);
break;
}
case VOLUME_GRID_VECTOR_INT: {
openvdb::tools::Dense<openvdb::Vec3f, openvdb::tools::LayoutXYZ> dense(
bbox, (openvdb::Vec3f *)voxels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Vec3IGrid>(grid), dense);
break;
}
case VOLUME_GRID_STRING:
case VOLUME_GRID_POINTS:
case VOLUME_GRID_UNKNOWN: {
/* Zero channels to copy. */
break;
}
} }
#else
UNUSED_VARS(volume, volume_grid, min, max, voxels);
#endif
} }
/* Wireframe */ /* Wireframe */

View File

@@ -762,6 +762,12 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
} }
} }
if (!MAIN_VERSION_ATLEAST(bmain, 291, 7)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
scene->r.simplify_volumes = 1.0f;
}
}
/** /**
* Versioning code until next subversion bump goes here. * Versioning code until next subversion bump goes here.
* *

View File

@@ -42,6 +42,8 @@
#include "GPU_batch.h" #include "GPU_batch.h"
#include "GPU_texture.h" #include "GPU_texture.h"
#include "DEG_depsgraph_query.h"
#include "DRW_render.h" #include "DRW_render.h"
#include "draw_cache.h" /* own include */ #include "draw_cache.h" /* own include */
@@ -260,6 +262,8 @@ static DRWVolumeGrid *volume_grid_cache_get(Volume *volume,
VolumeGrid *grid, VolumeGrid *grid,
VolumeBatchCache *cache) VolumeBatchCache *cache)
{ {
const DRWContextState *draw_ctx = DRW_context_state_get();
const char *name = BKE_volume_grid_name(grid); const char *name = BKE_volume_grid_name(grid);
/* Return cached grid. */ /* Return cached grid. */
@@ -289,35 +293,32 @@ static DRWVolumeGrid *volume_grid_cache_get(Volume *volume,
const bool was_loaded = BKE_volume_grid_is_loaded(grid); const bool was_loaded = BKE_volume_grid_is_loaded(grid);
BKE_volume_grid_load(volume, grid); BKE_volume_grid_load(volume, grid);
/* Compute dense voxel grid size. */ float resolution_factor = 1.0f;
int64_t dense_min[3], dense_max[3], resolution[3] = {0}; if (DEG_get_mode(draw_ctx->depsgraph) != DAG_EVAL_RENDER) {
if (BKE_volume_grid_dense_bounds(volume, grid, dense_min, dense_max)) { if (draw_ctx->scene->r.mode & R_SIMPLIFY) {
resolution[0] = dense_max[0] - dense_min[0]; resolution_factor = draw_ctx->scene->r.simplify_volumes;
resolution[1] = dense_max[1] - dense_min[1]; }
resolution[2] = dense_max[2] - dense_min[2]; }
if (resolution_factor == 0.0f) {
return cache_grid;
} }
size_t num_voxels = resolution[0] * resolution[1] * resolution[2];
size_t elem_size = sizeof(float) * channels;
/* Allocate and load voxels. */ DenseFloatVolumeGrid dense_grid;
float *voxels = (num_voxels > 0) ? MEM_malloc_arrayN(num_voxels, elem_size, __func__) : NULL; if (BKE_volume_grid_dense_floats(volume, grid, resolution_factor, &dense_grid)) {
if (voxels != NULL) { copy_m4_m4(cache_grid->texture_to_object, dense_grid.texture_to_object);
BKE_volume_grid_dense_voxels(volume, grid, dense_min, dense_max, voxels); invert_m4_m4(cache_grid->object_to_texture, dense_grid.texture_to_object);
/* Create GPU texture. */ /* Create GPU texture. */
eGPUTextureFormat format = (channels == 3) ? GPU_RGB16F : GPU_R16F; eGPUTextureFormat format = (channels == 3) ? GPU_RGB16F : GPU_R16F;
cache_grid->texture = GPU_texture_create_3d( cache_grid->texture = GPU_texture_create_3d("volume_grid",
"volume_grid", UNPACK3(resolution), 1, format, GPU_DATA_FLOAT, voxels); UNPACK3(dense_grid.resolution),
1,
format,
GPU_DATA_FLOAT,
dense_grid.voxels);
GPU_texture_swizzle_set(cache_grid->texture, (channels == 3) ? "rgb1" : "rrr1"); GPU_texture_swizzle_set(cache_grid->texture, (channels == 3) ? "rgb1" : "rrr1");
GPU_texture_wrap_mode(cache_grid->texture, false, false); GPU_texture_wrap_mode(cache_grid->texture, false, false);
BKE_volume_dense_float_grid_clear(&dense_grid);
MEM_freeN(voxels);
/* Compute transform matrices. */
BKE_volume_grid_dense_transform_matrix(
grid, dense_min, dense_max, cache_grid->texture_to_object);
invert_m4_m4(cache_grid->object_to_texture, cache_grid->texture_to_object);
} }
/* Free grid from memory if it wasn't previously loaded. */ /* Free grid from memory if it wasn't previously loaded. */

View File

@@ -128,6 +128,7 @@
\ \
.simplify_subsurf = 6, \ .simplify_subsurf = 6, \
.simplify_particles = 1.0f, \ .simplify_particles = 1.0f, \
.simplify_volumes = 1.0f, \
\ \
.border.xmin = 0.0f, \ .border.xmin = 0.0f, \
.border.ymin = 0.0f, \ .border.ymin = 0.0f, \

View File

@@ -731,7 +731,7 @@ typedef struct RenderData {
char seq_rend_type; char seq_rend_type;
/** Flag use for sequence render/draw. */ /** Flag use for sequence render/draw. */
char seq_flag; char seq_flag;
char _pad5[7]; char _pad5[3];
/* render simplify */ /* render simplify */
short simplify_subsurf; short simplify_subsurf;
@@ -739,6 +739,7 @@ typedef struct RenderData {
short simplify_gpencil; short simplify_gpencil;
float simplify_particles; float simplify_particles;
float simplify_particles_render; float simplify_particles_render;
float simplify_volumes;
/* Freestyle line thickness options */ /* Freestyle line thickness options */
int line_thickness_mode; int line_thickness_mode;

View File

@@ -44,6 +44,7 @@
#include "BKE_armature.h" #include "BKE_armature.h"
#include "BKE_editmesh.h" #include "BKE_editmesh.h"
#include "BKE_paint.h" #include "BKE_paint.h"
#include "BKE_volume.h"
#include "ED_gpencil.h" #include "ED_gpencil.h"
#include "ED_object.h" #include "ED_object.h"
@@ -1888,6 +1889,10 @@ static void object_simplify_update(Object *ob)
} }
FOREACH_COLLECTION_OBJECT_RECURSIVE_END; FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
} }
if (ob->type == OB_VOLUME) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
} }
static void rna_Scene_use_simplify_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) static void rna_Scene_use_simplify_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@@ -6473,6 +6478,12 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop, "Simplify Child Particles", "Global child particles percentage during rendering"); prop, "Simplify Child Particles", "Global child particles percentage during rendering");
RNA_def_property_update(prop, 0, "rna_Scene_simplify_update"); RNA_def_property_update(prop, 0, "rna_Scene_simplify_update");
prop = RNA_def_property(srna, "simplify_volumes", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0, 1.0f);
RNA_def_property_ui_text(
prop, "Simplify Volumes", "Resolution percentage of volume objects in viewport");
RNA_def_property_update(prop, 0, "rna_Scene_simplify_update");
/* Grease Pencil - Simplify Options */ /* Grease Pencil - Simplify Options */
prop = RNA_def_property(srna, "simplify_gpencil", PROP_BOOLEAN, PROP_NONE); prop = RNA_def_property(srna, "simplify_gpencil", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_ENABLE); RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_ENABLE);