BLEN-345-Refactor export process #2

Merged
Bogdan Nagirniak merged 14 commits from BLEN-345 into hydra-render 2023-02-18 08:00:29 +01:00
15 changed files with 803 additions and 590 deletions

View File

@ -62,10 +62,16 @@ set(SRC
sceneDelegate/blenderSceneDelegate.h sceneDelegate/blenderSceneDelegate.h
sceneDelegate/blenderSceneDelegate.cc sceneDelegate/blenderSceneDelegate.cc
sceneDelegate/id.h
sceneDelegate/id.cc
sceneDelegate/object.h sceneDelegate/object.h
sceneDelegate/object.cc sceneDelegate/object.cc
sceneDelegate/material.h sceneDelegate/material.h
sceneDelegate/material.cc sceneDelegate/material.cc
sceneDelegate/mesh.h
sceneDelegate/mesh.cc
sceneDelegate/light.h
sceneDelegate/light.cc
sceneDelegate/world.h sceneDelegate/world.h
sceneDelegate/world.cc sceneDelegate/world.cc
) )

View File

@ -25,75 +25,65 @@ BlenderSceneDelegate::BlenderSceneDelegate(HdRenderIndex* parentIndex, SdfPath c
{ {
} }
void BlenderSceneDelegate::set_material(ObjectData &obj_data) void BlenderSceneDelegate::set_material(MeshData &mesh_data)
{ {
Material *material = obj_data.material(); Material *material = mesh_data.material();
if (!material) { if (!material) {
obj_data.set_material_id(SdfPath::EmptyPath()); mesh_data.material_id = SdfPath::EmptyPath();
return; return;
} }
SdfPath mat_id = material_id(material); SdfPath id = MaterialData::prim_id(this, material);
if (!material_data(mat_id)) { MaterialData *mat_data = material_data(id);
MaterialData mat_data(material); if (!mat_data) {
GetRenderIndex().InsertSprim(HdPrimTypeTokens->material, this, mat_id); materials[id] = MaterialData::init(this, material);
mat_data.export_mtlx(); mat_data = material_data(id);
materials[mat_id] = mat_data; mat_data->export_mtlx();
LOG(INFO) << "Add material: " << mat_id << ", mtlx=" << mat_data.mtlx_path.GetResolvedPath(); mat_data->insert_prim();
} }
obj_data.set_material_id(mat_id); mesh_data.material_id = id;
} }
void BlenderSceneDelegate::update_material(Material *material) void BlenderSceneDelegate::update_material(Material *material)
{ {
SdfPath mat_id = material_id(material); MaterialData *mat_data = material_data(MaterialData::prim_id(this, material));
MaterialData *mat_data = material_data(mat_id);
if (mat_data) { if (mat_data) {
mat_data->export_mtlx(); mat_data->export_mtlx();
LOG(INFO) << "Update material: " << mat_id << ", mtlx=" << mat_data->mtlx_path.GetResolvedPath(); mat_data->mark_prim_dirty(IdData::DirtyBits::AllDirty);
GetRenderIndex().GetChangeTracker().MarkSprimDirty(mat_id, HdMaterial::AllDirty);
} }
} }
void BlenderSceneDelegate::add_update_world(World *world) void BlenderSceneDelegate::update_world()
{ {
SdfPath world_light_id = world_id(); World *world = (World *)b_depsgraph->scene().world().ptr.data;
LOG(INFO) << "Add world: " << world_light_id;
if (!world) {
world_data = nullptr;
GetRenderIndex().RemoveSprim(HdPrimTypeTokens->domeLight, world_light_id);
return;
}
if (!world_data) { if (!world_data) {
world_data = make_unique<WorldData>(world, (bContext *)b_context->ptr.data); if (world) {
GetRenderIndex().InsertSprim(HdPrimTypeTokens->domeLight, this, world_light_id); world_data = WorldData::init(this, world, (bContext *)b_context->ptr.data);
world_data->insert_prim();
}
} }
else { else {
world_data = make_unique<WorldData>(world, (bContext *)b_context->ptr.data); if (world) {
GetRenderIndex().GetChangeTracker().MarkSprimDirty(world_light_id, HdLight::AllDirty); world_data = WorldData::init(this, world, (bContext *)b_context->ptr.data);
world_data->mark_prim_dirty(IdData::DirtyBits::AllDirty);
}
else {
world_data->remove_prim();
world_data = nullptr;
}
} }
} }
bool BlenderSceneDelegate::GetVisible(SdfPath const &id) bool BlenderSceneDelegate::GetVisible(SdfPath const &id)
{ {
ObjectData *obj_data = object_data(id); if (id == WorldData::prim_id(this)) {
LOG(INFO) << "GetVisible: " << id.GetAsString(); return true;
HdRenderIndex &index = GetRenderIndex();
if (id == world_id()) {
return world_data->is_visible();
} }
return obj_data->is_visible(); return object_data(id)->visible;
} }
void BlenderSceneDelegate::update_collection() void BlenderSceneDelegate::update_collection()
{ {
HdRenderIndex &index = GetRenderIndex();
/* add new objects */ /* add new objects */
std::set<SdfPath> available_objects; std::set<SdfPath> available_objects;
for (auto &inst : b_depsgraph->object_instances) { for (auto &inst : b_depsgraph->object_instances) {
@ -104,8 +94,7 @@ void BlenderSceneDelegate::update_collection()
if (!supported_object(object)) { if (!supported_object(object)) {
continue; continue;
} }
SdfPath obj_id = object_id(object); available_objects.insert(ObjectData::prim_id(this, object));
available_objects.insert(obj_id);
if (!is_populated) { if (!is_populated) {
add_update_object(object, true, true, true); add_update_object(object, true, true, true);
@ -121,13 +110,7 @@ void BlenderSceneDelegate::update_collection()
if (available_objects.find(it->first) != available_objects.end()) { if (available_objects.find(it->first) != available_objects.end()) {
continue; continue;
} }
LOG(INFO) << "Remove: " << it->first; it->second->remove_prim();
if (it->second.prim_type() == HdPrimTypeTokens->mesh) {
index.RemoveRprim(it->first);
}
else if (it->second.prim_type() != HdBlenderTokens->empty) {
index.RemoveSprim(it->second.prim_type(), it->first);
}
objects.erase(it); objects.erase(it);
it = objects.begin(); it = objects.begin();
} }
@ -135,16 +118,16 @@ void BlenderSceneDelegate::update_collection()
/* remove unused materials */ /* remove unused materials */
std::set<SdfPath> available_materials; std::set<SdfPath> available_materials;
for (auto &obj : objects) { for (auto &obj : objects) {
if (obj.second.has_data(HdBlenderTokens->materialId)) { MeshData *m_data = dynamic_cast<MeshData *>(obj.second.get());
available_materials.insert(obj.second.get_data(HdBlenderTokens->materialId).Get<SdfPath>()); if (m_data && !m_data->material_id.IsEmpty()) {
available_materials.insert(m_data->material_id);
} }
} }
for (auto it = materials.begin(); it != materials.end(); ++it) { for (auto it = materials.begin(); it != materials.end(); ++it) {
if (available_materials.find(it->first) != available_materials.end()) { if (available_materials.find(it->first) != available_materials.end()) {
continue; continue;
} }
LOG(INFO) << "Remove material: " << it->first; it->second->remove_prim();
index.RemoveSprim(HdPrimTypeTokens->material, it->first);
materials.erase(it); materials.erase(it);
it = materials.begin(); it = materials.begin();
} }
@ -152,56 +135,38 @@ void BlenderSceneDelegate::update_collection()
void BlenderSceneDelegate::add_update_object(Object *object, bool geometry, bool transform, bool shading) void BlenderSceneDelegate::add_update_object(Object *object, bool geometry, bool transform, bool shading)
{ {
HdRenderIndex &index = GetRenderIndex(); SdfPath id = ObjectData::prim_id(this, object);
ObjectData *obj_data = object_data(id);
SdfPath obj_id = object_id(object);
ObjectData *obj_data = object_data(obj_id);
if (!obj_data) { if (!obj_data) {
ObjectData new_obj_data(object); objects[id] = ObjectData::init(this, object);
new_obj_data.update_visibility(view3d); obj_data = object_data(id);
if (new_obj_data.prim_type() == HdPrimTypeTokens->mesh) { obj_data->update_visibility(view3d);
LOG(INFO) << "Add mesh object: " << new_obj_data.name() << " id=" << obj_id; obj_data->insert_prim();
index.InsertRprim(new_obj_data.prim_type(), this, obj_id); MeshData *m_data = dynamic_cast<MeshData *>(obj_data);
set_material(new_obj_data); if (m_data) {
set_material(*m_data);
} }
else if (new_obj_data.type() == OB_LAMP) {
LOG(INFO) << "Add light object: " << new_obj_data.name() << " id=" << obj_id;
index.InsertSprim(new_obj_data.prim_type(), this, obj_id);
}
objects[obj_id] = new_obj_data;
return; return;
} }
if (geometry) { if (geometry) {
LOG(INFO) << "Full updated: " << obj_id; objects[id] = ObjectData::init(this, object);
ObjectData new_obj_data(object); obj_data = object_data(id);
new_obj_data.update_visibility(view3d); obj_data->update_visibility(view3d);
if (new_obj_data.prim_type() == HdPrimTypeTokens->mesh) { MeshData *m_data = dynamic_cast<MeshData *>(obj_data);
set_material(new_obj_data); if (m_data) {
index.GetChangeTracker().MarkRprimDirty(obj_id, HdChangeTracker::AllDirty); set_material(*m_data);
} }
else if (new_obj_data.type() == OB_LAMP) { obj_data->mark_prim_dirty(IdData::DirtyBits::AllDirty);
index.GetChangeTracker().MarkSprimDirty(obj_id, HdLight::AllDirty);
}
objects[obj_id] = new_obj_data;
return; return;
} }
if (transform) { if (transform) {
LOG(INFO) << "Transform updated: " << obj_id; obj_data->mark_prim_dirty(IdData::DirtyBits::DirtyTransform);
if (obj_data->prim_type() == HdPrimTypeTokens->mesh) {
index.GetChangeTracker().MarkRprimDirty(obj_id, HdChangeTracker::DirtyTransform);
}
else if (obj_data->type() == OB_LAMP) {
index.GetChangeTracker().MarkSprimDirty(obj_id, HdLight::DirtyTransform);
}
} }
if (shading) { if (shading) {
LOG(INFO) << "Shading updated: " << obj_id; obj_data->mark_prim_dirty(IdData::DirtyBits::DirtyMaterial);
if (obj_data->prim_type() == HdPrimTypeTokens->mesh) {
index.GetChangeTracker().MarkRprimDirty(obj_id, HdChangeTracker::DirtyMaterialId);
}
} }
} }
@ -211,7 +176,17 @@ ObjectData *BlenderSceneDelegate::object_data(SdfPath const &id)
if (it == objects.end()) { if (it == objects.end()) {
return nullptr; return nullptr;
} }
return &it->second; return it->second.get();
}
MeshData *BlenderSceneDelegate::mesh_data(SdfPath const &id)
{
return static_cast<MeshData *>(object_data(id));
}
LightData *BlenderSceneDelegate::light_data(SdfPath const &id)
{
return static_cast<LightData *>(object_data(id));
} }
MaterialData *BlenderSceneDelegate::material_data(SdfPath const &id) MaterialData *BlenderSceneDelegate::material_data(SdfPath const &id)
@ -220,28 +195,7 @@ MaterialData *BlenderSceneDelegate::material_data(SdfPath const &id)
if (it == materials.end()) { if (it == materials.end()) {
return nullptr; return nullptr;
} }
return &it->second; return it->second.get();
}
SdfPath BlenderSceneDelegate::object_id(Object *object)
{
/* Making id of object in form like O_<pointer in 16 hex digits format>. Example: O_000002073e369608 */
char str[32];
snprintf(str, 32, "O_%016llx", (uint64_t)object);
return GetDelegateID().AppendElementString(str);
}
SdfPath BlenderSceneDelegate::material_id(Material *material)
{
/* Making id of material in form like M_<pointer in 16 hex digits format>. Example: M_000002074e812088 */
char str[32];
snprintf(str, 32, "M_%016llx", (uint64_t)material);
return GetDelegateID().AppendElementString(str);
}
SdfPath BlenderSceneDelegate::world_id()
{
return GetDelegateID().AppendElementString("World");
} }
bool BlenderSceneDelegate::supported_object(Object *object) bool BlenderSceneDelegate::supported_object(Object *object)
@ -259,16 +213,14 @@ void BlenderSceneDelegate::Populate(BL::Depsgraph &b_deps, BL::Context &b_cont)
{ {
LOG(INFO) << "Populate " << is_populated; LOG(INFO) << "Populate " << is_populated;
view3d = (View3D *)b_cont.space_data().ptr.data;
b_depsgraph = &b_deps; b_depsgraph = &b_deps;
b_context = &b_cont; b_context = &b_cont;
view3d = (View3D *)b_context->space_data().ptr.data;
if (!is_populated) { if (!is_populated) {
/* Export initial objects */ /* Export initial objects */
update_collection(); update_collection();
update_world();
World *world = (World *)b_depsgraph->scene().world().ptr.data;
add_update_world(world);
is_populated = true; is_populated = true;
return; return;
@ -277,13 +229,14 @@ void BlenderSceneDelegate::Populate(BL::Depsgraph &b_deps, BL::Context &b_cont)
/* Working with updates */ /* Working with updates */
bool do_update_collection = false; bool do_update_collection = false;
bool do_update_visibility = false; bool do_update_visibility = false;
bool do_update_world = false;
for (auto &update : b_depsgraph->updates) { for (auto &update : b_depsgraph->updates) {
BL::ID id = update.id(); BL::ID id = update.id();
LOG(INFO) << "Update: " << id.name_full() << " " LOG(INFO) << "Update: " << id.name_full() << " ["
<< update.is_updated_transform() << update.is_updated_transform()
<< update.is_updated_geometry() << update.is_updated_geometry()
<< update.is_updated_shading(); << update.is_updated_shading() << "]";
if (id.is_a(&RNA_Object)) { if (id.is_a(&RNA_Object)) {
Object *object = (Object *)id.ptr.data; Object *object = (Object *)id.ptr.data;
@ -313,23 +266,21 @@ void BlenderSceneDelegate::Populate(BL::Depsgraph &b_deps, BL::Context &b_cont)
} }
if (id.is_a(&RNA_Scene)) { if (id.is_a(&RNA_Scene)) {
World *world = (World *)b_depsgraph->scene().world().ptr.data;
add_update_world(world);
if (!update.is_updated_geometry() && !update.is_updated_transform() && !update.is_updated_shading()) { if (!update.is_updated_geometry() && !update.is_updated_transform() && !update.is_updated_shading()) {
do_update_visibility = true; do_update_visibility = true;
Scene *scene = (Scene *)id.ptr.data;
if ((scene->world && !world_data) || (!scene->world && world_data)) {
do_update_world = true;
}
} }
continue; continue;
} }
if (id.is_a(&RNA_World)) { if (id.is_a(&RNA_World)) {
World *world = (World *)b_depsgraph->scene().world().ptr.data; if (update.is_updated_shading()) {
add_update_world(world); do_update_world = true;
continue; }
}
if (id.is_a(&RNA_ShaderNodeTree)) {
World *world = (World *)b_depsgraph->scene().world().ptr.data;
add_update_world(world);
continue; continue;
} }
} }
@ -340,22 +291,18 @@ void BlenderSceneDelegate::Populate(BL::Depsgraph &b_deps, BL::Context &b_cont)
if (do_update_visibility) { if (do_update_visibility) {
update_visibility(); update_visibility();
} }
if (do_update_world) {
update_world();
}
} }
void BlenderSceneDelegate::update_visibility() void BlenderSceneDelegate::update_visibility()
{ {
HdRenderIndex &index = GetRenderIndex();
/* Check and update visibility */ /* Check and update visibility */
for (auto &obj : objects) { for (auto &obj : objects) {
if (obj.second.update_visibility(view3d)) { if (obj.second->update_visibility(view3d)) {
LOG(INFO) << "Visible changed: " << obj.first.GetAsString() << " " << obj.second.is_visible(); obj.second->mark_prim_dirty(IdData::DirtyBits::DirtyVisibility);
if (obj.second.prim_type() == HdPrimTypeTokens->mesh) {
index.GetChangeTracker().MarkRprimDirty(obj.first, HdChangeTracker::DirtyVisibility);
}
else if (obj.second.type() == OB_LAMP) {
index.GetChangeTracker().MarkSprimDirty(obj.first, HdLight::DirtyParams);
}
}; };
} }
@ -369,8 +316,7 @@ void BlenderSceneDelegate::update_visibility()
continue; continue;
} }
SdfPath obj_id = object_id(object); if (!object_data(ObjectData::prim_id(this, object))) {
if (!object_data(obj_id)) {
add_update_object(object, true, true, true); add_update_object(object, true, true, true);
} }
} }
@ -378,113 +324,65 @@ void BlenderSceneDelegate::update_visibility()
HdMeshTopology BlenderSceneDelegate::GetMeshTopology(SdfPath const& id) HdMeshTopology BlenderSceneDelegate::GetMeshTopology(SdfPath const& id)
{ {
LOG(INFO) << "GetMeshTopology: " << id.GetAsString(); MeshData *m_data = mesh_data(id);
ObjectData &obj_data = objects[id]; return m_data->mesh_topology();
return HdMeshTopology(PxOsdOpenSubdivTokens->catmullClark, HdTokens->rightHanded,
obj_data.get_data<VtIntArray>(HdBlenderTokens->faceCounts),
obj_data.get_data<VtIntArray>(HdTokens->pointsIndices));
} }
VtValue BlenderSceneDelegate::Get(SdfPath const& id, TfToken const& key) VtValue BlenderSceneDelegate::Get(SdfPath const& id, TfToken const& key)
{ {
LOG(INFO) << "Get: " << id.GetAsString() << " [" << key.GetString() << "]";
VtValue ret;
ObjectData *obj_data = object_data(id); ObjectData *obj_data = object_data(id);
if (obj_data) { if (obj_data) {
if (obj_data->has_data(key)) { return obj_data->get_data(key);
ret = obj_data->get_data(key);
}
} }
else if (key.GetString() == "MaterialXFilename") {
MaterialData &mat_data = materials[id]; MaterialData *mat_data = material_data(id);
if (!mat_data.mtlx_path.GetResolvedPath().empty()) { if (mat_data) {
ret = mat_data.mtlx_path; return mat_data->get_data(key);
}
} }
else if (key == HdStRenderBufferTokens->stormMsaaSampleCount) { return VtValue();
// TODO: temporary value, it should be delivered through Python UI
ret = 16;
}
return ret;
} }
HdPrimvarDescriptorVector BlenderSceneDelegate::GetPrimvarDescriptors(SdfPath const& id, HdInterpolation interpolation) HdPrimvarDescriptorVector BlenderSceneDelegate::GetPrimvarDescriptors(SdfPath const& id, HdInterpolation interpolation)
{ {
LOG(INFO) << "GetPrimvarDescriptors: " << id.GetAsString() << " " << interpolation; return mesh_data(id)->primvar_descriptors(interpolation);
HdPrimvarDescriptorVector primvars;
ObjectData &obj_data = objects[id];
if (interpolation == HdInterpolationVertex) {
if (obj_data.has_data(HdTokens->points)) {
primvars.emplace_back(HdTokens->points, interpolation, HdPrimvarRoleTokens->point);
}
}
else if (interpolation == HdInterpolationFaceVarying) {
if (obj_data.has_data(HdTokens->normals)) {
primvars.emplace_back(HdTokens->normals, interpolation, HdPrimvarRoleTokens->normal);
}
if (obj_data.has_data(HdPrimvarRoleTokens->textureCoordinate)) {
primvars.emplace_back(HdPrimvarRoleTokens->textureCoordinate, interpolation, HdPrimvarRoleTokens->textureCoordinate);
}
}
return primvars;
} }
SdfPath BlenderSceneDelegate::GetMaterialId(SdfPath const & rprimId) SdfPath BlenderSceneDelegate::GetMaterialId(SdfPath const & rprimId)
{ {
SdfPath ret; return mesh_data(rprimId)->material_id;
ObjectData *obj_data = object_data(rprimId);
if (obj_data && obj_data->has_data(HdBlenderTokens->materialId)) {
ret = obj_data->get_data<SdfPath>(HdBlenderTokens->materialId);
}
LOG(INFO) << "GetMaterialId [" << rprimId.GetAsString() << "] = " << ret.GetAsString();
return ret;
} }
VtValue BlenderSceneDelegate::GetMaterialResource(SdfPath const& id) VtValue BlenderSceneDelegate::GetMaterialResource(SdfPath const& id)
{ {
LOG(INFO) << "GetMaterialResource: " << id.GetAsString(); MaterialData *mat_data = material_data(id);
if (mat_data) {
return mat_data->material_resource();
}
return VtValue(); return VtValue();
} }
GfMatrix4d BlenderSceneDelegate::GetTransform(SdfPath const& id) GfMatrix4d BlenderSceneDelegate::GetTransform(SdfPath const& id)
{ {
LOG(INFO) << "GetTransform: " << id.GetAsString(); ObjectData *obj_data = object_data(id);
if (obj_data) {
HdRenderIndex &index = GetRenderIndex(); return obj_data->transform();
if (id == world_id()) {
return world_data->transform(index.GetRenderDelegate()->GetRendererDisplayName());
} }
if (id == WorldData::prim_id(this)) {
return objects[id].transform(); return world_data->transform();
}
return GfMatrix4d();
} }
VtValue BlenderSceneDelegate::GetLightParamValue(SdfPath const& id, TfToken const& key) VtValue BlenderSceneDelegate::GetLightParamValue(SdfPath const& id, TfToken const& key)
{ {
LOG(INFO) << "GetLightParamValue: " << id.GetAsString() << " [" << key.GetString() << "]"; LightData *l_data = light_data(id);
VtValue ret; if (l_data) {
return l_data->get_data(key);
HdRenderIndex &index = GetRenderIndex();
ObjectData *obj_data = object_data(id);
if (obj_data) {
if (obj_data->has_data(key)) {
ret = obj_data->get_data(key);
}
else if (key == HdLightTokens->exposure) {
// TODO: temporary value, it should be delivered through Python UI
ret = 1.0f;
}
} }
else if (id == world_id()) { if (id == WorldData::prim_id(this)) {
if (world_data->has_data(key)) { return world_data->get_data(key);
ret = world_data->get_data(key);
}
} }
return VtValue();
return ret;
} }
} // namespace blender::render::hydra } // namespace blender::render::hydra

