/* SPDX-FileCopyrightText: 2022 NVIDIA Corporation * SPDX-FileCopyrightText: 2022 Blender Foundation * * SPDX-License-Identifier: Apache-2.0 */ #include "hydra/session.h" #include "scene/object.h" #include "scene/shader.h" // Have to include shader.h before background.h so that 'set_shader' uses the correct 'set' // overload taking a 'Node *', rather than the one taking a 'bool' #include "scene/background.h" #include "scene/light.h" #include "scene/shader_graph.h" #include "scene/shader_nodes.h" #include "session/session.h" HDCYCLES_NAMESPACE_OPEN_SCOPE namespace { const std::unordered_map kAovToPass = { {HdAovTokens->color, PASS_COMBINED}, {HdAovTokens->depth, PASS_DEPTH}, {HdAovTokens->normal, PASS_NORMAL}, {HdAovTokens->primId, PASS_OBJECT_ID}, {HdAovTokens->instanceId, PASS_AOV_VALUE}, }; } // namespace SceneLock::SceneLock(const HdRenderParam *renderParam) : scene(static_cast(renderParam)->session->scene.get()), sceneLock(scene->mutex) { } SceneLock::~SceneLock() = default; HdCyclesSession::HdCyclesSession(Session *session_, const bool keep_nodes) : session(session_), keep_nodes(keep_nodes), _ownCyclesSession(false) { } HdCyclesSession::HdCyclesSession(const SessionParams ¶ms) : session(new Session(params, SceneParams())), keep_nodes(false), _ownCyclesSession(true) { Scene *const scene = session->scene.get(); // Create background with ambient light { unique_ptr graph = make_unique(); BackgroundNode *bgNode = graph->create_node(); bgNode->set_color(one_float3()); graph->connect(bgNode->output("Background"), graph->output()->input("Surface")); scene->default_background->set_graph(std::move(graph)); scene->default_background->tag_update(scene); } // Wire up object color in default surface material { unique_ptr graph = make_unique(); ObjectInfoNode *objectNode = graph->create_node(); DiffuseBsdfNode *diffuseNode = graph->create_node(); graph->connect(objectNode->output("Color"), diffuseNode->input("Color")); graph->connect(diffuseNode->output("BSDF"), graph->output()->input("Surface")); // Create the instanceId AOV output const ustring instanceId(HdAovTokens->instanceId.GetString()); OutputAOVNode *aovNode = graph->create_node(); aovNode->set_name(instanceId); AttributeNode *instanceIdNode = graph->create_node(); instanceIdNode->set_attribute(instanceId); graph->connect(instanceIdNode->output("Fac"), aovNode->input("Value")); scene->default_surface->set_graph(std::move(graph)); scene->default_surface->tag_update(scene); } } HdCyclesSession::~HdCyclesSession() { if (_ownCyclesSession) { delete session; } } void HdCyclesSession::UpdateScene() { Scene *const scene = session->scene.get(); // Update background depending on presence of a background light if (scene->light_manager->need_update()) { Light *background_light = nullptr; bool have_lights = false; for (Object *object : scene->objects) { if (!object->get_geometry()->is_light()) { continue; } have_lights = true; Light *light = static_cast(object->get_geometry()); if (light->get_light_type() == LIGHT_BACKGROUND) { background_light = light; break; } } if (!background_light) { scene->background->set_shader(scene->default_background); scene->background->set_transparent(true); /* Set background color depending to non-zero value if there are no * lights in the scene, to match behavior of other renderers. */ for (ShaderNode *node : scene->default_background->graph->nodes) { if (node->is_a(BackgroundNode::get_node_type())) { BackgroundNode *bgNode = static_cast(node); bgNode->set_color((have_lights) ? zero_float3() : make_float3(0.5f)); } } } else { scene->background->set_shader(background_light->get_shader()); scene->background->set_transparent(false); } scene->background->tag_update(scene); } } void HdCyclesSession::SyncAovBindings(const HdRenderPassAovBindingVector &aovBindings) { Scene *const scene = session->scene.get(); // Delete all existing passes const vector &scene_passes = scene->passes; scene->delete_nodes(set(scene_passes.begin(), scene_passes.end())); // Update passes with requested AOV bindings _aovBindings = aovBindings; for (const HdRenderPassAovBinding &aovBinding : aovBindings) { const auto cyclesAov = kAovToPass.find(aovBinding.aovName); if (cyclesAov == kAovToPass.end()) { // TODO: Use PASS_AOV_COLOR and PASS_AOV_VALUE for these? TF_WARN("Unknown pass %s", aovBinding.aovName.GetText()); continue; } const PassType type = cyclesAov->second; const PassMode mode = PassMode::DENOISED; Pass *pass = scene->create_node(); pass->set_type(type); pass->set_mode(mode); pass->set_name(ustring(aovBinding.aovName.GetString())); } } void HdCyclesSession::RemoveAovBinding(HdRenderBuffer *renderBuffer) { for (HdRenderPassAovBinding &aovBinding : _aovBindings) { if (renderBuffer == aovBinding.renderBuffer) { aovBinding.renderBuffer = nullptr; break; } } if (renderBuffer == _displayAovBinding.renderBuffer) { _displayAovBinding.renderBuffer = nullptr; } } HDCYCLES_NAMESPACE_CLOSE_SCOPE