Fix visibility of instancer object #40

Closed
Georgiy Markelov wants to merge 21 commits from BLEN-405 into hydra-render

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
7 changed files with 146 additions and 47 deletions

View File

@ -301,9 +301,7 @@ void BlenderSceneDelegate::update_objects(Object *object)
if (obj_data) {
obj_data->update_parent();
obj_data->update();
return;
}
if (view3d && !BKE_object_is_visible_in_viewport(view3d, object)) {
obj_data->update_visibility();
return;
}
objects_[id] = ObjectData::create(this, object, id);
@ -326,8 +324,13 @@ void BlenderSceneDelegate::update_instancers(Object *object)
if (i_data) {
if (object->transflag & OB_DUPLI) {
i_data->update();
i_data->update_visibility();
}
else {
InstancerData *parent_i_data = instancer_data(instancer_prim_id(object->parent));
if (object->parent && parent_i_data) {
parent_i_data->update_visibility();
}
i_data->remove();
instancers_.erase(id);
}
@ -336,9 +339,6 @@ void BlenderSceneDelegate::update_instancers(Object *object)
if ((object->transflag & OB_DUPLI) == 0) {
return;
}
if (view3d && !BKE_object_is_visible_in_viewport(view3d, object)) {
return;
}
instancers_[id] = std::make_unique<InstancerData>(this, object, id);
i_data = instancer_data(id);
i_data->init();
@ -376,8 +376,8 @@ void BlenderSceneDelegate::check_updates()
DEGIDIterData data = {0};
data.graph = depsgraph;
data.only_updated = true;
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,
2,
@ -406,12 +406,15 @@ void BlenderSceneDelegate::check_updates()
} break;
case ID_SCE: {
if (id->recalc & ID_RECALC_BASE_FLAGS) {
do_update_visibility = true;
if (id->recalc & ID_RECALC_COPY_ON_WRITE && !(id->recalc & ID_RECALC_SELECT)) {
do_update_collection = true;
}
if (id->recalc & (ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY)) {
do_update_collection = true;
}
if (id->recalc & ID_RECALC_BASE_FLAGS) {
do_update_visibility = true;
}
if (id->recalc & ID_RECALC_AUDIO_VOLUME) {
if ((scene->world && !world_data_) || (!scene->world && world_data_)) {
do_update_world = true;
@ -440,8 +443,7 @@ void BlenderSceneDelegate::add_new_objects()
{
DEGObjectIterSettings settings = {0};
settings.depsgraph = depsgraph;
settings.flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_VISIBLE |
DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET;
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;
@ -451,7 +453,8 @@ void BlenderSceneDelegate::add_new_objects()
DEG_iterator_objects_end,
&data,
Object *,
object) {
object)
{
update_objects(object);
update_instancers(object);
@ -476,7 +479,8 @@ void BlenderSceneDelegate::remove_unused_objects()
DEG_iterator_objects_end,
&data,
Object *,
object) {
object)
{
if (ObjectData::is_supported(object)) {
available_objects.insert(object_prim_id(object).GetName());
}
@ -485,25 +489,29 @@ void BlenderSceneDelegate::remove_unused_objects()
ITER_END;
/* Remove unused instancers */
for (auto it = instancers_.begin(); it != instancers_.end(); ++it) {
if (available_objects.find(it->first.GetName()) != available_objects.end()) {
auto it_inst = instancers_.begin();
while (it_inst != instancers_.end()) {
if (available_objects.find(it_inst->first.GetName()) != available_objects.end()) {
/* Remove objects from instancers */
it->second->check_remove(available_objects);
continue;
it_inst->second->check_remove(available_objects);
++it_inst;
}
else {
it_inst->second->remove();
instancers_.erase(it_inst++);
}
it->second->remove();
instancers_.erase(it);
it = instancers_.begin();
}
/* Remove unused objects */
for (auto it = objects_.begin(); it != objects_.end(); ++it) {
if (available_objects.find(it->first.GetName()) != available_objects.end()) {
continue;
auto it_obj = objects_.begin();
while (it_obj != objects_.end()) {
if (available_objects.find(it_obj->first.GetName()) != available_objects.end()) {
++it_obj;
}
else {
it_obj->second->remove();
objects_.erase(it_obj++);
}
it->second->remove();
objects_.erase(it);
it = objects_.begin();
}
/* Remove unused materials */
@ -521,13 +529,15 @@ void BlenderSceneDelegate::remove_unused_objects()
for (auto &it : instancers_) {
it.second->available_materials(available_materials);
}
for (auto it = materials_.begin(); it != materials_.end(); ++it) {
if (available_materials.find(it->first) != available_materials.end()) {
continue;
auto it_mat = materials_.begin();
while (it_mat != materials_.end()) {
if (available_materials.find(it_mat->first) != available_materials.end()) {
++it_mat;
}
else {
it_mat->second->remove();
materials_.erase(it_mat++);
}
it->second->remove();
materials_.erase(it);
it = materials_.begin();
}
}
@ -554,7 +564,8 @@ void BlenderSceneDelegate::update_visibility()
DEG_iterator_objects_end,
&data,
Object *,
object) {
object)
{
if (!object_data(object_prim_id(object))) {
update_objects(object);

View File

@ -22,9 +22,10 @@ namespace blender::render::hydra {
extern struct CLG_LogRef *LOG_RENDER_HYDRA_SCENE;
class BlenderSceneDelegate : public pxr::HdSceneDelegate {
friend ObjectData; /* has access to instances */
friend MeshData; /* has access to materials */
friend MaterialData; /* has access to objects and instancers */
friend ObjectData; /* has access to instances */
friend InstancerData; /* has access to instances */
friend MeshData; /* has access to materials */
friend MaterialData; /* has access to objects and instancers */
public:
enum class EngineType { VIEWPORT = 1, FINAL, PREVIEW };

View File

@ -4,6 +4,9 @@
#include <pxr/base/gf/vec2f.h>
#include <pxr/imaging/hd/light.h>
#include "BKE_object.h"
#include "DEG_depsgraph_query.h"
#include "blender_scene_delegate.h"
#include "instancer.h"
@ -66,7 +69,8 @@ void InstancerData::update()
Object *object = (Object *)id;
if (id->recalc & ID_RECALC_GEOMETRY ||
(object->data && ((ID *)object->data)->recalc & ID_RECALC_GEOMETRY) ||
id->recalc & ID_RECALC_TRANSFORM) {
id->recalc & ID_RECALC_TRANSFORM)
{
set_instances();
scene_delegate_->GetRenderIndex().GetChangeTracker().MarkInstancerDirty(
prim_id, pxr::HdChangeTracker::AllDirty);
@ -83,10 +87,66 @@ pxr::VtValue InstancerData::get_data(pxr::TfToken const &key) const
return ret;
}
bool InstancerData::is_duplicator_visible(BlenderSceneDelegate *scene_delegate, Object *object)
{
bool ret = true;
if (object->transflag & OB_DUPLI) {
Review

Use DEG_get_mode(scene_delegate_->depsgraph) instead EngineType

Use `DEG_get_mode(scene_delegate_->depsgraph)` instead `EngineType`
int flag = DEG_get_mode(scene_delegate->depsgraph) == DAG_EVAL_VIEWPORT ?
OB_DUPLI_FLAG_VIEWPORT :
OB_DUPLI_FLAG_RENDER;
ret = object->duplicator_visibility_flag & flag;
}
return ret;
}
bool InstancerData::update_duplicator_visibility()
{
bool prev_visible = duplicator_visible;
duplicator_visible = is_duplicator_visible(scene_delegate_, (Object *)id);
bool ret = duplicator_visible != prev_visible;
if (ret) {
ID_LOG(2, "");
}
return ret;
}
bool InstancerData::update_instances_visibility()
{
bool prev_visible = instances_visible;
instances_visible = BKE_object_visibility((Object *)id,
DEG_get_mode(scene_delegate_->depsgraph)) &
OB_VISIBLE_INSTANCES;
bool ret = instances_visible != prev_visible;
if (ret) {
ID_LOG(2, "");
}
return ret;
}
bool InstancerData::update_visibility()
{
bool ret = ObjectData::update_visibility();
if (ret) {
bool dup_ret = update_duplicator_visibility();
bool inst_ret = update_instances_visibility();
Object *ob = ((Object *)id)->parent;
InstancerData *parent_i_data = scene_delegate_->instancer_data(
scene_delegate_->instancer_prim_id(ob));
if (dup_ret || (ob && parent_i_data && parent_i_data->visible != duplicator_visible)) {
auto &change_tracker = scene_delegate_->GetRenderIndex().GetChangeTracker();
if (ob && parent_i_data) {
parent_i_data->visible = duplicator_visible;
change_tracker.MarkInstancerDirty(parent_i_data->prim_id,
pxr::HdChangeTracker::DirtyVisibility);
}
visible = instances_visible;
change_tracker.MarkInstancerDirty(prim_id, pxr::HdChangeTracker::DirtyVisibility);
}
if (ret || inst_ret) {
auto &change_tracker = scene_delegate_->GetRenderIndex().GetChangeTracker();
change_tracker.MarkInstancerDirty(prim_id, pxr::HdChangeTracker::DirtyVisibility);
for (auto &it : mesh_instances_) {
@ -103,7 +163,7 @@ bool InstancerData::update_visibility()
}
}
}
return ret;
return ret || dup_ret || inst_ret;
}
pxr::GfMatrix4d InstancerData::get_transform(pxr::SdfPath const &id) const
@ -174,7 +234,8 @@ void InstancerData::check_update(Object *object)
if (l_it != light_instances_.end()) {
Object *obj = (Object *)l_it->second.data->id;
if (obj->id.recalc & (ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY) ||
((ID *)obj->data)->recalc & ID_RECALC_GEOMETRY) {
((ID *)obj->data)->recalc & ID_RECALC_GEOMETRY)
{
set_instances();
}
return;

View File

@ -25,6 +25,7 @@ class InstancerData : public ObjectData {
public:
InstancerData(BlenderSceneDelegate *scene_delegate, Object *object, pxr::SdfPath const &prim_id);
static bool is_supported(Object *object);
static bool is_duplicator_visible(BlenderSceneDelegate *scene_delegate, Object *object);
void init() override;
void insert() override;
@ -32,7 +33,10 @@ class InstancerData : public ObjectData {
void update() override;
pxr::VtValue get_data(pxr::TfToken const &key) const override;
bool update_visibility() override;
bool update_duplicator_visibility();
bool update_instances_visibility();
pxr::GfMatrix4d get_transform(pxr::SdfPath const &id) const;
pxr::HdPrimvarDescriptorVector primvar_descriptors(pxr::HdInterpolation interpolation) const;
@ -45,6 +49,9 @@ class InstancerData : public ObjectData {
void update_as_parent();
void update_double_sided(MaterialData *mat_data);
bool duplicator_visible = true;
bool instances_visible = true;
private:
pxr::SdfPath object_prim_id(Object *object) const;
pxr::SdfPath light_prim_id(LightInstance const &inst, int index) const;

View File

@ -27,7 +27,8 @@ void MeshData::init()
Object *object = (Object *)id;
if (object->type == OB_MESH && object->mode == OB_MODE_OBJECT &&
BLI_listbase_is_empty(&object->modifiers)) {
BLI_listbase_is_empty(&object->modifiers))
{
write_mesh((Mesh *)object->data);
}
else {

View File

@ -2,6 +2,7 @@
* Copyright 2011-2022 Blender Foundation */
#include "BKE_object.h"
#include "DEG_depsgraph_query.h"
#include "blender_scene_delegate.h"
#include "light.h"
@ -59,14 +60,30 @@ bool ObjectData::is_supported(Object *object)
return false;
}
bool ObjectData::is_visible(BlenderSceneDelegate *scene_delegate, Object *object)
{
bool ret = true;
if (DEG_get_mode(scene_delegate->depsgraph) == DAG_EVAL_VIEWPORT) {
ret = BKE_object_is_visible_in_viewport(scene_delegate->view3d, object);
if (ret && object->transflag & OB_DUPLI) {
ret = object->duplicator_visibility_flag & OB_DUPLI_FLAG_VIEWPORT;
}
}
else {
if (object->transflag & OB_DUPLI) {
ret = object->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER;
}
if (object->parent && (object->parent->transflag & OB_DUPLI)) {
ret = false;
}
}
return ret;
}
bool ObjectData::update_visibility()
{
if (!scene_delegate_->view3d) {
return false;
}
bool prev_visible = visible;
visible = BKE_object_is_visible_in_viewport(scene_delegate_->view3d, (Object *)id);
visible = is_visible(scene_delegate_, (Object *)id);
bool ret = visible != prev_visible;
if (ret) {
ID_LOG(2, "");

View File

@ -22,6 +22,7 @@ class ObjectData : public IdData {
Object *object,
pxr::SdfPath const &prim_id);
static bool is_supported(Object *object);
static bool is_visible(BlenderSceneDelegate *scene_delegate, Object *object);
virtual bool update_visibility();
void update_parent();