blender/intern/cycles/hydra/geometry.inl
Brecht Van Lommel 9b92ce9dc0 Cycles: add USD as a file format for Cycles standalone rendering
Long term, this should replace the XML format. This reuses the Hydra render
delegate implementation, and so supports the same features. The same command
line options and GUI work for both XML and USD also.

The implementation of this is still disabled, waiting for some refactoring of
USD library linking. However we want the Cycles code to be in sync between
repositories for the 3.2 release.

Ref T96731
2022-04-29 19:19:19 +02:00

257 lines
7.8 KiB
C++

/* 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 <pxr/imaging/hd/sceneDelegate.h>
HDCYCLES_NAMESPACE_OPEN_SCOPE
extern Transform convert_transform(const GfMatrix4d &matrix);
template<typename Base, typename CyclesBase>
HdCyclesGeometry<Base, CyclesBase>::HdCyclesGeometry(const SdfPath &rprimId
#if PXR_VERSION < 2102
,
const SdfPath &instancerId
#endif
)
: Base(rprimId
#if PXR_VERSION < 2102
,
instancerId
#endif
),
_geomTransform(1.0)
{
}
template<typename Base, typename CyclesBase>
void HdCyclesGeometry<Base, CyclesBase>::_InitRepr(const TfToken &reprToken,
HdDirtyBits *dirtyBits)
{
TF_UNUSED(reprToken);
TF_UNUSED(dirtyBits);
}
template<typename Base, typename CyclesBase>
HdDirtyBits HdCyclesGeometry<Base, CyclesBase>::GetInitialDirtyBitsMask() const
{
return HdChangeTracker::DirtyPrimID | HdChangeTracker::DirtyTransform |
HdChangeTracker::DirtyMaterialId | HdChangeTracker::DirtyVisibility |
HdChangeTracker::DirtyInstancer;
}
template<typename Base, typename CyclesBase>
HdDirtyBits HdCyclesGeometry<Base, CyclesBase>::_PropagateDirtyBits(HdDirtyBits bits) const
{
return bits;
}
template<typename Base, typename CyclesBase>
void HdCyclesGeometry<Base, CyclesBase>::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<const HdCyclesMaterial *>(
sceneDelegate->GetRenderIndex().GetSprim(HdPrimTypeTokens->material,
Base::GetMaterialId()));
array<Node *> usedShaders(1);
if (material && material->GetCyclesShader()) {
usedShaders[0] = material->GetCyclesShader();
}
else {
usedShaders[0] = lock.scene->default_surface;
}
for (Node *shader : usedShaders) {
static_cast<Shader *>(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<HdCyclesInstancer *>(
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<Object>();
InitializeInstance(static_cast<int>(i));
}
// Update transforms of all instances
for (size_t i = 0; i < transforms.size(); ++i) {
const float metersPerUnit =
static_cast<HdCyclesSession *>(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<typename Base, typename CyclesBase>
void HdCyclesGeometry<Base, CyclesBase>::Finalize(HdRenderParam *renderParam)
{
if (!_geom && _instances.empty()) {
return;
}
const SceneLock lock(renderParam);
const bool keep_nodes = static_cast<const HdCyclesSession *>(renderParam)->keep_nodes;
if (!keep_nodes) {
lock.scene->delete_node(_geom);
}
_geom = nullptr;
if (!keep_nodes) {
lock.scene->delete_nodes(set<Object *>(_instances.begin(), _instances.end()));
}
_instances.clear();
_instances.shrink_to_fit();
}
template<typename Base, typename CyclesBase>
void HdCyclesGeometry<Base, CyclesBase>::Initialize(HdRenderParam *renderParam)
{
if (_geom) {
return;
}
const SceneLock lock(renderParam);
// Create geometry
_geom = lock.scene->create_node<CyclesBase>();
_geom->name = Base::GetId().GetString();
// Create default instance
_instances.push_back(lock.scene->create_node<Object>());
InitializeInstance(0);
}
template<typename Base, typename CyclesBase>
void HdCyclesGeometry<Base, CyclesBase>::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<float>(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<typename Base, typename CyclesBase>
HdInterpolation HdCyclesGeometry<Base, CyclesBase>::GetPrimvarInterpolation(
HdSceneDelegate *sceneDelegate, const TfToken &name) const
{
for (int i = 0; i < HdInterpolationCount; ++i) {
for (const HdPrimvarDescriptor &desc :
Base::GetPrimvarDescriptors(sceneDelegate, static_cast<HdInterpolation>(i))) {
if (desc.name == name) {
return static_cast<HdInterpolation>(i);
}
}
}
return HdInterpolationCount;
}
HDCYCLES_NAMESPACE_CLOSE_SCOPE