Files
test2/intern/cycles/hydra/session.cpp
Brecht Van Lommel e813e46327 Cycles: Refactor lights to be objects
This is an intermediate steps towards making lights actual geometry.
Light is now a subclass of Geometry, which simplifies some code.

The geometry is not added to the BVH yet, which would be the next
step and improve light intersection performance with many lights.

This makes object attributes work on lights.

Co-authored-by: Lukas Stockner <lukas@lukasstockner.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/134846
2025-02-24 23:44:14 +01:00

183 lines
5.5 KiB
C++

/* 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<TfToken, PassType, TfToken::HashFunctor> 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<const HdCyclesSession *>(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 &params)
: session(new Session(params, SceneParams())), keep_nodes(false), _ownCyclesSession(true)
{
Scene *const scene = session->scene.get();
// Create background with ambient light
{
unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
BackgroundNode *bgNode = graph->create_node<BackgroundNode>();
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<ShaderGraph> graph = make_unique<ShaderGraph>();
ObjectInfoNode *objectNode = graph->create_node<ObjectInfoNode>();
DiffuseBsdfNode *diffuseNode = graph->create_node<DiffuseBsdfNode>();
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<OutputAOVNode>();
aovNode->set_name(instanceId);
AttributeNode *instanceIdNode = graph->create_node<AttributeNode>();
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<Light *>(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<BackgroundNode *>(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<Pass *> &scene_passes = scene->passes;
scene->delete_nodes(set<Pass *>(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>();
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