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());
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)
@ -53,7 +53,7 @@ pxr::GfMatrix4d BlenderSceneDelegate::GetTransform(pxr::SdfPath const &id)
CLOG_INFO(LOG_RENDER_HYDRA_SCENE, 3, "%s", id.GetText());
InstancerData *i_data = instancer_data(id, true);
if (i_data) {
return i_data->get_transform(id);
return i_data->transform(id);
}
ObjectData *obj_data = object_data(id);
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());
InstancerData *i_data = instancer_data(prim_id, true);
if (i_data) {
if (i_data && mesh_data(prim_id)) {
return i_data->prim_id;
}
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());
InstancerData *i_data = instancer_data(instancer_id);
return i_data->get_transform(instancer_id);
return i_data->transform(instancer_id);
}
pxr::HdVolumeFieldDescriptorVector BlenderSceneDelegate::GetVolumeFieldDescriptors(
@ -449,17 +449,21 @@ void BlenderSceneDelegate::update_collection()
object)
{
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;
}
if (!ObjectData::is_supported(object)) {
continue;
}
if (!ObjectData::is_visible(this, object)) {
continue;
}
if (!shading_settings.use_scene_lights && object->type == OB_LAMP) {
if (!ObjectData::is_supported(object) || !ObjectData::is_visible(this, object) ||
(!shading_settings.use_scene_lights && object->type == OB_LAMP))
{
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::insert() {}
@ -48,11 +31,11 @@ void InstancerData::remove()
}
mesh_instances_.clear();
for (auto &l_inst : light_instances_.values()) {
for (auto &l_inst : nonmesh_instances_.values()) {
l_inst.transforms.clear();
update_light_instance(l_inst);
update_nonmesh_instance(l_inst);
}
light_instances_.clear();
nonmesh_instances_.clear();
}
void InstancerData::update() {}
@ -66,11 +49,11 @@ pxr::VtValue InstancerData::get_data(pxr::TfToken const &key) const
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);
if (l_inst) {
return l_inst->transforms[light_prim_id_index(id)];
NonmeshInstance *nm_inst = nonmesh_instance(id);
if (nm_inst) {
return nm_inst->transforms[nonmesh_prim_id_index(id)];
}
/* Mesh instance transform must be identity */
@ -99,9 +82,9 @@ ObjectData *InstancerData::object_data(pxr::SdfPath const &id) const
if (m_inst) {
return m_inst->data.get();
}
LightInstance *l_inst = light_instance(id);
if (l_inst) {
return l_inst->data.get();
NonmeshInstance *nm_inst = nonmesh_instance(id);
if (nm_inst) {
return nm_inst->data.get();
}
return nullptr;
}
@ -120,7 +103,10 @@ pxr::SdfPathVector InstancerData::prototypes() const
void InstancerData::available_materials(Set<pxr::SdfPath> &paths) const
{
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()) {
m_inst.indices.clear();
}
for (auto &l_inst : light_instances_.values()) {
for (auto &l_inst : nonmesh_instances_.values()) {
l_inst.transforms.clear();
}
}
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, (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();
Object *object = dupli->ob;
pxr::SdfPath p_id = object_prim_id(object);
if (ObjectData::is_mesh(object)) {
MeshInstance *m_inst = mesh_instance(p_id);
if (!m_inst) {
m_inst = &mesh_instances_.lookup_or_add_default(p_id);
m_inst->data = std::make_unique<MeshData>(scene_delegate_, object, p_id);
m_inst->data->init();
m_inst->data->insert();
}
else {
inst->data->update();
m_inst->data->update();
}
ID_LOG(2, "Mesh %s %d", inst->data->id->name, (int)mesh_transforms_.size());
inst->indices.push_back(mesh_transforms_.size());
ID_LOG(2, "Mesh %s %d", m_inst->data->id->name, (int)mesh_transforms_.size());
m_inst->indices.push_back(mesh_transforms_.size());
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()
@ -195,16 +170,16 @@ void InstancerData::post_update()
});
/* Update light intances and remove instances without transforms */
for (auto &l_inst : light_instances_.values()) {
update_light_instance(l_inst);
for (auto &l_inst : nonmesh_instances_.values()) {
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 */
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()) {
/* Important: removing instancer when nonmesh_instances_ are empty too */
if (index.HasInstancer(prim_id) && nonmesh_instances_.is_empty()) {
index.RemoveInstancer(prim_id);
ID_LOG(1, "Remove instancer");
}
@ -229,73 +204,62 @@ pxr::SdfPath InstancerData::object_prim_id(Object *object) const
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];
snprintf(name, sizeof(name), "L_%08x", index);
return inst.data->prim_id.AppendElementString(name);
snprintf(name, sizeof(name), "NM_%08x", index);
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;
sscanf(id.GetName().c_str(), "L_%x", &index);
sscanf(id.GetName().c_str(), "NM_%x", &index);
return index;
}
void InstancerData::update_light_instance(LightInstance &inst)
void InstancerData::update_nonmesh_instance(NonmeshInstance &nm_inst)
{
auto &render_index = scene_delegate_->GetRenderIndex();
LightData &l_data = *inst.data;
ObjectData *obj_data = nm_inst.data.get();
pxr::SdfPath prev_id = nm_inst.data->prim_id;
int i;
pxr::SdfPath p;
/* Remove old light instances */
while (inst.count > inst.transforms.size()) {
--inst.count;
p = light_prim_id(inst, inst.count);
render_index.RemoveSprim(l_data.prim_type_, p);
ID_LOG(2, "Remove %s", p.GetText());
while (nm_inst.count > nm_inst.transforms.size()) {
--nm_inst.count;
obj_data->prim_id = nonmesh_prim_id(prev_id, nm_inst.count);
obj_data->remove();
}
/* Update current light instances */
if (inst.data->prim_type((Light *)((Object *)l_data.id)->data) != l_data.prim_type_) {
/* Recreate instances when prim_type was changed */
for (i = 0; i < inst.count; ++i) {
p = light_prim_id(inst, i);
render_index.RemoveSprim(l_data.prim_type_, p);
ID_LOG(2, "Remove %s", p.GetText());
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_) {
/* Special case: recreate instances when prim_type was changed */
for (i = 0; i < nm_inst.count; ++i) {
obj_data->prim_id = nonmesh_prim_id(prev_id, i);
obj_data->remove();
}
inst.data->init();
for (i = 0; i < inst.count; ++i) {
p = light_prim_id(inst, i);
render_index.InsertSprim(l_data.prim_type_, scene_delegate_, p);
ID_LOG(2, "Insert %s (%s)", p.GetText(), l_data.id->name);
l_data->init();
for (i = 0; i < nm_inst.count; ++i) {
obj_data->prim_id = nonmesh_prim_id(prev_id, i);
obj_data->insert();
}
}
else {
/* Update light instances*/
pxr::HdDirtyBits bits = pxr::HdLight::DirtyTransform;
Object *obj = (Object *)inst.data->id;
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);
for (i = 0; i < nm_inst.count; ++i) {
obj_data->prim_id = nonmesh_prim_id(prev_id, i);
obj_data->update();
}
}
/* Add new light instances */
while (inst.count < inst.transforms.size()) {
p = light_prim_id(inst, inst.count);
render_index.InsertSprim(l_data.prim_type_, scene_delegate_, p);
ID_LOG(2, "Insert %s (%s)", p.GetText(), l_data.id->name);
++inst.count;
while (nm_inst.count < nm_inst.transforms.size()) {
obj_data->prim_id = nonmesh_prim_id(prev_id, nm_inst.count);
obj_data->insert();
++nm_inst.count;
}
obj_data->prim_id = prev_id;
}
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);
}
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);
if (!l_inst) {
if (!nm_inst) {
return nullptr;
}
return const_cast<LightInstance *>(l_inst);
return const_cast<NonmeshInstance *>(nm_inst);
}
} // namespace blender::render::hydra

