Cycles: experimental integration of Alembic procedural in viewport rendering

This patch exposes the Cycles Alembic Procedural through the MeshSequenceCache
modifier in order to use and test it from Blender.

To enable it, one has to switch the render feature set to experimental and
activate the Procedural in the modifier. An Alembic Procedural is then
created for each CacheFile from Blender set to use the Procedural, and each
Blender object having a MeshSequenceCache modifier is added to list of objects
of the right procedural.

The procedural's parameters derive from the CacheFile's properties which are
already exposed in the UI through the modifier, although more Cycles specific
options might be added in the future.

As there is currently no cache controls and since we load all the data at the
beginning of the render session, the procedural is only available during
viewport renders at the moment. When an Alembic procedural is rendered, data
from the archive are not read on the Blender side.

If a Cycles render is not active and the CacheFile is set to use the Cycles Procedural,
bounding boxes are used to display the objects in the scene as a signal that the
objects are not processed by Blender anymore. This is standard in other DCCs.
However this does not reduce the memory usage from Blender as the Alembic data
was already loaded either during an import or during a .blend file read.

This is mostly a hack to test the Cycles Alembic procedural until we have a
better Blender side mechanism for letting renderers load their own geometry,
which will be based on import and export settings on Collections (T68933).

Ref T79174, D3089

Reviewed By: brecht, sybren

Maniphest Tasks: T79174

Differential Revision: https://developer.blender.org/D10197
This commit is contained in:
Kévin Dietrich 2021-08-19 14:34:01 +02:00
parent 5b97c00e9f
commit 51862c8445
Notes: blender-bot 2023-02-14 07:17:43 +01:00
Referenced by issue #79174, Cycles Procedural API and faster scene update
43 changed files with 417 additions and 56 deletions

View File

