Support instancing for other objects: curves and volumes #74

Merged
Bogdan Nagirniak merged 4 commits from BLEN-449 into hydra-render 2023-07-26 10:27:51 +02:00
7 changed files with 121 additions and 137 deletions

View File

@ -38,7 +38,7 @@ pxr::HdMeshTopology BlenderSceneDelegate::GetMeshTopology(pxr::SdfPath const &id
{ {
CLOG_INFO(LOG_RENDER_HYDRA_SCENE, 3, "%s", id.GetText()); CLOG_INFO(LOG_RENDER_HYDRA_SCENE, 3, "%s", id.GetText());
MeshData *m_data = mesh_data(id); MeshData *m_data = mesh_data(id);
return m_data->mesh_topology(id); return m_data->topology(id);
} }
pxr::HdBasisCurvesTopology BlenderSceneDelegate::GetBasisCurvesTopology(pxr::SdfPath const &id) pxr::HdBasisCurvesTopology BlenderSceneDelegate::GetBasisCurvesTopology(pxr::SdfPath const &id)
@ -53,7 +53,7 @@ pxr::GfMatrix4d BlenderSceneDelegate::GetTransform(pxr::SdfPath const &id)
CLOG_INFO(LOG_RENDER_HYDRA_SCENE, 3, "%s", id.GetText()); CLOG_INFO(LOG_RENDER_HYDRA_SCENE, 3, "%s", id.GetText());
InstancerData *i_data = instancer_data(id, true); InstancerData *i_data = instancer_data(id, true);
if (i_data) { if (i_data) {
return i_data->get_transform(id); return i_data->transform(id);
} }
ObjectData *obj_data = object_data(id); ObjectData *obj_data = object_data(id);
if (obj_data) { if (obj_data) {
@ -162,7 +162,7 @@ pxr::SdfPath BlenderSceneDelegate::GetInstancerId(pxr::SdfPath const &prim_id)
{ {
CLOG_INFO(LOG_RENDER_HYDRA_SCENE, 3, "%s", prim_id.GetText()); CLOG_INFO(LOG_RENDER_HYDRA_SCENE, 3, "%s", prim_id.GetText());
InstancerData *i_data = instancer_data(prim_id, true); InstancerData *i_data = instancer_data(prim_id, true);
if (i_data) { if (i_data && mesh_data(prim_id)) {
return i_data->prim_id; return i_data->prim_id;
} }
return pxr::SdfPath(); return pxr::SdfPath();
@ -187,7 +187,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->get_transform(instancer_id); return i_data->transform(instancer_id);
} }
pxr::HdVolumeFieldDescriptorVector BlenderSceneDelegate::GetVolumeFieldDescriptors( pxr::HdVolumeFieldDescriptorVector BlenderSceneDelegate::GetVolumeFieldDescriptors(
@ -449,17 +449,21 @@ void BlenderSceneDelegate::update_collection()
object) object)
{ {
if (data.dupli_object_current) { if (data.dupli_object_current) {
instancer_data_->update_instance(data.dupli_parent, data.dupli_object_current); DupliObject *dupli = data.dupli_object_current;
if (!ObjectData::is_supported(dupli->ob) ||
!ObjectData::is_visible(this, data.dupli_parent, OB_VISIBLE_INSTANCES) ||
(!shading_settings.use_scene_lights && object->type == OB_LAMP))
{
continue;
}
instancer_data_->update_instance(data.dupli_parent, dupli);
continue; continue;
} }
if (!ObjectData::is_supported(object)) { if (!ObjectData::is_supported(object) || !ObjectData::is_visible(this, object) ||
continue; (!shading_settings.use_scene_lights && object->type == OB_LAMP))
} {
if (!ObjectData::is_visible(this, object)) {
continue;
}
if (!shading_settings.use_scene_lights && object->type == OB_LAMP) {
continue; continue;
} }

View File

@ -16,23 +16,6 @@ InstancerData::InstancerData(BlenderSceneDelegate *scene_delegate, pxr::SdfPath
{ {
} }
bool InstancerData::is_instance_supported(Object *object)
{
switch (object->type) {
case OB_MESH:
case OB_SURF:
case OB_FONT:
case OB_CURVES_LEGACY:
case OB_MBALL:
case OB_LAMP:
return true;
default:
break;
}
return false;
}
void InstancerData::init() {} void InstancerData::init() {}
void InstancerData::insert() {} void InstancerData::insert() {}
@ -48,11 +31,11 @@ void InstancerData::remove()
} }
mesh_instances_.clear(); mesh_instances_.clear();
for (auto &l_inst : light_instances_.values()) { for (auto &l_inst : nonmesh_instances_.values()) {
l_inst.transforms.clear(); l_inst.transforms.clear();
update_light_instance(l_inst); update_nonmesh_instance(l_inst);
} }
light_instances_.clear(); nonmesh_instances_.clear();
} }
void InstancerData::update() {} void InstancerData::update() {}
@ -66,11 +49,11 @@ pxr::VtValue InstancerData::get_data(pxr::TfToken const &key) const
return pxr::VtValue(); return pxr::VtValue();
} }
pxr::GfMatrix4d InstancerData::get_transform(pxr::SdfPath const &id) const pxr::GfMatrix4d InstancerData::transform(pxr::SdfPath const &id) const
{ {
LightInstance *l_inst = light_instance(id); NonmeshInstance *nm_inst = nonmesh_instance(id);
if (l_inst) { if (nm_inst) {
return l_inst->transforms[light_prim_id_index(id)]; return nm_inst->transforms[nonmesh_prim_id_index(id)];
} }
/* Mesh instance transform must be identity */ /* Mesh instance transform must be identity */
@ -99,9 +82,9 @@ ObjectData *InstancerData::object_data(pxr::SdfPath const &id) const
if (m_inst) { if (m_inst) {
return m_inst->data.get(); return m_inst->data.get();
} }
LightInstance *l_inst = light_instance(id); NonmeshInstance *nm_inst = nonmesh_instance(id);
if (l_inst) { if (nm_inst) {
return l_inst->data.get(); return nm_inst->data.get();
} }
return nullptr; return nullptr;
} }
@ -120,7 +103,10 @@ pxr::SdfPathVector InstancerData::prototypes() const
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()) {
((MeshData *)m_inst.data.get())->available_materials(paths); m_inst.data->available_materials(paths);
}
for (auto &l_inst : nonmesh_instances_.values()) {
l_inst.data->available_materials(paths);
} }
} }
@ -137,50 +123,39 @@ void InstancerData::pre_update()
for (auto &m_inst : mesh_instances_.values()) { for (auto &m_inst : mesh_instances_.values()) {
m_inst.indices.clear(); m_inst.indices.clear();
} }
for (auto &l_inst : light_instances_.values()) { for (auto &l_inst : nonmesh_instances_.values()) {
l_inst.transforms.clear(); l_inst.transforms.clear();
} }
} }
void InstancerData::update_instance(Object *parent_ob, DupliObject *dupli) void InstancerData::update_instance(Object *parent_ob, DupliObject *dupli)
{ {
if (!ObjectData::is_visible(scene_delegate_, parent_ob, OB_VISIBLE_INSTANCES)) { Object *object = dupli->ob;
return; pxr::SdfPath p_id = object_prim_id(object);
} if (ObjectData::is_mesh(object)) {
Object *ob = dupli->ob; MeshInstance *m_inst = mesh_instance(p_id);
if (!is_instance_supported(ob)) { if (!m_inst) {
return; m_inst = &mesh_instances_.lookup_or_add_default(p_id);
} m_inst->data = std::make_unique<MeshData>(scene_delegate_, object, p_id);
if (!scene_delegate_->shading_settings.use_scene_lights && ob->type == OB_LAMP) { m_inst->data->init();
return; m_inst->data->insert();
}
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, (int)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 { else {
inst->data->update(); m_inst->data->update();
} }
ID_LOG(2, "Mesh %s %d", inst->data->id->name, (int)mesh_transforms_.size()); ID_LOG(2, "Mesh %s %d", m_inst->data->id->name, (int)mesh_transforms_.size());
inst->indices.push_back(mesh_transforms_.size()); m_inst->indices.push_back(mesh_transforms_.size());
mesh_transforms_.push_back(gf_matrix_from_transform(dupli->mat)); mesh_transforms_.push_back(gf_matrix_from_transform(dupli->mat));
} }
else {
NonmeshInstance *nm_inst = nonmesh_instance(p_id);
if (!nm_inst) {
nm_inst = &nonmesh_instances_.lookup_or_add_default(p_id);
nm_inst->data = ObjectData::create(scene_delegate_, object, p_id);
}
ID_LOG(2, "Light %s %d", nm_inst->data->id->name, (int)nm_inst->transforms.size());
nm_inst->transforms.push_back(gf_matrix_from_transform(dupli->mat));
}
} }
void InstancerData::post_update() void InstancerData::post_update()
@ -195,16 +170,16 @@ void InstancerData::post_update()
}); });
/* Update light intances and remove instances without transforms */ /* Update light intances and remove instances without transforms */
for (auto &l_inst : light_instances_.values()) { for (auto &l_inst : nonmesh_instances_.values()) {
update_light_instance(l_inst); update_nonmesh_instance(l_inst);
} }
light_instances_.remove_if([&](auto item) { return item.value.transforms.empty(); }); nonmesh_instances_.remove_if([&](auto item) { return item.value.transforms.empty(); });
/* Insert/remove/update instancer in RenderIndex */ /* Insert/remove/update instancer in RenderIndex */
pxr::HdRenderIndex &index = scene_delegate_->GetRenderIndex(); pxr::HdRenderIndex &index = scene_delegate_->GetRenderIndex();
if (mesh_instances_.is_empty()) { if (mesh_instances_.is_empty()) {
/* Important: removing instancer when light_instances_ are empty too */ /* Important: removing instancer when nonmesh_instances_ are empty too */
if (index.HasInstancer(prim_id) && light_instances_.is_empty()) { if (index.HasInstancer(prim_id) && nonmesh_instances_.is_empty()) {
index.RemoveInstancer(prim_id); index.RemoveInstancer(prim_id);
ID_LOG(1, "Remove instancer"); ID_LOG(1, "Remove instancer");
} }
@ -229,73 +204,62 @@ pxr::SdfPath InstancerData::object_prim_id(Object *object) const
return prim_id.AppendElementString(name); return prim_id.AppendElementString(name);
} }
pxr::SdfPath InstancerData::light_prim_id(LightInstance const &inst, int index) const pxr::SdfPath InstancerData::nonmesh_prim_id(pxr::SdfPath const &prim_id, int index) const
{ {
char name[16]; char name[16];
snprintf(name, sizeof(name), "L_%08x", index); snprintf(name, sizeof(name), "NM_%08x", index);
return inst.data->prim_id.AppendElementString(name); return prim_id.AppendElementString(name);
} }
int InstancerData::light_prim_id_index(pxr::SdfPath const &id) const int InstancerData::nonmesh_prim_id_index(pxr::SdfPath const &id) const
{ {
int index; int index;
sscanf(id.GetName().c_str(), "L_%x", &index); sscanf(id.GetName().c_str(), "NM_%x", &index);
return index; return index;
} }
void InstancerData::update_light_instance(LightInstance &inst) void InstancerData::update_nonmesh_instance(NonmeshInstance &nm_inst)
{ {
auto &render_index = scene_delegate_->GetRenderIndex(); ObjectData *obj_data = nm_inst.data.get();
LightData &l_data = *inst.data; pxr::SdfPath prev_id = nm_inst.data->prim_id;
int i; int i;
pxr::SdfPath p;
/* Remove old light instances */ /* Remove old light instances */
while (inst.count > inst.transforms.size()) { while (nm_inst.count > nm_inst.transforms.size()) {
--inst.count; --nm_inst.count;
p = light_prim_id(inst, inst.count); obj_data->prim_id = nonmesh_prim_id(prev_id, nm_inst.count);
render_index.RemoveSprim(l_data.prim_type_, p); obj_data->remove();
ID_LOG(2, "Remove %s", p.GetText());
} }
/* Update current light instances */ /* Update current light instances */
if (inst.data->prim_type((Light *)((Object *)l_data.id)->data) != l_data.prim_type_) { LightData *l_data = dynamic_cast<LightData *>(obj_data);
/* Recreate instances when prim_type was changed */ if (l_data && l_data->prim_type((Light *)((Object *)l_data->id)->data) != l_data->prim_type_) {
for (i = 0; i < inst.count; ++i) { /* Special case: recreate instances when prim_type was changed */
p = light_prim_id(inst, i); for (i = 0; i < nm_inst.count; ++i) {
render_index.RemoveSprim(l_data.prim_type_, p); obj_data->prim_id = nonmesh_prim_id(prev_id, i);
ID_LOG(2, "Remove %s", p.GetText()); obj_data->remove();
} }
inst.data->init(); l_data->init();
for (i = 0; i < inst.count; ++i) { for (i = 0; i < nm_inst.count; ++i) {
p = light_prim_id(inst, i); obj_data->prim_id = nonmesh_prim_id(prev_id, i);
render_index.InsertSprim(l_data.prim_type_, scene_delegate_, p); obj_data->insert();
ID_LOG(2, "Insert %s (%s)", p.GetText(), l_data.id->name);
} }
} }
else { else {
/* Update light instances*/ for (i = 0; i < nm_inst.count; ++i) {
pxr::HdDirtyBits bits = pxr::HdLight::DirtyTransform; obj_data->prim_id = nonmesh_prim_id(prev_id, i);
Object *obj = (Object *)inst.data->id; obj_data->update();
if (obj->id.recalc & ID_RECALC_GEOMETRY || ((ID *)obj->data)->recalc & ID_RECALC_GEOMETRY) {
l_data.init();
bits = pxr::HdLight::AllDirty;
}
for (i = 0; i < inst.count; ++i) {
p = light_prim_id(inst, i);
render_index.GetChangeTracker().MarkSprimDirty(p, bits);
ID_LOG(2, "Update %s (%s)", p.GetText(), l_data.id->name);
} }
} }
/* Add new light instances */ /* Add new light instances */
while (inst.count < inst.transforms.size()) { while (nm_inst.count < nm_inst.transforms.size()) {
p = light_prim_id(inst, inst.count); obj_data->prim_id = nonmesh_prim_id(prev_id, nm_inst.count);
render_index.InsertSprim(l_data.prim_type_, scene_delegate_, p); obj_data->insert();
ID_LOG(2, "Insert %s (%s)", p.GetText(), l_data.id->name); ++nm_inst.count;
++inst.count;
} }
obj_data->prim_id = prev_id;
} }
InstancerData::MeshInstance *InstancerData::mesh_instance(pxr::SdfPath const &id) const InstancerData::MeshInstance *InstancerData::mesh_instance(pxr::SdfPath const &id) const
@ -308,14 +272,14 @@ InstancerData::MeshInstance *InstancerData::mesh_instance(pxr::SdfPath const &id
return const_cast<MeshInstance *>(m_inst); return const_cast<MeshInstance *>(m_inst);
} }
InstancerData::LightInstance *InstancerData::light_instance(pxr::SdfPath const &id) const InstancerData::NonmeshInstance *InstancerData::nonmesh_instance(pxr::SdfPath const &id) const
{ {
auto l_inst = light_instances_.lookup_ptr(id.GetPathElementCount() == 4 ? id.GetParentPath() : auto nm_inst = nonmesh_instances_.lookup_ptr(id.GetPathElementCount() == 4 ? id.GetParentPath() :
id); id);
if (!l_inst) { if (!nm_inst) {
return nullptr; return nullptr;
} }
return const_cast<LightInstance *>(l_inst); return const_cast<NonmeshInstance *>(nm_inst);
} }
} // namespace blender::render::hydra } // namespace blender::render::hydra