View File

@ -15,6 +15,8 @@
#include "RNA_blender_cpp.h" #include "RNA_blender_cpp.h"
#include "object.h" #include "object.h"
#include "mesh.h"
#include "light.h"
#include "world.h" #include "world.h"
using namespace pxr; using namespace pxr;
@ -40,16 +42,15 @@ public:
private: private:
ObjectData *object_data(SdfPath const &id); ObjectData *object_data(SdfPath const &id);
MeshData *mesh_data(SdfPath const &id);
LightData *light_data(SdfPath const &id);
MaterialData *material_data(SdfPath const &id); MaterialData *material_data(SdfPath const &id);
SdfPath object_id(Object *object);
SdfPath material_id(Material *material);
SdfPath world_id();
bool supported_object(Object *object); bool supported_object(Object *object);
void add_update_object(Object *object, bool geometry, bool transform, bool shading); void add_update_object(Object *object, bool geometry, bool transform, bool shading);
void set_material(ObjectData &obj_data); void set_material(MeshData &mesh_data);
void update_material(Material *material); void update_material(Material *material);
void add_update_world(World *world); void update_world();
void update_collection(); void update_collection();
void update_visibility(); void update_visibility();

View File

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include "BKE_lib_id.h"
#include "id.h"
using namespace pxr;
namespace blender::render::hydra {
IdData::IdData(pxr::HdSceneDelegate *scene_delegate, ID *id)
: scene_delegate(scene_delegate)
, id(id)
{
}
std::string IdData::name()
{
char str[MAX_ID_FULL_NAME];
BKE_id_full_name_get(str, id, 0);
return str;
}
VtValue IdData::get_data(TfToken const &key)
{
return VtValue();
}
} // namespace blender::render::hydra