@ -115,6 +115,16 @@ if(WITH_OPENVDB)
)
endif()
if(WITH_ALEMBIC)
add_definitions(-DWITH_ALEMBIC)
list(APPEND INC_SYS
${ALEMBIC_INCLUDE_DIRS}
)
list(APPEND LIB
${ALEMBIC_LIBRARIES}
)
endif()
if(WITH_OPENIMAGEDENOISE)
add_definitions(-DWITH_OPENIMAGEDENOISE)
list(APPEND INC_SYS

View File

@ -61,6 +61,7 @@ class CyclesRender(bpy.types.RenderEngine):
bl_use_save_buffers = True
bl_use_spherical_stereo = True
bl_use_custom_freestyle = True
bl_use_alembic_procedural = True
def __init__(self):
self.session = None

View File

@ -227,6 +227,11 @@ def update_render_passes(self, context):
view_layer.update_render_passes()
def update_render_engine(self, context):
scene = context.scene
scene.update_render_engine()
class CyclesRenderSettings(bpy.types.PropertyGroup):
device: EnumProperty(
@ -240,6 +245,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Feature set to use for rendering",
items=enum_feature_set,
default='SUPPORTED',
update=update_render_engine,
)
shading_system: BoolProperty(
name="Open Shading Language",

View File

@ -1038,23 +1038,6 @@ static void create_subd_mesh(Scene *scene,
/* Sync */
static BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob)
{
if (b_ob.modifiers.length() > 0) {
BL::Modifier b_mod = b_ob.modifiers[b_ob.modifiers.length() - 1];
if (b_mod.type() == BL::Modifier::type_MESH_SEQUENCE_CACHE) {
BL::MeshSequenceCacheModifier mesh_cache = BL::MeshSequenceCacheModifier(b_mod);
if (MeshSequenceCacheModifier_has_velocity_get(&mesh_cache.ptr)) {
return mesh_cache;
}
}
}
return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
}
/* Check whether some of "built-in" motion-related attributes are needed to be exported (includes
* things like velocity from cache modifier, fluid simulation).
*
@ -1095,7 +1078,7 @@ static void sync_mesh_cached_velocities(BL::Object &b_ob, Scene *scene, Mesh *me
return;
}
BL::MeshSequenceCacheModifier b_mesh_cache = object_mesh_cache_find(b_ob);
BL::MeshSequenceCacheModifier b_mesh_cache = object_mesh_cache_find(b_ob, true);
if (!b_mesh_cache) {
return;
@ -1258,7 +1241,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
}
/* Cached motion blur already exported. */
BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find(b_ob);
BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find(b_ob, true);
if (mesh_cache) {
return;
}

View File

@ -14,6 +14,7 @@
* limitations under the License.
*/
#include "render/alembic.h"
#include "render/camera.h"
#include "render/graph.h"
#include "render/integrator.h"
@ -484,6 +485,64 @@ bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance
/* Object Loop */
void BlenderSync::sync_procedural(BL::Object &b_ob, BL::MeshSequenceCacheModifier &b_mesh_cache)
{
#ifdef WITH_ALEMBIC
BL::CacheFile cache_file = b_mesh_cache.cache_file();
void *cache_file_key = cache_file.ptr.data;
AlembicProcedural *procedural = static_cast<AlembicProcedural *>(
procedural_map.find(cache_file_key));
if (procedural == nullptr) {
procedural = scene->create_node<AlembicProcedural>();
procedural_map.add(cache_file_key, procedural);
}
else {
procedural_map.used(procedural);
}
float current_frame = b_scene.frame_current();
if (cache_file.override_frame()) {
current_frame = cache_file.frame();
}
if (!cache_file.override_frame()) {
procedural->set_start_frame(b_scene.frame_start());
procedural->set_end_frame(b_scene.frame_end());
}
procedural->set_frame(current_frame);
procedural->set_frame_rate(b_scene.render().fps() / b_scene.render().fps_base());
procedural->set_frame_offset(cache_file.frame_offset());
string absolute_path = blender_absolute_path(b_data, b_ob, b_mesh_cache.cache_file().filepath());
procedural->set_filepath(ustring(absolute_path));
procedural->set_scale(cache_file.scale());
/* create or update existing AlembicObjects */
ustring object_path = ustring(b_mesh_cache.object_path());
AlembicObject *abc_object = procedural->get_or_create_object(object_path);
array<Node *> used_shaders = find_used_shaders(b_ob);
abc_object->set_used_shaders(used_shaders);
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);
abc_object->set_subd_dicing_rate(subd_dicing_rate);
abc_object->set_subd_max_level(max_subdivisions);
if (abc_object->is_modified() || procedural->is_modified()) {
procedural->tag_update(scene);
}
#else
(void)b_ob;
(void)b_mesh_cache;
#endif
}
void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
BL::SpaceView3D &b_v3d,
float motion_time)
@ -499,6 +558,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
light_map.pre_sync();
geometry_map.pre_sync();
object_map.pre_sync();
procedural_map.pre_sync();
particle_system_map.pre_sync();
motion_times.clear();
}
@ -539,15 +599,38 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
/* Object itself. */
if (b_instance.show_self()) {
sync_object(b_depsgraph,
b_view_layer,
b_instance,
motion_time,
false,
show_lights,
culling,
&use_portal,
sync_hair ? NULL : &geom_task_pool);
#ifdef WITH_ALEMBIC
bool use_procedural = false;
BL::MeshSequenceCacheModifier b_mesh_cache(PointerRNA_NULL);
/* Experimental as Blender does not have good support for procedurals at the moment, also
* only available in preview renders since currently do not have a good cache policy, the
* data being loaded at once for all the frames. */
if (experimental && b_v3d) {
b_mesh_cache = object_mesh_cache_find(b_ob, false);
use_procedural = b_mesh_cache && b_mesh_cache.cache_file().use_render_procedural();
}
if (use_procedural) {
/* Skip in the motion case, as generating motion blur data will be handled in the
* procedural. */
if (!motion) {
sync_procedural(b_ob, b_mesh_cache);
}
}
else
#endif
{
sync_object(b_depsgraph,
b_view_layer,
b_instance,
motion_time,
false,
show_lights,
culling,
&use_portal,
sync_hair ? NULL : &geom_task_pool);
}
}
/* Particle hair as separate object. */
@ -580,6 +663,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
object_map.post_sync();
geometry_map.post_sync();
particle_system_map.post_sync();
procedural_map.post_sync();
}
if (motion)