View File

@ -7,7 +7,6 @@
#include "BLI_map.hh" #include "BLI_map.hh"
#include "BLI_set.hh" #include "BLI_set.hh"
#include "light.h"
#include "mesh.h" #include "mesh.h"
namespace blender::render::hydra { namespace blender::render::hydra {
@ -18,15 +17,14 @@ class InstancerData : public IdData {
pxr::VtIntArray indices; pxr::VtIntArray indices;
}; };
struct LightInstance { struct NonmeshInstance {
std::unique_ptr<LightData> data; std::unique_ptr<ObjectData> data;
pxr::VtMatrix4dArray transforms; pxr::VtMatrix4dArray transforms;
int count = 0; int count = 0;
}; };
public: public:
InstancerData(BlenderSceneDelegate *scene_delegate, pxr::SdfPath const &prim_id); InstancerData(BlenderSceneDelegate *scene_delegate, pxr::SdfPath const &prim_id);
static bool is_instance_supported(Object *object);
void init() override; void init() override;
void insert() override; void insert() override;
@ -34,7 +32,7 @@ class InstancerData : public IdData {
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;
pxr::GfMatrix4d get_transform(pxr::SdfPath const &id) const; pxr::GfMatrix4d 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;
@ -54,14 +52,14 @@ class InstancerData : public IdData {
private: private:
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 nonmesh_prim_id(pxr::SdfPath const &prim_id, int index) const;
int light_prim_id_index(pxr::SdfPath const &id) const; int nonmesh_prim_id_index(pxr::SdfPath const &id) const;
void update_light_instance(LightInstance &inst); void update_nonmesh_instance(NonmeshInstance &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; NonmeshInstance *nonmesh_instance(pxr::SdfPath const &id) const;
Map<pxr::SdfPath, MeshInstance> mesh_instances_; Map<pxr::SdfPath, MeshInstance> mesh_instances_;
Map<pxr::SdfPath, LightInstance> light_instances_; Map<pxr::SdfPath, NonmeshInstance> nonmesh_instances_;
pxr::VtMatrix4dArray mesh_transforms_; pxr::VtMatrix4dArray mesh_transforms_;
}; };

View File

@ -119,7 +119,7 @@ void MeshData::available_materials(Set<pxr::SdfPath> &paths) const
} }
} }
pxr::HdMeshTopology MeshData::mesh_topology(pxr::SdfPath const &id) const pxr::HdMeshTopology MeshData::topology(pxr::SdfPath const &id) const
{ {
const SubMesh &sm = submesh(id); const SubMesh &sm = submesh(id);
return pxr::HdMeshTopology(pxr::PxOsdOpenSubdivTokens->none, return pxr::HdMeshTopology(pxr::PxOsdOpenSubdivTokens->none,

View File

@ -37,7 +37,7 @@ class MeshData : public ObjectData {
pxr::SdfPath material_id(pxr::SdfPath const &id) const override; pxr::SdfPath material_id(pxr::SdfPath const &id) const override;
void available_materials(Set<pxr::SdfPath> &paths) const override; void available_materials(Set<pxr::SdfPath> &paths) const override;
pxr::HdMeshTopology mesh_topology(pxr::SdfPath const &id) const; pxr::HdMeshTopology topology(pxr::SdfPath const &id) const;
pxr::HdPrimvarDescriptorVector primvar_descriptors(pxr::HdInterpolation interpolation) const; pxr::HdPrimvarDescriptorVector primvar_descriptors(pxr::HdInterpolation interpolation) const;
pxr::HdCullStyle cull_style(pxr::SdfPath const &id) const; pxr::HdCullStyle cull_style(pxr::SdfPath const &id) const;
bool double_sided(pxr::SdfPath const &id) const; bool double_sided(pxr::SdfPath const &id) const;

View File

@ -24,7 +24,6 @@ std::unique_ptr<ObjectData> ObjectData::create(BlenderSceneDelegate *scene_deleg
pxr::SdfPath const &prim_id) pxr::SdfPath const &prim_id)
{ {
std::unique_ptr<ObjectData> obj_data; std::unique_ptr<ObjectData> obj_data;
switch (object->type) { switch (object->type) {
case OB_MESH: case OB_MESH:
case OB_SURF: case OB_SURF:
@ -73,6 +72,24 @@ bool ObjectData::is_supported(Object *object)
return false; return false;
} }
bool ObjectData::is_mesh(Object *object)
{
switch (object->type) {
case OB_MESH:
case OB_SURF:
case OB_FONT:
case OB_CURVES_LEGACY:
case OB_MBALL:
if (VolumeModifierData::is_volume_modifier(object)) {
return false;
}
return true;
default:
break;
}
return false;
}
bool ObjectData::is_visible(BlenderSceneDelegate *scene_delegate, Object *object, int mode) 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);

View File

@ -25,6 +25,7 @@ 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_mesh(Object *object);
static bool is_visible(BlenderSceneDelegate *scene_delegate, static bool is_visible(BlenderSceneDelegate *scene_delegate,
Object *object, Object *object,
int mode = OB_VISIBLE_SELF); int mode = OB_VISIBLE_SELF);