View File

@ -7,7 +7,6 @@
#include "BLI_map.hh"
#include "BLI_set.hh"
#include "light.h"
#include "mesh.h"
namespace blender::render::hydra {
@ -18,15 +17,14 @@ class InstancerData : public IdData {
pxr::VtIntArray indices;
};
struct LightInstance {
std::unique_ptr<LightData> data;
struct NonmeshInstance {
std::unique_ptr<ObjectData> data;
pxr::VtMatrix4dArray transforms;
int count = 0;
};
public:
InstancerData(BlenderSceneDelegate *scene_delegate, pxr::SdfPath const &prim_id);
static bool is_instance_supported(Object *object);
void init() override;
void insert() override;
@ -34,7 +32,7 @@ class InstancerData : public IdData {
void update() 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::VtIntArray indices(pxr::SdfPath const &id) const;
ObjectData *object_data(pxr::SdfPath const &id) const;
@ -54,14 +52,14 @@ class InstancerData : public IdData {
private:
pxr::SdfPath object_prim_id(Object *object) const;
pxr::SdfPath light_prim_id(LightInstance const &inst, int index) const;
int light_prim_id_index(pxr::SdfPath const &id) const;
void update_light_instance(LightInstance &inst);
pxr::SdfPath nonmesh_prim_id(pxr::SdfPath const &prim_id, int index) const;
int nonmesh_prim_id_index(pxr::SdfPath const &id) const;
void update_nonmesh_instance(NonmeshInstance &inst);
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, LightInstance> light_instances_;
Map<pxr::SdfPath, NonmeshInstance> nonmesh_instances_;
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);
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;
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::HdCullStyle cull_style(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)
{
std::unique_ptr<ObjectData> obj_data;
switch (object->type) {
case OB_MESH:
case OB_SURF:
@ -73,6 +72,24 @@ bool ObjectData::is_supported(Object *object)
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)
{
eEvaluationMode deg_mode = DEG_get_mode(scene_delegate->depsgraph);

View File

@ -25,6 +25,7 @@ class ObjectData : public IdData {
Object *object,
pxr::SdfPath const &prim_id);
static bool is_supported(Object *object);
static bool is_mesh(Object *object);
static bool is_visible(BlenderSceneDelegate *scene_delegate,
Object *object,
int mode = OB_VISIBLE_SELF);