View File

@ -59,6 +59,7 @@ BlenderSync::BlenderSync(BL::RenderEngine &b_engine,
b_scene(b_scene),
shader_map(scene),
object_map(scene),
procedural_map(scene),
geometry_map(scene),
light_map(scene),
particle_system_map(scene),

View File

@ -151,6 +151,8 @@ class BlenderSync {
TaskPool *geom_task_pool);
void sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object);
void sync_procedural(BL::Object &b_ob, BL::MeshSequenceCacheModifier &b_mesh_cache);
bool sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object);
/* Volume */
@ -221,6 +223,7 @@ class BlenderSync {
id_map<void *, Shader> shader_map;
id_map<ObjectKey, Object> object_map;
id_map<void *, Procedural> procedural_map;
id_map<GeometryKey, Geometry> geometry_map;
id_map<ObjectKey, Light> light_map;
id_map<ParticleSystemKey, ParticleSystem> particle_system_map;

View File

@ -572,6 +572,35 @@ static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b
return BL::FluidDomainSettings(PointerRNA_NULL);
}
static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob,
bool check_velocity)
{
for (int i = b_ob.modifiers.length() - 1; i >= 0; --i) {
BL::Modifier b_mod = b_ob.modifiers[i];
if (b_mod.type() == BL::Modifier::type_MESH_SEQUENCE_CACHE) {
BL::MeshSequenceCacheModifier mesh_cache = BL::MeshSequenceCacheModifier(b_mod);
if (check_velocity) {
if (!MeshSequenceCacheModifier_has_velocity_get(&mesh_cache.ptr)) {
return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
}
}
return mesh_cache;
}
/* Skip possible particles system modifiers as they do not modify the geometry. */
if (b_mod.type() == BL::Modifier::type_PARTICLE_SYSTEM) {
continue;
}
break;
}
return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
}
static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
bool preview,
bool experimental)

View File

@ -32,6 +32,7 @@ struct CacheReader;
struct Depsgraph;
struct Main;
struct Object;
struct Scene;
void BKE_cachefiles_init(void);
void BKE_cachefiles_exit(void);
@ -60,6 +61,15 @@ void BKE_cachefile_reader_open(struct CacheFile *cache_file,
const char *object_path);
void BKE_cachefile_reader_free(struct CacheFile *cache_file, struct CacheReader **reader);
/* Determine whether the CacheFile should use a render engine procedural. If so, data is not read
* from the file and bouding boxes are used to represent the objects in the Scene. Render engines
* will receive the bounding box as a placeholder but can instead load the data directly if they
* support it.
*/
bool BKE_cache_file_uses_render_procedural(const struct CacheFile *cache_file,
struct Scene *scene,
const int dag_eval_mode);
#ifdef __cplusplus
}
#endif

View File

