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