forked from bartvdbraak/blender
d7d40745fa
* Split render/ into scene/ and session/. The scene/ folder now contains the scene and its nodes. The session/ folder contains the render session and associated data structures like drivers and render buffers. * Move top level kernel headers into new folders kernel/camera/, kernel/film/, kernel/light/, kernel/sample/, kernel/util/ * Move integrator related kernel headers into kernel/integrator/ * Move OSL shaders from kernel/shaders/ to kernel/osl/shaders/ For patches and branches, git merge and rebase should be able to detect the renames and move over code to the right file.
427 lines
13 KiB
C++
427 lines
13 KiB
C++
/*
|
|
* Copyright 2011-2021 Blender Foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "scene/pass.h"
|
|
|
|
#include "util/util_algorithm.h"
|
|
#include "util/util_logging.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
const char *pass_type_as_string(const PassType type)
|
|
{
|
|
const int type_int = static_cast<int>(type);
|
|
|
|
const NodeEnum *type_enum = Pass::get_type_enum();
|
|
|
|
if (!type_enum->exists(type_int)) {
|
|
LOG(DFATAL) << "Unhandled pass type " << static_cast<int>(type) << ", not supposed to happen.";
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
return (*type_enum)[type_int].c_str();
|
|
}
|
|
|
|
const char *pass_mode_as_string(PassMode mode)
|
|
{
|
|
switch (mode) {
|
|
case PassMode::NOISY:
|
|
return "NOISY";
|
|
case PassMode::DENOISED:
|
|
return "DENOISED";
|
|
}
|
|
|
|
LOG(DFATAL) << "Unhandled pass mode " << static_cast<int>(mode) << ", should never happen.";
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &os, PassMode mode)
|
|
{
|
|
os << pass_mode_as_string(mode);
|
|
return os;
|
|
}
|
|
|
|
const NodeEnum *Pass::get_type_enum()
|
|
{
|
|
static NodeEnum pass_type_enum;
|
|
|
|
if (pass_type_enum.empty()) {
|
|
|
|
/* Light Passes. */
|
|
pass_type_enum.insert("combined", PASS_COMBINED);
|
|
pass_type_enum.insert("emission", PASS_EMISSION);
|
|
pass_type_enum.insert("background", PASS_BACKGROUND);
|
|
pass_type_enum.insert("ao", PASS_AO);
|
|
pass_type_enum.insert("shadow", PASS_SHADOW);
|
|
pass_type_enum.insert("diffuse", PASS_DIFFUSE);
|
|
pass_type_enum.insert("diffuse_direct", PASS_DIFFUSE_DIRECT);
|
|
pass_type_enum.insert("diffuse_indirect", PASS_DIFFUSE_INDIRECT);
|
|
pass_type_enum.insert("glossy", PASS_GLOSSY);
|
|
pass_type_enum.insert("glossy_direct", PASS_GLOSSY_DIRECT);
|
|
pass_type_enum.insert("glossy_indirect", PASS_GLOSSY_INDIRECT);
|
|
pass_type_enum.insert("transmission", PASS_TRANSMISSION);
|
|
pass_type_enum.insert("transmission_direct", PASS_TRANSMISSION_DIRECT);
|
|
pass_type_enum.insert("transmission_indirect", PASS_TRANSMISSION_INDIRECT);
|
|
pass_type_enum.insert("volume", PASS_VOLUME);
|
|
pass_type_enum.insert("volume_direct", PASS_VOLUME_DIRECT);
|
|
pass_type_enum.insert("volume_indirect", PASS_VOLUME_INDIRECT);
|
|
|
|
/* Data passes. */
|
|
pass_type_enum.insert("depth", PASS_DEPTH);
|
|
pass_type_enum.insert("position", PASS_POSITION);
|
|
pass_type_enum.insert("normal", PASS_NORMAL);
|
|
pass_type_enum.insert("roughness", PASS_ROUGHNESS);
|
|
pass_type_enum.insert("uv", PASS_UV);
|
|
pass_type_enum.insert("object_id", PASS_OBJECT_ID);
|
|
pass_type_enum.insert("material_id", PASS_MATERIAL_ID);
|
|
pass_type_enum.insert("motion", PASS_MOTION);
|
|
pass_type_enum.insert("motion_weight", PASS_MOTION_WEIGHT);
|
|
pass_type_enum.insert("cryptomatte", PASS_CRYPTOMATTE);
|
|
pass_type_enum.insert("aov_color", PASS_AOV_COLOR);
|
|
pass_type_enum.insert("aov_value", PASS_AOV_VALUE);
|
|
pass_type_enum.insert("adaptive_aux_buffer", PASS_ADAPTIVE_AUX_BUFFER);
|
|
pass_type_enum.insert("sample_count", PASS_SAMPLE_COUNT);
|
|
pass_type_enum.insert("diffuse_color", PASS_DIFFUSE_COLOR);
|
|
pass_type_enum.insert("glossy_color", PASS_GLOSSY_COLOR);
|
|
pass_type_enum.insert("transmission_color", PASS_TRANSMISSION_COLOR);
|
|
pass_type_enum.insert("mist", PASS_MIST);
|
|
pass_type_enum.insert("denoising_normal", PASS_DENOISING_NORMAL);
|
|
pass_type_enum.insert("denoising_albedo", PASS_DENOISING_ALBEDO);
|
|
pass_type_enum.insert("denoising_depth", PASS_DENOISING_DEPTH);
|
|
|
|
pass_type_enum.insert("shadow_catcher", PASS_SHADOW_CATCHER);
|
|
pass_type_enum.insert("shadow_catcher_sample_count", PASS_SHADOW_CATCHER_SAMPLE_COUNT);
|
|
pass_type_enum.insert("shadow_catcher_matte", PASS_SHADOW_CATCHER_MATTE);
|
|
|
|
pass_type_enum.insert("bake_primitive", PASS_BAKE_PRIMITIVE);
|
|
pass_type_enum.insert("bake_differential", PASS_BAKE_DIFFERENTIAL);
|
|
}
|
|
|
|
return &pass_type_enum;
|
|
}
|
|
|
|
const NodeEnum *Pass::get_mode_enum()
|
|
{
|
|
static NodeEnum pass_mode_enum;
|
|
|
|
if (pass_mode_enum.empty()) {
|
|
pass_mode_enum.insert("noisy", static_cast<int>(PassMode::NOISY));
|
|
pass_mode_enum.insert("denoised", static_cast<int>(PassMode::DENOISED));
|
|
}
|
|
|
|
return &pass_mode_enum;
|
|
}
|
|
|
|
NODE_DEFINE(Pass)
|
|
{
|
|
NodeType *type = NodeType::add("pass", create);
|
|
|
|
const NodeEnum *pass_type_enum = get_type_enum();
|
|
const NodeEnum *pass_mode_enum = get_mode_enum();
|
|
|
|
SOCKET_ENUM(type, "Type", *pass_type_enum, PASS_COMBINED);
|
|
SOCKET_ENUM(mode, "Mode", *pass_mode_enum, static_cast<int>(PassMode::DENOISED));
|
|
SOCKET_STRING(name, "Name", ustring());
|
|
SOCKET_BOOLEAN(include_albedo, "Include Albedo", false);
|
|
|
|
return type;
|
|
}
|
|
|
|
Pass::Pass() : Node(get_node_type()), is_auto_(false)
|
|
{
|
|
}
|
|
|
|
PassInfo Pass::get_info() const
|
|
{
|
|
return get_info(type, include_albedo);
|
|
}
|
|
|
|
bool Pass::is_written() const
|
|
{
|
|
return get_info().is_written;
|
|
}
|
|
|
|
PassInfo Pass::get_info(const PassType type, const bool include_albedo)
|
|
{
|
|
PassInfo pass_info;
|
|
|
|
pass_info.use_filter = true;
|
|
pass_info.use_exposure = false;
|
|
pass_info.divide_type = PASS_NONE;
|
|
pass_info.use_compositing = false;
|
|
pass_info.use_denoising_albedo = true;
|
|
|
|
switch (type) {
|
|
case PASS_NONE:
|
|
pass_info.num_components = 0;
|
|
break;
|
|
case PASS_COMBINED:
|
|
pass_info.num_components = 4;
|
|
pass_info.use_exposure = true;
|
|
pass_info.support_denoise = true;
|
|
break;
|
|
case PASS_DEPTH:
|
|
pass_info.num_components = 1;
|
|
pass_info.use_filter = false;
|
|
break;
|
|
case PASS_MIST:
|
|
pass_info.num_components = 1;
|
|
break;
|
|
case PASS_POSITION:
|
|
pass_info.num_components = 3;
|
|
break;
|
|
case PASS_NORMAL:
|
|
pass_info.num_components = 3;
|
|
break;
|
|
case PASS_ROUGHNESS:
|
|
pass_info.num_components = 1;
|
|
break;
|
|
case PASS_UV:
|
|
pass_info.num_components = 3;
|
|
break;
|
|
case PASS_MOTION:
|
|
pass_info.num_components = 4;
|
|
pass_info.divide_type = PASS_MOTION_WEIGHT;
|
|
break;
|
|
case PASS_MOTION_WEIGHT:
|
|
pass_info.num_components = 1;
|
|
break;
|
|
case PASS_OBJECT_ID:
|
|
case PASS_MATERIAL_ID:
|
|
pass_info.num_components = 1;
|
|
pass_info.use_filter = false;
|
|
break;
|
|
|
|
case PASS_EMISSION:
|
|
case PASS_BACKGROUND:
|
|
pass_info.num_components = 3;
|
|
pass_info.use_exposure = true;
|
|
break;
|
|
case PASS_AO:
|
|
pass_info.num_components = 3;
|
|
break;
|
|
case PASS_SHADOW:
|
|
pass_info.num_components = 3;
|
|
pass_info.use_exposure = false;
|
|
break;
|
|
|
|
case PASS_DIFFUSE_COLOR:
|
|
case PASS_GLOSSY_COLOR:
|
|
case PASS_TRANSMISSION_COLOR:
|
|
pass_info.num_components = 3;
|
|
break;
|
|
case PASS_DIFFUSE:
|
|
pass_info.num_components = 3;
|
|
pass_info.use_exposure = true;
|
|
pass_info.direct_type = PASS_DIFFUSE_DIRECT;
|
|
pass_info.indirect_type = PASS_DIFFUSE_INDIRECT;
|
|
pass_info.divide_type = (!include_albedo) ? PASS_DIFFUSE_COLOR : PASS_NONE;
|
|
pass_info.use_compositing = true;
|
|
pass_info.is_written = false;
|
|
break;
|
|
case PASS_DIFFUSE_DIRECT:
|
|
case PASS_DIFFUSE_INDIRECT:
|
|
pass_info.num_components = 3;
|
|
pass_info.use_exposure = true;
|
|
pass_info.divide_type = (!include_albedo) ? PASS_DIFFUSE_COLOR : PASS_NONE;
|
|
pass_info.use_compositing = true;
|
|
break;
|
|
case PASS_GLOSSY:
|
|
pass_info.num_components = 3;
|
|
pass_info.use_exposure = true;
|
|
pass_info.direct_type = PASS_GLOSSY_DIRECT;
|
|
pass_info.indirect_type = PASS_GLOSSY_INDIRECT;
|
|
pass_info.divide_type = (!include_albedo) ? PASS_GLOSSY_COLOR : PASS_NONE;
|
|
pass_info.use_compositing = true;
|
|
pass_info.is_written = false;
|
|
break;
|
|
case PASS_GLOSSY_DIRECT:
|
|
case PASS_GLOSSY_INDIRECT:
|
|
pass_info.num_components = 3;
|
|
pass_info.use_exposure = true;
|
|
pass_info.divide_type = (!include_albedo) ? PASS_GLOSSY_COLOR : PASS_NONE;
|
|
pass_info.use_compositing = true;
|
|
break;
|
|
case PASS_TRANSMISSION:
|
|
pass_info.num_components = 3;
|
|
pass_info.use_exposure = true;
|
|
pass_info.direct_type = PASS_TRANSMISSION_DIRECT;
|
|
pass_info.indirect_type = PASS_TRANSMISSION_INDIRECT;
|
|
pass_info.divide_type = (!include_albedo) ? PASS_TRANSMISSION_COLOR : PASS_NONE;
|
|
pass_info.use_compositing = true;
|
|
pass_info.is_written = false;
|
|
break;
|
|
case PASS_TRANSMISSION_DIRECT:
|
|
case PASS_TRANSMISSION_INDIRECT:
|
|
pass_info.num_components = 3;
|
|
pass_info.use_exposure = true;
|
|
pass_info.divide_type = (!include_albedo) ? PASS_TRANSMISSION_COLOR : PASS_NONE;
|
|
pass_info.use_compositing = true;
|
|
break;
|
|
case PASS_VOLUME:
|
|
pass_info.num_components = 3;
|
|
pass_info.use_exposure = true;
|
|
pass_info.direct_type = PASS_VOLUME_DIRECT;
|
|
pass_info.indirect_type = PASS_VOLUME_INDIRECT;
|
|
pass_info.use_compositing = true;
|
|
pass_info.is_written = false;
|
|
break;
|
|
case PASS_VOLUME_DIRECT:
|
|
case PASS_VOLUME_INDIRECT:
|
|
pass_info.num_components = 3;
|
|
pass_info.use_exposure = true;
|
|
break;
|
|
|
|
case PASS_CRYPTOMATTE:
|
|
pass_info.num_components = 4;
|
|
break;
|
|
|
|
case PASS_DENOISING_NORMAL:
|
|
pass_info.num_components = 3;
|
|
break;
|
|
case PASS_DENOISING_ALBEDO:
|
|
pass_info.num_components = 3;
|
|
break;
|
|
case PASS_DENOISING_DEPTH:
|
|
pass_info.num_components = 1;
|
|
break;
|
|
|
|
case PASS_SHADOW_CATCHER:
|
|
pass_info.num_components = 3;
|
|
pass_info.use_exposure = true;
|
|
pass_info.use_compositing = true;
|
|
pass_info.use_denoising_albedo = false;
|
|
pass_info.support_denoise = true;
|
|
break;
|
|
case PASS_SHADOW_CATCHER_SAMPLE_COUNT:
|
|
pass_info.num_components = 1;
|
|
break;
|
|
case PASS_SHADOW_CATCHER_MATTE:
|
|
pass_info.num_components = 4;
|
|
pass_info.use_exposure = true;
|
|
pass_info.support_denoise = true;
|
|
/* Without shadow catcher approximation compositing is not needed.
|
|
* Since we don't know here whether approximation is used or not, leave the decision up to
|
|
* the caller which will know that. */
|
|
break;
|
|
|
|
case PASS_ADAPTIVE_AUX_BUFFER:
|
|
pass_info.num_components = 4;
|
|
break;
|
|
case PASS_SAMPLE_COUNT:
|
|
pass_info.num_components = 1;
|
|
pass_info.use_exposure = false;
|
|
break;
|
|
|
|
case PASS_AOV_COLOR:
|
|
pass_info.num_components = 3;
|
|
break;
|
|
case PASS_AOV_VALUE:
|
|
pass_info.num_components = 1;
|
|
break;
|
|
|
|
case PASS_BAKE_PRIMITIVE:
|
|
case PASS_BAKE_DIFFERENTIAL:
|
|
pass_info.num_components = 4;
|
|
pass_info.use_exposure = false;
|
|
pass_info.use_filter = false;
|
|
break;
|
|
|
|
case PASS_CATEGORY_LIGHT_END:
|
|
case PASS_CATEGORY_DATA_END:
|
|
case PASS_CATEGORY_BAKE_END:
|
|
case PASS_NUM:
|
|
LOG(DFATAL) << "Unexpected pass type is used " << type;
|
|
pass_info.num_components = 0;
|
|
break;
|
|
}
|
|
|
|
return pass_info;
|
|
}
|
|
|
|
bool Pass::contains(const vector<Pass *> &passes, PassType type)
|
|
{
|
|
for (const Pass *pass : passes) {
|
|
if (pass->get_type() != type) {
|
|
continue;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
const Pass *Pass::find(const vector<Pass *> &passes, const string &name)
|
|
{
|
|
for (const Pass *pass : passes) {
|
|
if (pass->get_name() == name) {
|
|
return pass;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
const Pass *Pass::find(const vector<Pass *> &passes, PassType type, PassMode mode)
|
|
{
|
|
for (const Pass *pass : passes) {
|
|
if (pass->get_type() != type || pass->get_mode() != mode) {
|
|
continue;
|
|
}
|
|
|
|
return pass;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
int Pass::get_offset(const vector<Pass *> &passes, const Pass *pass)
|
|
{
|
|
int pass_offset = 0;
|
|
|
|
for (const Pass *current_pass : passes) {
|
|
/* Note that pass name is allowed to be empty. This is why we check for type and mode. */
|
|
if (current_pass->get_type() == pass->get_type() &&
|
|
current_pass->get_mode() == pass->get_mode() &&
|
|
current_pass->get_name() == pass->get_name()) {
|
|
if (current_pass->is_written()) {
|
|
return pass_offset;
|
|
}
|
|
else {
|
|
return PASS_UNUSED;
|
|
}
|
|
}
|
|
if (current_pass->is_written()) {
|
|
pass_offset += current_pass->get_info().num_components;
|
|
}
|
|
}
|
|
|
|
return PASS_UNUSED;
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &os, const Pass &pass)
|
|
{
|
|
os << "type: " << pass_type_as_string(pass.get_type());
|
|
os << ", name: \"" << pass.get_name() << "\"";
|
|
os << ", mode: " << pass.get_mode();
|
|
os << ", is_written: " << string_from_bool(pass.is_written());
|
|
|
|
return os;
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|