@ -319,8 +319,10 @@ typedef struct ModifierTypeInfo {
* changes.
*
* This function is optional (assumes false if not present).
*
* The dag_eval_mode should be of type eEvaluationMode.
*/
bool (*dependsOnTime)(struct ModifierData *md);
bool (*dependsOnTime)(struct Scene *scene, struct ModifierData *md, const int dag_eval_mode);
/**
* True when a deform modifier uses normals, the requiredDataMask
@ -425,7 +427,9 @@ void BKE_modifier_copydata(struct ModifierData *md, struct ModifierData *target)
void BKE_modifier_copydata_ex(struct ModifierData *md,
struct ModifierData *target,
const int flag);
bool BKE_modifier_depends_ontime(struct ModifierData *md);
bool BKE_modifier_depends_ontime(struct Scene *scene,
struct ModifierData *md,
int dag_eval_mode);
bool BKE_modifier_supports_mapping(struct ModifierData *md);
bool BKE_modifier_supports_cage(struct Scene *scene, struct ModifierData *md);
bool BKE_modifier_couldbe_cage(struct Scene *scene, struct ModifierData *md);

View File

@ -401,7 +401,10 @@ void BKE_object_groups_clear(struct Main *bmain, struct Scene *scene, struct Obj
struct KDTree_3d *BKE_object_as_kdtree(struct Object *ob, int *r_tot);
bool BKE_object_modifier_use_time(struct Object *ob, struct ModifierData *md);
bool BKE_object_modifier_use_time(struct Scene *scene,
struct Object *ob,
struct ModifierData *md,
int dag_eval_mode);
bool BKE_object_modifier_update_subframe(struct Depsgraph *depsgraph,
struct Scene *scene,

View File

@ -174,6 +174,10 @@ bool BKE_scene_uses_blender_eevee(const struct Scene *scene);
bool BKE_scene_uses_blender_workbench(const struct Scene *scene);
bool BKE_scene_uses_cycles(const struct 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). */
bool BKE_scene_uses_cycles_experimental_features(struct Scene *scene);
void BKE_scene_copy_data_eevee(struct Scene *sce_dst, const struct Scene *sce_src);
void BKE_scene_disable_color_management(struct Scene *scene);

View File

@ -49,6 +49,8 @@
#include "DEG_depsgraph_query.h"
#include "RE_engine.h"
#include "BLO_read_write.h"
#ifdef WITH_ALEMBIC
@ -409,3 +411,19 @@ float BKE_cachefile_time_offset(const CacheFile *cache_file, const float time, c
const float frame = (cache_file->override_frame ? cache_file->frame : time);
return cache_file->is_sequence ? frame : frame / fps - time_offset;
}
bool BKE_cache_file_uses_render_procedural(const CacheFile *cache_file,
Scene *scene,
const int dag_eval_mode)
{
RenderEngineType *render_engine_type = RE_engines_find(scene->r.engine);
if (cache_file->type != CACHEFILE_TYPE_ALEMBIC ||
!RE_engine_supports_alembic_procedural(render_engine_type, scene)) {
return false;
}
/* The render time procedural is only enabled during viewport rendering. */
const bool is_final_render = (eEvaluationMode)dag_eval_mode == DAG_EVAL_RENDER;
return cache_file->use_render_procedural && !is_final_render;
}

View File

@ -5430,6 +5430,11 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa
return;
}
/* Do not process data if using a render time procedural. */
if (BKE_cache_file_uses_render_procedural(cache_file, scene, DEG_get_mode(cob->depsgraph))) {
return;
}
const float frame = DEG_get_ctime(cob->depsgraph);
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);

View File

@ -249,11 +249,11 @@ bool BKE_modifier_unique_name(ListBase *modifiers, ModifierData *md)
return false;
}
bool BKE_modifier_depends_ontime(ModifierData *md)
bool BKE_modifier_depends_ontime(Scene *scene, ModifierData *md, const int dag_eval_mode)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return mti->dependsOnTime && mti->dependsOnTime(md);
return mti->dependsOnTime && mti->dependsOnTime(scene, md, dag_eval_mode);
}
bool BKE_modifier_supports_mapping(ModifierData *md)

View File

