/* SPDX-License-Identifier: Apache-2.0 * Copyright 2022 NVIDIA Corporation * Copyright 2022 Blender Foundation */ #include "hydra/attribute.h" #include "hydra/geometry.h" #include "hydra/instancer.h" #include "hydra/material.h" #include "hydra/session.h" #include "scene/geometry.h" #include "scene/object.h" #include "scene/scene.h" #include "util/hash.h" #include HDCYCLES_NAMESPACE_OPEN_SCOPE extern Transform convert_transform(const GfMatrix4d &matrix); template HdCyclesGeometry::HdCyclesGeometry(const SdfPath &rprimId #if PXR_VERSION < 2102 , const SdfPath &instancerId #endif ) : Base(rprimId #if PXR_VERSION < 2102 , instancerId #endif ), _geomTransform(1.0) { } template void HdCyclesGeometry::_InitRepr(const TfToken &reprToken, HdDirtyBits *dirtyBits) { TF_UNUSED(reprToken); TF_UNUSED(dirtyBits); } template HdDirtyBits HdCyclesGeometry::GetInitialDirtyBitsMask() const { return HdChangeTracker::DirtyPrimID | HdChangeTracker::DirtyTransform | HdChangeTracker::DirtyMaterialId | HdChangeTracker::DirtyVisibility | HdChangeTracker::DirtyInstancer; } template HdDirtyBits HdCyclesGeometry::_PropagateDirtyBits(HdDirtyBits bits) const { return bits; } template void HdCyclesGeometry::Sync(HdSceneDelegate *sceneDelegate, HdRenderParam *renderParam, HdDirtyBits *dirtyBits, const TfToken &reprToken) { TF_UNUSED(reprToken); if (*dirtyBits == HdChangeTracker::Clean) { return; } Initialize(renderParam); #if PXR_VERSION >= 2102 Base::_UpdateInstancer(sceneDelegate, dirtyBits); HdInstancer::_SyncInstancerAndParents(sceneDelegate->GetRenderIndex(), Base::GetInstancerId()); #endif Base::_UpdateVisibility(sceneDelegate, dirtyBits); const SceneLock lock(renderParam); if (*dirtyBits & HdChangeTracker::DirtyMaterialId) { #if HD_API_VERSION >= 37 && PXR_VERSION >= 2105 Base::SetMaterialId(sceneDelegate->GetMaterialId(Base::GetId())); #else Base::_SetMaterialId(sceneDelegate->GetRenderIndex().GetChangeTracker(), sceneDelegate->GetMaterialId(Base::GetId())); #endif const auto material = static_cast( sceneDelegate->GetRenderIndex().GetSprim(HdPrimTypeTokens->material, Base::GetMaterialId())); array usedShaders(1); if (material && material->GetCyclesShader()) { usedShaders[0] = material->GetCyclesShader(); } else { usedShaders[0] = lock.scene->default_surface; } for (Node *shader : usedShaders) { static_cast(shader)->tag_used(lock.scene); } _geom->set_used_shaders(usedShaders); } const SdfPath &id = Base::GetId(); if (HdChangeTracker::IsPrimIdDirty(*dirtyBits, id)) { // This needs to be corrected in the AOV _instances[0]->set_pass_id(Base::GetPrimId() + 1); } if (HdChangeTracker::IsTransformDirty(*dirtyBits, id)) { _geomTransform = sceneDelegate->GetTransform(id); } if (HdChangeTracker::IsTransformDirty(*dirtyBits, id) || HdChangeTracker::IsInstancerDirty(*dirtyBits, id)) { const auto instancer = static_cast( sceneDelegate->GetRenderIndex().GetInstancer(Base::GetInstancerId())); // Make sure the first object attribute is the instanceId assert(_instances[0]->attributes.size() >= 1 && _instances[0]->attributes.front().name() == HdAovTokens->instanceId.GetString()); VtMatrix4dArray transforms; if (instancer) { transforms = instancer->ComputeInstanceTransforms(id); _instances[0]->attributes.front() = ParamValue(HdAovTokens->instanceId.GetString(), +0.0f); } else { // Default to a single instance with an identity transform transforms.push_back(GfMatrix4d(1.0)); _instances[0]->attributes.front() = ParamValue(HdAovTokens->instanceId.GetString(), -1.0f); } const size_t oldSize = _instances.size(); const size_t newSize = transforms.size(); // Resize instance list for (size_t i = newSize; i < oldSize; ++i) { lock.scene->delete_node(_instances[i]); } _instances.resize(newSize); for (size_t i = oldSize; i < newSize; ++i) { _instances[i] = lock.scene->create_node(); InitializeInstance(static_cast(i)); } // Update transforms of all instances for (size_t i = 0; i < transforms.size(); ++i) { const float metersPerUnit = static_cast(renderParam)->GetStageMetersPerUnit(); const Transform tfm = transform_scale(make_float3(metersPerUnit)) * convert_transform(_geomTransform * transforms[i]); _instances[i]->set_tfm(tfm); } } if (HdChangeTracker::IsVisibilityDirty(*dirtyBits, id)) { for (Object *instance : _instances) { instance->set_visibility(Base::IsVisible() ? ~0 : 0); } } // Must happen after material ID update, so that attribute decisions can be made // based on it (e.g. check whether an attribute is actually needed) bool rebuild = false; Populate(sceneDelegate, *dirtyBits, rebuild); if (_geom->is_modified() || rebuild) { _geom->tag_update(lock.scene, rebuild); } for (Object *instance : _instances) { instance->tag_update(lock.scene); } *dirtyBits = HdChangeTracker::Clean; } template void HdCyclesGeometry::Finalize(HdRenderParam *renderParam) { if (!_geom && _instances.empty()) { return; } const SceneLock lock(renderParam); const bool keep_nodes = static_cast(renderParam)->keep_nodes; if (!keep_nodes) { lock.scene->delete_node(_geom); } _geom = nullptr; if (!keep_nodes) { lock.scene->delete_nodes(set(_instances.begin(), _instances.end())); } _instances.clear(); _instances.shrink_to_fit(); } template void HdCyclesGeometry::Initialize(HdRenderParam *renderParam) { if (_geom) { return; } const SceneLock lock(renderParam); // Create geometry _geom = lock.scene->create_node(); _geom->name = Base::GetId().GetString(); // Create default instance _instances.push_back(lock.scene->create_node()); InitializeInstance(0); } template void HdCyclesGeometry::InitializeInstance(int index) { Object *instance = _instances[index]; instance->set_geometry(_geom); instance->attributes.emplace_back(HdAovTokens->instanceId.GetString(), _instances.size() == 1 ? -1.0f : static_cast(index)); instance->set_color(make_float3(0.8f, 0.8f, 0.8f)); instance->set_random_id(hash_uint2(hash_string(_geom->name.c_str()), index)); } template HdInterpolation HdCyclesGeometry::GetPrimvarInterpolation( HdSceneDelegate *sceneDelegate, const TfToken &name) const { for (int i = 0; i < HdInterpolationCount; ++i) { for (const HdPrimvarDescriptor &desc : Base::GetPrimvarDescriptors(sceneDelegate, static_cast(i))) { if (desc.name == name) { return static_cast(i); } } } return HdInterpolationCount; } HDCYCLES_NAMESPACE_CLOSE_SCOPE