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