@ -5411,9 +5411,12 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
return tree;
}
bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
bool BKE_object_modifier_use_time(Scene *scene,
Object *ob,
ModifierData *md,
const int dag_eval_mode)
{
if (BKE_modifier_depends_ontime(md)) {
if (BKE_modifier_depends_ontime(scene, md, dag_eval_mode)) {
return true;
}

View File

@ -109,6 +109,8 @@
#include "RE_engine.h"
#include "RNA_access.h"
#include "SEQ_edit.h"
#include "SEQ_iterator.h"
#include "SEQ_modifier.h"
@ -2938,6 +2940,22 @@ bool BKE_scene_uses_cycles(const Scene *scene)
return STREQ(scene->r.engine, RE_engine_id_CYCLES);
}
/* This enumeration has to match the one defined in the Cycles addon. */
typedef enum eCyclesFeatureSet {
CYCLES_FEATURES_SUPPORTED = 0,
CYCLES_FEATURES_EXPERIMENTAL = 1,
} eCyclesFeatureSet;
/* We cannot use const as RNA_id_pointer_create is not using a const ID. */
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, &scene_ptr);
PointerRNA cycles_ptr = RNA_pointer_get(&scene_ptr, "cycles");
return RNA_enum_get(&cycles_ptr, "feature_set") == CYCLES_FEATURES_EXPERIMENTAL;
}
void BKE_scene_base_flag_to_objects(ViewLayer *view_layer)
{
Base *base = view_layer->object_bases.first;

View File

@ -118,6 +118,7 @@
#include "intern/node/deg_node_operation.h"
#include "intern/node/deg_node_time.h"
#include "intern/depsgraph.h"
#include "intern/depsgraph_relation.h"
#include "intern/depsgraph_type.h"
@ -2095,7 +2096,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
mti->updateDepsgraph(md, &ctx);
}
if (BKE_object_modifier_use_time(object, md)) {
if (BKE_object_modifier_use_time(scene_, object, md, graph_->mode)) {
TimeSourceKey time_src_key;
add_relation(time_src_key, obdata_ubereval_key, "Time Source");
}

View File

@ -84,6 +84,8 @@
#include "ED_screen.h"
#include "ED_undo.h"
#include "RE_engine.h"
#include "RNA_access.h"
#include "WM_api.h"
@ -6463,6 +6465,29 @@ void uiTemplateCacheFile(uiLayout *layout,
row = uiLayoutRow(layout, false);
uiItemR(row, &fileptr, "is_sequence", 0, NULL, ICON_NONE);
/* Only enable render procedural option if the active engine supports it. */
const struct RenderEngineType *engine_type = CTX_data_engine_type(C);
Scene *scene = CTX_data_scene(C);
const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type, scene);
if (!engine_supports_procedural) {
row = uiLayoutRow(layout, false);
/* For Cycles, verify that experimental features are enabled. */
if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) {
uiItemL(row,
"The Cycles Alembic Procedural is only available with the experimental feature set",
ICON_INFO);
}
else {
uiItemL(row, "The active render engine does not have an Alembic Procedural", ICON_INFO);
}
}
row = uiLayoutRow(layout, false);
uiLayoutSetActive(row, engine_supports_procedural);
uiItemR(row, &fileptr, "use_render_procedural", 0, NULL, ICON_NONE);
row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame"));
sub = uiLayoutRow(row, true);
uiLayoutSetPropDecorate(sub, false);

View File

@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include "DNA_cachefile_types.h"
#include "DNA_light_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
@ -204,6 +205,19 @@ void ED_render_engine_changed(Main *bmain, const bool update_scene_data)
ntreeCompositUpdateRLayers(scene->nodetree);
}
}
/* Update CacheFiles to ensure that procedurals are properly taken into account. */
LISTBASE_FOREACH (CacheFile *, cachefile, &bmain->cachefiles) {
/* Only update cachefiles which are set to use a render procedural. We do not use
* BKE_cachefile_uses_render_procedural here as we need to update regardless of the current
* engine or its settings. */
if (cachefile->use_render_procedural) {
DEG_id_tag_update(&cachefile->id, ID_RECALC_COPY_ON_WRITE);
/* Rebuild relations so that modifiers are reconnected to or disconnected from the cachefile.
*/
DEG_relations_tag_update(bmain);
}
}
}
void ED_render_view_layer_changed(Main *bmain, bScreen *screen)

View File