View File

@ -0,0 +1,44 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#pragma once
#include <pxr/base/vt/value.h>
#include <pxr/base/tf/token.h>
#include <pxr/imaging/hd/sceneDelegate.h>
#include "DNA_ID.h"
namespace blender::render::hydra {
class IdData {
public:
IdData(pxr::HdSceneDelegate *scene_delegate, ID *id);
virtual ~IdData() = default;
std::string name();
virtual pxr::VtValue get_data(pxr::TfToken const &key);
BogdanNagirniak marked this conversation as resolved
Review

seems like we can do this pure virtual, because we override this method in every subclass of ObjectData

seems like we can do this `pure virtual`, because we override this method in every subclass of `ObjectData`
Review

Let it be not virtual, due to IdData classes design

Let it be not virtual, due to IdData classes design
template<class T> const T get_data(pxr::TfToken const &key);
enum class DirtyBits {
DirtyTransform = 1,
DirtyVisibility,
DirtyMaterial,
AllDirty
};
virtual void insert_prim() = 0;
virtual void remove_prim() = 0;
virtual void mark_prim_dirty(DirtyBits dirty_bits) = 0;
protected:
pxr::HdSceneDelegate *scene_delegate;
ID *id;
};
template<class T> const T IdData::get_data(pxr::TfToken const &key)
{
return get_data(key).Get<T>();
}
} // namespace blender::render::hydra

