Make object visibility and instancing creation to be calculated via depsgraph #57

Merged
Bogdan Nagirniak merged 16 commits from BLEN-442 into hydra-render 2023-07-08 10:09:53 +02:00
13 changed files with 199 additions and 558 deletions

View File

@ -3,7 +3,6 @@
#include <bitset> #include <bitset>
#include "BKE_object.h"
#include "BLI_set.hh" #include "BLI_set.hh"
#include "DEG_depsgraph_query.h" #include "DEG_depsgraph_query.h"
#include "DNA_scene_types.h" #include "DNA_scene_types.h"
@ -32,6 +31,7 @@ BlenderSceneDelegate::BlenderSceneDelegate(pxr::HdRenderIndex *parent_index,
Engine *engine) Engine *engine)
: HdSceneDelegate(parent_index, delegate_id), engine(engine) : HdSceneDelegate(parent_index, delegate_id), engine(engine)
{ {
instancer_data_ = std::make_unique<InstancerData>(this, instancer_prim_id());
} }
pxr::HdMeshTopology BlenderSceneDelegate::GetMeshTopology(pxr::SdfPath const &id) pxr::HdMeshTopology BlenderSceneDelegate::GetMeshTopology(pxr::SdfPath const &id)
@ -164,7 +164,7 @@ bool BlenderSceneDelegate::GetVisible(pxr::SdfPath const &id)
} }
InstancerData *i_data = instancer_data(id, true); InstancerData *i_data = instancer_data(id, true);
if (i_data) { if (i_data) {
return i_data->visible; return true;
} }
return object_data(id)->visible; return object_data(id)->visible;
} }
@ -210,7 +210,7 @@ pxr::GfMatrix4d BlenderSceneDelegate::GetInstancerTransform(pxr::SdfPath const &
{ {
CLOG_INFO(LOG_RENDER_HYDRA_SCENE, 3, "%s", instancer_id.GetText()); CLOG_INFO(LOG_RENDER_HYDRA_SCENE, 3, "%s", instancer_id.GetText());
InstancerData *i_data = instancer_data(instancer_id); InstancerData *i_data = instancer_data(instancer_id);
return i_data->transform; return i_data->get_transform(instancer_id);
} }
pxr::HdVolumeFieldDescriptorVector BlenderSceneDelegate::GetVolumeFieldDescriptors( pxr::HdVolumeFieldDescriptorVector BlenderSceneDelegate::GetVolumeFieldDescriptors(
@ -236,7 +236,7 @@ void BlenderSceneDelegate::populate(Depsgraph *deps, bContext *cont)
else { else {
set_light_shading_settings(); set_light_shading_settings();
set_world_shading_settings(); set_world_shading_settings();
add_new_objects(); update_collection();
update_world(); update_world();
} }
} }
@ -246,15 +246,11 @@ void BlenderSceneDelegate::clear()
for (auto &obj_data : objects_.values()) { for (auto &obj_data : objects_.values()) {
obj_data->remove(); obj_data->remove();
} }
for (auto &i_data : instancers_.values()) { objects_.clear();
i_data->remove(); instancer_data_->remove();
}
for (auto &mat_data : materials_.values()) { for (auto &mat_data : materials_.values()) {
mat_data->remove(); mat_data->remove();
} }
objects_.clear();
instancers_.clear();
materials_.clear(); materials_.clear();
depsgraph = nullptr; depsgraph = nullptr;
@ -291,9 +287,9 @@ pxr::SdfPath BlenderSceneDelegate::material_prim_id(Material *mat) const
return prim_id((ID *)mat, "M"); return prim_id((ID *)mat, "M");
} }
pxr::SdfPath BlenderSceneDelegate::instancer_prim_id(Object *object) const pxr::SdfPath BlenderSceneDelegate::instancer_prim_id() const
{ {
return prim_id((ID *)object, "I"); return GetDelegateID().AppendElementString("Instancer");
} }
pxr::SdfPath BlenderSceneDelegate::world_prim_id() const pxr::SdfPath BlenderSceneDelegate::world_prim_id() const
@ -327,6 +323,11 @@ CurvesData *BlenderSceneDelegate::curves_data(pxr::SdfPath const &id) const
return dynamic_cast<CurvesData *>(object_data(id)); return dynamic_cast<CurvesData *>(object_data(id));
} }
VolumeData *BlenderSceneDelegate::volume_data(pxr::SdfPath const &id) const
{
return dynamic_cast<VolumeData *>(object_data(id));
}
LightData *BlenderSceneDelegate::light_data(pxr::SdfPath const &id) const LightData *BlenderSceneDelegate::light_data(pxr::SdfPath const &id) const
{ {
return dynamic_cast<LightData *>(object_data(id)); return dynamic_cast<LightData *>(object_data(id));
@ -359,82 +360,12 @@ InstancerData *BlenderSceneDelegate::instancer_data(pxr::SdfPath const &id, bool
p_id = id; p_id = id;
} }
auto i_data = instancers_.lookup_ptr(p_id); if (instancer_data_ && p_id == instancer_data_->prim_id) {
if (i_data) { return instancer_data_.get();
return i_data->get();
} }
return nullptr; return nullptr;
} }
VolumeData *BlenderSceneDelegate::volume_data(pxr::SdfPath const &id) const
{
return dynamic_cast<VolumeData *>(object_data(id));
}
void BlenderSceneDelegate::update_objects(Object *object)
{
if (!ObjectData::is_supported(object)) {
return;
}
if (!shading_settings.use_scene_lights && object->type == OB_LAMP) {
return;
}
pxr::SdfPath id = object_prim_id(object);
ObjectData *obj_data = object_data(id);
if (obj_data) {
obj_data->update_parent();
obj_data->update();
obj_data->update_visibility();
return;
}
if (!ObjectData::is_visible(this, object)) {
/* Do not export new object if it is invisible */
return;
}
objects_.add_new(id, ObjectData::create(this, object, id));
obj_data = object_data(id);
obj_data->update_parent();
obj_data->init();
obj_data->insert();
}
void BlenderSceneDelegate::update_instancers(Object *object)
{
/* Check object inside instancers */
for (auto &i_data : instancers_.values()) {
i_data->check_update(object);
}
pxr::SdfPath id = instancer_prim_id(object);
InstancerData *i_data = instancer_data(id);
if (i_data) {
if ((object->transflag & OB_DUPLI) == 0) {
/* Object isn't instancer anymore and should be removed */
i_data->remove();
instancers_.remove(id);
return;
}
i_data->update();
return;
}
if ((object->transflag & OB_DUPLI) == 0) {
return;
}
if (!InstancerData::is_visible(this, object)) {
/* Do not export new instancer if it is invisible */
return;
}
i_data = instancers_.lookup_or_add(id, std::make_unique<InstancerData>(this, object, id)).get();
i_data->init();
i_data->insert();
}
void BlenderSceneDelegate::update_world() void BlenderSceneDelegate::update_world()
{ {
if (!world_data_) { if (!world_data_) {
@ -458,7 +389,6 @@ void BlenderSceneDelegate::update_world()
void BlenderSceneDelegate::check_updates() void BlenderSceneDelegate::check_updates()
{ {
bool do_update_collection = false; bool do_update_collection = false;
bool do_update_visibility = false;
bool do_update_world = false; bool do_update_world = false;
if (set_world_shading_settings()) { if (set_world_shading_settings()) {
@ -466,19 +396,12 @@ void BlenderSceneDelegate::check_updates()
} }
if (set_light_shading_settings()) { if (set_light_shading_settings()) {
if (shading_settings.use_scene_lights) {
add_new_objects();
}
else {
do_update_collection = true; do_update_collection = true;
} }
}
DEGIDIterData data = {0}; DEGIDIterData data = {0};
data.graph = depsgraph; data.graph = depsgraph;
data.only_updated = true; data.only_updated = true;
eEvaluationMode deg_mode = DEG_get_mode(depsgraph);
ITER_BEGIN (DEG_iterator_ids_begin, DEG_iterator_ids_next, DEG_iterator_ids_end, &data, ID *, id) ITER_BEGIN (DEG_iterator_ids_begin, DEG_iterator_ids_next, DEG_iterator_ids_end, &data, ID *, id)
{ {
CLOG_INFO(LOG_RENDER_HYDRA_SCENE, CLOG_INFO(LOG_RENDER_HYDRA_SCENE,
@ -489,14 +412,7 @@ void BlenderSceneDelegate::check_updates()
switch (GS(id->name)) { switch (GS(id->name)) {
case ID_OB: { case ID_OB: {
Object *object = (Object *)id; do_update_collection = true;
CLOG_INFO(LOG_RENDER_HYDRA_SCENE,
2,
"Visibility: %s [%s]",
object->id.name,
std::bitset<3>(BKE_object_visibility(object, deg_mode)).to_string().c_str());
update_objects(object);
update_instancers(object);
} break; } break;
case ID_MA: { case ID_MA: {
@ -513,21 +429,16 @@ void BlenderSceneDelegate::check_updates()
} break; } break;
case ID_SCE: { case ID_SCE: {
if (id->recalc & ID_RECALC_COPY_ON_WRITE && !(id->recalc & ID_RECALC_SELECT)) { if ((id->recalc & ID_RECALC_COPY_ON_WRITE && !(id->recalc & ID_RECALC_SELECT)) ||
do_update_collection = true; id->recalc & (ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_BASE_FLAGS))
do_update_visibility = true; {
}
if (id->recalc & ID_RECALC_BASE_FLAGS) {
do_update_visibility = true;
}
if (id->recalc & (ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY)) {
do_update_collection = true; do_update_collection = true;
} }
if (id->recalc & ID_RECALC_AUDIO_VOLUME) { if (id->recalc & ID_RECALC_AUDIO_VOLUME &&
if ((scene->world && !world_data_) || (!scene->world && world_data_)) { ((scene->world && !world_data_) || (!scene->world && world_data_)))
{
do_update_world = true; do_update_world = true;
} }

use macro DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS here

use macro `DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS` here
}
} break; } break;
default: default:
@ -540,58 +451,24 @@ void BlenderSceneDelegate::check_updates()
update_world(); update_world();
} }
if (do_update_collection) { if (do_update_collection) {
remove_unused_objects(); update_collection();
}
if (do_update_visibility) {
update_visibility();
} }
} }
void BlenderSceneDelegate::add_new_objects() void BlenderSceneDelegate::update_collection()
{ {
DEGObjectIterSettings settings = {0};
settings.depsgraph = depsgraph;
settings.flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET;
DEGObjectIterData data = {0};
data.settings = &settings;
data.graph = settings.depsgraph;
data.flag = settings.flags;
eEvaluationMode deg_mode = DEG_get_mode(depsgraph);
ITER_BEGIN (DEG_iterator_objects_begin,
DEG_iterator_objects_next,
DEG_iterator_objects_end,
&data,
Object *,
object)
{
CLOG_INFO(LOG_RENDER_HYDRA_SCENE,
2,
"Visibility: %s [%s]",
object->id.name,
std::bitset<3>(BKE_object_visibility(object, deg_mode)).to_string().c_str());
if (object_data(object_prim_id(object))) {
continue;
}
update_objects(object);
update_instancers(object);
}
ITER_END;
}
void BlenderSceneDelegate::remove_unused_objects()
{
/* Get available objects */
Set<std::string> available_objects; Set<std::string> available_objects;
DEGObjectIterSettings settings = {0}; DEGObjectIterSettings settings = {0};
settings.depsgraph = depsgraph; settings.depsgraph = depsgraph;
settings.flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET; settings.flags = DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS;
DEGObjectIterData data = {0}; DEGObjectIterData data = {0};
data.settings = &settings; data.settings = &settings;
data.graph = settings.depsgraph; data.graph = settings.depsgraph;
data.flag = settings.flags; data.flag = settings.flags;
instancer_data_->pre_update();
ITER_BEGIN (DEG_iterator_objects_begin, ITER_BEGIN (DEG_iterator_objects_begin,
DEG_iterator_objects_next, DEG_iterator_objects_next,
DEG_iterator_objects_end, DEG_iterator_objects_end,
@ -599,27 +476,37 @@ void BlenderSceneDelegate::remove_unused_objects()
Object *, Object *,
object) object)
{ {
available_objects.add(instancer_prim_id(object).GetName()); if (data.dupli_object_current) {
if (ObjectData::is_supported(object)) { instancer_data_->update_instance(data.dupli_parent, data.dupli_object_current);
continue;
}
if (!ObjectData::is_supported(object)) {
continue;
}
if (!ObjectData::is_visible(this, object)) {
continue;
}
if (!shading_settings.use_scene_lights && object->type == OB_LAMP) { if (!shading_settings.use_scene_lights && object->type == OB_LAMP) {
continue; continue;
} }
available_objects.add(object_prim_id(object).GetName()); available_objects.add(object_prim_id(object).GetName());
pxr::SdfPath id = object_prim_id(object);
ObjectData *obj_data = object_data(id);
if (obj_data) {
obj_data->update();
}
else {
obj_data = objects_.lookup_or_add(id, ObjectData::create(this, object, id)).get();
obj_data->init();
obj_data->insert();
} }
} }
ITER_END; ITER_END;
/* Remove unused instancers */ instancer_data_->post_update();
instancers_.remove_if([&](auto item) {
bool ret = !available_objects.contains(item.key.GetName());
if (ret) {
item.value->remove();
}
else {
item.value->check_remove(available_objects);
}
return ret;
});
/* Remove unused objects */ /* Remove unused objects */
objects_.remove_if([&](auto item) { objects_.remove_if([&](auto item) {
@ -646,9 +533,7 @@ void BlenderSceneDelegate::remove_unused_objects()
v_data->available_materials(available_materials); v_data->available_materials(available_materials);
} }
} }
for (auto &val : instancers_.values()) { instancer_data_->available_materials(available_materials);
val->available_materials(available_materials);
}
materials_.remove_if([&](auto item) { materials_.remove_if([&](auto item) {
bool ret = !available_materials.contains(item.key); bool ret = !available_materials.contains(item.key);
@ -659,48 +544,6 @@ void BlenderSceneDelegate::remove_unused_objects()
}); });
} }
void BlenderSceneDelegate::update_visibility()
{
/* Updating visibility of existing objects/instancers */
for (auto &val : objects_.values()) {
val->update_visibility();
}
for (auto &val : instancers_.values()) {
val->update_visibility();
}
/* Add objects/instancers which were invisible before and not added yet */
DEGObjectIterSettings settings = {0};
settings.depsgraph = depsgraph;
settings.flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET;
DEGObjectIterData data = {0};
data.settings = &settings;
data.graph = settings.depsgraph;
data.flag = settings.flags;
eEvaluationMode deg_mode = DEG_get_mode(depsgraph);
ITER_BEGIN (DEG_iterator_objects_begin,
DEG_iterator_objects_next,
DEG_iterator_objects_end,
&data,
Object *,
object)
{
CLOG_INFO(LOG_RENDER_HYDRA_SCENE,
2,
"Visibility: %s [%s]",
object->id.name,
std::bitset<3>(BKE_object_visibility(object, deg_mode)).to_string().c_str());
if (!object_data(object_prim_id(object))) {
update_objects(object);
}
if (!instancer_data(instancer_prim_id(object))) {
update_instancers(object);
}
}
ITER_END;
}
bool BlenderSceneDelegate::set_light_shading_settings() bool BlenderSceneDelegate::set_light_shading_settings()
{ {
if (!view3d) { if (!view3d) {

View File

@ -91,30 +91,26 @@ class BlenderSceneDelegate : public pxr::HdSceneDelegate {
pxr::SdfPath prim_id(ID *id, const char *prefix) const; pxr::SdfPath prim_id(ID *id, const char *prefix) const;
pxr::SdfPath object_prim_id(Object *object) const; pxr::SdfPath object_prim_id(Object *object) const;
pxr::SdfPath material_prim_id(Material *mat) const; pxr::SdfPath material_prim_id(Material *mat) const;
pxr::SdfPath instancer_prim_id(Object *object) const; pxr::SdfPath instancer_prim_id() const;
pxr::SdfPath world_prim_id() const; pxr::SdfPath world_prim_id() const;
ObjectData *object_data(pxr::SdfPath const &id) const; ObjectData *object_data(pxr::SdfPath const &id) const;
MeshData *mesh_data(pxr::SdfPath const &id) const; MeshData *mesh_data(pxr::SdfPath const &id) const;
CurvesData *curves_data(pxr::SdfPath const &id) const; CurvesData *curves_data(pxr::SdfPath const &id) const;
VolumeData *volume_data(pxr::SdfPath const &id) const;
LightData *light_data(pxr::SdfPath const &id) const; LightData *light_data(pxr::SdfPath const &id) const;
MaterialData *material_data(pxr::SdfPath const &id) const; MaterialData *material_data(pxr::SdfPath const &id) const;
InstancerData *instancer_data(pxr::SdfPath const &id, bool child_id = false) const; InstancerData *instancer_data(pxr::SdfPath const &id, bool child_id = false) const;
VolumeData *volume_data(pxr::SdfPath const &id) const;
void update_objects(Object *object);
void update_instancers(Object *object);
void update_world(); void update_world();
void check_updates(); void check_updates();
void add_new_objects(); void update_collection();
void remove_unused_objects();
void update_visibility();
bool set_light_shading_settings(); bool set_light_shading_settings();
bool set_world_shading_settings(); bool set_world_shading_settings();
ObjectDataMap objects_; ObjectDataMap objects_;
MaterialDataMap materials_; MaterialDataMap materials_;
InstancerDataMap instancers_; std::unique_ptr<InstancerData> instancer_data_;
std::unique_ptr<WorldData> world_data_; std::unique_ptr<WorldData> world_data_;
}; };

View File

@ -6,7 +6,6 @@
#include "BKE_customdata.h" #include "BKE_customdata.h"
#include "BKE_material.h" #include "BKE_material.h"
#include "BKE_object.h"
#include "blender_scene_delegate.h" #include "blender_scene_delegate.h"

View File

@ -58,7 +58,7 @@ template<class T> const T IdData::get_data(pxr::TfToken const &key) const
level, \ level, \
"%s (%s): " msg, \ "%s (%s): " msg, \
prim_id.GetText(), \ prim_id.GetText(), \
id->name, \ id ? id->name : "", \
##__VA_ARGS__); ##__VA_ARGS__);
} // namespace blender::render::hydra } // namespace blender::render::hydra

View File

@ -64,8 +64,6 @@ static std::string cache_image_file(Image *image,
} }
} }
BKE_image_save_options_free(&opts); BKE_image_save_options_free(&opts);
CLOG_INFO(LOG_RENDER_HYDRA_SCENE, 2, "%s -> %s", image->id.name, file_path.c_str());
return file_path; return file_path;
} }
@ -98,7 +96,7 @@ std::string cache_image_color(float color[4])
char name[128]; char name[128];
snprintf(name, snprintf(name,
sizeof(name), sizeof(name),
"color_%02x-%02x-%02x.hdr", "color_%02x%02x%02x.hdr",
int(color[0] * 255), int(color[0] * 255),
int(color[1] * 255), int(color[1] * 255),
int(color[2] * 255)); int(color[2] * 255));

View File

@ -4,7 +4,6 @@
#include <pxr/base/gf/vec2f.h> #include <pxr/base/gf/vec2f.h>
#include <pxr/imaging/hd/light.h> #include <pxr/imaging/hd/light.h>
#include "BKE_object.h"
#include "DEG_depsgraph_query.h" #include "DEG_depsgraph_query.h"
#include "blender_scene_delegate.h" #include "blender_scene_delegate.h"
@ -12,14 +11,12 @@
namespace blender::render::hydra { namespace blender::render::hydra {
InstancerData::InstancerData(BlenderSceneDelegate *scene_delegate, InstancerData::InstancerData(BlenderSceneDelegate *scene_delegate, pxr::SdfPath const &prim_id)
Object *object, : IdData(scene_delegate, nullptr, prim_id)
pxr::SdfPath const &prim_id)
: ObjectData(scene_delegate, object, prim_id)
{ {
} }
bool InstancerData::is_supported(Object *object) bool InstancerData::is_instance_supported(Object *object)
{ {
switch (object->type) { switch (object->type) {
case OB_MESH: case OB_MESH:
@ -36,40 +33,9 @@ bool InstancerData::is_supported(Object *object)
return false; return false;
} }
bool InstancerData::is_visible(BlenderSceneDelegate *scene_delegate, Object *object) void InstancerData::init() {}
{
eEvaluationMode deg_mode = DEG_get_mode(scene_delegate->depsgraph);
int vis = BKE_object_visibility(object, deg_mode);
bool ret = vis & OB_VISIBLE_INSTANCES;
if (deg_mode == DAG_EVAL_VIEWPORT) {
ret &= BKE_object_is_visible_in_viewport(scene_delegate->view3d, object);
}
else {
if (ret) {
/* If some of parent object is instancer, then currenct object as instancer
* is invisible in Final render */
for (Object *ob = object->parent; ob != nullptr; ob = ob->parent) {
if (ob->transflag & OB_DUPLI) {
ret = false;
break;
}
}
}
}
return ret;
}
void InstancerData::init() void InstancerData::insert() {}
{
ID_LOG(1, "");
write_instances();
}
void InstancerData::insert()
{
ID_LOG(1, "");
scene_delegate_->GetRenderIndex().InsertInstancer(scene_delegate_, prim_id);
}
void InstancerData::remove() void InstancerData::remove()
{ {
@ -77,27 +43,19 @@ void InstancerData::remove()
for (auto &m_inst : mesh_instances_.values()) { for (auto &m_inst : mesh_instances_.values()) {
m_inst.data->remove(); m_inst.data->remove();
} }
if (!mesh_instances_.is_empty()) {
scene_delegate_->GetRenderIndex().RemoveInstancer(prim_id); scene_delegate_->GetRenderIndex().RemoveInstancer(prim_id);
}
mesh_instances_.clear();
for (auto &l_inst : light_instances_.values()) { for (auto &l_inst : light_instances_.values()) {
l_inst.transforms.clear(); l_inst.transforms.clear();
update_light_instance(l_inst); update_light_instance(l_inst);
} }
light_instances_.clear();
} }
void InstancerData::update() void InstancerData::update() {}
{
ID_LOG(1, "");
Object *object = (Object *)id;
if (id->recalc & ID_RECALC_GEOMETRY ||
(object->data && ((ID *)object->data)->recalc & ID_RECALC_GEOMETRY) ||
id->recalc & ID_RECALC_TRANSFORM)
{
write_instances();
scene_delegate_->GetRenderIndex().GetChangeTracker().MarkInstancerDirty(
prim_id, pxr::HdChangeTracker::AllDirty);
}
}
pxr::VtValue InstancerData::get_data(pxr::TfToken const &key) const pxr::VtValue InstancerData::get_data(pxr::TfToken const &key) const
{ {
@ -108,34 +66,6 @@ pxr::VtValue InstancerData::get_data(pxr::TfToken const &key) const
return pxr::VtValue(); return pxr::VtValue();
} }
bool InstancerData::update_visibility()
{
bool prev_visible = visible;
visible = is_visible(scene_delegate_, (Object *)id);
bool ret = visible != prev_visible;
if (ret) {
ID_LOG(1, "");
auto &change_tracker = scene_delegate_->GetRenderIndex().GetChangeTracker();
change_tracker.MarkInstancerDirty(prim_id, pxr::HdChangeTracker::DirtyVisibility);
for (auto &m_inst : mesh_instances_.values()) {
m_inst.data->visible = visible;
for (auto &p : m_inst.data->submesh_paths()) {
change_tracker.MarkRprimDirty(p, pxr::HdChangeTracker::DirtyVisibility);
}
}
char name[16];
for (auto &l_inst : light_instances_.values()) {
for (int i = 0; i < l_inst.count; ++i) {
snprintf(name, sizeof(name), "L_%08x", i);
change_tracker.MarkRprimDirty(l_inst.data->prim_id.AppendElementString(name),
pxr::HdChangeTracker::DirtyVisibility);
}
}
}
return ret;
}
pxr::GfMatrix4d InstancerData::get_transform(pxr::SdfPath const &id) const pxr::GfMatrix4d InstancerData::get_transform(pxr::SdfPath const &id) const
{ {
LightInstance *l_inst = light_instance(id); LightInstance *l_inst = light_instance(id);
@ -187,99 +117,6 @@ pxr::SdfPathVector InstancerData::prototypes() const
return paths; return paths;
} }
void InstancerData::check_update(Object *object)
{
pxr::SdfPath path = object_prim_id(object);
MeshInstance *m_inst = mesh_instance(path);
if (m_inst) {
if (!is_instance_visible(object)) {
m_inst->data->remove();
mesh_instances_.remove(path);
scene_delegate_->GetRenderIndex().GetChangeTracker().MarkInstancerDirty(
prim_id, pxr::HdChangeTracker::AllDirty);
return;
}
m_inst->data->update();
if (m_inst->data->id->recalc & ID_RECALC_TRANSFORM) {
write_instances();
scene_delegate_->GetRenderIndex().GetChangeTracker().MarkInstancerDirty(
prim_id, pxr::HdChangeTracker::AllDirty);
}
return;
}
LightInstance *l_inst = light_instance(path);
if (l_inst) {
if (!is_instance_visible(object)) {
l_inst->transforms.clear();
update_light_instance(*l_inst);
light_instances_.remove(path);
return;
}
Object *obj = (Object *)l_inst->data->id;
if (obj->id.recalc & (ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY) ||
((ID *)obj->data)->recalc & ID_RECALC_GEOMETRY)
{
write_instances();
}
return;
}
/* Checking if object wasn't added to instances before */
if (is_supported(object) && is_instance_visible(object)) {
bool do_write_instances = false;
ListBase *lb = object_duplilist(
scene_delegate_->depsgraph, scene_delegate_->scene, (Object *)id);
LISTBASE_FOREACH (DupliObject *, dupli, lb) {
if (dupli->ob == object) {
do_write_instances = true;
break;
}
}
free_object_duplilist(lb);
if (do_write_instances) {
write_instances();
if (!mesh_instances_.is_empty()) {
scene_delegate_->GetRenderIndex().GetChangeTracker().MarkInstancerDirty(
prim_id, pxr::HdChangeTracker::AllDirty);
}
}
}
}
void InstancerData::check_remove(Set<std::string> &available_objects)
{
bool ret = false;
mesh_instances_.remove_if([&](auto item) {
bool res = !available_objects.contains(item.key.GetName());
if (res) {
item.value.data->remove();
ret = true;
};
return res;
});
if (ret) {
write_instances();
scene_delegate_->GetRenderIndex().GetChangeTracker().MarkInstancerDirty(
prim_id, pxr::HdChangeTracker::AllDirty);
}
light_instances_.remove_if([&](auto item) {
bool res = !available_objects.contains(item.key.GetName());
if (res) {
item.value.transforms.clear();
update_light_instance(item.value);
};
return res;
});
}
void InstancerData::available_materials(Set<pxr::SdfPath> &paths) const void InstancerData::available_materials(Set<pxr::SdfPath> &paths) const
{ {
for (auto &m_inst : mesh_instances_.values()) { for (auto &m_inst : mesh_instances_.values()) {
@ -287,13 +124,6 @@ void InstancerData::available_materials(Set<pxr::SdfPath> &paths) const
} }
} }
void InstancerData::update_as_parent()
{
write_instances();
scene_delegate_->GetRenderIndex().GetChangeTracker().MarkInstancerDirty(
prim_id, pxr::HdChangeTracker::AllDirty);
}
void InstancerData::update_double_sided(MaterialData *mat_data) void InstancerData::update_double_sided(MaterialData *mat_data)
{ {
for (auto &m_inst : mesh_instances_.values()) { for (auto &m_inst : mesh_instances_.values()) {
@ -301,20 +131,94 @@ void InstancerData::update_double_sided(MaterialData *mat_data)
} }
} }
bool InstancerData::is_instance_visible(Object *object) void InstancerData::pre_update()
{ {
eEvaluationMode deg_mode = DEG_get_mode(scene_delegate_->depsgraph); mesh_transforms_.clear();
int vis = BKE_object_visibility(object, deg_mode); for (auto &m_inst : mesh_instances_.values()) {
bool ret = vis & OB_VISIBLE_SELF; m_inst.indices.clear();
if (deg_mode == DAG_EVAL_VIEWPORT) { }
if (!ret && ((object->transflag & OB_DUPLI) == 0 || for (auto &l_inst : light_instances_.values()) {
(object->transflag & OB_DUPLI && l_inst.transforms.clear();
object->duplicator_visibility_flag & OB_DUPLI_FLAG_VIEWPORT))) }
{ }
ret = true;
void InstancerData::update_instance(Object *parent_ob, DupliObject *dupli)
{
if (!ObjectData::is_visible(scene_delegate_, parent_ob, OB_VISIBLE_INSTANCES)) {
return;
}
Object *ob = dupli->ob;
if (!is_instance_supported(ob)) {
return;
}
if (!scene_delegate_->shading_settings.use_scene_lights && ob->type == OB_LAMP) {
return;
}
pxr::SdfPath p_id = object_prim_id(ob);
if (ob->type == OB_LAMP) {
LightInstance *inst = light_instance(p_id);
if (!inst) {
inst = &light_instances_.lookup_or_add_default(p_id);
inst->data = std::make_unique<LightData>(scene_delegate_, ob, p_id);
inst->data->init();
}
ID_LOG(2, "Light %s %d", inst->data->id->name, inst->transforms.size());
inst->transforms.push_back(gf_matrix_from_transform(dupli->mat));
}
else {
MeshInstance *inst = mesh_instance(p_id);
if (!inst) {
inst = &mesh_instances_.lookup_or_add_default(p_id);
inst->data = std::make_unique<MeshData>(scene_delegate_, ob, p_id);
inst->data->init();
inst->data->insert();
}
else {
inst->data->update();
}
ID_LOG(2, "Mesh %s %d", inst->data->id->name, mesh_transforms_.size());
inst->indices.push_back(mesh_transforms_.size());
mesh_transforms_.push_back(gf_matrix_from_transform(dupli->mat));
}
}
void InstancerData::post_update()
{
/* Remove mesh intances without indices */
mesh_instances_.remove_if([&](auto item) {
bool res = item.value.indices.empty();
if (res) {
item.value.data->remove();
}
return res;
});
/* Update light intances and remove instances without transforms */
for (auto &l_inst : light_instances_.values()) {
update_light_instance(l_inst);
}
light_instances_.remove_if([&](auto item) { return item.value.transforms.empty(); });
/* Insert/remove/update instancer in RenderIndex */
pxr::HdRenderIndex &index = scene_delegate_->GetRenderIndex();
if (mesh_instances_.is_empty()) {
/* Important: removing instancer when light_instances_ are empty too */
if (index.HasInstancer(prim_id) && light_instances_.is_empty()) {
index.RemoveInstancer(prim_id);
ID_LOG(1, "Remove instancer");
}
}
else {
if (index.HasInstancer(prim_id)) {
index.GetChangeTracker().MarkInstancerDirty(prim_id, pxr::HdChangeTracker::AllDirty);
ID_LOG(1, "Update instancer");
}
else {
index.InsertInstancer(scene_delegate_, prim_id);
ID_LOG(1, "Insert instancer");
} }
} }
return ret;
} }
pxr::SdfPath InstancerData::object_prim_id(Object *object) const pxr::SdfPath InstancerData::object_prim_id(Object *object) const
@ -339,69 +243,6 @@ int InstancerData::light_prim_id_index(pxr::SdfPath const &id) const
return index; return index;
} }
void InstancerData::write_instances()
{
mesh_transforms_.clear();
for (auto &m_inst : mesh_instances_.values()) {
m_inst.indices.clear();
}
for (auto &l_inst : light_instances_.values()) {
l_inst.transforms.clear();
}
ListBase *lb = object_duplilist(
scene_delegate_->depsgraph, scene_delegate_->scene, (Object *)id);
LISTBASE_FOREACH (DupliObject *, dupli, lb) {
Object *ob = dupli->ob;
if (!scene_delegate_->shading_settings.use_scene_lights && ob->type == OB_LAMP) {
continue;
}
if (!is_supported(ob) || !is_instance_visible(ob)) {
continue;
}
pxr::SdfPath p_id = object_prim_id(ob);
if (ob->type == OB_LAMP) {
LightInstance *inst = light_instance(p_id);
if (!inst) {
inst = &light_instances_.lookup_or_add_default(p_id);
inst->data = std::make_unique<LightData>(scene_delegate_, ob, p_id);
inst->data->init();
}
ID_LOG(2, "Light %s %d", inst->data->id->name, inst->transforms.size());
inst->transforms.push_back(gf_matrix_from_transform(dupli->mat));
}
else {
MeshInstance *inst = mesh_instance(p_id);
if (!inst) {
inst = &mesh_instances_.lookup_or_add_default(p_id);
inst->data = std::make_unique<MeshData>(scene_delegate_, ob, p_id);
inst->data->init();
inst->data->insert();
}
ID_LOG(2, "Mesh %s %d", inst->data->id->name, mesh_transforms_.size());
inst->indices.push_back(mesh_transforms_.size());
mesh_transforms_.push_back(gf_matrix_from_transform(dupli->mat));
}
}
free_object_duplilist(lb);
/* Remove mesh intances without indices */
mesh_instances_.remove_if([&](auto item) {
bool res = item.value.indices.empty();
if (res) {
item.value.data->remove();
}
return res;
});
/* Update light intances and remove instances without transforms */
light_instances_.remove_if([&](auto item) {
update_light_instance(item.value);
return item.value.transforms.empty();
});
}
void InstancerData::update_light_instance(LightInstance &inst) void InstancerData::update_light_instance(LightInstance &inst)
{ {
auto &render_index = scene_delegate_->GetRenderIndex(); auto &render_index = scene_delegate_->GetRenderIndex();

View File

@ -12,7 +12,7 @@
namespace blender::render::hydra { namespace blender::render::hydra {
class InstancerData : public ObjectData { class InstancerData : public IdData {
struct MeshInstance { struct MeshInstance {
std::unique_ptr<MeshData> data; std::unique_ptr<MeshData> data;
pxr::VtIntArray indices; pxr::VtIntArray indices;
@ -25,9 +25,8 @@ class InstancerData : public ObjectData {
}; };
public: public:
InstancerData(BlenderSceneDelegate *scene_delegate, Object *object, pxr::SdfPath const &prim_id); InstancerData(BlenderSceneDelegate *scene_delegate, pxr::SdfPath const &prim_id);
static bool is_supported(Object *object); static bool is_instance_supported(Object *object);
static bool is_visible(BlenderSceneDelegate *scene_delegate, Object *object);
void init() override; void init() override;
void insert() override; void insert() override;
@ -35,25 +34,28 @@ class InstancerData : public ObjectData {
void update() override; void update() override;
pxr::VtValue get_data(pxr::TfToken const &key) const override; pxr::VtValue get_data(pxr::TfToken const &key) const override;
bool update_visibility() override;
pxr::GfMatrix4d get_transform(pxr::SdfPath const &id) const; pxr::GfMatrix4d get_transform(pxr::SdfPath const &id) const;
pxr::HdPrimvarDescriptorVector primvar_descriptors(pxr::HdInterpolation interpolation) const; pxr::HdPrimvarDescriptorVector primvar_descriptors(pxr::HdInterpolation interpolation) const;
pxr::VtIntArray indices(pxr::SdfPath const &id) const; pxr::VtIntArray indices(pxr::SdfPath const &id) const;
ObjectData *object_data(pxr::SdfPath const &id) const; ObjectData *object_data(pxr::SdfPath const &id) const;
pxr::SdfPathVector prototypes() const; pxr::SdfPathVector prototypes() const;
void check_update(Object *object);
void check_remove(Set<std::string> &available_objects);
void available_materials(Set<pxr::SdfPath> &paths) const; void available_materials(Set<pxr::SdfPath> &paths) const;
void update_as_parent();
void update_double_sided(MaterialData *mat_data); void update_double_sided(MaterialData *mat_data);
/* Following update functions are working together:

Please add comment why this is done in this way

Please add comment why this is done in this way
pre_update()
update_instance()
update_instance()
...
post_update() */
void pre_update();
void update_instance(Object *parent_ob, DupliObject *dupli);
void post_update();
private: private:
bool is_instance_visible(Object *object);
pxr::SdfPath object_prim_id(Object *object) const; pxr::SdfPath object_prim_id(Object *object) const;
pxr::SdfPath light_prim_id(LightInstance const &inst, int index) const; pxr::SdfPath light_prim_id(LightInstance const &inst, int index) const;
int light_prim_id_index(pxr::SdfPath const &id) const; int light_prim_id_index(pxr::SdfPath const &id) const;
void write_instances();
void update_light_instance(LightInstance &inst); void update_light_instance(LightInstance &inst);
MeshInstance *mesh_instance(pxr::SdfPath const &id) const; MeshInstance *mesh_instance(pxr::SdfPath const &id) const;
LightInstance *light_instance(pxr::SdfPath const &id) const; LightInstance *light_instance(pxr::SdfPath const &id) const;
@ -63,6 +65,4 @@ class InstancerData : public ObjectData {
pxr::VtMatrix4dArray mesh_transforms_; pxr::VtMatrix4dArray mesh_transforms_;
}; };
using InstancerDataMap = Map<pxr::SdfPath, std::unique_ptr<InstancerData>>;
} // namespace blender::render::hydra } // namespace blender::render::hydra

View File

@ -111,19 +111,16 @@ void LightData::remove()
void LightData::update() void LightData::update()
{ {
ID_LOG(1, "");
Object *object = (Object *)id; Object *object = (Object *)id;
Light *light = (Light *)object->data; Light *light = (Light *)object->data;
pxr::HdDirtyBits bits = pxr::HdLight::Clean;
if (id->recalc & ID_RECALC_GEOMETRY || light->id.recalc & ID_RECALC_GEOMETRY) {
if (prim_type(light) != prim_type_) { if (prim_type(light) != prim_type_) {
remove(); remove();
init(); init();
insert(); insert();
return; return;
} }
pxr::HdDirtyBits bits = pxr::HdLight::Clean;
if (id->recalc & ID_RECALC_GEOMETRY || light->id.recalc & ID_RECALC_GEOMETRY) {
init(); init();
bits = pxr::HdLight::AllDirty; bits = pxr::HdLight::AllDirty;
} }
@ -133,6 +130,7 @@ void LightData::update()
} }
if (bits != pxr::HdChangeTracker::Clean) { if (bits != pxr::HdChangeTracker::Clean) {
scene_delegate_->GetRenderIndex().GetChangeTracker().MarkSprimDirty(prim_id, bits); scene_delegate_->GetRenderIndex().GetChangeTracker().MarkSprimDirty(prim_id, bits);
ID_LOG(1, "");
} }
} }

View File

@ -67,9 +67,7 @@ void MaterialData::update()
m_data->update_double_sided(this); m_data->update_double_sided(this);
} }
} }
for (auto &i_data : scene_delegate_->instancers_.values()) { scene_delegate_->instancer_data_->update_double_sided(this);
i_data->update_double_sided(this);
}
} }
} }

View File

@ -8,7 +8,6 @@
#include "BKE_material.h" #include "BKE_material.h"
#include "BKE_mesh.hh" #include "BKE_mesh.hh"
#include "BKE_mesh_runtime.h" #include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "blender_scene_delegate.h" #include "blender_scene_delegate.h"
#include "mesh.h" #include "mesh.h"
@ -299,6 +298,8 @@ void MeshData::write_materials()
} }
pxr::SdfPath p_id = scene_delegate_->material_prim_id(mat); pxr::SdfPath p_id = scene_delegate_->material_prim_id(mat);
m.mat_data = scene_delegate_->material_data(p_id);
if (!m.mat_data) {
m.mat_data = scene_delegate_->materials_ m.mat_data = scene_delegate_->materials_
.lookup_or_add(p_id, .lookup_or_add(p_id,
std::make_unique<MaterialData>(scene_delegate_, mat, p_id)) std::make_unique<MaterialData>(scene_delegate_, mat, p_id))
@ -306,6 +307,7 @@ void MeshData::write_materials()
m.mat_data->init(); m.mat_data->init();
m.mat_data->insert(); m.mat_data->insert();
} }
}
} }
} // namespace blender::render::hydra } // namespace blender::render::hydra