@ -87,14 +87,21 @@ typedef struct CacheFile {
/** The frame offset to subtract. */
float frame_offset;
char _pad[4];
/** Animation flag. */
short flag;
short draw_flag; /* UNUSED */
/* eCacheFileType enum. */
char type;
char _pad[2];
/** Do not load data from the cache file and display objects in the scene as boxes, Cycles will
* load objects directly from the CacheFile. Other render engines which can load Alembic data
* directly can take care of rendering it themselves.
*/
char use_render_procedural;
char _pad1[7];
char velocity_unit;
/* Name of the velocity property in the archive. */

View File

@ -37,6 +37,7 @@
# include "BKE_cachefile.h"
# include "DEG_depsgraph.h"
# include "DEG_depsgraph_build.h"
# include "WM_api.h"
# include "WM_types.h"
@ -53,6 +54,12 @@ static void rna_CacheFile_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
}
static void rna_CacheFile_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
rna_CacheFile_update(bmain, scene, ptr);
DEG_relations_tag_update(bmain);
}
static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
CacheFile *cache_file = (CacheFile *)ptr->data;
@ -105,6 +112,16 @@ static void rna_def_cachefile(BlenderRNA *brna)
prop, "Sequence", "Whether the cache is separated in a series of files");
RNA_def_property_update(prop, 0, "rna_CacheFile_update");
prop = RNA_def_property(srna, "use_render_procedural", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(
prop,
"Use Render Engine Procedural",
"Display boxes in the viewport as placeholders for the objects, Cycles will use a "
"procedural to load the objects during viewport rendering in experimental mode, "
"other render engines will also receive a placeholder and should take care of loading the "
"Alembic data themselves if possible");
RNA_def_property_update(prop, 0, "rna_CacheFile_dependency_update");
/* ----------------- For Scene time ------------------- */
prop = RNA_def_property(srna, "override_frame", PROP_BOOLEAN, PROP_NONE);

View File

@ -896,6 +896,12 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
RNA_def_property_ui_text(prop, "Use Stereo Viewport", "Support rendering stereo 3D viewport");
prop = RNA_def_property(srna, "bl_use_alembic_procedural", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_ALEMBIC_PROCEDURAL);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
RNA_def_property_ui_text(
prop, "Use Alembic Procedural", "Support loading Alembic data at render time");
RNA_define_verify_sdna(1);
}

View File

@ -616,6 +616,7 @@ const EnumPropertyItem rna_enum_transform_orientation_items[] = {
# include "BLI_string_utils.h"
# include "DNA_anim_types.h"
# include "DNA_cachefile_types.h"
# include "DNA_color_types.h"
# include "DNA_mesh_types.h"
# include "DNA_node_types.h"
@ -1619,6 +1620,11 @@ static void rna_RenderSettings_engine_update(Main *bmain,
ED_render_engine_changed(bmain, true);
}
static void rna_Scene_update_render_engine(Main *bmain)
{
ED_render_engine_changed(bmain, true);
}
static bool rna_RenderSettings_multiple_engines_get(PointerRNA *UNUSED(ptr))
{
return (BLI_listbase_count(&R_engines) > 1);
@ -7836,6 +7842,10 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE, NULL);
RNA_def_property_update(prop, NC_SCENE, "rna_Scene_volume_update");
func = RNA_def_function(srna, "update_render_engine", "rna_Scene_update_render_engine");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_MAIN);
RNA_def_function_ui_description(func, "Trigger a render engine update");
/* Statistics */
func = RNA_def_function(srna, "statistics", "rna_Scene_statistics_string_get");
RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS);

View File

@ -61,7 +61,9 @@ static void initData(ModifierData *md)
MEMCPY_STRUCT_AFTER(bmd, DNA_struct_default_get(BuildModifierData), modifier);
}
static bool dependsOnTime(ModifierData *UNUSED(md))
static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *UNUSED(md),
const int UNUSED(dag_eval_mode))
{
return true;
}

View File

@ -220,7 +220,9 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
tclmd->solver_result = NULL;
}
static bool dependsOnTime(ModifierData *UNUSED(md))
static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *UNUSED(md),
const int UNUSED(dag_eval_mode))
{
return true;
}

View File

@ -95,7 +95,9 @@ static void freeData(ModifierData *md)
}
}
static bool dependsOnTime(ModifierData *UNUSED(md))
static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *UNUSED(md),
const int UNUSED(dag_eval_mode))
{
return true;
}

View File