View File

@ -0,0 +1,173 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include <boost/algorithm/string/predicate.hpp>
#include <pxr/imaging/hd/light.h>
#include <pxr/imaging/hd/tokens.h>
#include <pxr/usd/usdLux/tokens.h>
#include "glog/logging.h"
#include "BKE_light.h"
#include "DNA_light_types.h"
#include "light.h"
using namespace pxr;
using namespace boost::algorithm;
namespace blender::render::hydra {
LightData::LightData(pxr::HdSceneDelegate *scene_delegate, Object *object)
: ObjectData(scene_delegate, object)
{
Light *light = (Light *)((Object *)id)->data;
data[HdLightTokens->intensity] = light->energy;
data[HdLightTokens->color] = GfVec3f(light->r, light->g, light->b);
switch (light->type) {
case LA_LOCAL:
data[HdLightTokens->radius] = light->area_size / 2;
break;
case LA_SUN:
data[HdLightTokens->angle] = light->sun_angle * 180.0 / M_PI;
break;
case LA_SPOT:
data[HdLightTokens->shapingConeAngle] = light->spotsize / 2;
data[HdLightTokens->shapingConeSoftness] = light->spotblend;
data[UsdLuxTokens->treatAsPoint] = true;
break;
case LA_AREA:
switch (light->area_shape) {
case LA_AREA_SQUARE:
data[HdLightTokens->width] = light->area_size;
data[HdLightTokens->height] = light->area_size;
break;
case LA_AREA_RECT:
data[HdLightTokens->width] = light->area_size;
data[HdLightTokens->height] = light->area_sizey;
break;
case LA_AREA_DISK:
data[HdLightTokens->radius] = light->area_size / 2;
break;
case LA_AREA_ELLIPSE:
data[HdLightTokens->radius] = (light->area_size + light->area_sizey) / 4;
break;
default:
break;
}
data[HdLightTokens->normalize] = true;
break;
default:
break;
}
/* TODO: temporary value, it should be delivered through Python UI */
data[HdLightTokens->exposure] = 1.0f;
}
pxr::TfToken LightData::prim_type()
{
Light *light = (Light *)((Object *)id)->data;
TfToken ret;
switch (light->type) {
case LA_LOCAL:
case LA_SPOT:
ret = HdPrimTypeTokens->sphereLight;
break;
case LA_SUN:
ret = HdPrimTypeTokens->distantLight;
break;
case LA_AREA:
switch (light->area_shape) {
case LA_AREA_SQUARE:
case LA_AREA_RECT:
ret = HdPrimTypeTokens->rectLight;
break;
case LA_AREA_DISK:
case LA_AREA_ELLIPSE:
ret = HdPrimTypeTokens->diskLight;
break;
default:
ret = HdPrimTypeTokens->rectLight;
}
break;
default:
ret = HdPrimTypeTokens->sphereLight;
}
return ret;
}
VtValue LightData::get_data(TfToken const &key)
{
LOG(INFO) << "Get data light: " << name() << " [" << key.GetString() << "]";
VtValue ret;
auto it = data.find(key);
if (it != data.end()) {
ret = it->second;
}
else {
std::string n = key.GetString();
if (contains(n, "object:visibility:")) {
if (ends_with(n, "camera") || ends_with(n, "shadow")) {
ret = false;
}
else {
ret = true;
}
}
}
return ret;
}
void LightData::insert_prim()
{
SdfPath p_id = prim_id(scene_delegate, (Object *)id);
scene_delegate->GetRenderIndex().InsertSprim(prim_type(), scene_delegate, p_id);
LOG(INFO) << "Add light: " << name() << " id=" << p_id.GetAsString();
}
void LightData::remove_prim()
{
SdfPath p_id = prim_id(scene_delegate, (Object *)id);
scene_delegate->GetRenderIndex().RemoveSprim(prim_type(), p_id);
LOG(INFO) << "Remove light: " << name();
}
void LightData::mark_prim_dirty(DirtyBits dirty_bits)
{
HdDirtyBits bits = HdLight::Clean;
switch (dirty_bits) {
case DirtyBits::DirtyTransform:
bits = HdLight::DirtyTransform;
break;
case DirtyBits::DirtyVisibility:
bits = HdLight::DirtyParams;
break;
case DirtyBits::AllDirty:
bits = HdLight::AllDirty;
break;
default:
break;
}
SdfPath p_id = prim_id(scene_delegate, (Object *)id);
scene_delegate->GetRenderIndex().GetChangeTracker().MarkSprimDirty(p_id, bits);
LOG(INFO) << "Update light: " << name() << " [" << (int)dirty_bits << "]";
}
} // namespace blender::render::hydra

View File

@ -0,0 +1,28 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#pragma once
#include <pxr/usd/sdf/assetPath.h>
#include <pxr/usd/sdf/path.h>
#include "pxr/base/tf/hashmap.h"
#include "object.h"
namespace blender::render::hydra {
class LightData: public ObjectData {
public:
LightData(pxr::HdSceneDelegate *scene_delegate, Object *object);
pxr::VtValue get_data(pxr::TfToken const &key) override;
void insert_prim() override;
void remove_prim() override;
void mark_prim_dirty(DirtyBits dirty_bits) override;
private:
std::map<pxr::TfToken, pxr::VtValue> data;
pxr::TfToken prim_type();
};
} // namespace blender::render::hydra

View File