View File

@ -1,7 +1,6 @@
/* SPDX-License-Identifier: Apache-2.0 /* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */ * Copyright 2011-2022 Blender Foundation */
#include "BKE_object.h"
#include "DEG_depsgraph_query.h" #include "DEG_depsgraph_query.h"
#include "blender_scene_delegate.h" #include "blender_scene_delegate.h"
@ -68,26 +67,14 @@ bool ObjectData::is_supported(Object *object)
return false; return false;
} }
bool ObjectData::is_visible(BlenderSceneDelegate *scene_delegate, Object *object) bool ObjectData::is_visible(BlenderSceneDelegate *scene_delegate, Object *object, int mode)
{ {
eEvaluationMode deg_mode = DEG_get_mode(scene_delegate->depsgraph); eEvaluationMode deg_mode = DEG_get_mode(scene_delegate->depsgraph);
int vis = BKE_object_visibility(object, deg_mode); bool ret = BKE_object_visibility(object, deg_mode) & mode;
bool ret = vis & OB_VISIBLE_SELF;
if (deg_mode == DAG_EVAL_VIEWPORT) { if (deg_mode == DAG_EVAL_VIEWPORT) {
ret &= BKE_object_is_visible_in_viewport(scene_delegate->view3d, object); ret &= BKE_object_is_visible_in_viewport(scene_delegate->view3d, object);
} }
else { /* Note: visibility for final render we are taking from depsgraph */
if (ret) {
/* If some of parent object is instancer, then currenct object
* is invisible in Final render */
for (Object *ob = object->parent; ob != nullptr; ob = ob->parent) {
if (ob->transflag & OB_DUPLI) {
ret = false;
break;
}
}
}
}
return ret; return ret;
} }
@ -98,24 +85,6 @@ bool ObjectData::update_visibility()
return visible != prev_visible; return visible != prev_visible;
} }
void ObjectData::update_parent()
{
Object *object = (Object *)id;
if (parent_ != object->parent) {
ID_LOG(1, "");
parent_ = object->parent;
/* Looking for corresponded instancer and update it as parent */
for (Object *ob = parent_; ob != nullptr; ob = ob->parent) {
InstancerData *i_data = scene_delegate_->instancer_data(
scene_delegate_->instancer_prim_id(ob));
if (i_data) {
i_data->update_as_parent();
}
}
}
}
void ObjectData::write_transform() void ObjectData::write_transform()
{ {
transform = gf_matrix_from_transform(((Object *)id)->object_to_world); transform = gf_matrix_from_transform(((Object *)id)->object_to_world);

View File

@ -7,6 +7,7 @@
#include <pxr/base/gf/matrix4d.h> #include <pxr/base/gf/matrix4d.h>
#include "BKE_layer.h" #include "BKE_layer.h"
#include "BKE_object.h"
#include "BLI_map.hh" #include "BLI_map.hh"
#include "DNA_object_types.h" #include "DNA_object_types.h"
@ -23,18 +24,17 @@ class ObjectData : public IdData {
Object *object, Object *object,
pxr::SdfPath const &prim_id); pxr::SdfPath const &prim_id);
static bool is_supported(Object *object); static bool is_supported(Object *object);
static bool is_visible(BlenderSceneDelegate *scene_delegate, Object *object); static bool is_visible(BlenderSceneDelegate *scene_delegate,
Object *object,
int mode = OB_VISIBLE_SELF);
virtual bool update_visibility(); virtual bool update_visibility();
void update_parent();
pxr::GfMatrix4d transform; pxr::GfMatrix4d transform;
bool visible = true; bool visible = true;
protected: protected:
void write_transform(); void write_transform();
Object *parent_ = nullptr;
}; };
using ObjectDataMap = Map<pxr::SdfPath, std::unique_ptr<ObjectData>>; using ObjectDataMap = Map<pxr::SdfPath, std::unique_ptr<ObjectData>>;

View File

@ -176,11 +176,8 @@ void WorldData::write_transform()
{ {
transform = pxr::GfMatrix4d(pxr::GfRotation(pxr::GfVec3d(1.0, 0.0, 0.0), -90), pxr::GfVec3d()); transform = pxr::GfMatrix4d(pxr::GfRotation(pxr::GfVec3d(1.0, 0.0, 0.0), -90), pxr::GfVec3d());
transform *= pxr::GfMatrix4d(pxr::GfRotation(pxr::GfVec3d(1.0, 0.0, 0.0), -180), transform *= pxr::GfMatrix4d(pxr::GfRotation(pxr::GfVec3d(1.0, 0.0, 0.0), -180), pxr::GfVec3d());
pxr::GfVec3d()); transform *= pxr::GfMatrix4d(pxr::GfRotation(pxr::GfVec3d(0.0, 0.0, 1.0), 90.0), pxr::GfVec3d());
transform *= pxr::GfMatrix4d(pxr::GfRotation(pxr::GfVec3d(0.0, 0.0, 1.0), 90.0),
pxr::GfVec3d());
} }
} // namespace blender::render::hydra } // namespace blender::render::hydra