@ -95,7 +95,9 @@ static void requiredDataMask(Object *UNUSED(ob),
}
}
static bool dependsOnTime(ModifierData *md)
static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *md,
const int UNUSED(dag_eval_mode))
{
DisplaceModifierData *dmd = (DisplaceModifierData *)md;

View File

@ -155,7 +155,9 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
}
static bool dependsOnTime(ModifierData *UNUSED(md))
static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *UNUSED(md),
const int UNUSED(dag_eval_mode))
{
return true;
}

View File

@ -86,7 +86,9 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
temd->facepa = NULL;
}
static bool dependsOnTime(ModifierData *UNUSED(md))
static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *UNUSED(md),
const int UNUSED(dag_eval_mode))
{
return true;
}

View File

@ -132,7 +132,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
#endif /* WITH_FLUID */
}
static bool dependsOnTime(ModifierData *UNUSED(md))
static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *UNUSED(md),
const int UNUSED(dag_eval_mode))
{
return true;
}

View File

@ -63,7 +63,9 @@ static void initData(ModifierData *md)
MEMCPY_STRUCT_AFTER(mcmd, DNA_struct_default_get(MeshCacheModifierData), modifier);
}
static bool dependsOnTime(ModifierData *md)
static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *md,
const int UNUSED(dag_eval_mode))
{
MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md;
return (mcmd->play_mode == MOD_MESHCACHE_PLAY_CFEA);

View File

@ -20,6 +20,7 @@
#include <string.h>
#include "BLI_math_vector.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@ -39,6 +40,8 @@
#include "BKE_cachefile.h"
#include "BKE_context.h"
#include "BKE_lib_query.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@ -118,6 +121,44 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0');
}
static Mesh *generate_bounding_box_mesh(Object *object, Mesh *org_mesh)
{
BoundBox *bb = BKE_object_boundbox_get(object);
Mesh *result = BKE_mesh_new_nomain_from_template(org_mesh, 8, 0, 0, 24, 6);
MVert *mvert = result->mvert;
for (int i = 0; i < 8; ++i) {
copy_v3_v3(mvert[i].co, bb->vec[i]);
}
/* See DNA_object_types.h for the diagram showing the order of the vertices for a BoundBox. */
static unsigned int loops_v[6][4] = {
{0, 4, 5, 1},
{4, 7, 6, 5},
{7, 3, 2, 6},
{3, 0, 1, 2},
{1, 5, 6, 2},
{3, 7, 4, 0},
};
MLoop *mloop = result->mloop;
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 4; ++j, ++mloop) {
mloop->v = loops_v[i][j];
}
}
MPoly *mpoly = result->mpoly;
for (int i = 0; i < 6; ++i) {
mpoly[i].loopstart = i * 4;
mpoly[i].totloop = 4;
}
BKE_mesh_calc_edges(result, false, false);
return result;
}
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
#if defined(WITH_USD) || defined(WITH_ALEMBIC)
@ -143,6 +184,12 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
}
}
/* Do not process data if using a render procedural, return a box instead for displaying in the
* viewport. */
if (BKE_cache_file_uses_render_procedural(cache_file, scene, DEG_get_mode(ctx->depsgraph))) {
return generate_bounding_box_mesh(ctx->object, org_mesh);
}
/* If this invocation is for the ORCO mesh, and the mesh hasn't changed topology, we
* must return the mesh as-is instead of deforming it. */
if (ctx->flag & MOD_APPLY_ORCO) {
@ -228,11 +275,13 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
#endif
}
static bool dependsOnTime(ModifierData *md)
static bool dependsOnTime(Scene *scene, ModifierData *md, const int dag_eval_mode)
{
#if defined(WITH_USD) || defined(WITH_ALEMBIC)
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
return (mcmd->cache_file != NULL);
/* Do not evaluate animations if using the render engine procedural. */
return (mcmd->cache_file != NULL) &&
!BKE_cache_file_uses_render_procedural(mcmd->cache_file, scene, dag_eval_mode);
#else
UNUSED_VARS(md);
return false;

View File

@ -62,7 +62,9 @@ static void deformVerts(ModifierData *UNUSED(md),
ctx->depsgraph, scene, ctx->object, DEG_get_ctime(ctx->depsgraph), vertexCos, numVerts);
}
static bool dependsOnTime(ModifierData *UNUSED(md))
static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *UNUSED(md),
const int UNUSED(dag_eval_mode))
{
return true;
}