@ -3,6 +3,11 @@
#include <Python.h> #include <Python.h>
#include <pxr/imaging/hd/tokens.h>
#include <pxr/imaging/hd/material.h>
#include "glog/logging.h"
#include "BKE_material.h" #include "BKE_material.h"
#include "BKE_lib_id.h" #include "BKE_lib_id.h"
@ -12,32 +17,50 @@ using namespace pxr;
namespace blender::render::hydra { namespace blender::render::hydra {
MaterialData::MaterialData() std::unique_ptr<MaterialData> MaterialData::init(pxr::HdSceneDelegate *scene_delegate, Material *material)
: material(nullptr) {
return std::make_unique<MaterialData>(scene_delegate, material);
}
pxr::SdfPath MaterialData::prim_id(pxr::HdSceneDelegate *scene_delegate, Material *material)
{
/* Making id of material in form like M_<pointer in 16 hex digits format>.
* Example: M_000002074e812088 */
char str[32];
snprintf(str, 32, "M_%016llx", (uint64_t)material);
return scene_delegate->GetDelegateID().AppendElementString(str);
}
MaterialData::MaterialData(pxr::HdSceneDelegate *scene_delegate, Material *material)
: IdData(scene_delegate, (ID *)material)
{ {
} }
MaterialData::MaterialData(Material *material) VtValue MaterialData::get_data(TfToken const &key)
: material(material)
{ {
VtValue ret;
if (key.GetString() == "MaterialXFilename") {
if (!mtlx_path.GetResolvedPath().empty()) {
ret = mtlx_path;
}
}
return ret;
} }
std::string MaterialData::name() pxr::VtValue MaterialData::material_resource()
{ {
char str[MAX_ID_FULL_NAME]; /* TODO: Implement return of HdMaterialNetwork */
BKE_id_full_name_get(str, (ID *)material, 0); return pxr::VtValue();
return str;
} }
void MaterialData::export_mtlx() void MaterialData::export_mtlx()
{ {
/* Call of python function hydra.export_mtlx() */ /* Call of python function hydra.export_mtlx() */
PyObject *module, *dict, *func, *result;
PyGILState_STATE gstate; PyGILState_STATE gstate;
gstate = PyGILState_Ensure(); gstate = PyGILState_Ensure();
PyObject *module, *dict, *func, *result;
module = PyImport_ImportModule("hydra"); module = PyImport_ImportModule("hydra");
dict = PyModule_GetDict(module); dict = PyModule_GetDict(module);
func = PyDict_GetItemString(dict, "export_mtlx"); func = PyDict_GetItemString(dict, "export_mtlx");
@ -51,6 +74,36 @@ void MaterialData::export_mtlx()
PyGILState_Release(gstate); PyGILState_Release(gstate);
mtlx_path = SdfAssetPath(path, path); mtlx_path = SdfAssetPath(path, path);
LOG(INFO) << "Material export: " << name() << " mtlx=" << mtlx_path.GetResolvedPath();
}
void MaterialData::insert_prim()
{
SdfPath p_id = prim_id(scene_delegate, (Material *)id);
scene_delegate->GetRenderIndex().InsertSprim(HdPrimTypeTokens->material, scene_delegate, p_id);
LOG(INFO) << "Add material: " << name() << " id=" << p_id.GetAsString();
}
void MaterialData::remove_prim()
{
SdfPath p_id = prim_id(scene_delegate, (Material *)id);
scene_delegate->GetRenderIndex().RemoveSprim(HdPrimTypeTokens->material, p_id);
LOG(INFO) << "Remove material: " << name();
}
void MaterialData::mark_prim_dirty(DirtyBits dirty_bits)
{
HdDirtyBits bits = HdMaterial::Clean;
switch (dirty_bits) {
case DirtyBits::AllDirty:
bits = HdMaterial::AllDirty;
break;
default:
break;
}
SdfPath p_id = prim_id(scene_delegate, (Material *)id);
scene_delegate->GetRenderIndex().GetChangeTracker().MarkSprimDirty(p_id, bits);
LOG(INFO) << "Update material: " << name() << ", mtlx=" << mtlx_path.GetResolvedPath();
} }
} // namespace blender::render::hydra } // namespace blender::render::hydra

View File

@ -3,28 +3,36 @@
#pragma once #pragma once
#include <map>
#include <pxr/usd/sdf/assetPath.h> #include <pxr/usd/sdf/assetPath.h>
#include <pxr/usd/sdf/path.h> #include <pxr/usd/sdf/path.h>
#include "pxr/base/tf/hashmap.h"
#include "DNA_material_types.h" #include "DNA_material_types.h"
#include "id.h"
namespace blender::render::hydra { namespace blender::render::hydra {
class MaterialData { class MaterialData;
using MaterialDataMap = pxr::TfHashMap<pxr::SdfPath, std::unique_ptr<MaterialData>, pxr::SdfPath::Hash>;
class MaterialData: IdData {
public: public:
MaterialData(); static std::unique_ptr<MaterialData> init(pxr::HdSceneDelegate *scene_delegate, Material *material);
MaterialData(Material *material); static pxr::SdfPath prim_id(pxr::HdSceneDelegate *scene_delegate, Material *material);
std::string name(); MaterialData(pxr::HdSceneDelegate *scene_delegate, Material *material);
pxr::VtValue get_data(pxr::TfToken const &key) override;
void insert_prim() override;
void remove_prim() override;
void mark_prim_dirty(DirtyBits dirty_bits) override;
pxr::VtValue material_resource();
void export_mtlx(); void export_mtlx();
pxr::SdfAssetPath mtlx_path;
private: private:
Material *material; pxr::SdfAssetPath mtlx_path;
}; };
using MaterialDataMap = std::map<pxr::SdfPath, MaterialData>;
} // namespace blender::render::hydra } // namespace blender::render::hydra

View File

@ -0,0 +1,187 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include <pxr/base/gf/vec2f.h>
#include <pxr/imaging/hd/tokens.h>
#include "glog/logging.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_material.h"
#include "mesh.h"
using namespace pxr;
namespace blender::render::hydra {
MeshData::MeshData(pxr::HdSceneDelegate *scene_delegate, Object *object)
: ObjectData(scene_delegate, object)
{
if (object->type == OB_MESH && object->mode == OB_MODE_OBJECT &&
BLI_listbase_is_empty(&object->modifiers)) {
set_mesh((Mesh *)object->data);
}
else {
Mesh *mesh = BKE_object_to_mesh(nullptr, object, false);
set_mesh(mesh);
BKE_object_to_mesh_clear(object);
}
}
VtValue MeshData::get_data(TfToken const &key)
{
VtValue ret;
if (key == HdTokens->points) {
ret = vertices;
}
else if (key == HdTokens->normals) {
ret = normals;
}
else if (key == HdPrimvarRoleTokens->textureCoordinate) {
ret = uvs;
}
return ret;
}
Material *MeshData::material()
{
Object *object = (Object *)id;
if (BKE_object_material_count_eval(object) == 0) {
return nullptr;
}
return BKE_object_material_get_eval(object, object->actcol);
}
HdMeshTopology MeshData::mesh_topology()
{
return HdMeshTopology(PxOsdOpenSubdivTokens->catmullClark, HdTokens->rightHanded,
face_vertex_counts, face_vertex_indices);
}
HdPrimvarDescriptorVector MeshData::primvar_descriptors(HdInterpolation interpolation)
{
HdPrimvarDescriptorVector primvars;
if (interpolation == HdInterpolationVertex) {
if (!vertices.empty()) {
primvars.emplace_back(HdTokens->points, interpolation, HdPrimvarRoleTokens->point);
}
}
else if (interpolation == HdInterpolationFaceVarying) {
if (!vertices.empty()) {
primvars.emplace_back(HdTokens->normals, interpolation, HdPrimvarRoleTokens->normal);
}
if (!uvs.empty()) {
primvars.emplace_back(HdPrimvarRoleTokens->textureCoordinate, interpolation,
HdPrimvarRoleTokens->textureCoordinate);
}
}
return primvars;
}
void MeshData::set_mesh(Mesh *mesh)
{
BKE_mesh_calc_normals_split(mesh);
int tris_len = BKE_mesh_runtime_looptri_len(mesh);
if (tris_len == 0) {
return;
}
blender::Span<MLoopTri> loopTris = mesh->looptris();
/* face_vertex_counts */
face_vertex_counts = VtIntArray(tris_len, 3);
/* face_vertex_indices */
blender::Span<MLoop> loops = mesh->loops();
face_vertex_indices.reserve(loopTris.size() * 3);
for (MLoopTri lt : loopTris) {
face_vertex_indices.push_back(loops[lt.tri[0]].v);
face_vertex_indices.push_back(loops[lt.tri[1]].v);
face_vertex_indices.push_back(loops[lt.tri[2]].v);
}
/* vertices */
vertices.reserve(mesh->totvert);
blender::Span<blender::float3> verts = mesh->vert_positions();
for (blender::float3 v : verts) {
vertices.push_back(GfVec3f(v.x, v.y, v.z));
}
/* normals */
const float(*lnors)[3] = (float(*)[3])CustomData_get_layer(&mesh->ldata, CD_NORMAL);
if (lnors) {
normals.reserve(loopTris.size() * 3);
for (MLoopTri lt : loopTris) {
normals.push_back(GfVec3f(lnors[lt.tri[0]]));
normals.push_back(GfVec3f(lnors[lt.tri[1]]));
normals.push_back(GfVec3f(lnors[lt.tri[2]]));
}
}
/* uvs*/
const float(*luvs)[2] = (float(*)[2])CustomData_get_layer(&mesh->ldata, CD_PROP_FLOAT2);
if (luvs) {
uvs.reserve(loopTris.size() * 3);
for (MLoopTri lt : loopTris) {
uvs.push_back(GfVec2f(luvs[lt.tri[0]]));
uvs.push_back(GfVec2f(luvs[lt.tri[1]]));
uvs.push_back(GfVec2f(luvs[lt.tri[2]]));
}
}
}
void MeshData::insert_prim()
{
if (face_vertex_counts.empty()) {
return;
}
SdfPath p_id = prim_id(scene_delegate, (Object *)id);
scene_delegate->GetRenderIndex().InsertRprim(HdPrimTypeTokens->mesh, scene_delegate, p_id);
LOG(INFO) << "Add mesh: " << name() << " id=" << p_id.GetAsString();
}
void MeshData::remove_prim()
{
SdfPath p_id = prim_id(scene_delegate, (Object *)id);
if (!scene_delegate->GetRenderIndex().HasRprim(p_id)) {
return;
}
scene_delegate->GetRenderIndex().RemoveRprim(p_id);
LOG(INFO) << "Remove mesh: " << name();
}
void MeshData::mark_prim_dirty(DirtyBits dirty_bits)
{
SdfPath p_id = prim_id(scene_delegate, (Object *)id);
if (!scene_delegate->GetRenderIndex().HasRprim(p_id)) {
return;
}
HdDirtyBits bits = HdChangeTracker::Clean;
switch (dirty_bits) {
BogdanNagirniak marked this conversation as resolved
Review

consider adding map<OurDirty, TheirDirty> so we can get needed value by key without switch case

consider adding `map<OurDirty, TheirDirty>` so we can get needed value by key without `switch case`
Review

switch case is preferable here

`switch case` is preferable here
case DirtyBits::DirtyTransform:
bits = HdChangeTracker::DirtyTransform;
break;
case DirtyBits::DirtyVisibility:
bits = HdChangeTracker::DirtyVisibility;
break;
case DirtyBits::DirtyMaterial:
bits = HdChangeTracker::DirtyMaterialId;
break;
case DirtyBits::AllDirty:
bits = HdChangeTracker::AllDirty;
break;
default:
break;
}
scene_delegate->GetRenderIndex().GetChangeTracker().MarkRprimDirty(p_id, bits);
LOG(INFO) << "Update mesh: " << name() << " [" << (int)dirty_bits << "]";
}
} // namespace blender::render::hydra

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#pragma once
#include <pxr/base/vt/array.h>
#include <pxr/imaging/hd/sceneDelegate.h>
#include "object.h"
namespace blender::render::hydra {
class MeshData: public ObjectData {
public:
MeshData(pxr::HdSceneDelegate *scene_delegate, Object *object);
pxr::VtValue get_data(pxr::TfToken const &key) override;
void insert_prim() override;
void remove_prim() override;
void mark_prim_dirty(DirtyBits dirty_bits) override;
Material *material();
pxr::HdMeshTopology mesh_topology();
pxr::HdPrimvarDescriptorVector primvar_descriptors(pxr::HdInterpolation interpolation);
pxr::SdfPath material_id;
private:
void set_mesh(Mesh *mesh);
pxr::VtIntArray face_vertex_counts;
pxr::VtIntArray face_vertex_indices;
pxr::VtVec3fArray vertices;
pxr::VtVec3fArray normals;
pxr::VtVec2fArray uvs;
};
} // namespace blender::render::hydra

View File

@ -1,173 +1,60 @@
/* SPDX-License-Identifier: Apache-2.0 /* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */ * Copyright 2011-2022 Blender Foundation */
#include <pxr/base/vt/array.h>
#include <pxr/base/gf/vec2f.h>
#include <pxr/imaging/hd/light.h>
#include <pxr/imaging/hd/camera.h>
#include <pxr/imaging/hd/tokens.h>
#include <pxr/usd/usdLux/tokens.h>
#include "DNA_light_types.h"
#include "DNA_camera_types.h"
#include "BKE_object.h" #include "BKE_object.h"
#include "BKE_lib_id.h"
#include "BKE_material.h"
#include "BKE_light.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_layer.h"
#include "object.h" #include "object.h"
#include "mesh.h"
#include "light.h"
#include "../utils.h" #include "../utils.h"
PXR_NAMESPACE_OPEN_SCOPE
TF_DEFINE_PUBLIC_TOKENS(HdBlenderTokens, HD_BLENDER_TOKENS);
PXR_NAMESPACE_CLOSE_SCOPE
using namespace pxr; using namespace pxr;
namespace blender::render::hydra { namespace blender::render::hydra {
ObjectData::ObjectData() std::unique_ptr<ObjectData> ObjectData::init(pxr::HdSceneDelegate *scene_delegate, Object *object)
: object(nullptr)
, visible(true)
{
}
ObjectData::ObjectData(Object *object)
: object(object)
{ {
switch (object->type) { switch (object->type) {
case OB_MESH: case OB_MESH:
if (object->mode == OB_MODE_OBJECT && BLI_listbase_is_empty(&object->modifiers)) {
set_as_mesh();
}
else {
set_as_meshable();
}
break;
case OB_SURF: case OB_SURF:
case OB_FONT: case OB_FONT:
case OB_CURVES: case OB_CURVES:
case OB_CURVES_LEGACY: case OB_CURVES_LEGACY:
case OB_MBALL: case OB_MBALL:
set_as_meshable(); return std::make_unique<MeshData>(scene_delegate, object);
break;
case OB_LAMP: case OB_LAMP:
set_as_light(); return std::make_unique<LightData>(scene_delegate, object);
break;
default: default:
break; break;
} }
return nullptr;
} }
std::string ObjectData::name() pxr::SdfPath ObjectData::prim_id(pxr::HdSceneDelegate *scene_delegate, Object *object)
{
/* Making id of object in form like O_<pointer in 16 hex digits format>. Example:
* O_000002073e369608 */
char str[32];
snprintf(str, 32, "O_%016llx", (uint64_t)object);
return scene_delegate->GetDelegateID().AppendElementString(str);
}
ObjectData::ObjectData(pxr::HdSceneDelegate *scene_delegate, Object *object)
: IdData(scene_delegate, (ID *)object)
, visible(true)
{ {
char str[MAX_ID_FULL_NAME];
BKE_id_full_name_get(str, (ID *)object, 0);
return str;
} }
int ObjectData::type() int ObjectData::type()
{ {
return object->type; return ((Object *)id)->type;
}
TfToken ObjectData::prim_type()
{
TfToken ret = HdBlenderTokens->empty;
Light *light;
switch (object->type) {
case OB_MESH:
case OB_SURF:
case OB_FONT:
case OB_CURVES:
case OB_CURVES_LEGACY:
case OB_MBALL:
if (!has_data(HdTokens->points)) {
break;
}
ret = HdPrimTypeTokens->mesh;
break;
case OB_LAMP:
light = (Light *)object->data;
switch (light->type) {
case LA_LOCAL:
case LA_SPOT:
ret = HdPrimTypeTokens->sphereLight;
break;
case LA_SUN:
ret = HdPrimTypeTokens->distantLight;
break;
case LA_AREA:
switch (light->area_shape) {
case LA_AREA_SQUARE:
case LA_AREA_RECT:
ret = HdPrimTypeTokens->rectLight;
break;
case LA_AREA_DISK:
case LA_AREA_ELLIPSE:
ret = HdPrimTypeTokens->diskLight;
break;
default:
ret = HdPrimTypeTokens->rectLight;
}
break;
default:
ret = HdPrimTypeTokens->sphereLight;
}
break;
default:
break;
}
return ret;
} }
GfMatrix4d ObjectData::transform() GfMatrix4d ObjectData::transform()
{ {
return gf_matrix_from_transform(object->object_to_world); return gf_matrix_from_transform(((Object *)id)->object_to_world);
}
Material *ObjectData::material()
{
if (BKE_object_material_count_eval(object) == 0) {
return nullptr;
}
return BKE_object_material_get_eval(object, object->actcol);
}
VtValue &ObjectData::get_data(TfToken const &key)
{
return data[key];
}
bool ObjectData::has_data(TfToken const &key)
{
return data.find(key) != data.end();
}
void ObjectData::set_material_id(SdfPath const &id)
{
if (id.IsEmpty()) {
data.erase(HdBlenderTokens->materialId);
}
else {
data[HdBlenderTokens->materialId] = id;
}
} }
bool ObjectData::update_visibility(View3D *view3d) bool ObjectData::update_visibility(View3D *view3d)
@ -177,136 +64,8 @@ bool ObjectData::update_visibility(View3D *view3d)
} }
bool prev_visible = visible; bool prev_visible = visible;
visible = BKE_object_is_visible_in_viewport(view3d, object); visible = BKE_object_is_visible_in_viewport(view3d, (Object *)id);
return visible != prev_visible; return visible != prev_visible;
} }
bool ObjectData::is_visible()
{
return visible;
}
void ObjectData::set_as_mesh()
{
Mesh *mesh = (Mesh *)object->data;
set_mesh(mesh);
}
void ObjectData::set_as_meshable()
{
Mesh *mesh = BKE_object_to_mesh(nullptr, object, false);
set_mesh(mesh);
BKE_object_to_mesh_clear(object);
}
void ObjectData::set_mesh(Mesh *mesh)
{
BKE_mesh_calc_normals_split(mesh);
int tris_len = BKE_mesh_runtime_looptri_len(mesh);
if (tris_len == 0) {
return;
}
blender::Span<MLoopTri> loopTris = mesh->looptris();
/* faceVertexCounts */
data[HdBlenderTokens->faceCounts] = VtIntArray(tris_len, 3);
/* faceVertexIndices */
VtIntArray faceVertexIndices;
blender::Span<MLoop> loops = mesh->loops();
faceVertexIndices.reserve(loopTris.size() * 3);
for (MLoopTri lt : loopTris) {
faceVertexIndices.push_back(loops[lt.tri[0]].v);
faceVertexIndices.push_back(loops[lt.tri[1]].v);
faceVertexIndices.push_back(loops[lt.tri[2]].v);
}
data[HdTokens->pointsIndices] = faceVertexIndices;
/* vertices */
VtVec3fArray vertices;
vertices.reserve(mesh->totvert);
blender::Span<blender::float3> verts = mesh->vert_positions();
for (blender::float3 v : verts) {
vertices.push_back(GfVec3f(v.x, v.y, v.z));
}
data[HdTokens->points] = vertices;
/* normals */
const float(*lnors)[3] = (float(*)[3])CustomData_get_layer(&mesh->ldata, CD_NORMAL);
if (lnors) {
VtVec3fArray normals;
normals.reserve(loopTris.size() * 3);
for (MLoopTri lt : loopTris) {
normals.push_back(GfVec3f(lnors[lt.tri[0]]));
normals.push_back(GfVec3f(lnors[lt.tri[1]]));
normals.push_back(GfVec3f(lnors[lt.tri[2]]));
}
data[HdTokens->normals] = normals;
}
/* UVs*/
const float(*luvs)[2] = (float(*)[2])CustomData_get_layer(&mesh->ldata, CD_PROP_FLOAT2);
if (luvs) {
VtVec2fArray uvs;
uvs.reserve(loopTris.size() * 3);
for (MLoopTri lt : loopTris) {
uvs.push_back(GfVec2f(luvs[lt.tri[0]]));
uvs.push_back(GfVec2f(luvs[lt.tri[1]]));
uvs.push_back(GfVec2f(luvs[lt.tri[2]]));
}
data[HdPrimvarRoleTokens->textureCoordinate] = uvs;
}
}
void ObjectData::set_as_light()
{
Light *light = (Light *)object->data;
data[HdLightTokens->intensity] = light->energy;
data[HdLightTokens->color] = GfVec3f(light->r, light->g, light->b);
switch (light->type) {
case LA_LOCAL:
data[HdLightTokens->radius] = light->area_size / 2;
break;
case LA_SUN:
data[HdLightTokens->angle] = light->sun_angle * 180.0 / M_PI;
break;
case LA_SPOT:
data[HdLightTokens->shapingConeAngle] = light->spotsize / 2;
data[HdLightTokens->shapingConeSoftness] = light->spotblend;
data[UsdLuxTokens->treatAsPoint] = 1;
break;
case LA_AREA:
switch (light->area_shape) {
case LA_AREA_SQUARE:
data[HdLightTokens->width] = light->area_size;
data[HdLightTokens->height] = light->area_size;
break;
case LA_AREA_RECT:
data[HdLightTokens->width] = light->area_size;
data[HdLightTokens->height] = light->area_sizey;
break;
case LA_AREA_DISK:
data[HdLightTokens->radius] = light->area_size / 2;
break;
case LA_AREA_ELLIPSE:
data[HdLightTokens->radius] = (light->area_size + light->area_sizey) / 4;
break;
default:
break;
}
break;
default:
break;
}
}
} // namespace blender::render::hydra } // namespace blender::render::hydra

