Blender V4.5
hydra_scene_delegate.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
7#include <bitset>
8
9#include "DNA_view3d_types.h"
10
11#include "BKE_duplilist.hh"
12#include "BKE_particle.h"
13
14#include "BLI_listbase.h"
15#include "BLI_set.hh"
16#include "BLI_string.h"
17
19
20namespace blender::io::hydra {
21
23
25{
26 bool ret = use_scene_lights == other.use_scene_lights &&
28 if (ret && !use_scene_world) {
29 /* compare studiolight settings when studiolight is using */
33 }
34 return ret;
35}
36
37HydraSceneDelegate::HydraSceneDelegate(pxr::HdRenderIndex *parent_index,
38 pxr::SdfPath const &delegate_id,
39 const bool use_materialx)
40 : HdSceneDelegate(parent_index, delegate_id), use_materialx(use_materialx)
41{
42 instancer_data_ = std::make_unique<InstancerData>(this, instancer_prim_id());
43 world_data_ = std::make_unique<WorldData>(this, world_prim_id());
44}
45
46pxr::HdMeshTopology HydraSceneDelegate::GetMeshTopology(pxr::SdfPath const &id)
47{
48 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s", id.GetText());
49 MeshData *m_data = mesh_data(id);
50 return m_data->topology(id);
51}
52
53pxr::HdBasisCurvesTopology HydraSceneDelegate::GetBasisCurvesTopology(pxr::SdfPath const &id)
54{
55 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s", id.GetText());
56 CurvesData *c_data = curves_data(id);
57 return c_data->topology();
58};
59
60pxr::GfMatrix4d HydraSceneDelegate::GetTransform(pxr::SdfPath const &id)
61{
62 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s", id.GetText());
63 InstancerData *i_data = instancer_data(id, true);
64 if (i_data) {
65 return i_data->transform(id);
66 }
67 ObjectData *obj_data = object_data(id);
68 if (obj_data) {
69 return obj_data->transform;
70 }
71 return pxr::GfMatrix4d();
72}
73
74pxr::VtValue HydraSceneDelegate::Get(pxr::SdfPath const &id, pxr::TfToken const &key)
75{
76 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s, %s", id.GetText(), key.GetText());
77 ObjectData *obj_data = object_data(id);
78 if (obj_data) {
79 return obj_data->get_data(id, key);
80 }
81 MaterialData *mat_data = material_data(id);
82 if (mat_data) {
83 return mat_data->get_data(key);
84 }
85 InstancerData *i_data = instancer_data(id);
86 if (i_data) {
87 return i_data->get_data(key);
88 }
89 return pxr::VtValue();
90}
91
92pxr::VtValue HydraSceneDelegate::GetLightParamValue(pxr::SdfPath const &id,
93 pxr::TfToken const &key)
94{
95 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s, %s", id.GetText(), key.GetText());
96 LightData *l_data = light_data(id);
97 if (l_data) {
98 return l_data->get_data(key);
99 }
100 return pxr::VtValue();
101}
102
103pxr::HdPrimvarDescriptorVector HydraSceneDelegate::GetPrimvarDescriptors(
104 pxr::SdfPath const &id, pxr::HdInterpolation interpolation)
105{
106 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s, %d", id.GetText(), interpolation);
107 MeshData *m_data = mesh_data(id);
108 if (m_data) {
109 return m_data->primvar_descriptors(interpolation);
110 }
111 CurvesData *c_data = curves_data(id);
112 if (c_data) {
113 return c_data->primvar_descriptors(interpolation);
114 }
115 InstancerData *i_data = instancer_data(id);
116 if (i_data) {
117 return i_data->primvar_descriptors(interpolation);
118 }
119 return pxr::HdPrimvarDescriptorVector();
120}
121
122pxr::SdfPath HydraSceneDelegate::GetMaterialId(pxr::SdfPath const &rprim_id)
123{
124 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s", rprim_id.GetText());
125 ObjectData *obj_data = object_data(rprim_id);
126 if (obj_data) {
127 return obj_data->material_id(rprim_id);
128 }
129 return pxr::SdfPath();
130}
131
132pxr::VtValue HydraSceneDelegate::GetMaterialResource(pxr::SdfPath const &id)
133{
134 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s", id.GetText());
135 MaterialData *mat_data = material_data(id);
136 if (mat_data) {
137 return mat_data->get_material_resource();
138 }
139 return pxr::VtValue();
140}
141
142bool HydraSceneDelegate::GetVisible(pxr::SdfPath const &id)
143{
144 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s", id.GetText());
145 if (id == world_prim_id()) {
146 return true;
147 }
148 InstancerData *i_data = instancer_data(id, true);
149 if (i_data) {
150 return true;
151 }
152 return object_data(id)->visible;
153}
154
155bool HydraSceneDelegate::GetDoubleSided(pxr::SdfPath const &id)
156{
157 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s", id.GetText());
158 return mesh_data(id)->double_sided(id);
159}
160
161pxr::HdCullStyle HydraSceneDelegate::GetCullStyle(pxr::SdfPath const &id)
162{
163 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s", id.GetText());
164 return mesh_data(id)->cull_style(id);
165}
166
167pxr::SdfPath HydraSceneDelegate::GetInstancerId(pxr::SdfPath const &prim_id)
168{
169 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s", prim_id.GetText());
170 InstancerData *i_data = instancer_data(prim_id, true);
171 if (i_data && mesh_data(prim_id)) {
172 return i_data->prim_id;
173 }
174 return pxr::SdfPath();
175}
176
177pxr::SdfPathVector HydraSceneDelegate::GetInstancerPrototypes(pxr::SdfPath const &instancer_id)
178{
179 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s", instancer_id.GetText());
180 InstancerData *i_data = instancer_data(instancer_id);
181 return i_data->prototypes();
182}
183
184pxr::VtIntArray HydraSceneDelegate::GetInstanceIndices(pxr::SdfPath const &instancer_id,
185 pxr::SdfPath const &prototype_id)
186{
187 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s, %s", instancer_id.GetText(), prototype_id.GetText());
188 InstancerData *i_data = instancer_data(instancer_id);
189 return i_data->indices(prototype_id);
190}
191
192pxr::GfMatrix4d HydraSceneDelegate::GetInstancerTransform(pxr::SdfPath const &instancer_id)
193{
194 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s", instancer_id.GetText());
195 InstancerData *i_data = instancer_data(instancer_id);
196 return i_data->transform(instancer_id);
197}
198
199pxr::HdVolumeFieldDescriptorVector HydraSceneDelegate::GetVolumeFieldDescriptors(
200 pxr::SdfPath const &volume_id)
201{
202 CLOG_INFO(LOG_HYDRA_SCENE, 3, "%s", volume_id.GetText());
203 VolumeData *v_data = volume_data(volume_id);
204 return v_data->field_descriptors();
205}
206
207void HydraSceneDelegate::populate(Depsgraph *deps, View3D *v3d)
208{
209 bool is_populated = depsgraph != nullptr;
210
211 depsgraph = deps;
212 bmain = DEG_get_bmain(deps);
214 view3d = v3d;
215
216 if (is_populated) {
217 check_updates();
218 }
219 else {
220 set_light_shading_settings();
221 set_world_shading_settings();
222 update_collection();
223 world_data_->update();
224 }
225}
226
228{
229 for (auto &obj_data : objects_.values()) {
230 obj_data->remove();
231 }
232 objects_.clear();
233 instancer_data_->remove();
234 for (auto &mat_data : materials_.values()) {
235 mat_data->remove();
236 }
237 materials_.clear();
238
239 depsgraph = nullptr;
240 bmain = nullptr;
241 scene = nullptr;
242 view3d = nullptr;
243}
244
245pxr::SdfPath HydraSceneDelegate::prim_id(const ID *id, const char *prefix) const
246{
247 /* Making id of object in form like <prefix>_<pointer in 16 hex digits format> */
248 char name[32];
249 SNPRINTF(name, "%s_%p", prefix, id);
250 return GetDelegateID().AppendElementString(name);
251}
252
253pxr::SdfPath HydraSceneDelegate::object_prim_id(const Object *object) const
254{
255 return prim_id((ID *)object, "O");
256}
257
258pxr::SdfPath HydraSceneDelegate::material_prim_id(const Material *mat) const
259{
260 return prim_id((ID *)mat, "M");
261}
262
263pxr::SdfPath HydraSceneDelegate::hair_prim_id(Object *parent_obj, const ParticleSystem *psys) const
264{
265 char name[128];
266 SNPRINTF(name,
267 "%s_%s",
268 object_prim_id(parent_obj).GetName().c_str(),
269 prim_id((ID *)psys, "PS").GetName().c_str());
270 return GetDelegateID().AppendElementString(name);
271}
272
273pxr::SdfPath HydraSceneDelegate::instancer_prim_id() const
274{
275 return GetDelegateID().AppendElementString("Instancer");
276}
277
278pxr::SdfPath HydraSceneDelegate::world_prim_id() const
279{
280 return GetDelegateID().AppendElementString("World");
281}
282
283ObjectData *HydraSceneDelegate::object_data(pxr::SdfPath const &id) const
284{
285 if (id == world_prim_id()) {
286 return world_data_.get();
287 }
288 auto name = id.GetName();
289 pxr::SdfPath p_id = (STRPREFIX(name.c_str(), "SM_") || STRPREFIX(name.c_str(), "VF_")) ?
290 id.GetParentPath() :
291 id;
292 const auto *obj_data = objects_.lookup_ptr(p_id);
293 if (obj_data) {
294 return obj_data->get();
295 }
296 InstancerData *i_data = instancer_data(p_id, true);
297 if (i_data) {
298 return i_data->object_data(id);
299 }
300 return nullptr;
301}
302
303MeshData *HydraSceneDelegate::mesh_data(pxr::SdfPath const &id) const
304{
305 return dynamic_cast<MeshData *>(object_data(id));
306}
307
308CurvesData *HydraSceneDelegate::curves_data(pxr::SdfPath const &id) const
309{
310 return dynamic_cast<CurvesData *>(object_data(id));
311}
312
313VolumeData *HydraSceneDelegate::volume_data(pxr::SdfPath const &id) const
314{
315 return dynamic_cast<VolumeData *>(object_data(id));
316}
317
318LightData *HydraSceneDelegate::light_data(pxr::SdfPath const &id) const
319{
320 return dynamic_cast<LightData *>(object_data(id));
321}
322
323MaterialData *HydraSceneDelegate::material_data(pxr::SdfPath const &id) const
324{
325 const auto *mat_data = materials_.lookup_ptr(id);
326 if (!mat_data) {
327 return nullptr;
328 }
329 return mat_data->get();
330}
331
332HairData *HydraSceneDelegate::hair_data(pxr::SdfPath const &id) const
333{
334 return dynamic_cast<HairData *>(object_data(id));
335}
336
337InstancerData *HydraSceneDelegate::instancer_data(pxr::SdfPath const &id, bool child_id) const
338{
339 pxr::SdfPath p_id;
340 if (child_id) {
341 /* Getting instancer path id from child Mesh instance (consist with 3 path elements) and
342 * Light instance (consist with 4 path elements) */
343 int n = id.GetPathElementCount();
344 if (n == 3) {
345 p_id = id.GetParentPath();
346 }
347 else if (n == 4) {
348 p_id = id.GetParentPath().GetParentPath();
349 }
350 }
351 else {
352 p_id = id;
353 }
354
355 if (instancer_data_ && p_id == instancer_data_->prim_id) {
356 return instancer_data_.get();
357 }
358 return nullptr;
359}
360
361void HydraSceneDelegate::check_updates()
362{
363 bool do_update_collection = false;
364 bool do_update_world = false;
365
366 if (set_world_shading_settings()) {
367 do_update_world = true;
368 }
369
370 if (set_light_shading_settings()) {
371 do_update_collection = true;
372 }
373
374 DEGIDIterData data = {nullptr};
375 data.graph = depsgraph;
376 data.only_updated = true;
378 {
380 0,
381 "Update: %s [%s]",
382 id->name,
383 std::bitset<32>(id->recalc).to_string().c_str());
384
385 switch (GS(id->name)) {
386 case ID_OB: {
387 do_update_collection = true;
388 break;
389 }
390 case ID_MA: {
391 MaterialData *mat_data = material_data(material_prim_id((Material *)id));
392 if (mat_data) {
393 mat_data->update();
394 }
395 break;
396 }
397 case ID_WO: {
398 if (shading_settings.use_scene_world && id->recalc & ID_RECALC_SHADING) {
399 do_update_world = true;
400 }
401 break;
402 }
403 case ID_SCE: {
404 if ((id->recalc & ID_RECALC_SYNC_TO_EVAL && !(id->recalc & ID_RECALC_SELECT)) ||
406 {
407 do_update_collection = true;
408 }
409 if (id->recalc & ID_RECALC_AUDIO_VOLUME) {
410 do_update_world = true;
411 }
412 break;
413 }
414
415 default:
416 break;
417 }
418 }
419 ITER_END;
420
421 if (do_update_world) {
422 world_data_->update();
423 }
424 if (do_update_collection) {
425 update_collection();
426 }
427}
428
429void HydraSceneDelegate::update_collection()
430{
431 Set<std::string> available_objects;
432
433 DEGObjectIterSettings settings = {nullptr};
434 settings.depsgraph = depsgraph;
436 DEGObjectIterData data = {nullptr};
437 data.settings = &settings;
438 data.graph = settings.depsgraph;
439 data.flag = settings.flags;
440
441 instancer_data_->pre_update();
442
443 auto update_psys = [this, &available_objects](Object *object) {
445 if (psys_in_edit_mode(depsgraph, psys)) {
446 continue;
447 }
448 if (HairData::is_supported(psys) && HairData::is_visible(this, object, psys)) {
449 pxr::SdfPath id = hair_prim_id(object, psys);
450 HairData *h_data = hair_data(id);
451 if (h_data) {
452 h_data->update();
453 }
454 else {
455 h_data = dynamic_cast<HairData *>(
456 objects_.lookup_or_add(id, std::make_unique<HairData>(this, object, id, psys))
457 .get());
458 h_data->init();
459 h_data->insert();
460 }
461 available_objects.add(id.GetName());
462 }
463 }
464 };
465
466 auto update_object = [this, &available_objects](Object *object) {
467 if (!ObjectData::is_supported(object) || !ObjectData::is_visible(this, object) ||
468 (!shading_settings.use_scene_lights && object->type == OB_LAMP))
469 {
470 return;
471 }
472
473 available_objects.add(object_prim_id(object).GetName());
474
475 pxr::SdfPath id = object_prim_id(object);
476 ObjectData *obj_data = object_data(id);
477 if (obj_data) {
478 obj_data->update();
479 }
480 else {
481 obj_data = objects_.lookup_or_add(id, ObjectData::create(this, object, id)).get();
482 obj_data->insert();
483 }
484 };
485
489 &data,
490 Object *,
491 object)
492 {
493 if (data.dupli_object_current) {
494 DupliObject *dupli = data.dupli_object_current;
495 if (!ObjectData::is_supported(dupli->ob) ||
496 !ObjectData::is_visible(this, data.dupli_parent, OB_VISIBLE_INSTANCES) ||
497 (!shading_settings.use_scene_lights && object->type == OB_LAMP))
498 {
499 continue;
500 }
501
502 instancer_data_->update_instance(dupli);
503 continue;
504 }
505
506 update_psys(object);
507 update_object(object);
508 }
509 ITER_END;
510
511 instancer_data_->post_update();
512
513 /* Remove unused objects */
514 objects_.remove_if([&](auto item) {
515 bool ret = !available_objects.contains(item.key.GetName());
516 if (ret) {
517 item.value->remove();
518 }
519 return ret;
520 });
521
522 /* Remove unused materials */
523 Set<pxr::SdfPath> available_materials;
524 for (auto &val : objects_.values()) {
525 MeshData *m_data = dynamic_cast<MeshData *>(val.get());
526 if (m_data) {
527 m_data->available_materials(available_materials);
528 }
529 CurvesData *c_data = dynamic_cast<CurvesData *>(val.get());
530 if (c_data) {
531 c_data->available_materials(available_materials);
532 }
533 VolumeData *v_data = dynamic_cast<VolumeData *>(val.get());
534 if (v_data) {
535 v_data->available_materials(available_materials);
536 }
537 }
538 instancer_data_->available_materials(available_materials);
539
540 materials_.remove_if([&](auto item) {
541 bool ret = !available_materials.contains(item.key);
542 if (ret) {
543 item.value->remove();
544 }
545 return ret;
546 });
547}
548
549bool HydraSceneDelegate::set_light_shading_settings()
550{
551 if (!view3d) {
552 return false;
553 }
554 ShadingSettings prev_settings(shading_settings);
556 return !(shading_settings == prev_settings);
557}
558
559bool HydraSceneDelegate::set_world_shading_settings()
560{
561 if (!view3d) {
562 return false;
563 }
564 ShadingSettings prev_settings(shading_settings);
566 shading_settings.studiolight_name = view3d->shading.lookdev_light;
567 shading_settings.studiolight_rotation = view3d->shading.studiolight_rot_z;
568 shading_settings.studiolight_intensity = view3d->shading.studiolight_intensity;
569 return !(shading_settings == prev_settings);
570}
571
572} // namespace blender::io::hydra
@ OB_VISIBLE_INSTANCES
bool psys_in_edit_mode(struct Depsgraph *depsgraph, const struct ParticleSystem *psys)
#define ITER_END
#define ITER_BEGIN(callback_begin, callback_next, callback_end, _data_in, _type, _instance)
#define LISTBASE_FOREACH(type, var, list)
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
#define STRPREFIX(a, b)
#define CLG_LOGREF_DECLARE_GLOBAL(var, id)
Definition CLG_log.h:145
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
void DEG_iterator_ids_begin(BLI_Iterator *iter, DEGIDIterData *data)
void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data)
void DEG_iterator_objects_end(BLI_Iterator *iter)
void DEG_iterator_ids_end(BLI_Iterator *iter)
Main * DEG_get_bmain(const Depsgraph *graph)
#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS
void DEG_iterator_objects_next(BLI_Iterator *iter)
void DEG_iterator_ids_next(BLI_Iterator *iter)
Scene * DEG_get_input_scene(const Depsgraph *graph)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:962
@ ID_RECALC_SHADING
Definition DNA_ID.h:1002
@ ID_RECALC_SELECT
Definition DNA_ID.h:1009
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ ID_RECALC_AUDIO_VOLUME
Definition DNA_ID.h:1036
@ ID_RECALC_BASE_FLAGS
Definition DNA_ID.h:1012
struct ID ID
@ ID_SCE
@ ID_WO
@ ID_MA
@ ID_OB
struct Material Material
@ OB_LAMP
struct Object Object
struct ParticleSystem ParticleSystem
#define V3D_USES_SCENE_WORLD(v3d)
#define V3D_USES_SCENE_LIGHTS(v3d)
BMesh const char void * data
btAlignedObjectArray< btScalar > m_data
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
pxr::HdBasisCurvesTopology topology() const
pxr::HdPrimvarDescriptorVector primvar_descriptors(pxr::HdInterpolation interpolation) const
static bool is_supported(const ParticleSystem *particle_system)
static bool is_visible(HydraSceneDelegate *scene_delegate, Object *object, ParticleSystem *particle_system)
pxr::VtValue GetMaterialResource(pxr::SdfPath const &material_id) override
bool GetVisible(pxr::SdfPath const &id) override
pxr::VtIntArray GetInstanceIndices(pxr::SdfPath const &instancer_id, pxr::SdfPath const &prototype_id) override
pxr::HdPrimvarDescriptorVector GetPrimvarDescriptors(pxr::SdfPath const &id, pxr::HdInterpolation interpolation) override
pxr::VtValue GetLightParamValue(pxr::SdfPath const &id, pxr::TfToken const &key) override
HydraSceneDelegate(pxr::HdRenderIndex *parent_index, pxr::SdfPath const &delegate_id, bool use_materialx)
pxr::HdVolumeFieldDescriptorVector GetVolumeFieldDescriptors(pxr::SdfPath const &volume_id) override
pxr::HdCullStyle GetCullStyle(pxr::SdfPath const &id) override
pxr::VtValue Get(pxr::SdfPath const &id, pxr::TfToken const &key) override
void populate(Depsgraph *depsgraph, View3D *v3d)
pxr::SdfPath GetMaterialId(pxr::SdfPath const &rprim_id) override
pxr::GfMatrix4d GetInstancerTransform(pxr::SdfPath const &instancer_id) override
pxr::HdBasisCurvesTopology GetBasisCurvesTopology(pxr::SdfPath const &id) override
pxr::GfMatrix4d GetTransform(pxr::SdfPath const &id) override
pxr::SdfPath GetInstancerId(pxr::SdfPath const &prim_id) override
pxr::SdfPathVector GetInstancerPrototypes(pxr::SdfPath const &instancer_id) override
pxr::HdMeshTopology GetMeshTopology(pxr::SdfPath const &id) override
bool GetDoubleSided(pxr::SdfPath const &id) override
pxr::SdfPath prim_id
Definition id.hh:36
pxr::GfMatrix4d transform(pxr::SdfPath const &id) const
Definition instancer.cc:62
pxr::VtIntArray indices(pxr::SdfPath const &id) const
Definition instancer.cc:84
pxr::HdPrimvarDescriptorVector primvar_descriptors(pxr::HdInterpolation interpolation) const
Definition instancer.cc:73
pxr::VtValue get_data(pxr::TfToken const &key) const override
Definition instancer.cc:53
pxr::SdfPathVector prototypes() const
Definition instancer.cc:102
pxr::VtValue get_data(pxr::TfToken const &key) const override
pxr::VtValue get_data(pxr::TfToken const &key) const override
pxr::GfMatrix4d transform
Definition object.hh:24
virtual pxr::SdfPath material_id() const
static bool is_visible(HydraSceneDelegate *scene_delegate, const Object *object, int mode=OB_VISIBLE_SELF)
static std::unique_ptr< ObjectData > create(HydraSceneDelegate *scene_delegate, const Object *object, pxr::SdfPath const &prim_id)
static bool is_supported(const Object *object)
virtual pxr::VtValue get_data(pxr::SdfPath const &id, pxr::TfToken const &key) const
pxr::HdVolumeFieldDescriptorVector field_descriptors() const
#define GS(a)
struct CLG_LogRef * LOG_HYDRA_SCENE
std::shared_ptr< const T > get(const GenericKey &key, FunctionRef< std::unique_ptr< T >()> compute_fn)
return ret
Definition DNA_ID.h:404
ListBase particlesystem
bool operator==(const ShadingSettings &other) const