View File

@ -98,7 +98,9 @@ static void freeData(ModifierData *md)
}
}
static bool dependsOnTime(ModifierData *UNUSED(md))
static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *UNUSED(md),
const int UNUSED(dag_eval_mode))
{
return true;
}

View File

@ -95,7 +95,7 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "texture");
}
static bool dependsOnTime(ModifierData *md)
static bool dependsOnTime(struct Scene *UNUSED(scene), ModifierData *md, const int UNUSED(dag_eval_mode))
{
VolumeDisplaceModifierData *vdmd = reinterpret_cast<VolumeDisplaceModifierData *>(md);
if (vdmd->texture) {

View File

@ -116,7 +116,9 @@ static void matrix_from_obj_pchan(float mat[4][4],
}
}
static bool dependsOnTime(ModifierData *md)
static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *md,
const int UNUSED(dag_eval_mode))
{
WarpModifierData *wmd = (WarpModifierData *)md;

View File

@ -70,7 +70,9 @@ static void initData(ModifierData *md)
MEMCPY_STRUCT_AFTER(wmd, DNA_struct_default_get(WaveModifierData), modifier);
}
static bool dependsOnTime(ModifierData *UNUSED(md))
static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *UNUSED(md),
const int UNUSED(dag_eval_mode))
{
return true;
}

View File

@ -112,7 +112,9 @@ static void requiredDataMask(Object *UNUSED(ob),
/* No need to ask for CD_PREVIEW_MLOOPCOL... */
}
static bool dependsOnTime(ModifierData *md)
static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *md,
const int UNUSED(dag_eval_mode))
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;

View File

@ -154,7 +154,9 @@ static void requiredDataMask(Object *UNUSED(ob),
/* No need to ask for CD_PREVIEW_MLOOPCOL... */
}
static bool dependsOnTime(ModifierData *md)
static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *md,
const int UNUSED(dag_eval_mode))
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;

View File

@ -362,7 +362,9 @@ static void requiredDataMask(Object *UNUSED(ob),
/* No need to ask for CD_PREVIEW_MLOOPCOL... */
}
static bool dependsOnTime(ModifierData *md)
static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *md,
const int UNUSED(dag_eval_mode))
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md;

View File

@ -66,6 +66,7 @@ extern "C" {
#define RE_USE_GPU_CONTEXT 512
#define RE_USE_CUSTOM_FREESTYLE 1024
#define RE_USE_NO_IMAGE_SAVE 2048
#define RE_USE_ALEMBIC_PROCEDURAL 4096
/* RenderEngine.flag */
#define RE_ENGINE_ANIMATION 1
@ -235,6 +236,12 @@ void RE_engines_register(RenderEngineType *render_type);
bool RE_engine_is_opengl(RenderEngineType *render_type);
/**
* Return true if the RenderEngineType has native support for direct loading of Alembic data. For
* Cycles, this also checks that the experimental feature set is enabled.
*/
bool RE_engine_supports_alembic_procedural(const RenderEngineType *render_type, Scene *scene);
RenderEngineType *RE_engines_find(const char *idname);
rcti *RE_engine_get_current_tiles(struct Render *re, int *r_total_tiles, bool *r_needs_free);

View File

@ -128,6 +128,19 @@ bool RE_engine_is_opengl(RenderEngineType *render_type)
return (render_type->draw_engine != NULL) && DRW_engine_render_support(render_type->draw_engine);
}
bool RE_engine_supports_alembic_procedural(const RenderEngineType *render_type, Scene *scene)
{
if ((render_type->flag & RE_USE_ALEMBIC_PROCEDURAL) == 0) {
return false;
}
if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) {
return false;
}
return true;
}
/* Create, Free */
RenderEngine *RE_engine_create(RenderEngineType *type)