View File

@ -3,66 +3,34 @@
#pragma once #pragma once
#include <map>
#include <pxr/base/gf/matrix4d.h> #include <pxr/base/gf/matrix4d.h>
#include <pxr/usd/sdf/path.h> #include "pxr/base/tf/hashmap.h"
#include <pxr/base/vt/value.h>
#include "pxr/base/tf/staticTokens.h"
#include "DNA_object_types.h" #include "DNA_object_types.h"
#include "BKE_layer.h"
#include "id.h"
#include "material.h" #include "material.h"
PXR_NAMESPACE_OPEN_SCOPE
#define HD_BLENDER_TOKENS \
(materialId) \
(faceCounts) \
(empty)
TF_DECLARE_PUBLIC_TOKENS(HdBlenderTokens, HD_BLENDER_TOKENS);
PXR_NAMESPACE_CLOSE_SCOPE
namespace blender::render::hydra { namespace blender::render::hydra {
class ObjectData;
using ObjectDataMap = pxr::TfHashMap<pxr::SdfPath, std::unique_ptr<ObjectData>, pxr::SdfPath::Hash>;
class ObjectData { class ObjectData: public IdData {
public: public:
ObjectData(); static std::unique_ptr<ObjectData> init(pxr::HdSceneDelegate *scene_delegate, Object *object);
ObjectData(Object *object); static pxr::SdfPath prim_id(pxr::HdSceneDelegate *scene_delegate, Object *object);
ObjectData(pxr::HdSceneDelegate *scene_delegate, Object *object);
std::string name();
int type(); int type();
pxr::TfToken prim_type();
pxr::GfMatrix4d transform(); pxr::GfMatrix4d transform();
Material *material();
pxr::VtValue &get_data(pxr::TfToken const &key);
template<class T>
const T &get_data(pxr::TfToken const &key);
bool has_data(pxr::TfToken const &key);
void set_material_id(pxr::SdfPath const &id);
bool update_visibility(View3D *view3d); bool update_visibility(View3D *view3d);
bool is_visible();
private:
Object *object;
std::map<pxr::TfToken, pxr::VtValue> data;
bool visible; bool visible;
void set_as_mesh();
void set_as_meshable();
void set_mesh(Mesh *mesh);
void set_as_light();
}; };
using ObjectDataMap = std::map<pxr::SdfPath, ObjectData>;
template<class T>
const T &ObjectData::get_data(pxr::TfToken const &key)
{
return get_data(key).Get<T>();
}
} // namespace blender::render::hydra } // namespace blender::render::hydra

View File

@ -8,6 +8,7 @@
#include <pxr/base/gf/rotation.h> #include <pxr/base/gf/rotation.h>
#include <pxr/imaging/hd/light.h> #include <pxr/imaging/hd/light.h>
#include <pxr/imaging/hd/tokens.h> #include <pxr/imaging/hd/tokens.h>
#include <pxr/imaging/hd/renderDelegate.h>
#include <pxr/usd/usdLux/tokens.h> #include <pxr/usd/usdLux/tokens.h>
#include "BKE_context.h" #include "BKE_context.h"
@ -19,31 +20,36 @@
#include "BKE_image.h" #include "BKE_image.h"
#include "NOD_shader.h" #include "NOD_shader.h"
#include "glog/logging.h"
#include "world.h" #include "world.h"
#include "../utils.h" #include "../utils.h"
/* TODO : add custom tftoken "transparency"? */ /* TODO : add custom tftoken "transparency"? */
using namespace pxr; using namespace pxr;
using namespace std;
namespace blender::render::hydra { namespace blender::render::hydra {
WorldData::WorldData() std::unique_ptr<WorldData> WorldData::init(pxr::HdSceneDelegate *scene_delegate,
: b_context(nullptr), World *world, bContext *context)
world(nullptr)
{ {
return std::make_unique<WorldData>(scene_delegate, world, context);
} }
WorldData::WorldData(World *world, bContext *b_context) SdfPath WorldData::prim_id(HdSceneDelegate *scene_delegate)
: b_context(b_context),
world(world)
{ {
data.clear(); return scene_delegate->GetDelegateID().AppendElementString("World");
}
WorldData::WorldData(pxr::HdSceneDelegate *scene_delegate, World *world, bContext *context)
: IdData(scene_delegate, (ID *)world)
{
data[UsdLuxTokens->orientToStageUpAxis] = true; data[UsdLuxTokens->orientToStageUpAxis] = true;
if (world->use_nodes) { if (world->use_nodes) {
/* TODO: Create nodes parsing system */
bNode *output_node = ntreeShaderOutputNode(world->nodetree, SHD_OUTPUT_ALL); bNode *output_node = ntreeShaderOutputNode(world->nodetree, SHD_OUTPUT_ALL);
bNodeSocket input_socket = output_node->input_by_identifier("Surface"); bNodeSocket input_socket = output_node->input_by_identifier("Surface");
bNodeLink const *link = input_socket.directly_linked_links()[0]; bNodeLink const *link = input_socket.directly_linked_links()[0];
@ -69,16 +75,16 @@ WorldData::WorldData(World *world, bContext *b_context)
Image *image = (Image *)color_input_node->id; Image *image = (Image *)color_input_node->id;
if (image) { if (image) {
Main *bmain = CTX_data_main(b_context); Main *bmain = CTX_data_main(context);
Scene *scene = CTX_data_scene(b_context); Scene *scene = CTX_data_scene(context);
ReportList reports; ReportList reports;
ImageSaveOptions opts; ImageSaveOptions opts;
opts.im_format.imtype = R_IMF_IMTYPE_PNG; opts.im_format.imtype = R_IMF_IMTYPE_PNG;
string cached_image_path = cache_image(bmain, scene, image, &tex->iuser, &opts, &reports); std::string image_path = cache_image(bmain, scene, image, &tex->iuser, &opts, &reports);
if (!cached_image_path.empty()) { if (!image_path.empty()) {
data[HdLightTokens->textureFile] = SdfAssetPath(cached_image_path, cached_image_path); data[HdLightTokens->textureFile] = SdfAssetPath(image_path, image_path);
} }
} }
} }
@ -91,35 +97,55 @@ WorldData::WorldData(World *world, bContext *b_context)
} }
} }
GfMatrix4d WorldData::transform(string const &renderer_name) GfMatrix4d WorldData::transform()
{ {
GfMatrix4d transform = GfMatrix4d().SetIdentity(); GfMatrix4d transform = GfMatrix4d(GfRotation(GfVec3d(1.0, 0.0, 0.0), -90), GfVec3d());
if (has_data(UsdLuxTokens->orientToStageUpAxis)) {
transform *= GfMatrix4d(GfRotation(GfVec3d(1.0, 0.0, 0.0), -90), GfVec3d());
}
/* TODO : do this check via RenderSettings*/ /* TODO : do this check via RenderSettings*/
if (renderer_name == "RPR") { if (scene_delegate->GetRenderIndex().GetRenderDelegate()->GetRendererDisplayName() == "RPR") {
transform *= GfMatrix4d(GfRotation(GfVec3d(1.0, 0.0, 0.0), -180), GfVec3d()); transform *= GfMatrix4d(GfRotation(GfVec3d(1.0, 0.0, 0.0), -180), GfVec3d());
transform *= GfMatrix4d(GfRotation(GfVec3d(0.0, 0.0, 1.0), 90.0), GfVec3d()); transform *= GfMatrix4d(GfRotation(GfVec3d(0.0, 0.0, 1.0), 90.0), GfVec3d());
} }
return transform; return transform;
} }
VtValue &WorldData::get_data(TfToken const &key) VtValue WorldData::get_data(TfToken const &key)
{ {
return data[key]; VtValue ret;
auto it = data.find(key);
if (it != data.end()) {
ret = it->second;
}
return ret;
} }
bool WorldData::has_data(TfToken const &key) void WorldData::insert_prim()
{ {
return data.find(key) != data.end(); SdfPath p_id = prim_id(scene_delegate);
scene_delegate->GetRenderIndex().InsertSprim(HdPrimTypeTokens->domeLight, scene_delegate, p_id);
LOG(INFO) << "Add World: id=" << p_id.GetAsString();
} }
bool WorldData::is_visible() void WorldData::remove_prim()
{ {
return true; SdfPath p_id = prim_id(scene_delegate);
scene_delegate->GetRenderIndex().RemoveSprim(HdPrimTypeTokens->domeLight, p_id);
LOG(INFO) << "Remove World";
}
void WorldData::mark_prim_dirty(DirtyBits dirty_bits)
{
HdDirtyBits bits = HdLight::Clean;
switch (dirty_bits) {
case DirtyBits::AllDirty:
bits = HdLight::AllDirty;
break;
default:
break;
}
SdfPath p_id = prim_id(scene_delegate);
scene_delegate->GetRenderIndex().GetChangeTracker().MarkSprimDirty(p_id, bits);
LOG(INFO) << "Update World";
} }
} // namespace blender::render::hydra } // namespace blender::render::hydra

