Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/render/pass.cpp
- This file was added.
| /* | |||||
| * 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 "render/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("render_time", PASS_RENDER_TIME); | |||||
| 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("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) | |||||
| { | |||||
| } | |||||
| const PassInfo &Pass::get_info() const | |||||
| { | |||||
| return info_; | |||||
| } | |||||
| bool Pass::is_written() const | |||||
| { | |||||
| return 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_RENDER_TIME: | |||||
| /* This pass is handled entirely on the host side. */ | |||||
| pass_info.num_components = 0; | |||||
| 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_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->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->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->type != type || pass->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->type == pass->type && current_pass->mode == pass->mode && | |||||
| current_pass->name == pass->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.type); | |||||
| os << ", name: \"" << pass.name << "\""; | |||||
| os << ", mode: " << pass.mode; | |||||
| os << ", is_written: " << string_from_bool(pass.is_written()); | |||||
| return os; | |||||
| } | |||||
| CCL_NAMESPACE_END | |||||