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 98 additions and 107 deletions
Showing only changes of commit acf8145e1e - Show all commits

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)
@ -451,17 +451,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; continue;
} }
if (!ObjectData::is_supported(object)) { instancer_data_->update_instance(data.dupli_parent, dupli);
continue; continue;
} }
if (!ObjectData::is_visible(this, object)) {
continue; if (!ObjectData::is_supported(object) || !ObjectData::is_visible(this, object) ||
} (!shading_settings.use_scene_lights && object->type == OB_LAMP))
if (!shading_settings.use_scene_lights && object->type == OB_LAMP) { {
continue; continue;
} }

View File

@ -16,25 +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:
case OB_CURVES:
case OB_VOLUME:
return true;
default:
break;
}
return false;
}
void InstancerData::init() {} void InstancerData::init() {}
void InstancerData::insert() {} void InstancerData::insert() {}
@ -50,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() {}
@ -70,9 +51,9 @@ pxr::VtValue InstancerData::get_data(pxr::TfToken const &key) const
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); 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 */
@ -101,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;
} }
@ -124,7 +105,7 @@ void InstancerData::available_materials(Set<pxr::SdfPath> &paths) const
for (auto &m_inst : mesh_instances_.values()) { for (auto &m_inst : mesh_instances_.values()) {
m_inst.data->available_materials(paths); m_inst.data->available_materials(paths);
} }
for (auto &l_inst : light_instances_.values()) { for (auto &l_inst : nonmesh_instances_.values()) {
l_inst.data->available_materials(paths); l_inst.data->available_materials(paths);
} }
} }
@ -142,49 +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 (ELEM(ob->type, OB_LAMP, OB_VOLUME, OB_CURVES)) {
LightInstance *inst = light_instance(p_id);
if (!inst) {
inst = &light_instances_.lookup_or_add_default(p_id);
inst->data = ObjectData::create(scene_delegate_, ob, p_id);
}
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 { else {
MeshInstance *inst = mesh_instance(p_id); m_inst->data->update();
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 { ID_LOG(2, "Mesh %s %d", m_inst->data->id->name, (int)mesh_transforms_.size());
inst->data->update(); m_inst->indices.push_back(mesh_transforms_.size());
}
ID_LOG(2, "Mesh %s %d", inst->data->id->name, (int)mesh_transforms_.size());
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()
@ -199,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");
} }
@ -233,30 +204,30 @@ 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(pxr::SdfPath const &prim_id, 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), "L_%08x", index);
return 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(), "L_%x", &index);
return index; return index;
} }
void InstancerData::update_light_instance(LightInstance &inst) void InstancerData::update_nonmesh_instance(NonmeshInstance &nm_inst)
{ {
ObjectData *obj_data = inst.data.get(); ObjectData *obj_data = nm_inst.data.get();
pxr::SdfPath prev_id = inst.data->prim_id; pxr::SdfPath prev_id = nm_inst.data->prim_id;
int i; int i;
/* 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;
obj_data->prim_id = light_prim_id(prev_id, inst.count); obj_data->prim_id = nonmesh_prim_id(prev_id, nm_inst.count);
obj_data->remove(); obj_data->remove();
} }
@ -264,28 +235,28 @@ void InstancerData::update_light_instance(LightInstance &inst)
LightData *l_data = dynamic_cast<LightData *>(obj_data); LightData *l_data = dynamic_cast<LightData *>(obj_data);
if (l_data && l_data->prim_type((Light *)((Object *)l_data->id)->data) != l_data->prim_type_) { if (l_data && l_data->prim_type((Light *)((Object *)l_data->id)->data) != l_data->prim_type_) {
/* Special case: recreate instances when prim_type was changed */ /* Special case: recreate instances when prim_type was changed */
for (i = 0; i < inst.count; ++i) { for (i = 0; i < nm_inst.count; ++i) {
obj_data->prim_id = light_prim_id(prev_id, i); obj_data->prim_id = nonmesh_prim_id(prev_id, i);
obj_data->remove(); obj_data->remove();
} }
l_data->init(); l_data->init();
for (i = 0; i < inst.count; ++i) { for (i = 0; i < nm_inst.count; ++i) {
obj_data->prim_id = light_prim_id(prev_id, i); obj_data->prim_id = nonmesh_prim_id(prev_id, i);
obj_data->insert(); obj_data->insert();
} }
} }
else { else {
for (i = 0; i < inst.count; ++i) { for (i = 0; i < nm_inst.count; ++i) {
obj_data->prim_id = light_prim_id(prev_id, i); obj_data->prim_id = nonmesh_prim_id(prev_id, i);
obj_data->update(); obj_data->update();
} }
} }
/* Add new light instances */ /* Add new light instances */
while (inst.count < inst.transforms.size()) { while (nm_inst.count < nm_inst.transforms.size()) {
obj_data->prim_id = light_prim_id(prev_id, inst.count); obj_data->prim_id = nonmesh_prim_id(prev_id, nm_inst.count);
obj_data->insert(); obj_data->insert();
++inst.count; ++nm_inst.count;
} }
obj_data->prim_id = prev_id; obj_data->prim_id = prev_id;
@ -301,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,7 +17,7 @@ class InstancerData : public IdData {
pxr::VtIntArray indices; pxr::VtIntArray indices;
}; };
struct LightInstance { struct NonmeshInstance {
std::unique_ptr<ObjectData> data; std::unique_ptr<ObjectData> data;
pxr::VtMatrix4dArray transforms; pxr::VtMatrix4dArray transforms;
int count = 0; int count = 0;
@ -26,7 +25,6 @@ class InstancerData : public IdData {
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;
@ -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(pxr::SdfPath const &prim_id, 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);