View File

@ -14,33 +14,26 @@
#include "DNA_view3d_types.h" #include "DNA_view3d_types.h"
#include "DNA_world_types.h" #include "DNA_world_types.h"
#include "id.h"
namespace blender::render::hydra { namespace blender::render::hydra {
class WorldData { class WorldData: public IdData {
public: public:
WorldData(); static std::unique_ptr<WorldData> init(pxr::HdSceneDelegate *scene_delegate, World *world, bContext *context);
WorldData(World *world, bContext *b_context); static pxr::SdfPath prim_id(pxr::HdSceneDelegate *scene_delegate);
pxr::TfToken prim_type(); WorldData(pxr::HdSceneDelegate *scene_delegate, World *world, bContext *context);
pxr::GfMatrix4d transform(std::string const &renderer_name);
pxr::VtValue &get_data(pxr::TfToken const &key); pxr::GfMatrix4d transform();
template<class T>
const T &get_data(pxr::TfToken const &key);
bool has_data(pxr::TfToken const &key);
bool is_visible();
bContext *b_context; pxr::VtValue get_data(pxr::TfToken const &key) override;
World *world; void insert_prim() override;
void remove_prim() override;
void mark_prim_dirty(DirtyBits dirty_bits) override;
private: private:
std::map<pxr::TfToken, pxr::VtValue> data; std::map<pxr::TfToken, pxr::VtValue> data;
}; };
template<class T>
const T &WorldData::get_data(pxr::TfToken const &key)
{
return get_data(key).Get<T>();
}
} // namespace blender::render::hydra } // namespace blender::render::hydra