2023-06-14 16:52:36 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-05-02 15:45:31 +02:00
|
|
|
#include "device/device.h"
|
|
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "scene/background.h"
|
|
|
|
|
#include "scene/camera.h"
|
|
|
|
|
#include "scene/integrator.h"
|
|
|
|
|
#include "scene/light.h"
|
|
|
|
|
#include "scene/mesh.h"
|
|
|
|
|
#include "scene/object.h"
|
|
|
|
|
#include "scene/osl.h"
|
|
|
|
|
#include "scene/procedural.h"
|
|
|
|
|
#include "scene/scene.h"
|
|
|
|
|
#include "scene/shader.h"
|
|
|
|
|
#include "scene/shader_graph.h"
|
|
|
|
|
#include "scene/shader_nodes.h"
|
|
|
|
|
#include "scene/svm.h"
|
|
|
|
|
#include "scene/tables.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2024-12-31 10:28:46 +01:00
|
|
|
#include "util/log.h"
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "util/murmurhash.h"
|
|
|
|
|
#include "util/transform.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2018-06-14 17:48:19 +02:00
|
|
|
#ifdef WITH_OCIO
|
|
|
|
|
# include <OpenColorIO/OpenColorIO.h>
|
|
|
|
|
namespace OCIO = OCIO_NAMESPACE;
|
|
|
|
|
#endif
|
|
|
|
|
|
Cycles: Remove MultiGGX code, replace with albedo scaling
While the multiscattering GGX code is cool and solves the darkening problem at higher roughnesses, it's also currently buggy, hard to maintain and often impractical to use due to the higher noise and render time.
In practice, though, having the exact correct directional distribution is not that important as long as the overall albedo is correct and we a) don't get the darkening effect and b) do get the saturation effect at higher roughnesses.
This can simply be achieved by adding a second lobe (https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) or scaling the single-scattering GGX lobe (https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf). Both approaches require the same precomputation and produce outputs of comparable quality, so I went for the simple albedo scaling since it's easier to implement and more efficient.
Overall, the results are pretty good: All scenarios that I tested (Glossy BSDF, Glass BSDF, Principled BSDF with metallic or transmissive = 1) pass the white furnace test (a material with pure-white color in front of a pure-white background should be indistinguishable from the background if it preserves energy), and the overall albedo for non-white materials matches that produced by the real multi-scattering code (with the expected saturation increase as the roughness increases).
In order to produce the precomputed tables, the PR also includes a utility that computes them. This is not built by default, since there's no reason for a user to run it (it only makes sense for documentation/reproducibility purposes and when making changes to the microfacet models).
Pull Request: https://projects.blender.org/blender/blender/pulls/107958
2023-06-05 02:20:57 +02:00
|
|
|
#include "scene/shader.tables"
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
|
2017-10-06 21:06:15 +05:00
|
|
|
thread_mutex ShaderManager::lookup_table_mutex;
|
2014-06-20 21:21:05 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Shader */
|
|
|
|
|
|
2016-05-08 00:18:32 +02:00
|
|
|
NODE_DEFINE(Shader)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("shader", create);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-11-30 20:50:11 +01:00
|
|
|
static NodeEnum emission_sampling_method_enum;
|
|
|
|
|
emission_sampling_method_enum.insert("none", EMISSION_SAMPLING_NONE);
|
|
|
|
|
emission_sampling_method_enum.insert("auto", EMISSION_SAMPLING_AUTO);
|
|
|
|
|
emission_sampling_method_enum.insert("front", EMISSION_SAMPLING_FRONT);
|
|
|
|
|
emission_sampling_method_enum.insert("back", EMISSION_SAMPLING_BACK);
|
|
|
|
|
emission_sampling_method_enum.insert("front_back", EMISSION_SAMPLING_FRONT_BACK);
|
|
|
|
|
SOCKET_ENUM(emission_sampling_method,
|
|
|
|
|
"Emission Sampling Method",
|
|
|
|
|
emission_sampling_method_enum,
|
|
|
|
|
EMISSION_SAMPLING_AUTO);
|
|
|
|
|
|
2016-05-08 00:18:32 +02:00
|
|
|
SOCKET_BOOLEAN(use_transparent_shadow, "Use Transparent Shadow", true);
|
2023-10-11 15:07:21 +02:00
|
|
|
SOCKET_BOOLEAN(use_bump_map_correction, "Bump Map Correction", true);
|
2016-05-08 00:18:32 +02:00
|
|
|
SOCKET_BOOLEAN(heterogeneous_volume, "Heterogeneous Volume", true);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:18:32 +02:00
|
|
|
static NodeEnum volume_sampling_method_enum;
|
|
|
|
|
volume_sampling_method_enum.insert("distance", VOLUME_SAMPLING_DISTANCE);
|
|
|
|
|
volume_sampling_method_enum.insert("equiangular", VOLUME_SAMPLING_EQUIANGULAR);
|
|
|
|
|
volume_sampling_method_enum.insert("multiple_importance", VOLUME_SAMPLING_MULTIPLE_IMPORTANCE);
|
|
|
|
|
SOCKET_ENUM(volume_sampling_method,
|
|
|
|
|
"Volume Sampling Method",
|
|
|
|
|
volume_sampling_method_enum,
|
2020-03-11 17:49:00 +01:00
|
|
|
VOLUME_SAMPLING_MULTIPLE_IMPORTANCE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:18:32 +02:00
|
|
|
static NodeEnum volume_interpolation_method_enum;
|
|
|
|
|
volume_interpolation_method_enum.insert("linear", VOLUME_INTERPOLATION_LINEAR);
|
|
|
|
|
volume_interpolation_method_enum.insert("cubic", VOLUME_INTERPOLATION_CUBIC);
|
|
|
|
|
SOCKET_ENUM(volume_interpolation_method,
|
|
|
|
|
"Volume Interpolation Method",
|
|
|
|
|
volume_interpolation_method_enum,
|
|
|
|
|
VOLUME_INTERPOLATION_LINEAR);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-07 14:38:52 +01:00
|
|
|
SOCKET_FLOAT(volume_step_rate, "Volume Step Rate", 1.0f);
|
|
|
|
|
|
2016-08-02 05:13:58 -04:00
|
|
|
static NodeEnum displacement_method_enum;
|
|
|
|
|
displacement_method_enum.insert("bump", DISPLACE_BUMP);
|
|
|
|
|
displacement_method_enum.insert("true", DISPLACE_TRUE);
|
|
|
|
|
displacement_method_enum.insert("both", DISPLACE_BOTH);
|
|
|
|
|
SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_INT(pass_id, "Pass ID", 0);
|
|
|
|
|
|
2016-05-08 00:18:32 +02:00
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
Shader::Shader() : Node(get_node_type())
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
pass_id = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 17:53:55 +01:00
|
|
|
graph = nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-10-12 23:03:12 +00:00
|
|
|
has_surface = false;
|
2011-09-27 20:37:24 +00:00
|
|
|
has_surface_transparent = false;
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
has_surface_raytrace = false;
|
2013-04-01 20:26:52 +00:00
|
|
|
has_surface_bssrdf = false;
|
2011-04-27 11:58:34 +00:00
|
|
|
has_volume = false;
|
|
|
|
|
has_displacement = false;
|
2017-08-20 14:02:16 +02:00
|
|
|
has_bump = false;
|
2013-08-18 14:15:57 +00:00
|
|
|
has_bssrdf_bump = false;
|
2016-02-05 22:13:51 +01:00
|
|
|
has_surface_spatial_varying = false;
|
2016-02-05 21:33:37 +01:00
|
|
|
has_volume_spatial_varying = false;
|
2020-03-07 14:38:52 +01:00
|
|
|
has_volume_attribute_dependency = false;
|
2017-07-21 04:18:11 +02:00
|
|
|
has_volume_connected = false;
|
2020-03-07 14:38:52 +01:00
|
|
|
prev_volume_step_rate = 0.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-11-30 20:50:11 +01:00
|
|
|
emission_estimate = zero_float3();
|
|
|
|
|
emission_sampling = EMISSION_SAMPLING_NONE;
|
|
|
|
|
emission_is_constant = true;
|
|
|
|
|
|
2016-08-02 05:13:58 -04:00
|
|
|
displacement_method = DISPLACE_BUMP;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-14 14:50:03 +02:00
|
|
|
id = -1;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 15:01:26 +01:00
|
|
|
need_update_uvs = true;
|
|
|
|
|
need_update_attribute = true;
|
|
|
|
|
need_update_displacement = true;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2022-11-30 20:50:11 +01:00
|
|
|
static float3 output_estimate_emission(ShaderOutput *output, bool &is_constant)
|
2016-09-03 22:40:07 +02:00
|
|
|
{
|
2022-11-30 20:50:11 +01:00
|
|
|
/* Only supports a few nodes for now, not arbitrary shader graphs. */
|
|
|
|
|
ShaderNode *node = (output) ? output->parent : nullptr;
|
|
|
|
|
|
|
|
|
|
if (node == nullptr) {
|
|
|
|
|
return zero_float3();
|
2019-12-04 19:57:28 +01:00
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
if (node->type == EmissionNode::get_node_type() ||
|
|
|
|
|
node->type == BackgroundNode::get_node_type() ||
|
|
|
|
|
node->type == PrincipledBsdfNode::get_node_type())
|
2022-11-30 20:50:11 +01:00
|
|
|
{
|
2023-09-13 03:05:27 +02:00
|
|
|
const bool is_principled = (node->type == PrincipledBsdfNode::get_node_type());
|
2022-11-30 20:50:11 +01:00
|
|
|
/* Emission and Background node. */
|
2023-09-22 17:05:47 +02:00
|
|
|
ShaderInput *color_in = node->input(is_principled ? "Emission Color" : "Color");
|
2023-09-13 03:05:27 +02:00
|
|
|
ShaderInput *strength_in = node->input(is_principled ? "Emission Strength" : "Strength");
|
|
|
|
|
|
|
|
|
|
if (is_principled) {
|
|
|
|
|
/* Too many parameters (coat, sheen, alpha) influence Emission for the Principled BSDF. */
|
|
|
|
|
is_constant = false;
|
|
|
|
|
}
|
2019-12-04 19:57:28 +01:00
|
|
|
|
2022-11-30 20:50:11 +01:00
|
|
|
float3 estimate = one_float3();
|
2016-09-03 22:40:07 +02:00
|
|
|
|
2022-11-30 20:50:11 +01:00
|
|
|
if (color_in->link) {
|
|
|
|
|
is_constant = false;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
estimate *= node->get_float3(color_in->socket_type);
|
|
|
|
|
}
|
2016-09-03 22:40:07 +02:00
|
|
|
|
2022-11-30 20:50:11 +01:00
|
|
|
if (strength_in->link) {
|
|
|
|
|
is_constant = false;
|
|
|
|
|
estimate *= output_estimate_emission(strength_in->link, is_constant);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
estimate *= node->get_float(strength_in->socket_type);
|
|
|
|
|
}
|
2016-09-03 22:40:07 +02:00
|
|
|
|
2022-11-30 20:50:11 +01:00
|
|
|
return estimate;
|
|
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
if (node->type == LightFalloffNode::get_node_type() ||
|
|
|
|
|
node->type == IESLightNode::get_node_type())
|
2023-01-05 19:06:05 +01:00
|
|
|
{
|
|
|
|
|
/* Get strength from Light Falloff and IES texture node. */
|
2022-11-30 20:50:11 +01:00
|
|
|
ShaderInput *strength_in = node->input("Strength");
|
|
|
|
|
is_constant = false;
|
2016-09-03 22:40:07 +02:00
|
|
|
|
2022-11-30 20:50:11 +01:00
|
|
|
return (strength_in->link) ? output_estimate_emission(strength_in->link, is_constant) :
|
|
|
|
|
make_float3(node->get_float(strength_in->socket_type));
|
|
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
if (node->type == AddClosureNode::get_node_type()) {
|
2022-11-30 20:50:11 +01:00
|
|
|
/* Add Closure. */
|
|
|
|
|
ShaderInput *closure1_in = node->input("Closure1");
|
|
|
|
|
ShaderInput *closure2_in = node->input("Closure2");
|
|
|
|
|
|
|
|
|
|
const float3 estimate1 = (closure1_in->link) ?
|
|
|
|
|
output_estimate_emission(closure1_in->link, is_constant) :
|
|
|
|
|
zero_float3();
|
|
|
|
|
const float3 estimate2 = (closure2_in->link) ?
|
|
|
|
|
output_estimate_emission(closure2_in->link, is_constant) :
|
|
|
|
|
zero_float3();
|
|
|
|
|
|
|
|
|
|
return estimate1 + estimate2;
|
|
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
if (node->type == MixClosureNode::get_node_type()) {
|
2022-11-30 20:50:11 +01:00
|
|
|
/* Mix Closure. */
|
|
|
|
|
ShaderInput *fac_in = node->input("Fac");
|
|
|
|
|
ShaderInput *closure1_in = node->input("Closure1");
|
|
|
|
|
ShaderInput *closure2_in = node->input("Closure2");
|
|
|
|
|
|
|
|
|
|
const float3 estimate1 = (closure1_in->link) ?
|
|
|
|
|
output_estimate_emission(closure1_in->link, is_constant) :
|
|
|
|
|
zero_float3();
|
|
|
|
|
const float3 estimate2 = (closure2_in->link) ?
|
|
|
|
|
output_estimate_emission(closure2_in->link, is_constant) :
|
|
|
|
|
zero_float3();
|
|
|
|
|
|
|
|
|
|
if (fac_in->link) {
|
|
|
|
|
is_constant = false;
|
|
|
|
|
return estimate1 + estimate2;
|
|
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
|
|
|
|
|
const float fac = node->get_float(fac_in->socket_type);
|
|
|
|
|
return (1.0f - fac) * estimate1 + fac * estimate2;
|
2022-11-30 20:50:11 +01:00
|
|
|
}
|
|
|
|
|
|
2024-12-26 17:53:59 +01:00
|
|
|
/* Other nodes, potentially OSL nodes with arbitrary code for which all we can
|
|
|
|
|
* determine is if it has emission or not. */
|
|
|
|
|
const bool has_emission = node->has_surface_emission();
|
|
|
|
|
float3 estimate;
|
|
|
|
|
|
|
|
|
|
if (output->type() == SocketType::CLOSURE) {
|
|
|
|
|
if (has_emission) {
|
2022-11-30 20:50:11 +01:00
|
|
|
estimate = one_float3();
|
|
|
|
|
is_constant = false;
|
2019-02-19 17:44:58 +01:00
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
else {
|
|
|
|
|
estimate = zero_float3();
|
|
|
|
|
}
|
2019-02-19 17:44:58 +01:00
|
|
|
|
2024-12-26 19:41:25 +01:00
|
|
|
for (const ShaderInput *in : node->inputs) {
|
2024-12-26 17:53:59 +01:00
|
|
|
if (in->type() == SocketType::CLOSURE && in->link) {
|
|
|
|
|
estimate += output_estimate_emission(in->link, is_constant);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-09-03 22:40:07 +02:00
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
else {
|
|
|
|
|
estimate = one_float3();
|
|
|
|
|
is_constant = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return estimate;
|
2022-11-30 20:50:11 +01:00
|
|
|
}
|
2016-09-03 22:40:07 +02:00
|
|
|
|
2022-11-30 20:50:11 +01:00
|
|
|
void Shader::estimate_emission()
|
|
|
|
|
{
|
|
|
|
|
/* If the shader has AOVs, they need to be evaluated, so we can't skip the shader. */
|
|
|
|
|
emission_is_constant = true;
|
2019-02-19 17:44:58 +01:00
|
|
|
|
2024-12-26 19:41:25 +01:00
|
|
|
for (ShaderNode *node : graph->nodes) {
|
2022-11-30 20:50:11 +01:00
|
|
|
if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
|
|
|
|
|
emission_is_constant = false;
|
2019-02-19 17:44:58 +01:00
|
|
|
}
|
2022-11-30 20:50:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ShaderInput *surf = graph->output()->input("Surface");
|
2024-02-22 19:06:22 +01:00
|
|
|
emission_estimate = output_estimate_emission(surf->link, emission_is_constant);
|
2019-02-19 17:44:58 +01:00
|
|
|
|
2022-11-30 20:50:11 +01:00
|
|
|
if (is_zero(emission_estimate)) {
|
|
|
|
|
emission_sampling = EMISSION_SAMPLING_NONE;
|
|
|
|
|
}
|
|
|
|
|
else if (emission_sampling_method == EMISSION_SAMPLING_AUTO) {
|
|
|
|
|
/* Automatically disable MIS when emission is low, to avoid weakly emitting
|
|
|
|
|
* using a lot of memory in the light tree and potentially wasting samples
|
|
|
|
|
* where indirect light samples are sufficient.
|
|
|
|
|
* Possible optimization: estimate front and back emission separately. */
|
2025-04-17 19:11:38 +02:00
|
|
|
|
|
|
|
|
/* Lower importance of emission nodes from automatic value/color to shader conversion, as these
|
|
|
|
|
* are likely used for previewing and can be slow to build a light tree for on dense meshes. */
|
|
|
|
|
float scale = 1.0f;
|
|
|
|
|
const ShaderOutput *output = surf->link;
|
|
|
|
|
if (output && output->parent->type == EmissionNode::get_node_type()) {
|
|
|
|
|
const EmissionNode *emission_node = static_cast<const EmissionNode *>(output->parent);
|
|
|
|
|
if (emission_node->from_auto_conversion) {
|
|
|
|
|
scale = 0.1f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
emission_sampling = (reduce_max(fabs(emission_estimate * scale)) > 0.5f) ?
|
2024-02-22 19:06:22 +01:00
|
|
|
EMISSION_SAMPLING_FRONT_BACK :
|
|
|
|
|
EMISSION_SAMPLING_NONE;
|
2019-02-19 17:44:58 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2022-11-30 20:50:11 +01:00
|
|
|
emission_sampling = emission_sampling_method;
|
2019-02-19 17:44:58 +01:00
|
|
|
}
|
2016-09-03 22:40:07 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-29 23:13:45 +01:00
|
|
|
void Shader::set_graph(unique_ptr<ShaderGraph> &&graph_)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2013-05-10 11:31:57 +00:00
|
|
|
/* do this here already so that we can detect if mesh or object attributes
|
|
|
|
|
* are needed, since the node attribute callbacks check if their sockets
|
|
|
|
|
* are connected but proxy nodes should not count */
|
2018-01-24 20:19:48 +01:00
|
|
|
if (graph_) {
|
2016-05-02 00:05:16 +02:00
|
|
|
graph_->remove_proxy_nodes();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-24 20:19:48 +01:00
|
|
|
if (displacement_method != DISPLACE_BUMP) {
|
|
|
|
|
graph_->compute_displacement_hash();
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-24 20:19:48 +01:00
|
|
|
/* update geometry if displacement changed */
|
|
|
|
|
if (displacement_method != DISPLACE_BUMP) {
|
|
|
|
|
const char *old_hash = (graph) ? graph->displacement_hash.c_str() : "";
|
|
|
|
|
const char *new_hash = (graph_) ? graph_->displacement_hash.c_str() : "";
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-24 20:19:48 +01:00
|
|
|
if (strcmp(old_hash, new_hash) != 0) {
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 15:01:26 +01:00
|
|
|
need_update_displacement = true;
|
2018-01-24 20:19:48 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* assign graph */
|
2024-12-29 23:13:45 +01:00
|
|
|
graph = std::move(graph_);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-05-19 04:59:35 +02:00
|
|
|
/* Store info here before graph optimization to make sure that
|
|
|
|
|
* nodes that get optimized away still count. */
|
2024-12-26 17:53:55 +01:00
|
|
|
has_volume_connected = (graph->output()->input("Volume")->link != nullptr);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Shader::tag_update(Scene *scene)
|
|
|
|
|
{
|
|
|
|
|
/* update tag */
|
2020-11-04 11:17:38 +01:00
|
|
|
tag_modified();
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 15:01:26 +01:00
|
|
|
|
|
|
|
|
scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* if the shader previously was emissive, update light distribution,
|
|
|
|
|
* if the new shader is emissive, a light manager update tag will be
|
|
|
|
|
* done in the shader manager device update. */
|
2023-09-17 09:01:48 +10:00
|
|
|
if (emission_sampling != EMISSION_SAMPLING_NONE) {
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 15:01:26 +01:00
|
|
|
scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-09-02 09:58:41 +02:00
|
|
|
/* Special handle of background MIS light for now: for some reason it
|
|
|
|
|
* has use_mis set to false. We are quite close to release now, so
|
|
|
|
|
* better to be safe.
|
|
|
|
|
*/
|
2020-05-14 17:41:37 +02:00
|
|
|
if (this == scene->background->get_shader(scene)) {
|
|
|
|
|
scene->light_manager->need_update_background = true;
|
|
|
|
|
if (scene->light_manager->has_background_light(scene)) {
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 15:01:26 +01:00
|
|
|
scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED);
|
2020-05-14 17:41:37 +02:00
|
|
|
}
|
2016-09-02 09:58:41 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
/* quick detection of which kind of shaders we have to avoid loading
|
|
|
|
|
* e.g. surface attributes when there is only a volume shader. this could
|
|
|
|
|
* be more fine grained but it's better than nothing */
|
|
|
|
|
OutputNode *output = graph->output();
|
2024-12-29 17:32:00 +01:00
|
|
|
const bool prev_has_volume = has_volume;
|
2013-12-31 17:30:34 +01:00
|
|
|
has_surface = has_surface || output->input("Surface")->link;
|
|
|
|
|
has_volume = has_volume || output->input("Volume")->link;
|
|
|
|
|
has_displacement = has_displacement || output->input("Displacement")->link;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-10-20 15:24:46 +02:00
|
|
|
if (!has_surface && !has_volume) {
|
2023-10-18 15:39:38 +02:00
|
|
|
/* If we need to output surface AOVs, add a Transparent BSDF so that the
|
|
|
|
|
* surface shader runs. */
|
2024-12-26 19:41:25 +01:00
|
|
|
for (ShaderNode *node : graph->nodes) {
|
2023-07-28 17:33:39 +02:00
|
|
|
if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
|
2024-12-26 19:41:25 +01:00
|
|
|
for (const ShaderInput *in : node->inputs) {
|
2023-07-28 17:33:39 +02:00
|
|
|
if (in->link) {
|
2023-10-18 15:39:38 +02:00
|
|
|
TransparentBsdfNode *transparent = graph->create_node<TransparentBsdfNode>();
|
|
|
|
|
graph->connect(transparent->output("BSDF"), output->input("Surface"));
|
2023-07-28 17:33:39 +02:00
|
|
|
has_surface = true;
|
2023-10-18 15:39:38 +02:00
|
|
|
break;
|
2023-07-28 17:33:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
2023-10-18 15:39:38 +02:00
|
|
|
if (has_surface) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2023-07-28 17:33:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* get requested attributes. this could be optimized by pruning unused
|
2012-06-09 17:22:52 +00:00
|
|
|
* nodes here already, but that's the job of the shader manager currently,
|
|
|
|
|
* and may not be so great for interactive rendering where you temporarily
|
|
|
|
|
* disconnect a node */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
const AttributeRequestSet prev_attributes = attributes;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
attributes.clear();
|
2024-12-26 19:41:25 +01:00
|
|
|
for (ShaderNode *node : graph->nodes) {
|
2013-12-31 17:30:34 +01:00
|
|
|
node->attributes(this, &attributes);
|
2023-07-28 17:33:39 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-12-14 13:42:34 +01:00
|
|
|
if (has_displacement) {
|
|
|
|
|
if (displacement_method == DISPLACE_BOTH) {
|
|
|
|
|
attributes.add(ATTR_STD_POSITION_UNDISPLACED);
|
|
|
|
|
}
|
|
|
|
|
if (displacement_method_is_modified()) {
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 15:01:26 +01:00
|
|
|
need_update_displacement = true;
|
|
|
|
|
scene->geometry_manager->tag_update(scene, GeometryManager::SHADER_DISPLACEMENT_MODIFIED);
|
2020-12-14 13:42:34 +01:00
|
|
|
scene->object_manager->need_flags_update = true;
|
|
|
|
|
}
|
2016-08-13 12:27:17 -04:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* compare if the attributes changed, mesh manager will check
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 15:01:26 +01:00
|
|
|
* need_update_attribute, update the relevant meshes and clear it. */
|
2011-04-27 11:58:34 +00:00
|
|
|
if (attributes.modified(prev_attributes)) {
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 15:01:26 +01:00
|
|
|
need_update_attribute = true;
|
|
|
|
|
scene->geometry_manager->tag_update(scene, GeometryManager::SHADER_ATTRIBUTE_MODIFIED);
|
2021-01-25 14:56:57 +01:00
|
|
|
scene->procedural_manager->tag_update();
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-07 14:38:52 +01:00
|
|
|
if (has_volume != prev_has_volume || volume_step_rate != prev_volume_step_rate) {
|
2020-02-02 12:04:19 +01:00
|
|
|
scene->geometry_manager->need_flags_update = true;
|
2015-01-19 19:08:58 +05:00
|
|
|
scene->object_manager->need_flags_update = true;
|
2020-03-07 14:38:52 +01:00
|
|
|
prev_volume_step_rate = volume_step_rate;
|
2015-01-19 19:08:58 +05:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2012-10-30 11:51:17 +00:00
|
|
|
void Shader::tag_used(Scene *scene)
|
|
|
|
|
{
|
|
|
|
|
/* if an unused shader suddenly gets used somewhere, it needs to be
|
|
|
|
|
* recompiled because it was skipped for compilation before */
|
2021-05-02 02:34:56 +02:00
|
|
|
if (!reference_count()) {
|
2020-11-04 11:17:38 +01:00
|
|
|
tag_modified();
|
2021-05-02 02:34:56 +02:00
|
|
|
/* We do not reference here as the shader will be referenced when added to a socket. */
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 15:01:26 +01:00
|
|
|
scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED);
|
2012-10-30 11:51:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 15:01:26 +01:00
|
|
|
bool Shader::need_update_geometry() const
|
|
|
|
|
{
|
|
|
|
|
return need_update_uvs || need_update_attribute || need_update_displacement;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Shader Manager */
|
|
|
|
|
|
Cycles: Replace thin-film basis function approximation with accurate LUTs
Previously, we used precomputed Gaussian fits to the XYZ CMFs, performed
the spectral integration in that space, and then converted the result
to the RGB working space.
That worked because we're only supporting dielectric base layers for
the thin film code, so the inputs to the spectral integration
(reflectivity and phase) are both constant w.r.t. wavelength.
However, this will no longer work for conductive base layers.
We could handle reflectivity by converting to XYZ, but that won't work
for phase since its effect on the output is nonlinear.
Therefore, it's time to do this properly by performing the spectral
integration directly in the RGB primaries. To do this, we need to:
- Compute the RGB CMFs from the XYZ CMFs and XYZ-to-RGB matrix
- Resample the RGB CMFs to be parametrized by frequency instead of wavelength
- Compute the FFT of the CMFs
- Store it as a LUT to be used by the kernel code
However, there's two optimizations we can make:
- Both the resampling and the FFT are linear operations, as is the
XYZ-to-RGB conversion. Therefore, we can resample and Fourier-transform
the XYZ CMFs once, store the result in a precomputed table, and then just
multiply the entries by the XYZ-to-RGB matrix at runtime.
- I've included the Python script used to compute the table under
`intern/cycles/doc/precompute`.
- The reference implementation by the paper authors [1] simply stores the
real and imaginary parts in the LUT, and then computes
`cos(shift)*real + sin(shift)*imag`. However, the real and imaginary parts
are oscillating, so the LUT with linear interpolation is not particularly
good at representing them. Instead, we can convert the table to
Magnitude/Phase representation, which is much smoother, and do
`mag * cos(phase - shift)` in the kernel.
- Phase needs to be unwrapped to handle the interpolation decently,
but that's easy.
- This requires an extra trig operation in the kernel in the dielectric case,
but for the conductive case we'll actually save three.
Rendered output is mostly the same, just slightly different because we're
no longer using the Gaussian approximation.
[1] "A Practical Extension to Microfacet Theory for the Modeling of
Varying Iridescence" by Laurent Belcour and Pascal Barla,
https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html
Pull Request: https://projects.blender.org/blender/blender/pulls/140944
2025-07-09 22:10:28 +02:00
|
|
|
ShaderManager::ShaderManager() : thin_film_table_offset_(TABLE_OFFSET_INVALID)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 15:01:26 +01:00
|
|
|
update_flags = UPDATE_ALL;
|
2018-06-14 17:48:19 +02:00
|
|
|
|
OpenColorIO: upgrade to version 2.0.0
Ref T84819
Build System
============
This is an API breaking new version, and the updated code only builds with
OpenColorIO 2.0 and later. Adding backwards compatibility was too complicated.
* Tinyxml was replaced with Expat, adding a new dependency.
* Yaml-cpp is now built as a dependency on Unix, as was already done on Windows.
* Removed currently unused LCMS code.
* Pystring remains built as part of OCIO itself, since it has no good build system.
* Linux and macOS check for the OpenColorIO verison, and disable it if too old.
Ref D10270
Processors and Transforms
=========================
CPU processors now need to be created to do CPU processing. These are cached
internally, but the cache lookup is not fast enough to execute per pixel or
texture sample, so for performance these are now also exposed in the C API.
The C API for transforms will no longer be needed afer all changes, so remove
it to simplify the API and fallback implementation.
Ref D10271
Display Transforms
==================
Needs a bit more manual work constructing the transform. LegacyViewingPipeline
could also have been used, but isn't really any simpler and since it's legacy
we better not rely on it.
We moved more logic into the opencolorio module, to simplify the API. There is
no need to wrap a dozen functions just to be able to do this in C rather than C++.
It's also tightly coupled to the GPU shader logic, and so should be in the same
module.
Ref D10271
GPU Display Shader
==================
To avoid baking exposure and gamma into the GLSL shader and requiring slow
recompiles when tweaking, we manually apply them in the shader. This leads
to some logic duplicaton between the CPU and GPU display processor, but it
seems unavoidable.
Caching was also changed. Previously this was done both on the imbuf and
opencolorio module levels. Now it's all done in the opencolorio module by
simply matching color space names. We no longer use cacheIDs from OpenColorIO
since computing them is expensive, and they are unlikely to match now that
more is baked into the shader code.
Shaders can now use multiple 2D textures, 3D textures and uniforms, rather
than a single 3D texture. So allocating and binding those adds some code.
Color space conversions for blending with overlays is now hardcoded in the
shader. This was using harcoded numbers anyway, if this every becomes a
general OpenColorIO transform it can be changed, but for now there is no
point to add code complexity.
Ref D10273
CIE XYZ
=======
We need standard CIE XYZ values for rendering effects like blackbody emission.
The relation to the scene linear role is based on OpenColorIO configuration.
In OpenColorIO 2.0 configs roles can no longer have the same name as color
spaces, which means our XYZ role and colorspace in the configuration give an
error.
Instead use the new standard aces_interchange role, which relates scene linear
to a known scene referred color space. Compatibility with the old XYZ role is
preserved, if the configuration file has no conflicting names.
Also includes a non-functional change to the configuraton file to use an
XYZ-to-ACES matrix instead of REC709-to-ACES, makes debugging a little easier
since the matrix is the same one we have in the code now and that is also
found easily in the ACES specs.
Ref D10274
2021-01-31 19:35:00 +01:00
|
|
|
init_xyz_transforms();
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-26 17:53:59 +01:00
|
|
|
ShaderManager::~ShaderManager() = default;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
unique_ptr<ShaderManager> ShaderManager::create(const int shadingsystem)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-29 23:13:45 +01:00
|
|
|
unique_ptr<ShaderManager> manager;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2018-11-09 12:08:51 +01:00
|
|
|
(void)shadingsystem; /* Ignored when built without OSL. */
|
2015-03-27 19:09:41 +05:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
#ifdef WITH_OSL
|
2017-05-20 05:21:27 -07:00
|
|
|
if (shadingsystem == SHADINGSYSTEM_OSL) {
|
2025-03-04 17:27:10 +01:00
|
|
|
manager = make_unique<OSLShaderManager>();
|
2017-05-20 05:21:27 -07:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
else
|
|
|
|
|
#endif
|
2017-05-20 05:21:27 -07:00
|
|
|
{
|
2024-12-29 23:13:45 +01:00
|
|
|
manager = make_unique<SVMShaderManager>();
|
2017-05-20 05:21:27 -07:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
return manager;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-09 11:55:35 +02:00
|
|
|
uint64_t ShaderManager::get_attribute_id(ustring name)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
const thread_scoped_spin_lock lock(attribute_lock_);
|
2017-04-10 16:53:01 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* get a unique id for each name, for SVM attribute lookup */
|
2024-12-29 17:32:00 +01:00
|
|
|
const AttributeIDMap::iterator it = unique_attribute_id.find(name);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (it != unique_attribute_id.end()) {
|
2011-04-27 11:58:34 +00:00
|
|
|
return it->second;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
const uint64_t id = ATTR_STD_NUM + unique_attribute_id.size();
|
2011-04-27 11:58:34 +00:00
|
|
|
unique_attribute_id[name] = id;
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-09 11:55:35 +02:00
|
|
|
uint64_t ShaderManager::get_attribute_id(AttributeStandard std)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2022-09-09 11:55:35 +02:00
|
|
|
return (uint64_t)std;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-16 19:42:08 -04:00
|
|
|
int ShaderManager::get_shader_id(Shader *shader, bool smooth)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
/* get a shader id to pass to the kernel */
|
2016-08-16 19:42:08 -04:00
|
|
|
int id = shader->id;
|
|
|
|
|
|
2011-09-27 20:37:24 +00:00
|
|
|
/* smooth flag */
|
2023-09-17 09:01:48 +10:00
|
|
|
if (smooth) {
|
2011-09-27 20:37:24 +00:00
|
|
|
id |= SHADER_SMOOTH_NORMAL;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2011-09-27 20:37:24 +00:00
|
|
|
/* default flags */
|
|
|
|
|
id |= SHADER_CAST_SHADOW | SHADER_AREA_LIGHT;
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-11 19:14:14 +02:00
|
|
|
void ShaderManager::device_update_pre(Device *device,
|
|
|
|
|
DeviceScene *dscene,
|
|
|
|
|
Scene *scene,
|
|
|
|
|
Progress &progress)
|
2012-10-30 11:51:17 +00:00
|
|
|
{
|
2025-04-11 19:14:14 +02:00
|
|
|
/* This runs before kernels have been loaded, so can't copy to device yet. */
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 15:01:26 +01:00
|
|
|
if (!need_update()) {
|
2020-03-11 17:49:00 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-14 14:50:03 +02:00
|
|
|
uint id = 0;
|
2024-12-26 19:41:25 +01:00
|
|
|
for (Shader *shader : scene->shaders) {
|
2016-05-14 14:50:03 +02:00
|
|
|
shader->id = id++;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-06-02 17:13:56 -04:00
|
|
|
/* Those shaders should always be compiled as they are used as a fallback if a shader cannot be
|
2021-05-02 02:34:56 +02:00
|
|
|
* found, e.g. bad shader index for the triangle shaders on a Mesh. */
|
|
|
|
|
assert(scene->default_surface->reference_count() != 0);
|
|
|
|
|
assert(scene->default_light->reference_count() != 0);
|
|
|
|
|
assert(scene->default_background->reference_count() != 0);
|
|
|
|
|
assert(scene->default_empty->reference_count() != 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-05-02 02:34:56 +02:00
|
|
|
device_update_specific(device, dscene, scene, progress);
|
2012-10-30 11:51:17 +00:00
|
|
|
}
|
|
|
|
|
|
2025-04-11 19:14:14 +02:00
|
|
|
void ShaderManager::device_update_post(Device * /*device*/,
|
|
|
|
|
DeviceScene *dscene,
|
|
|
|
|
Scene * /*scene*/,
|
|
|
|
|
Progress & /*progress*/)
|
|
|
|
|
{
|
|
|
|
|
/* This runs after kernels have been loaded, so can copy to device. */
|
|
|
|
|
dscene->shaders.copy_to_device_if_modified();
|
|
|
|
|
dscene->svm_nodes.copy_to_device_if_modified();
|
|
|
|
|
}
|
|
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
void ShaderManager::device_update_common(Device * /*device*/,
|
2015-03-27 15:47:55 +05:00
|
|
|
DeviceScene *dscene,
|
|
|
|
|
Scene *scene,
|
|
|
|
|
Progress & /*progress*/)
|
2011-09-27 20:37:24 +00:00
|
|
|
{
|
2018-03-08 00:35:24 +01:00
|
|
|
dscene->shaders.free();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 17:53:59 +01:00
|
|
|
if (scene->shaders.empty()) {
|
2011-09-27 20:37:24 +00:00
|
|
|
return;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-03-08 00:35:24 +01:00
|
|
|
KernelShader *kshader = dscene->shaders.alloc(scene->shaders.size());
|
2013-12-28 02:27:48 +01:00
|
|
|
bool has_volumes = false;
|
2015-09-08 11:28:02 +05:00
|
|
|
bool has_transparent_shadow = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 19:41:25 +01:00
|
|
|
for (Shader *shader : scene->shaders) {
|
2011-09-27 20:37:24 +00:00
|
|
|
uint flag = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-11-30 20:50:11 +01:00
|
|
|
if (shader->emission_sampling == EMISSION_SAMPLING_FRONT) {
|
|
|
|
|
flag |= SD_MIS_FRONT;
|
|
|
|
|
}
|
|
|
|
|
else if (shader->emission_sampling == EMISSION_SAMPLING_BACK) {
|
|
|
|
|
flag |= SD_MIS_BACK;
|
|
|
|
|
}
|
|
|
|
|
else if (shader->emission_sampling == EMISSION_SAMPLING_FRONT_BACK) {
|
|
|
|
|
flag |= SD_MIS_FRONT | SD_MIS_BACK;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!is_zero(shader->emission_estimate)) {
|
2021-04-15 16:21:37 +02:00
|
|
|
flag |= SD_HAS_EMISSION;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (shader->has_surface_transparent && shader->get_use_transparent_shadow()) {
|
2013-06-18 09:36:00 +00:00
|
|
|
flag |= SD_HAS_TRANSPARENT_SHADOW;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (shader->has_surface_raytrace) {
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
flag |= SD_HAS_RAYTRACE;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2013-12-28 02:27:48 +01:00
|
|
|
if (shader->has_volume) {
|
2011-09-27 20:37:24 +00:00
|
|
|
flag |= SD_HAS_VOLUME;
|
2013-12-28 02:27:48 +01:00
|
|
|
has_volumes = true;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-12-28 02:27:48 +01:00
|
|
|
/* todo: this could check more fine grained, to skip useless volumes
|
2015-09-08 11:29:14 +05:00
|
|
|
* enclosed inside an opaque bsdf.
|
|
|
|
|
*/
|
2013-12-28 02:27:48 +01:00
|
|
|
flag |= SD_HAS_TRANSPARENT_SHADOW;
|
|
|
|
|
}
|
2017-05-19 04:59:35 +02:00
|
|
|
/* in this case we can assume transparent surface */
|
2023-09-17 09:01:48 +10:00
|
|
|
if (shader->has_volume_connected && !shader->has_surface) {
|
2017-05-19 04:59:35 +02:00
|
|
|
flag |= SD_HAS_ONLY_VOLUME;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2020-03-07 14:38:52 +01:00
|
|
|
if (shader->has_volume) {
|
2023-09-17 09:01:48 +10:00
|
|
|
if (shader->get_heterogeneous_volume() && shader->has_volume_spatial_varying) {
|
2020-03-07 14:38:52 +01:00
|
|
|
flag |= SD_HETEROGENEOUS_VOLUME;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2020-03-07 14:38:52 +01:00
|
|
|
}
|
2023-09-17 09:01:48 +10:00
|
|
|
if (shader->has_volume_attribute_dependency) {
|
2020-03-07 14:38:52 +01:00
|
|
|
flag |= SD_NEED_VOLUME_ATTRIBUTES;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (shader->has_bssrdf_bump) {
|
2013-08-18 14:15:57 +00:00
|
|
|
flag |= SD_HAS_BSSRDF_BUMP;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (shader->get_volume_sampling_method() == VOLUME_SAMPLING_EQUIANGULAR) {
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
flag |= SD_VOLUME_EQUIANGULAR;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (shader->get_volume_sampling_method() == VOLUME_SAMPLING_MULTIPLE_IMPORTANCE) {
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
flag |= SD_VOLUME_MIS;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (shader->get_volume_interpolation_method() == VOLUME_INTERPOLATION_CUBIC) {
|
2014-10-22 19:23:45 +06:00
|
|
|
flag |= SD_VOLUME_CUBIC;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (shader->has_bump) {
|
2014-11-11 18:21:56 -02:00
|
|
|
flag |= SD_HAS_BUMP;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (shader->get_displacement_method() != DISPLACE_BUMP) {
|
2016-08-14 11:44:25 -04:00
|
|
|
flag |= SD_HAS_DISPLACEMENT;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2023-10-11 15:07:21 +02:00
|
|
|
if (shader->get_use_bump_map_correction()) {
|
|
|
|
|
flag |= SD_USE_BUMP_MAP_CORRECTION;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-09-14 18:53:35 +02:00
|
|
|
/* constant emission check */
|
2023-09-17 09:01:48 +10:00
|
|
|
if (shader->emission_is_constant) {
|
2016-09-14 18:53:35 +02:00
|
|
|
flag |= SD_HAS_CONSTANT_EMISSION;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
const uint32_t cryptomatte_id = util_murmur_hash3(
|
|
|
|
|
shader->name.c_str(), shader->name.length(), 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-08-16 19:42:08 -04:00
|
|
|
/* regular shader */
|
2018-03-08 00:35:24 +01:00
|
|
|
kshader->flags = flag;
|
2020-11-04 11:17:38 +01:00
|
|
|
kshader->pass_id = shader->get_pass_id();
|
2022-11-30 20:50:11 +01:00
|
|
|
kshader->constant_emission[0] = shader->emission_estimate.x;
|
|
|
|
|
kshader->constant_emission[1] = shader->emission_estimate.y;
|
|
|
|
|
kshader->constant_emission[2] = shader->emission_estimate.z;
|
2018-10-28 05:37:41 -04:00
|
|
|
kshader->cryptomatte_id = util_hash_to_float(cryptomatte_id);
|
2018-03-08 00:35:24 +01:00
|
|
|
kshader++;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-01-07 11:45:13 +05:00
|
|
|
has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
|
2011-09-27 20:37:24 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: Remove MultiGGX code, replace with albedo scaling
While the multiscattering GGX code is cool and solves the darkening problem at higher roughnesses, it's also currently buggy, hard to maintain and often impractical to use due to the higher noise and render time.
In practice, though, having the exact correct directional distribution is not that important as long as the overall albedo is correct and we a) don't get the darkening effect and b) do get the saturation effect at higher roughnesses.
This can simply be achieved by adding a second lobe (https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) or scaling the single-scattering GGX lobe (https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf). Both approaches require the same precomputation and produce outputs of comparable quality, so I went for the simple albedo scaling since it's easier to implement and more efficient.
Overall, the results are pretty good: All scenarios that I tested (Glossy BSDF, Glass BSDF, Principled BSDF with metallic or transmissive = 1) pass the white furnace test (a material with pure-white color in front of a pure-white background should be indistinguishable from the background if it preserves energy), and the overall albedo for non-white materials matches that produced by the real multi-scattering code (with the expected saturation increase as the roughness increases).
In order to produce the precomputed tables, the PR also includes a utility that computes them. This is not built by default, since there's no reason for a user to run it (it only makes sense for documentation/reproducibility purposes and when making changes to the microfacet models).
Pull Request: https://projects.blender.org/blender/blender/pulls/107958
2023-06-05 02:20:57 +02:00
|
|
|
/* lookup tables */
|
|
|
|
|
KernelTables *ktables = &dscene->data.tables;
|
|
|
|
|
ktables->ggx_E = ensure_bsdf_table(dscene, scene, table_ggx_E);
|
|
|
|
|
ktables->ggx_Eavg = ensure_bsdf_table(dscene, scene, table_ggx_Eavg);
|
|
|
|
|
ktables->ggx_glass_E = ensure_bsdf_table(dscene, scene, table_ggx_glass_E);
|
|
|
|
|
ktables->ggx_glass_Eavg = ensure_bsdf_table(dscene, scene, table_ggx_glass_Eavg);
|
|
|
|
|
ktables->ggx_glass_inv_E = ensure_bsdf_table(dscene, scene, table_ggx_glass_inv_E);
|
|
|
|
|
ktables->ggx_glass_inv_Eavg = ensure_bsdf_table(dscene, scene, table_ggx_glass_inv_Eavg);
|
2023-07-24 15:36:36 +02:00
|
|
|
ktables->sheen_ltc = ensure_bsdf_table(dscene, scene, table_sheen_ltc);
|
2023-08-10 23:53:37 +02:00
|
|
|
ktables->ggx_gen_schlick_ior_s = ensure_bsdf_table(dscene, scene, table_ggx_gen_schlick_ior_s);
|
|
|
|
|
ktables->ggx_gen_schlick_s = ensure_bsdf_table(dscene, scene, table_ggx_gen_schlick_s);
|
Cycles: Remove MultiGGX code, replace with albedo scaling
While the multiscattering GGX code is cool and solves the darkening problem at higher roughnesses, it's also currently buggy, hard to maintain and often impractical to use due to the higher noise and render time.
In practice, though, having the exact correct directional distribution is not that important as long as the overall albedo is correct and we a) don't get the darkening effect and b) do get the saturation effect at higher roughnesses.
This can simply be achieved by adding a second lobe (https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) or scaling the single-scattering GGX lobe (https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf). Both approaches require the same precomputation and produce outputs of comparable quality, so I went for the simple albedo scaling since it's easier to implement and more efficient.
Overall, the results are pretty good: All scenarios that I tested (Glossy BSDF, Glass BSDF, Principled BSDF with metallic or transmissive = 1) pass the white furnace test (a material with pure-white color in front of a pure-white background should be indistinguishable from the background if it preserves energy), and the overall albedo for non-white materials matches that produced by the real multi-scattering code (with the expected saturation increase as the roughness increases).
In order to produce the precomputed tables, the PR also includes a utility that computes them. This is not built by default, since there's no reason for a user to run it (it only makes sense for documentation/reproducibility purposes and when making changes to the microfacet models).
Pull Request: https://projects.blender.org/blender/blender/pulls/107958
2023-06-05 02:20:57 +02:00
|
|
|
|
Cycles: Replace thin-film basis function approximation with accurate LUTs
Previously, we used precomputed Gaussian fits to the XYZ CMFs, performed
the spectral integration in that space, and then converted the result
to the RGB working space.
That worked because we're only supporting dielectric base layers for
the thin film code, so the inputs to the spectral integration
(reflectivity and phase) are both constant w.r.t. wavelength.
However, this will no longer work for conductive base layers.
We could handle reflectivity by converting to XYZ, but that won't work
for phase since its effect on the output is nonlinear.
Therefore, it's time to do this properly by performing the spectral
integration directly in the RGB primaries. To do this, we need to:
- Compute the RGB CMFs from the XYZ CMFs and XYZ-to-RGB matrix
- Resample the RGB CMFs to be parametrized by frequency instead of wavelength
- Compute the FFT of the CMFs
- Store it as a LUT to be used by the kernel code
However, there's two optimizations we can make:
- Both the resampling and the FFT are linear operations, as is the
XYZ-to-RGB conversion. Therefore, we can resample and Fourier-transform
the XYZ CMFs once, store the result in a precomputed table, and then just
multiply the entries by the XYZ-to-RGB matrix at runtime.
- I've included the Python script used to compute the table under
`intern/cycles/doc/precompute`.
- The reference implementation by the paper authors [1] simply stores the
real and imaginary parts in the LUT, and then computes
`cos(shift)*real + sin(shift)*imag`. However, the real and imaginary parts
are oscillating, so the LUT with linear interpolation is not particularly
good at representing them. Instead, we can convert the table to
Magnitude/Phase representation, which is much smoother, and do
`mag * cos(phase - shift)` in the kernel.
- Phase needs to be unwrapped to handle the interpolation decently,
but that's easy.
- This requires an extra trig operation in the kernel in the dielectric case,
but for the conductive case we'll actually save three.
Rendered output is mostly the same, just slightly different because we're
no longer using the Gaussian approximation.
[1] "A Practical Extension to Microfacet Theory for the Modeling of
Varying Iridescence" by Laurent Belcour and Pascal Barla,
https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html
Pull Request: https://projects.blender.org/blender/blender/pulls/140944
2025-07-09 22:10:28 +02:00
|
|
|
if (thin_film_table_offset_ == TABLE_OFFSET_INVALID) {
|
|
|
|
|
thin_film_table_offset_ = scene->lookup_tables->add_table(dscene, thin_film_table);
|
|
|
|
|
}
|
|
|
|
|
dscene->data.tables.thin_film_table = (int)thin_film_table_offset_;
|
|
|
|
|
|
2014-06-01 07:11:13 +02:00
|
|
|
/* integrator */
|
2013-12-28 02:27:48 +01:00
|
|
|
KernelIntegrator *kintegrator = &dscene->data.integrator;
|
|
|
|
|
kintegrator->use_volumes = has_volumes;
|
2015-09-08 11:28:02 +05:00
|
|
|
/* TODO(sergey): De-duplicate with flags set in integrator.cpp. */
|
2017-08-02 15:23:50 +02:00
|
|
|
kintegrator->transparent_shadows = has_transparent_shadow;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-14 17:48:19 +02:00
|
|
|
/* film */
|
|
|
|
|
KernelFilm *kfilm = &dscene->data.film;
|
|
|
|
|
/* color space, needs to be here because e.g. displacement shaders could depend on it */
|
2024-12-19 09:41:55 +01:00
|
|
|
kfilm->xyz_to_r = make_float4(xyz_to_r);
|
|
|
|
|
kfilm->xyz_to_g = make_float4(xyz_to_g);
|
|
|
|
|
kfilm->xyz_to_b = make_float4(xyz_to_b);
|
|
|
|
|
kfilm->rgb_to_y = make_float4(rgb_to_y);
|
|
|
|
|
kfilm->white_xyz = make_float4(white_xyz);
|
|
|
|
|
kfilm->rec709_to_r = make_float4(rec709_to_r);
|
|
|
|
|
kfilm->rec709_to_g = make_float4(rec709_to_g);
|
|
|
|
|
kfilm->rec709_to_b = make_float4(rec709_to_b);
|
2022-03-22 20:41:46 +01:00
|
|
|
kfilm->is_rec709 = is_rec709;
|
2011-09-27 20:37:24 +00:00
|
|
|
}
|
|
|
|
|
|
Cycles: Remove MultiGGX code, replace with albedo scaling
While the multiscattering GGX code is cool and solves the darkening problem at higher roughnesses, it's also currently buggy, hard to maintain and often impractical to use due to the higher noise and render time.
In practice, though, having the exact correct directional distribution is not that important as long as the overall albedo is correct and we a) don't get the darkening effect and b) do get the saturation effect at higher roughnesses.
This can simply be achieved by adding a second lobe (https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) or scaling the single-scattering GGX lobe (https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf). Both approaches require the same precomputation and produce outputs of comparable quality, so I went for the simple albedo scaling since it's easier to implement and more efficient.
Overall, the results are pretty good: All scenarios that I tested (Glossy BSDF, Glass BSDF, Principled BSDF with metallic or transmissive = 1) pass the white furnace test (a material with pure-white color in front of a pure-white background should be indistinguishable from the background if it preserves energy), and the overall albedo for non-white materials matches that produced by the real multi-scattering code (with the expected saturation increase as the roughness increases).
In order to produce the precomputed tables, the PR also includes a utility that computes them. This is not built by default, since there's no reason for a user to run it (it only makes sense for documentation/reproducibility purposes and when making changes to the microfacet models).
Pull Request: https://projects.blender.org/blender/blender/pulls/107958
2023-06-05 02:20:57 +02:00
|
|
|
void ShaderManager::device_free_common(Device * /*device*/, DeviceScene *dscene, Scene *scene)
|
2011-09-27 20:37:24 +00:00
|
|
|
{
|
Cycles: Remove MultiGGX code, replace with albedo scaling
While the multiscattering GGX code is cool and solves the darkening problem at higher roughnesses, it's also currently buggy, hard to maintain and often impractical to use due to the higher noise and render time.
In practice, though, having the exact correct directional distribution is not that important as long as the overall albedo is correct and we a) don't get the darkening effect and b) do get the saturation effect at higher roughnesses.
This can simply be achieved by adding a second lobe (https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) or scaling the single-scattering GGX lobe (https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf). Both approaches require the same precomputation and produce outputs of comparable quality, so I went for the simple albedo scaling since it's easier to implement and more efficient.
Overall, the results are pretty good: All scenarios that I tested (Glossy BSDF, Glass BSDF, Principled BSDF with metallic or transmissive = 1) pass the white furnace test (a material with pure-white color in front of a pure-white background should be indistinguishable from the background if it preserves energy), and the overall albedo for non-white materials matches that produced by the real multi-scattering code (with the expected saturation increase as the roughness increases).
In order to produce the precomputed tables, the PR also includes a utility that computes them. This is not built by default, since there's no reason for a user to run it (it only makes sense for documentation/reproducibility purposes and when making changes to the microfacet models).
Pull Request: https://projects.blender.org/blender/blender/pulls/107958
2023-06-05 02:20:57 +02:00
|
|
|
for (auto &entry : bsdf_tables) {
|
|
|
|
|
scene->lookup_tables->remove_table(&entry.second);
|
|
|
|
|
}
|
|
|
|
|
bsdf_tables.clear();
|
Cycles: Replace thin-film basis function approximation with accurate LUTs
Previously, we used precomputed Gaussian fits to the XYZ CMFs, performed
the spectral integration in that space, and then converted the result
to the RGB working space.
That worked because we're only supporting dielectric base layers for
the thin film code, so the inputs to the spectral integration
(reflectivity and phase) are both constant w.r.t. wavelength.
However, this will no longer work for conductive base layers.
We could handle reflectivity by converting to XYZ, but that won't work
for phase since its effect on the output is nonlinear.
Therefore, it's time to do this properly by performing the spectral
integration directly in the RGB primaries. To do this, we need to:
- Compute the RGB CMFs from the XYZ CMFs and XYZ-to-RGB matrix
- Resample the RGB CMFs to be parametrized by frequency instead of wavelength
- Compute the FFT of the CMFs
- Store it as a LUT to be used by the kernel code
However, there's two optimizations we can make:
- Both the resampling and the FFT are linear operations, as is the
XYZ-to-RGB conversion. Therefore, we can resample and Fourier-transform
the XYZ CMFs once, store the result in a precomputed table, and then just
multiply the entries by the XYZ-to-RGB matrix at runtime.
- I've included the Python script used to compute the table under
`intern/cycles/doc/precompute`.
- The reference implementation by the paper authors [1] simply stores the
real and imaginary parts in the LUT, and then computes
`cos(shift)*real + sin(shift)*imag`. However, the real and imaginary parts
are oscillating, so the LUT with linear interpolation is not particularly
good at representing them. Instead, we can convert the table to
Magnitude/Phase representation, which is much smoother, and do
`mag * cos(phase - shift)` in the kernel.
- Phase needs to be unwrapped to handle the interpolation decently,
but that's easy.
- This requires an extra trig operation in the kernel in the dielectric case,
but for the conductive case we'll actually save three.
Rendered output is mostly the same, just slightly different because we're
no longer using the Gaussian approximation.
[1] "A Practical Extension to Microfacet Theory for the Modeling of
Varying Iridescence" by Laurent Belcour and Pascal Barla,
https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html
Pull Request: https://projects.blender.org/blender/blender/pulls/140944
2025-07-09 22:10:28 +02:00
|
|
|
scene->lookup_tables->remove_table(&thin_film_table_offset_);
|
|
|
|
|
thin_film_table_offset_ = TABLE_OFFSET_INVALID;
|
Cycles: Remove MultiGGX code, replace with albedo scaling
While the multiscattering GGX code is cool and solves the darkening problem at higher roughnesses, it's also currently buggy, hard to maintain and often impractical to use due to the higher noise and render time.
In practice, though, having the exact correct directional distribution is not that important as long as the overall albedo is correct and we a) don't get the darkening effect and b) do get the saturation effect at higher roughnesses.
This can simply be achieved by adding a second lobe (https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) or scaling the single-scattering GGX lobe (https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf). Both approaches require the same precomputation and produce outputs of comparable quality, so I went for the simple albedo scaling since it's easier to implement and more efficient.
Overall, the results are pretty good: All scenarios that I tested (Glossy BSDF, Glass BSDF, Principled BSDF with metallic or transmissive = 1) pass the white furnace test (a material with pure-white color in front of a pure-white background should be indistinguishable from the background if it preserves energy), and the overall albedo for non-white materials matches that produced by the real multi-scattering code (with the expected saturation increase as the roughness increases).
In order to produce the precomputed tables, the PR also includes a utility that computes them. This is not built by default, since there's no reason for a user to run it (it only makes sense for documentation/reproducibility purposes and when making changes to the microfacet models).
Pull Request: https://projects.blender.org/blender/blender/pulls/107958
2023-06-05 02:20:57 +02:00
|
|
|
|
2018-03-08 00:35:24 +01:00
|
|
|
dscene->shaders.free();
|
2011-09-27 20:37:24 +00:00
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void ShaderManager::add_default(Scene *scene)
|
|
|
|
|
{
|
|
|
|
|
/* default surface */
|
|
|
|
|
{
|
2024-12-29 23:13:45 +01:00
|
|
|
unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
DiffuseBsdfNode *diffuse = graph->create_node<DiffuseBsdfNode>();
|
2020-11-04 11:17:38 +01:00
|
|
|
diffuse->set_color(make_float3(0.8f, 0.8f, 0.8f));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
graph->connect(diffuse->output("BSDF"), graph->output()->input("Surface"));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
Shader *shader = scene->create_node<Shader>();
|
2011-04-27 11:58:34 +00:00
|
|
|
shader->name = "default_surface";
|
2024-12-29 23:13:45 +01:00
|
|
|
shader->set_graph(std::move(graph));
|
2021-05-02 02:34:56 +02:00
|
|
|
shader->reference();
|
2016-05-14 14:50:03 +02:00
|
|
|
scene->default_surface = shader;
|
2020-03-11 17:49:00 +01:00
|
|
|
shader->tag_update(scene);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* default volume */
|
|
|
|
|
{
|
2024-12-29 23:13:45 +01:00
|
|
|
unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
|
2020-03-11 17:49:00 +01:00
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
PrincipledVolumeNode *principled = graph->create_node<PrincipledVolumeNode>();
|
2020-03-11 17:49:00 +01:00
|
|
|
|
|
|
|
|
graph->connect(principled->output("Volume"), graph->output()->input("Volume"));
|
|
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
Shader *shader = scene->create_node<Shader>();
|
2020-03-11 17:49:00 +01:00
|
|
|
shader->name = "default_volume";
|
2024-12-29 23:13:45 +01:00
|
|
|
shader->set_graph(std::move(graph));
|
2020-03-11 17:49:00 +01:00
|
|
|
scene->default_volume = shader;
|
|
|
|
|
shader->tag_update(scene);
|
2022-11-30 20:50:11 +01:00
|
|
|
/* No default reference for the volume to avoid compiling volume kernels if there are no
|
|
|
|
|
* actual volumes in the scene */
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* default light */
|
|
|
|
|
{
|
2024-12-29 23:13:45 +01:00
|
|
|
unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
EmissionNode *emission = graph->create_node<EmissionNode>();
|
2020-11-04 11:17:38 +01:00
|
|
|
emission->set_color(make_float3(0.8f, 0.8f, 0.8f));
|
|
|
|
|
emission->set_strength(0.0f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
graph->connect(emission->output("Emission"), graph->output()->input("Surface"));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
Shader *shader = scene->create_node<Shader>();
|
2011-04-27 11:58:34 +00:00
|
|
|
shader->name = "default_light";
|
2024-12-29 23:13:45 +01:00
|
|
|
shader->set_graph(std::move(graph));
|
2021-05-02 02:34:56 +02:00
|
|
|
shader->reference();
|
2016-05-14 14:50:03 +02:00
|
|
|
scene->default_light = shader;
|
2020-03-11 17:49:00 +01:00
|
|
|
shader->tag_update(scene);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* default background */
|
|
|
|
|
{
|
2024-12-29 23:13:45 +01:00
|
|
|
unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
Shader *shader = scene->create_node<Shader>();
|
2011-04-27 11:58:34 +00:00
|
|
|
shader->name = "default_background";
|
2024-12-29 23:13:45 +01:00
|
|
|
shader->set_graph(std::move(graph));
|
2021-05-02 02:34:56 +02:00
|
|
|
shader->reference();
|
2016-05-14 14:50:03 +02:00
|
|
|
scene->default_background = shader;
|
2020-03-11 17:49:00 +01:00
|
|
|
shader->tag_update(scene);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-13 12:58:12 +00:00
|
|
|
/* default empty */
|
|
|
|
|
{
|
2024-12-29 23:13:45 +01:00
|
|
|
unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
Shader *shader = scene->create_node<Shader>();
|
2012-04-13 12:58:12 +00:00
|
|
|
shader->name = "default_empty";
|
2024-12-29 23:13:45 +01:00
|
|
|
shader->set_graph(std::move(graph));
|
2021-05-02 02:34:56 +02:00
|
|
|
shader->reference();
|
2016-05-14 14:50:03 +02:00
|
|
|
scene->default_empty = shader;
|
2020-03-11 17:49:00 +01:00
|
|
|
shader->tag_update(scene);
|
2012-04-13 12:58:12 +00:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
uint ShaderManager::get_graph_kernel_features(ShaderGraph *graph)
|
2015-06-01 15:52:00 +05:00
|
|
|
{
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
uint kernel_features = 0;
|
|
|
|
|
|
2024-12-26 19:41:25 +01:00
|
|
|
for (ShaderNode *node : graph->nodes) {
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
kernel_features |= node->get_feature();
|
2015-06-01 15:52:00 +05:00
|
|
|
if (node->special_type == SHADER_SPECIAL_TYPE_CLOSURE) {
|
2019-01-18 02:56:59 +01:00
|
|
|
BsdfBaseNode *bsdf_node = static_cast<BsdfBaseNode *>(node);
|
2020-11-04 11:17:38 +01:00
|
|
|
if (CLOSURE_IS_VOLUME(bsdf_node->get_closure_type())) {
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
kernel_features |= KERNEL_FEATURE_NODE_VOLUME;
|
2015-06-01 15:52:00 +05:00
|
|
|
}
|
|
|
|
|
}
|
2015-11-21 22:31:58 +05:00
|
|
|
if (node->has_surface_bssrdf()) {
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
kernel_features |= KERNEL_FEATURE_SUBSURFACE;
|
2015-11-21 22:31:58 +05:00
|
|
|
}
|
2016-12-09 08:28:04 -07:00
|
|
|
if (node->has_surface_transparent()) {
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
kernel_features |= KERNEL_FEATURE_TRANSPARENT;
|
2017-10-30 20:25:08 +01:00
|
|
|
}
|
2015-06-01 15:52:00 +05:00
|
|
|
}
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
|
|
|
|
|
return kernel_features;
|
2015-06-01 15:52:00 +05:00
|
|
|
}
|
|
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
uint ShaderManager::get_kernel_features(Scene *scene)
|
2015-05-09 19:22:16 +05:00
|
|
|
{
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
uint kernel_features = KERNEL_FEATURE_NODE_BSDF | KERNEL_FEATURE_NODE_EMISSION;
|
2015-05-09 19:22:16 +05:00
|
|
|
for (int i = 0; i < scene->shaders.size(); i++) {
|
|
|
|
|
Shader *shader = scene->shaders[i];
|
2021-05-02 02:34:56 +02:00
|
|
|
if (!shader->reference_count()) {
|
2020-03-11 17:49:00 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-01 15:26:36 +05:00
|
|
|
/* Gather requested features from all the nodes from the graph nodes. */
|
2024-12-29 23:13:45 +01:00
|
|
|
kernel_features |= get_graph_kernel_features(shader->graph.get());
|
2015-06-01 15:26:36 +05:00
|
|
|
ShaderNode *output_node = shader->graph->output();
|
2024-12-26 17:53:55 +01:00
|
|
|
if (output_node->input("Displacement")->link != nullptr) {
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
kernel_features |= KERNEL_FEATURE_NODE_BUMP;
|
2020-11-04 11:17:38 +01:00
|
|
|
if (shader->get_displacement_method() == DISPLACE_BOTH) {
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
kernel_features |= KERNEL_FEATURE_NODE_BUMP_STATE;
|
2016-09-08 01:33:41 +02:00
|
|
|
}
|
2015-06-01 15:26:36 +05:00
|
|
|
}
|
2016-05-06 23:11:41 +02:00
|
|
|
/* On top of volume nodes, also check if we need volume sampling because
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
* e.g. an Emission node would slip through the KERNEL_FEATURE_NODE_VOLUME check */
|
2021-09-22 17:05:44 +02:00
|
|
|
if (shader->has_volume_connected) {
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
kernel_features |= KERNEL_FEATURE_VOLUME;
|
|
|
|
|
}
|
2015-05-09 19:22:16 +05:00
|
|
|
}
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
|
2022-11-09 14:25:32 +01:00
|
|
|
if (use_osl()) {
|
2025-04-25 19:27:30 +02:00
|
|
|
kernel_features |= KERNEL_FEATURE_OSL_SHADING;
|
2022-11-09 14:25:32 +01:00
|
|
|
}
|
|
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
return kernel_features;
|
2015-05-09 19:22:16 +05:00
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
float ShaderManager::linear_rgb_to_gray(const float3 c)
|
2018-06-14 17:48:19 +02:00
|
|
|
{
|
|
|
|
|
return dot(c, rgb_to_y);
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
float3 ShaderManager::rec709_to_scene_linear(const float3 c)
|
2022-03-22 20:41:46 +01:00
|
|
|
{
|
2024-10-07 02:18:49 +02:00
|
|
|
return to_local(c, rec709_to_r, rec709_to_g, rec709_to_b);
|
2022-03-22 20:41:46 +01:00
|
|
|
}
|
|
|
|
|
|
2018-11-07 04:05:47 +01:00
|
|
|
string ShaderManager::get_cryptomatte_materials(Scene *scene)
|
|
|
|
|
{
|
|
|
|
|
string manifest = "{";
|
2024-10-17 19:48:38 +02:00
|
|
|
unordered_set<ustring> materials;
|
2024-12-26 19:41:25 +01:00
|
|
|
for (Shader *shader : scene->shaders) {
|
2018-11-07 04:05:47 +01:00
|
|
|
if (materials.count(shader->name)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
materials.insert(shader->name);
|
2024-12-29 17:32:00 +01:00
|
|
|
const uint32_t cryptomatte_id = util_murmur_hash3(
|
|
|
|
|
shader->name.c_str(), shader->name.length(), 0);
|
2018-11-07 04:05:47 +01:00
|
|
|
manifest += string_printf("\"%s\":\"%08x\",", shader->name.c_str(), cryptomatte_id);
|
|
|
|
|
}
|
|
|
|
|
manifest[manifest.size() - 1] = '}';
|
|
|
|
|
return manifest;
|
|
|
|
|
}
|
|
|
|
|
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 15:01:26 +01:00
|
|
|
void ShaderManager::tag_update(Scene * /*scene*/, uint32_t /*flag*/)
|
|
|
|
|
{
|
|
|
|
|
/* update everything for now */
|
|
|
|
|
update_flags = ShaderManager::UPDATE_ALL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ShaderManager::need_update() const
|
|
|
|
|
{
|
|
|
|
|
return update_flags != UPDATE_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
OpenColorIO: upgrade to version 2.0.0
Ref T84819
Build System
============
This is an API breaking new version, and the updated code only builds with
OpenColorIO 2.0 and later. Adding backwards compatibility was too complicated.
* Tinyxml was replaced with Expat, adding a new dependency.
* Yaml-cpp is now built as a dependency on Unix, as was already done on Windows.
* Removed currently unused LCMS code.
* Pystring remains built as part of OCIO itself, since it has no good build system.
* Linux and macOS check for the OpenColorIO verison, and disable it if too old.
Ref D10270
Processors and Transforms
=========================
CPU processors now need to be created to do CPU processing. These are cached
internally, but the cache lookup is not fast enough to execute per pixel or
texture sample, so for performance these are now also exposed in the C API.
The C API for transforms will no longer be needed afer all changes, so remove
it to simplify the API and fallback implementation.
Ref D10271
Display Transforms
==================
Needs a bit more manual work constructing the transform. LegacyViewingPipeline
could also have been used, but isn't really any simpler and since it's legacy
we better not rely on it.
We moved more logic into the opencolorio module, to simplify the API. There is
no need to wrap a dozen functions just to be able to do this in C rather than C++.
It's also tightly coupled to the GPU shader logic, and so should be in the same
module.
Ref D10271
GPU Display Shader
==================
To avoid baking exposure and gamma into the GLSL shader and requiring slow
recompiles when tweaking, we manually apply them in the shader. This leads
to some logic duplicaton between the CPU and GPU display processor, but it
seems unavoidable.
Caching was also changed. Previously this was done both on the imbuf and
opencolorio module levels. Now it's all done in the opencolorio module by
simply matching color space names. We no longer use cacheIDs from OpenColorIO
since computing them is expensive, and they are unlikely to match now that
more is baked into the shader code.
Shaders can now use multiple 2D textures, 3D textures and uniforms, rather
than a single 3D texture. So allocating and binding those adds some code.
Color space conversions for blending with overlays is now hardcoded in the
shader. This was using harcoded numbers anyway, if this every becomes a
general OpenColorIO transform it can be changed, but for now there is no
point to add code complexity.
Ref D10273
CIE XYZ
=======
We need standard CIE XYZ values for rendering effects like blackbody emission.
The relation to the scene linear role is based on OpenColorIO configuration.
In OpenColorIO 2.0 configs roles can no longer have the same name as color
spaces, which means our XYZ role and colorspace in the configuration give an
error.
Instead use the new standard aces_interchange role, which relates scene linear
to a known scene referred color space. Compatibility with the old XYZ role is
preserved, if the configuration file has no conflicting names.
Also includes a non-functional change to the configuraton file to use an
XYZ-to-ACES matrix instead of REC709-to-ACES, makes debugging a little easier
since the matrix is the same one we have in the code now and that is also
found easily in the ACES specs.
Ref D10274
2021-01-31 19:35:00 +01:00
|
|
|
#ifdef WITH_OCIO
|
|
|
|
|
static bool to_scene_linear_transform(OCIO::ConstConfigRcPtr &config,
|
|
|
|
|
const char *colorspace,
|
|
|
|
|
Transform &to_scene_linear)
|
|
|
|
|
{
|
|
|
|
|
OCIO::ConstProcessorRcPtr processor;
|
|
|
|
|
try {
|
2022-09-18 17:32:53 +02:00
|
|
|
processor = config->getProcessor("scene_linear", colorspace);
|
OpenColorIO: upgrade to version 2.0.0
Ref T84819
Build System
============
This is an API breaking new version, and the updated code only builds with
OpenColorIO 2.0 and later. Adding backwards compatibility was too complicated.
* Tinyxml was replaced with Expat, adding a new dependency.
* Yaml-cpp is now built as a dependency on Unix, as was already done on Windows.
* Removed currently unused LCMS code.
* Pystring remains built as part of OCIO itself, since it has no good build system.
* Linux and macOS check for the OpenColorIO verison, and disable it if too old.
Ref D10270
Processors and Transforms
=========================
CPU processors now need to be created to do CPU processing. These are cached
internally, but the cache lookup is not fast enough to execute per pixel or
texture sample, so for performance these are now also exposed in the C API.
The C API for transforms will no longer be needed afer all changes, so remove
it to simplify the API and fallback implementation.
Ref D10271
Display Transforms
==================
Needs a bit more manual work constructing the transform. LegacyViewingPipeline
could also have been used, but isn't really any simpler and since it's legacy
we better not rely on it.
We moved more logic into the opencolorio module, to simplify the API. There is
no need to wrap a dozen functions just to be able to do this in C rather than C++.
It's also tightly coupled to the GPU shader logic, and so should be in the same
module.
Ref D10271
GPU Display Shader
==================
To avoid baking exposure and gamma into the GLSL shader and requiring slow
recompiles when tweaking, we manually apply them in the shader. This leads
to some logic duplicaton between the CPU and GPU display processor, but it
seems unavoidable.
Caching was also changed. Previously this was done both on the imbuf and
opencolorio module levels. Now it's all done in the opencolorio module by
simply matching color space names. We no longer use cacheIDs from OpenColorIO
since computing them is expensive, and they are unlikely to match now that
more is baked into the shader code.
Shaders can now use multiple 2D textures, 3D textures and uniforms, rather
than a single 3D texture. So allocating and binding those adds some code.
Color space conversions for blending with overlays is now hardcoded in the
shader. This was using harcoded numbers anyway, if this every becomes a
general OpenColorIO transform it can be changed, but for now there is no
point to add code complexity.
Ref D10273
CIE XYZ
=======
We need standard CIE XYZ values for rendering effects like blackbody emission.
The relation to the scene linear role is based on OpenColorIO configuration.
In OpenColorIO 2.0 configs roles can no longer have the same name as color
spaces, which means our XYZ role and colorspace in the configuration give an
error.
Instead use the new standard aces_interchange role, which relates scene linear
to a known scene referred color space. Compatibility with the old XYZ role is
preserved, if the configuration file has no conflicting names.
Also includes a non-functional change to the configuraton file to use an
XYZ-to-ACES matrix instead of REC709-to-ACES, makes debugging a little easier
since the matrix is the same one we have in the code now and that is also
found easily in the ACES specs.
Ref D10274
2021-01-31 19:35:00 +01:00
|
|
|
}
|
2021-02-18 08:09:08 -07:00
|
|
|
catch (OCIO::Exception &) {
|
OpenColorIO: upgrade to version 2.0.0
Ref T84819
Build System
============
This is an API breaking new version, and the updated code only builds with
OpenColorIO 2.0 and later. Adding backwards compatibility was too complicated.
* Tinyxml was replaced with Expat, adding a new dependency.
* Yaml-cpp is now built as a dependency on Unix, as was already done on Windows.
* Removed currently unused LCMS code.
* Pystring remains built as part of OCIO itself, since it has no good build system.
* Linux and macOS check for the OpenColorIO verison, and disable it if too old.
Ref D10270
Processors and Transforms
=========================
CPU processors now need to be created to do CPU processing. These are cached
internally, but the cache lookup is not fast enough to execute per pixel or
texture sample, so for performance these are now also exposed in the C API.
The C API for transforms will no longer be needed afer all changes, so remove
it to simplify the API and fallback implementation.
Ref D10271
Display Transforms
==================
Needs a bit more manual work constructing the transform. LegacyViewingPipeline
could also have been used, but isn't really any simpler and since it's legacy
we better not rely on it.
We moved more logic into the opencolorio module, to simplify the API. There is
no need to wrap a dozen functions just to be able to do this in C rather than C++.
It's also tightly coupled to the GPU shader logic, and so should be in the same
module.
Ref D10271
GPU Display Shader
==================
To avoid baking exposure and gamma into the GLSL shader and requiring slow
recompiles when tweaking, we manually apply them in the shader. This leads
to some logic duplicaton between the CPU and GPU display processor, but it
seems unavoidable.
Caching was also changed. Previously this was done both on the imbuf and
opencolorio module levels. Now it's all done in the opencolorio module by
simply matching color space names. We no longer use cacheIDs from OpenColorIO
since computing them is expensive, and they are unlikely to match now that
more is baked into the shader code.
Shaders can now use multiple 2D textures, 3D textures and uniforms, rather
than a single 3D texture. So allocating and binding those adds some code.
Color space conversions for blending with overlays is now hardcoded in the
shader. This was using harcoded numbers anyway, if this every becomes a
general OpenColorIO transform it can be changed, but for now there is no
point to add code complexity.
Ref D10273
CIE XYZ
=======
We need standard CIE XYZ values for rendering effects like blackbody emission.
The relation to the scene linear role is based on OpenColorIO configuration.
In OpenColorIO 2.0 configs roles can no longer have the same name as color
spaces, which means our XYZ role and colorspace in the configuration give an
error.
Instead use the new standard aces_interchange role, which relates scene linear
to a known scene referred color space. Compatibility with the old XYZ role is
preserved, if the configuration file has no conflicting names.
Also includes a non-functional change to the configuraton file to use an
XYZ-to-ACES matrix instead of REC709-to-ACES, makes debugging a little easier
since the matrix is the same one we have in the code now and that is also
found easily in the ACES specs.
Ref D10274
2021-01-31 19:35:00 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!processor) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
const OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
|
OpenColorIO: upgrade to version 2.0.0
Ref T84819
Build System
============
This is an API breaking new version, and the updated code only builds with
OpenColorIO 2.0 and later. Adding backwards compatibility was too complicated.
* Tinyxml was replaced with Expat, adding a new dependency.
* Yaml-cpp is now built as a dependency on Unix, as was already done on Windows.
* Removed currently unused LCMS code.
* Pystring remains built as part of OCIO itself, since it has no good build system.
* Linux and macOS check for the OpenColorIO verison, and disable it if too old.
Ref D10270
Processors and Transforms
=========================
CPU processors now need to be created to do CPU processing. These are cached
internally, but the cache lookup is not fast enough to execute per pixel or
texture sample, so for performance these are now also exposed in the C API.
The C API for transforms will no longer be needed afer all changes, so remove
it to simplify the API and fallback implementation.
Ref D10271
Display Transforms
==================
Needs a bit more manual work constructing the transform. LegacyViewingPipeline
could also have been used, but isn't really any simpler and since it's legacy
we better not rely on it.
We moved more logic into the opencolorio module, to simplify the API. There is
no need to wrap a dozen functions just to be able to do this in C rather than C++.
It's also tightly coupled to the GPU shader logic, and so should be in the same
module.
Ref D10271
GPU Display Shader
==================
To avoid baking exposure and gamma into the GLSL shader and requiring slow
recompiles when tweaking, we manually apply them in the shader. This leads
to some logic duplicaton between the CPU and GPU display processor, but it
seems unavoidable.
Caching was also changed. Previously this was done both on the imbuf and
opencolorio module levels. Now it's all done in the opencolorio module by
simply matching color space names. We no longer use cacheIDs from OpenColorIO
since computing them is expensive, and they are unlikely to match now that
more is baked into the shader code.
Shaders can now use multiple 2D textures, 3D textures and uniforms, rather
than a single 3D texture. So allocating and binding those adds some code.
Color space conversions for blending with overlays is now hardcoded in the
shader. This was using harcoded numbers anyway, if this every becomes a
general OpenColorIO transform it can be changed, but for now there is no
point to add code complexity.
Ref D10273
CIE XYZ
=======
We need standard CIE XYZ values for rendering effects like blackbody emission.
The relation to the scene linear role is based on OpenColorIO configuration.
In OpenColorIO 2.0 configs roles can no longer have the same name as color
spaces, which means our XYZ role and colorspace in the configuration give an
error.
Instead use the new standard aces_interchange role, which relates scene linear
to a known scene referred color space. Compatibility with the old XYZ role is
preserved, if the configuration file has no conflicting names.
Also includes a non-functional change to the configuraton file to use an
XYZ-to-ACES matrix instead of REC709-to-ACES, makes debugging a little easier
since the matrix is the same one we have in the code now and that is also
found easily in the ACES specs.
Ref D10274
2021-01-31 19:35:00 +01:00
|
|
|
if (!device_processor) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
to_scene_linear = transform_identity();
|
|
|
|
|
device_processor->applyRGB(&to_scene_linear.x.x);
|
|
|
|
|
device_processor->applyRGB(&to_scene_linear.y.x);
|
|
|
|
|
device_processor->applyRGB(&to_scene_linear.z.x);
|
|
|
|
|
to_scene_linear = transform_transposed_inverse(to_scene_linear);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
Cycles: Replace thin-film basis function approximation with accurate LUTs
Previously, we used precomputed Gaussian fits to the XYZ CMFs, performed
the spectral integration in that space, and then converted the result
to the RGB working space.
That worked because we're only supporting dielectric base layers for
the thin film code, so the inputs to the spectral integration
(reflectivity and phase) are both constant w.r.t. wavelength.
However, this will no longer work for conductive base layers.
We could handle reflectivity by converting to XYZ, but that won't work
for phase since its effect on the output is nonlinear.
Therefore, it's time to do this properly by performing the spectral
integration directly in the RGB primaries. To do this, we need to:
- Compute the RGB CMFs from the XYZ CMFs and XYZ-to-RGB matrix
- Resample the RGB CMFs to be parametrized by frequency instead of wavelength
- Compute the FFT of the CMFs
- Store it as a LUT to be used by the kernel code
However, there's two optimizations we can make:
- Both the resampling and the FFT are linear operations, as is the
XYZ-to-RGB conversion. Therefore, we can resample and Fourier-transform
the XYZ CMFs once, store the result in a precomputed table, and then just
multiply the entries by the XYZ-to-RGB matrix at runtime.
- I've included the Python script used to compute the table under
`intern/cycles/doc/precompute`.
- The reference implementation by the paper authors [1] simply stores the
real and imaginary parts in the LUT, and then computes
`cos(shift)*real + sin(shift)*imag`. However, the real and imaginary parts
are oscillating, so the LUT with linear interpolation is not particularly
good at representing them. Instead, we can convert the table to
Magnitude/Phase representation, which is much smoother, and do
`mag * cos(phase - shift)` in the kernel.
- Phase needs to be unwrapped to handle the interpolation decently,
but that's easy.
- This requires an extra trig operation in the kernel in the dielectric case,
but for the conductive case we'll actually save three.
Rendered output is mostly the same, just slightly different because we're
no longer using the Gaussian approximation.
[1] "A Practical Extension to Microfacet Theory for the Modeling of
Varying Iridescence" by Laurent Belcour and Pascal Barla,
https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html
Pull Request: https://projects.blender.org/blender/blender/pulls/140944
2025-07-09 22:10:28 +02:00
|
|
|
void ShaderManager::compute_thin_film_table(const Transform &xyz_to_rgb)
|
|
|
|
|
{
|
|
|
|
|
/* Our implementation of Thin Film Fresnel is based on
|
|
|
|
|
* "A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence"
|
|
|
|
|
* by Laurent Belcour and Pascal Barla
|
|
|
|
|
* (https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html).
|
|
|
|
|
*
|
|
|
|
|
* The idea there is that for a naive implementation of Thin Film interference, you'd compute
|
|
|
|
|
* the reflectivity for a given wavelength using Airy summation, and then numerically integrate
|
|
|
|
|
* the product of this reflectivity function and the Color Matching Functions of the colorspace
|
|
|
|
|
* you're working in to obtain the RGB (or XYZ) values.
|
|
|
|
|
* However, this integration would require too many evaluations to be practical.
|
|
|
|
|
* Therefore, they reformulate the computation as a rapidly converging series involving the
|
|
|
|
|
* Fourier transform of the CMFs.
|
|
|
|
|
*
|
|
|
|
|
* Specifically, we need to:
|
|
|
|
|
* - Compute the RGB CMFs from the XYZ CMFs using the working color space's XYZ-to-RGB matrix
|
|
|
|
|
* - Resample the RGB CMFs to be parametrized by frequency instead of wavelength as usual
|
|
|
|
|
* - Compute the FFT of the CMFs
|
|
|
|
|
* - Store the result as a LUT
|
|
|
|
|
* - Look up the values for each channel at runtime based on the optical path difference and
|
|
|
|
|
* phase shift.
|
|
|
|
|
*
|
|
|
|
|
* Computing an FFT here would be annoying, so we'd like to precompute it, but we only know
|
|
|
|
|
* the XYZ-to-RGB matrix at runtime. Luckily, both resampling and FFT are linear operations,
|
|
|
|
|
* so we can precompute the FFT of the resampled XYZ CMFs and then multiply each entry with
|
|
|
|
|
* the XYZ-to-RGB matrix to get the RGB LUT.
|
|
|
|
|
*
|
|
|
|
|
* That's what this function does: We load the precomputed values, convert to RGB, normalize
|
|
|
|
|
* the result to make the DC term equal to 1, convert from real/imaginary to magnitude/phase
|
|
|
|
|
* since that form is smoother and therefore interpolates more nicely, and then store that
|
|
|
|
|
* into the final table that's used by the kernel.
|
|
|
|
|
*/
|
|
|
|
|
assert(sizeof(table_thin_film_cmf) == 6 * THIN_FILM_TABLE_SIZE * sizeof(float));
|
|
|
|
|
thin_film_table.resize(6 * THIN_FILM_TABLE_SIZE);
|
|
|
|
|
|
|
|
|
|
float3 normalization;
|
|
|
|
|
float3 prevPhase = zero_float3();
|
|
|
|
|
for (int i = 0; i < THIN_FILM_TABLE_SIZE; i++) {
|
|
|
|
|
const float *table_row = table_thin_film_cmf[i];
|
|
|
|
|
/* Load precomputed resampled Fourier-transformed XYZ CMFs. */
|
|
|
|
|
const float3 xyzReal = make_float3(table_row[0], table_row[1], table_row[2]);
|
|
|
|
|
const float3 xyzImag = make_float3(table_row[3], table_row[4], table_row[5]);
|
|
|
|
|
|
|
|
|
|
/* Linearly combine precomputed data to produce the RGB equivalents. Works since both
|
|
|
|
|
* resampling and Fourier transformation are linear operations. */
|
|
|
|
|
const float3 rgbReal = transform_direction(&xyz_to_rgb, xyzReal);
|
|
|
|
|
const float3 rgbImag = transform_direction(&xyz_to_rgb, xyzImag);
|
|
|
|
|
|
|
|
|
|
/* We normalize all entries by the first element. Since that is the DC component, it normalizes
|
|
|
|
|
* the CMF (in non-Fourier space) to an area of 1. */
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
normalization = 1.0f / rgbReal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convert the complex value into magnitude/phase representation. */
|
|
|
|
|
const float3 rgbMag = sqrt(sqr(rgbReal) + sqr(rgbImag));
|
|
|
|
|
float3 rgbPhase = atan2(rgbImag, rgbReal);
|
|
|
|
|
|
|
|
|
|
/* Unwrap phase to avoid jumps. */
|
|
|
|
|
rgbPhase -= M_2PI_F * round((rgbPhase - prevPhase) * M_1_2PI_F);
|
|
|
|
|
prevPhase = rgbPhase;
|
|
|
|
|
|
|
|
|
|
/* Store in lookup table. */
|
|
|
|
|
thin_film_table[i + 0 * THIN_FILM_TABLE_SIZE] = rgbMag.x * normalization.x;
|
|
|
|
|
thin_film_table[i + 1 * THIN_FILM_TABLE_SIZE] = rgbMag.y * normalization.y;
|
|
|
|
|
thin_film_table[i + 2 * THIN_FILM_TABLE_SIZE] = rgbMag.z * normalization.z;
|
|
|
|
|
thin_film_table[i + 3 * THIN_FILM_TABLE_SIZE] = rgbPhase.x;
|
|
|
|
|
thin_film_table[i + 4 * THIN_FILM_TABLE_SIZE] = rgbPhase.y;
|
|
|
|
|
thin_film_table[i + 5 * THIN_FILM_TABLE_SIZE] = rgbPhase.z;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
OpenColorIO: upgrade to version 2.0.0
Ref T84819
Build System
============
This is an API breaking new version, and the updated code only builds with
OpenColorIO 2.0 and later. Adding backwards compatibility was too complicated.
* Tinyxml was replaced with Expat, adding a new dependency.
* Yaml-cpp is now built as a dependency on Unix, as was already done on Windows.
* Removed currently unused LCMS code.
* Pystring remains built as part of OCIO itself, since it has no good build system.
* Linux and macOS check for the OpenColorIO verison, and disable it if too old.
Ref D10270
Processors and Transforms
=========================
CPU processors now need to be created to do CPU processing. These are cached
internally, but the cache lookup is not fast enough to execute per pixel or
texture sample, so for performance these are now also exposed in the C API.
The C API for transforms will no longer be needed afer all changes, so remove
it to simplify the API and fallback implementation.
Ref D10271
Display Transforms
==================
Needs a bit more manual work constructing the transform. LegacyViewingPipeline
could also have been used, but isn't really any simpler and since it's legacy
we better not rely on it.
We moved more logic into the opencolorio module, to simplify the API. There is
no need to wrap a dozen functions just to be able to do this in C rather than C++.
It's also tightly coupled to the GPU shader logic, and so should be in the same
module.
Ref D10271
GPU Display Shader
==================
To avoid baking exposure and gamma into the GLSL shader and requiring slow
recompiles when tweaking, we manually apply them in the shader. This leads
to some logic duplicaton between the CPU and GPU display processor, but it
seems unavoidable.
Caching was also changed. Previously this was done both on the imbuf and
opencolorio module levels. Now it's all done in the opencolorio module by
simply matching color space names. We no longer use cacheIDs from OpenColorIO
since computing them is expensive, and they are unlikely to match now that
more is baked into the shader code.
Shaders can now use multiple 2D textures, 3D textures and uniforms, rather
than a single 3D texture. So allocating and binding those adds some code.
Color space conversions for blending with overlays is now hardcoded in the
shader. This was using harcoded numbers anyway, if this every becomes a
general OpenColorIO transform it can be changed, but for now there is no
point to add code complexity.
Ref D10273
CIE XYZ
=======
We need standard CIE XYZ values for rendering effects like blackbody emission.
The relation to the scene linear role is based on OpenColorIO configuration.
In OpenColorIO 2.0 configs roles can no longer have the same name as color
spaces, which means our XYZ role and colorspace in the configuration give an
error.
Instead use the new standard aces_interchange role, which relates scene linear
to a known scene referred color space. Compatibility with the old XYZ role is
preserved, if the configuration file has no conflicting names.
Also includes a non-functional change to the configuraton file to use an
XYZ-to-ACES matrix instead of REC709-to-ACES, makes debugging a little easier
since the matrix is the same one we have in the code now and that is also
found easily in the ACES specs.
Ref D10274
2021-01-31 19:35:00 +01:00
|
|
|
void ShaderManager::init_xyz_transforms()
|
|
|
|
|
{
|
2021-03-10 16:38:26 +01:00
|
|
|
/* Default to ITU-BT.709 in case no appropriate transform found.
|
|
|
|
|
* Note XYZ here is defined as having a D65 white point. */
|
2022-03-22 20:41:46 +01:00
|
|
|
const Transform xyz_to_rec709 = make_transform(3.2404542f,
|
|
|
|
|
-1.5371385f,
|
|
|
|
|
-0.4985314f,
|
|
|
|
|
0.0f,
|
|
|
|
|
-0.9692660f,
|
|
|
|
|
1.8760108f,
|
|
|
|
|
0.0415560f,
|
|
|
|
|
0.0f,
|
|
|
|
|
0.0556434f,
|
|
|
|
|
-0.2040259f,
|
|
|
|
|
1.0572252f,
|
|
|
|
|
0.0f);
|
|
|
|
|
|
2024-12-19 09:41:55 +01:00
|
|
|
xyz_to_r = make_float3(xyz_to_rec709.x);
|
|
|
|
|
xyz_to_g = make_float3(xyz_to_rec709.y);
|
|
|
|
|
xyz_to_b = make_float3(xyz_to_rec709.z);
|
OpenColorIO: upgrade to version 2.0.0
Ref T84819
Build System
============
This is an API breaking new version, and the updated code only builds with
OpenColorIO 2.0 and later. Adding backwards compatibility was too complicated.
* Tinyxml was replaced with Expat, adding a new dependency.
* Yaml-cpp is now built as a dependency on Unix, as was already done on Windows.
* Removed currently unused LCMS code.
* Pystring remains built as part of OCIO itself, since it has no good build system.
* Linux and macOS check for the OpenColorIO verison, and disable it if too old.
Ref D10270
Processors and Transforms
=========================
CPU processors now need to be created to do CPU processing. These are cached
internally, but the cache lookup is not fast enough to execute per pixel or
texture sample, so for performance these are now also exposed in the C API.
The C API for transforms will no longer be needed afer all changes, so remove
it to simplify the API and fallback implementation.
Ref D10271
Display Transforms
==================
Needs a bit more manual work constructing the transform. LegacyViewingPipeline
could also have been used, but isn't really any simpler and since it's legacy
we better not rely on it.
We moved more logic into the opencolorio module, to simplify the API. There is
no need to wrap a dozen functions just to be able to do this in C rather than C++.
It's also tightly coupled to the GPU shader logic, and so should be in the same
module.
Ref D10271
GPU Display Shader
==================
To avoid baking exposure and gamma into the GLSL shader and requiring slow
recompiles when tweaking, we manually apply them in the shader. This leads
to some logic duplicaton between the CPU and GPU display processor, but it
seems unavoidable.
Caching was also changed. Previously this was done both on the imbuf and
opencolorio module levels. Now it's all done in the opencolorio module by
simply matching color space names. We no longer use cacheIDs from OpenColorIO
since computing them is expensive, and they are unlikely to match now that
more is baked into the shader code.
Shaders can now use multiple 2D textures, 3D textures and uniforms, rather
than a single 3D texture. So allocating and binding those adds some code.
Color space conversions for blending with overlays is now hardcoded in the
shader. This was using harcoded numbers anyway, if this every becomes a
general OpenColorIO transform it can be changed, but for now there is no
point to add code complexity.
Ref D10273
CIE XYZ
=======
We need standard CIE XYZ values for rendering effects like blackbody emission.
The relation to the scene linear role is based on OpenColorIO configuration.
In OpenColorIO 2.0 configs roles can no longer have the same name as color
spaces, which means our XYZ role and colorspace in the configuration give an
error.
Instead use the new standard aces_interchange role, which relates scene linear
to a known scene referred color space. Compatibility with the old XYZ role is
preserved, if the configuration file has no conflicting names.
Also includes a non-functional change to the configuraton file to use an
XYZ-to-ACES matrix instead of REC709-to-ACES, makes debugging a little easier
since the matrix is the same one we have in the code now and that is also
found easily in the ACES specs.
Ref D10274
2021-01-31 19:35:00 +01:00
|
|
|
rgb_to_y = make_float3(0.2126729f, 0.7151522f, 0.0721750f);
|
Cycles: Add thin film iridescence to Principled BSDF
This is an implementation of thin film iridescence in the Principled BSDF based on "A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence".
There are still several open topics that are left for future work:
- Currently, the thin film only affects dielectric Fresnel, not metallic. Properly specifying thin films on metals requires a proper conductive Fresnel term with complex IOR inputs, any attempt of trying to hack it into the F82 model we currently use for the Principled BSDF is fundamentally flawed. In the future, we'll add a node for proper conductive Fresnel, including thin films.
- The F0/F90 control is not very elegantly implemented right now. It fundamentally works, but enabling thin film while using a Specular Tint causes a jump in appearance since the models integrate it differently. Then again, thin film interference is a physical effect, so of course a non-physical tweak doesn't play nicely with it.
- The white point handling is currently quite crude. In short: The code computes XYZ values of the reflectance spectrum, but we'd need the XYZ values of the product of the reflectance spectrum and the neutral illuminant of the working color space. Currently, this is addressed by just dividing by the XYZ values of the illuminant, but it would be better to do a proper chromatic adaptation transform or to use the proper reference curves for the working space instead of the XYZ curves from the paper.
Pull Request: https://projects.blender.org/blender/blender/pulls/118477
2024-05-02 14:28:44 +02:00
|
|
|
white_xyz = make_float3(0.95047f, 1.0f, 1.08883f);
|
OpenColorIO: upgrade to version 2.0.0
Ref T84819
Build System
============
This is an API breaking new version, and the updated code only builds with
OpenColorIO 2.0 and later. Adding backwards compatibility was too complicated.
* Tinyxml was replaced with Expat, adding a new dependency.
* Yaml-cpp is now built as a dependency on Unix, as was already done on Windows.
* Removed currently unused LCMS code.
* Pystring remains built as part of OCIO itself, since it has no good build system.
* Linux and macOS check for the OpenColorIO verison, and disable it if too old.
Ref D10270
Processors and Transforms
=========================
CPU processors now need to be created to do CPU processing. These are cached
internally, but the cache lookup is not fast enough to execute per pixel or
texture sample, so for performance these are now also exposed in the C API.
The C API for transforms will no longer be needed afer all changes, so remove
it to simplify the API and fallback implementation.
Ref D10271
Display Transforms
==================
Needs a bit more manual work constructing the transform. LegacyViewingPipeline
could also have been used, but isn't really any simpler and since it's legacy
we better not rely on it.
We moved more logic into the opencolorio module, to simplify the API. There is
no need to wrap a dozen functions just to be able to do this in C rather than C++.
It's also tightly coupled to the GPU shader logic, and so should be in the same
module.
Ref D10271
GPU Display Shader
==================
To avoid baking exposure and gamma into the GLSL shader and requiring slow
recompiles when tweaking, we manually apply them in the shader. This leads
to some logic duplicaton between the CPU and GPU display processor, but it
seems unavoidable.
Caching was also changed. Previously this was done both on the imbuf and
opencolorio module levels. Now it's all done in the opencolorio module by
simply matching color space names. We no longer use cacheIDs from OpenColorIO
since computing them is expensive, and they are unlikely to match now that
more is baked into the shader code.
Shaders can now use multiple 2D textures, 3D textures and uniforms, rather
than a single 3D texture. So allocating and binding those adds some code.
Color space conversions for blending with overlays is now hardcoded in the
shader. This was using harcoded numbers anyway, if this every becomes a
general OpenColorIO transform it can be changed, but for now there is no
point to add code complexity.
Ref D10273
CIE XYZ
=======
We need standard CIE XYZ values for rendering effects like blackbody emission.
The relation to the scene linear role is based on OpenColorIO configuration.
In OpenColorIO 2.0 configs roles can no longer have the same name as color
spaces, which means our XYZ role and colorspace in the configuration give an
error.
Instead use the new standard aces_interchange role, which relates scene linear
to a known scene referred color space. Compatibility with the old XYZ role is
preserved, if the configuration file has no conflicting names.
Also includes a non-functional change to the configuraton file to use an
XYZ-to-ACES matrix instead of REC709-to-ACES, makes debugging a little easier
since the matrix is the same one we have in the code now and that is also
found easily in the ACES specs.
Ref D10274
2021-01-31 19:35:00 +01:00
|
|
|
|
2022-03-22 20:41:46 +01:00
|
|
|
rec709_to_r = make_float3(1.0f, 0.0f, 0.0f);
|
|
|
|
|
rec709_to_g = make_float3(0.0f, 1.0f, 0.0f);
|
|
|
|
|
rec709_to_b = make_float3(0.0f, 0.0f, 1.0f);
|
|
|
|
|
is_rec709 = true;
|
|
|
|
|
|
Cycles: Replace thin-film basis function approximation with accurate LUTs
Previously, we used precomputed Gaussian fits to the XYZ CMFs, performed
the spectral integration in that space, and then converted the result
to the RGB working space.
That worked because we're only supporting dielectric base layers for
the thin film code, so the inputs to the spectral integration
(reflectivity and phase) are both constant w.r.t. wavelength.
However, this will no longer work for conductive base layers.
We could handle reflectivity by converting to XYZ, but that won't work
for phase since its effect on the output is nonlinear.
Therefore, it's time to do this properly by performing the spectral
integration directly in the RGB primaries. To do this, we need to:
- Compute the RGB CMFs from the XYZ CMFs and XYZ-to-RGB matrix
- Resample the RGB CMFs to be parametrized by frequency instead of wavelength
- Compute the FFT of the CMFs
- Store it as a LUT to be used by the kernel code
However, there's two optimizations we can make:
- Both the resampling and the FFT are linear operations, as is the
XYZ-to-RGB conversion. Therefore, we can resample and Fourier-transform
the XYZ CMFs once, store the result in a precomputed table, and then just
multiply the entries by the XYZ-to-RGB matrix at runtime.
- I've included the Python script used to compute the table under
`intern/cycles/doc/precompute`.
- The reference implementation by the paper authors [1] simply stores the
real and imaginary parts in the LUT, and then computes
`cos(shift)*real + sin(shift)*imag`. However, the real and imaginary parts
are oscillating, so the LUT with linear interpolation is not particularly
good at representing them. Instead, we can convert the table to
Magnitude/Phase representation, which is much smoother, and do
`mag * cos(phase - shift)` in the kernel.
- Phase needs to be unwrapped to handle the interpolation decently,
but that's easy.
- This requires an extra trig operation in the kernel in the dielectric case,
but for the conductive case we'll actually save three.
Rendered output is mostly the same, just slightly different because we're
no longer using the Gaussian approximation.
[1] "A Practical Extension to Microfacet Theory for the Modeling of
Varying Iridescence" by Laurent Belcour and Pascal Barla,
https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html
Pull Request: https://projects.blender.org/blender/blender/pulls/140944
2025-07-09 22:10:28 +02:00
|
|
|
compute_thin_film_table(xyz_to_rec709);
|
|
|
|
|
|
OpenColorIO: upgrade to version 2.0.0
Ref T84819
Build System
============
This is an API breaking new version, and the updated code only builds with
OpenColorIO 2.0 and later. Adding backwards compatibility was too complicated.
* Tinyxml was replaced with Expat, adding a new dependency.
* Yaml-cpp is now built as a dependency on Unix, as was already done on Windows.
* Removed currently unused LCMS code.
* Pystring remains built as part of OCIO itself, since it has no good build system.
* Linux and macOS check for the OpenColorIO verison, and disable it if too old.
Ref D10270
Processors and Transforms
=========================
CPU processors now need to be created to do CPU processing. These are cached
internally, but the cache lookup is not fast enough to execute per pixel or
texture sample, so for performance these are now also exposed in the C API.
The C API for transforms will no longer be needed afer all changes, so remove
it to simplify the API and fallback implementation.
Ref D10271
Display Transforms
==================
Needs a bit more manual work constructing the transform. LegacyViewingPipeline
could also have been used, but isn't really any simpler and since it's legacy
we better not rely on it.
We moved more logic into the opencolorio module, to simplify the API. There is
no need to wrap a dozen functions just to be able to do this in C rather than C++.
It's also tightly coupled to the GPU shader logic, and so should be in the same
module.
Ref D10271
GPU Display Shader
==================
To avoid baking exposure and gamma into the GLSL shader and requiring slow
recompiles when tweaking, we manually apply them in the shader. This leads
to some logic duplicaton between the CPU and GPU display processor, but it
seems unavoidable.
Caching was also changed. Previously this was done both on the imbuf and
opencolorio module levels. Now it's all done in the opencolorio module by
simply matching color space names. We no longer use cacheIDs from OpenColorIO
since computing them is expensive, and they are unlikely to match now that
more is baked into the shader code.
Shaders can now use multiple 2D textures, 3D textures and uniforms, rather
than a single 3D texture. So allocating and binding those adds some code.
Color space conversions for blending with overlays is now hardcoded in the
shader. This was using harcoded numbers anyway, if this every becomes a
general OpenColorIO transform it can be changed, but for now there is no
point to add code complexity.
Ref D10273
CIE XYZ
=======
We need standard CIE XYZ values for rendering effects like blackbody emission.
The relation to the scene linear role is based on OpenColorIO configuration.
In OpenColorIO 2.0 configs roles can no longer have the same name as color
spaces, which means our XYZ role and colorspace in the configuration give an
error.
Instead use the new standard aces_interchange role, which relates scene linear
to a known scene referred color space. Compatibility with the old XYZ role is
preserved, if the configuration file has no conflicting names.
Also includes a non-functional change to the configuraton file to use an
XYZ-to-ACES matrix instead of REC709-to-ACES, makes debugging a little easier
since the matrix is the same one we have in the code now and that is also
found easily in the ACES specs.
Ref D10274
2021-01-31 19:35:00 +01:00
|
|
|
#ifdef WITH_OCIO
|
|
|
|
|
/* Get from OpenColorO config if it has the required roles. */
|
2024-12-31 10:28:46 +01:00
|
|
|
OCIO::ConstConfigRcPtr config = nullptr;
|
|
|
|
|
try {
|
|
|
|
|
config = OCIO::GetCurrentConfig();
|
|
|
|
|
}
|
|
|
|
|
catch (OCIO::Exception &exception) {
|
2025-06-12 02:19:58 +02:00
|
|
|
LOG(WARNING) << "OCIO config error: " << exception.what();
|
2024-12-31 10:28:46 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-18 17:32:53 +02:00
|
|
|
if (!(config && config->hasRole("scene_linear"))) {
|
OpenColorIO: upgrade to version 2.0.0
Ref T84819
Build System
============
This is an API breaking new version, and the updated code only builds with
OpenColorIO 2.0 and later. Adding backwards compatibility was too complicated.
* Tinyxml was replaced with Expat, adding a new dependency.
* Yaml-cpp is now built as a dependency on Unix, as was already done on Windows.
* Removed currently unused LCMS code.
* Pystring remains built as part of OCIO itself, since it has no good build system.
* Linux and macOS check for the OpenColorIO verison, and disable it if too old.
Ref D10270
Processors and Transforms
=========================
CPU processors now need to be created to do CPU processing. These are cached
internally, but the cache lookup is not fast enough to execute per pixel or
texture sample, so for performance these are now also exposed in the C API.
The C API for transforms will no longer be needed afer all changes, so remove
it to simplify the API and fallback implementation.
Ref D10271
Display Transforms
==================
Needs a bit more manual work constructing the transform. LegacyViewingPipeline
could also have been used, but isn't really any simpler and since it's legacy
we better not rely on it.
We moved more logic into the opencolorio module, to simplify the API. There is
no need to wrap a dozen functions just to be able to do this in C rather than C++.
It's also tightly coupled to the GPU shader logic, and so should be in the same
module.
Ref D10271
GPU Display Shader
==================
To avoid baking exposure and gamma into the GLSL shader and requiring slow
recompiles when tweaking, we manually apply them in the shader. This leads
to some logic duplicaton between the CPU and GPU display processor, but it
seems unavoidable.
Caching was also changed. Previously this was done both on the imbuf and
opencolorio module levels. Now it's all done in the opencolorio module by
simply matching color space names. We no longer use cacheIDs from OpenColorIO
since computing them is expensive, and they are unlikely to match now that
more is baked into the shader code.
Shaders can now use multiple 2D textures, 3D textures and uniforms, rather
than a single 3D texture. So allocating and binding those adds some code.
Color space conversions for blending with overlays is now hardcoded in the
shader. This was using harcoded numbers anyway, if this every becomes a
general OpenColorIO transform it can be changed, but for now there is no
point to add code complexity.
Ref D10273
CIE XYZ
=======
We need standard CIE XYZ values for rendering effects like blackbody emission.
The relation to the scene linear role is based on OpenColorIO configuration.
In OpenColorIO 2.0 configs roles can no longer have the same name as color
spaces, which means our XYZ role and colorspace in the configuration give an
error.
Instead use the new standard aces_interchange role, which relates scene linear
to a known scene referred color space. Compatibility with the old XYZ role is
preserved, if the configuration file has no conflicting names.
Also includes a non-functional change to the configuraton file to use an
XYZ-to-ACES matrix instead of REC709-to-ACES, makes debugging a little easier
since the matrix is the same one we have in the code now and that is also
found easily in the ACES specs.
Ref D10274
2021-01-31 19:35:00 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Transform xyz_to_rgb;
|
|
|
|
|
|
|
|
|
|
if (config->hasRole("aces_interchange")) {
|
2022-02-17 19:37:55 +01:00
|
|
|
/* Standard OpenColorIO role, defined as ACES AP0 (ACES2065-1). */
|
OpenColorIO: upgrade to version 2.0.0
Ref T84819
Build System
============
This is an API breaking new version, and the updated code only builds with
OpenColorIO 2.0 and later. Adding backwards compatibility was too complicated.
* Tinyxml was replaced with Expat, adding a new dependency.
* Yaml-cpp is now built as a dependency on Unix, as was already done on Windows.
* Removed currently unused LCMS code.
* Pystring remains built as part of OCIO itself, since it has no good build system.
* Linux and macOS check for the OpenColorIO verison, and disable it if too old.
Ref D10270
Processors and Transforms
=========================
CPU processors now need to be created to do CPU processing. These are cached
internally, but the cache lookup is not fast enough to execute per pixel or
texture sample, so for performance these are now also exposed in the C API.
The C API for transforms will no longer be needed afer all changes, so remove
it to simplify the API and fallback implementation.
Ref D10271
Display Transforms
==================
Needs a bit more manual work constructing the transform. LegacyViewingPipeline
could also have been used, but isn't really any simpler and since it's legacy
we better not rely on it.
We moved more logic into the opencolorio module, to simplify the API. There is
no need to wrap a dozen functions just to be able to do this in C rather than C++.
It's also tightly coupled to the GPU shader logic, and so should be in the same
module.
Ref D10271
GPU Display Shader
==================
To avoid baking exposure and gamma into the GLSL shader and requiring slow
recompiles when tweaking, we manually apply them in the shader. This leads
to some logic duplicaton between the CPU and GPU display processor, but it
seems unavoidable.
Caching was also changed. Previously this was done both on the imbuf and
opencolorio module levels. Now it's all done in the opencolorio module by
simply matching color space names. We no longer use cacheIDs from OpenColorIO
since computing them is expensive, and they are unlikely to match now that
more is baked into the shader code.
Shaders can now use multiple 2D textures, 3D textures and uniforms, rather
than a single 3D texture. So allocating and binding those adds some code.
Color space conversions for blending with overlays is now hardcoded in the
shader. This was using harcoded numbers anyway, if this every becomes a
general OpenColorIO transform it can be changed, but for now there is no
point to add code complexity.
Ref D10273
CIE XYZ
=======
We need standard CIE XYZ values for rendering effects like blackbody emission.
The relation to the scene linear role is based on OpenColorIO configuration.
In OpenColorIO 2.0 configs roles can no longer have the same name as color
spaces, which means our XYZ role and colorspace in the configuration give an
error.
Instead use the new standard aces_interchange role, which relates scene linear
to a known scene referred color space. Compatibility with the old XYZ role is
preserved, if the configuration file has no conflicting names.
Also includes a non-functional change to the configuraton file to use an
XYZ-to-ACES matrix instead of REC709-to-ACES, makes debugging a little easier
since the matrix is the same one we have in the code now and that is also
found easily in the ACES specs.
Ref D10274
2021-01-31 19:35:00 +01:00
|
|
|
Transform aces_to_rgb;
|
|
|
|
|
if (!to_scene_linear_transform(config, "aces_interchange", aces_to_rgb)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-17 19:37:55 +01:00
|
|
|
/* This is the OpenColorIO builtin transform:
|
|
|
|
|
* UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD. */
|
2022-02-17 20:27:45 +01:00
|
|
|
const Transform ACES_AP0_to_xyz_D65 = make_transform(0.938280f,
|
|
|
|
|
-0.004451f,
|
|
|
|
|
0.016628f,
|
|
|
|
|
0.000000f,
|
|
|
|
|
0.337369f,
|
|
|
|
|
0.729522f,
|
|
|
|
|
-0.066890f,
|
|
|
|
|
0.000000f,
|
|
|
|
|
0.001174f,
|
|
|
|
|
-0.003711f,
|
|
|
|
|
1.091595f,
|
|
|
|
|
0.000000f);
|
2022-02-17 19:37:55 +01:00
|
|
|
const Transform xyz_to_aces = transform_inverse(ACES_AP0_to_xyz_D65);
|
|
|
|
|
xyz_to_rgb = aces_to_rgb * xyz_to_aces;
|
OpenColorIO: upgrade to version 2.0.0
Ref T84819
Build System
============
This is an API breaking new version, and the updated code only builds with
OpenColorIO 2.0 and later. Adding backwards compatibility was too complicated.
* Tinyxml was replaced with Expat, adding a new dependency.
* Yaml-cpp is now built as a dependency on Unix, as was already done on Windows.
* Removed currently unused LCMS code.
* Pystring remains built as part of OCIO itself, since it has no good build system.
* Linux and macOS check for the OpenColorIO verison, and disable it if too old.
Ref D10270
Processors and Transforms
=========================
CPU processors now need to be created to do CPU processing. These are cached
internally, but the cache lookup is not fast enough to execute per pixel or
texture sample, so for performance these are now also exposed in the C API.
The C API for transforms will no longer be needed afer all changes, so remove
it to simplify the API and fallback implementation.
Ref D10271
Display Transforms
==================
Needs a bit more manual work constructing the transform. LegacyViewingPipeline
could also have been used, but isn't really any simpler and since it's legacy
we better not rely on it.
We moved more logic into the opencolorio module, to simplify the API. There is
no need to wrap a dozen functions just to be able to do this in C rather than C++.
It's also tightly coupled to the GPU shader logic, and so should be in the same
module.
Ref D10271
GPU Display Shader
==================
To avoid baking exposure and gamma into the GLSL shader and requiring slow
recompiles when tweaking, we manually apply them in the shader. This leads
to some logic duplicaton between the CPU and GPU display processor, but it
seems unavoidable.
Caching was also changed. Previously this was done both on the imbuf and
opencolorio module levels. Now it's all done in the opencolorio module by
simply matching color space names. We no longer use cacheIDs from OpenColorIO
since computing them is expensive, and they are unlikely to match now that
more is baked into the shader code.
Shaders can now use multiple 2D textures, 3D textures and uniforms, rather
than a single 3D texture. So allocating and binding those adds some code.
Color space conversions for blending with overlays is now hardcoded in the
shader. This was using harcoded numbers anyway, if this every becomes a
general OpenColorIO transform it can be changed, but for now there is no
point to add code complexity.
Ref D10273
CIE XYZ
=======
We need standard CIE XYZ values for rendering effects like blackbody emission.
The relation to the scene linear role is based on OpenColorIO configuration.
In OpenColorIO 2.0 configs roles can no longer have the same name as color
spaces, which means our XYZ role and colorspace in the configuration give an
error.
Instead use the new standard aces_interchange role, which relates scene linear
to a known scene referred color space. Compatibility with the old XYZ role is
preserved, if the configuration file has no conflicting names.
Also includes a non-functional change to the configuraton file to use an
XYZ-to-ACES matrix instead of REC709-to-ACES, makes debugging a little easier
since the matrix is the same one we have in the code now and that is also
found easily in the ACES specs.
Ref D10274
2021-01-31 19:35:00 +01:00
|
|
|
}
|
|
|
|
|
else if (config->hasRole("XYZ")) {
|
|
|
|
|
/* Custom role used before the standard existed. */
|
|
|
|
|
if (!to_scene_linear_transform(config, "XYZ", xyz_to_rgb)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-17 06:13:49 +01:00
|
|
|
else {
|
|
|
|
|
/* No reference role found to determine XYZ. */
|
|
|
|
|
return;
|
|
|
|
|
}
|
OpenColorIO: upgrade to version 2.0.0
Ref T84819
Build System
============
This is an API breaking new version, and the updated code only builds with
OpenColorIO 2.0 and later. Adding backwards compatibility was too complicated.
* Tinyxml was replaced with Expat, adding a new dependency.
* Yaml-cpp is now built as a dependency on Unix, as was already done on Windows.
* Removed currently unused LCMS code.
* Pystring remains built as part of OCIO itself, since it has no good build system.
* Linux and macOS check for the OpenColorIO verison, and disable it if too old.
Ref D10270
Processors and Transforms
=========================
CPU processors now need to be created to do CPU processing. These are cached
internally, but the cache lookup is not fast enough to execute per pixel or
texture sample, so for performance these are now also exposed in the C API.
The C API for transforms will no longer be needed afer all changes, so remove
it to simplify the API and fallback implementation.
Ref D10271
Display Transforms
==================
Needs a bit more manual work constructing the transform. LegacyViewingPipeline
could also have been used, but isn't really any simpler and since it's legacy
we better not rely on it.
We moved more logic into the opencolorio module, to simplify the API. There is
no need to wrap a dozen functions just to be able to do this in C rather than C++.
It's also tightly coupled to the GPU shader logic, and so should be in the same
module.
Ref D10271
GPU Display Shader
==================
To avoid baking exposure and gamma into the GLSL shader and requiring slow
recompiles when tweaking, we manually apply them in the shader. This leads
to some logic duplicaton between the CPU and GPU display processor, but it
seems unavoidable.
Caching was also changed. Previously this was done both on the imbuf and
opencolorio module levels. Now it's all done in the opencolorio module by
simply matching color space names. We no longer use cacheIDs from OpenColorIO
since computing them is expensive, and they are unlikely to match now that
more is baked into the shader code.
Shaders can now use multiple 2D textures, 3D textures and uniforms, rather
than a single 3D texture. So allocating and binding those adds some code.
Color space conversions for blending with overlays is now hardcoded in the
shader. This was using harcoded numbers anyway, if this every becomes a
general OpenColorIO transform it can be changed, but for now there is no
point to add code complexity.
Ref D10273
CIE XYZ
=======
We need standard CIE XYZ values for rendering effects like blackbody emission.
The relation to the scene linear role is based on OpenColorIO configuration.
In OpenColorIO 2.0 configs roles can no longer have the same name as color
spaces, which means our XYZ role and colorspace in the configuration give an
error.
Instead use the new standard aces_interchange role, which relates scene linear
to a known scene referred color space. Compatibility with the old XYZ role is
preserved, if the configuration file has no conflicting names.
Also includes a non-functional change to the configuraton file to use an
XYZ-to-ACES matrix instead of REC709-to-ACES, makes debugging a little easier
since the matrix is the same one we have in the code now and that is also
found easily in the ACES specs.
Ref D10274
2021-01-31 19:35:00 +01:00
|
|
|
|
2024-12-19 09:41:55 +01:00
|
|
|
xyz_to_r = make_float3(xyz_to_rgb.x);
|
|
|
|
|
xyz_to_g = make_float3(xyz_to_rgb.y);
|
|
|
|
|
xyz_to_b = make_float3(xyz_to_rgb.z);
|
OpenColorIO: upgrade to version 2.0.0
Ref T84819
Build System
============
This is an API breaking new version, and the updated code only builds with
OpenColorIO 2.0 and later. Adding backwards compatibility was too complicated.
* Tinyxml was replaced with Expat, adding a new dependency.
* Yaml-cpp is now built as a dependency on Unix, as was already done on Windows.
* Removed currently unused LCMS code.
* Pystring remains built as part of OCIO itself, since it has no good build system.
* Linux and macOS check for the OpenColorIO verison, and disable it if too old.
Ref D10270
Processors and Transforms
=========================
CPU processors now need to be created to do CPU processing. These are cached
internally, but the cache lookup is not fast enough to execute per pixel or
texture sample, so for performance these are now also exposed in the C API.
The C API for transforms will no longer be needed afer all changes, so remove
it to simplify the API and fallback implementation.
Ref D10271
Display Transforms
==================
Needs a bit more manual work constructing the transform. LegacyViewingPipeline
could also have been used, but isn't really any simpler and since it's legacy
we better not rely on it.
We moved more logic into the opencolorio module, to simplify the API. There is
no need to wrap a dozen functions just to be able to do this in C rather than C++.
It's also tightly coupled to the GPU shader logic, and so should be in the same
module.
Ref D10271
GPU Display Shader
==================
To avoid baking exposure and gamma into the GLSL shader and requiring slow
recompiles when tweaking, we manually apply them in the shader. This leads
to some logic duplicaton between the CPU and GPU display processor, but it
seems unavoidable.
Caching was also changed. Previously this was done both on the imbuf and
opencolorio module levels. Now it's all done in the opencolorio module by
simply matching color space names. We no longer use cacheIDs from OpenColorIO
since computing them is expensive, and they are unlikely to match now that
more is baked into the shader code.
Shaders can now use multiple 2D textures, 3D textures and uniforms, rather
than a single 3D texture. So allocating and binding those adds some code.
Color space conversions for blending with overlays is now hardcoded in the
shader. This was using harcoded numbers anyway, if this every becomes a
general OpenColorIO transform it can be changed, but for now there is no
point to add code complexity.
Ref D10273
CIE XYZ
=======
We need standard CIE XYZ values for rendering effects like blackbody emission.
The relation to the scene linear role is based on OpenColorIO configuration.
In OpenColorIO 2.0 configs roles can no longer have the same name as color
spaces, which means our XYZ role and colorspace in the configuration give an
error.
Instead use the new standard aces_interchange role, which relates scene linear
to a known scene referred color space. Compatibility with the old XYZ role is
preserved, if the configuration file has no conflicting names.
Also includes a non-functional change to the configuraton file to use an
XYZ-to-ACES matrix instead of REC709-to-ACES, makes debugging a little easier
since the matrix is the same one we have in the code now and that is also
found easily in the ACES specs.
Ref D10274
2021-01-31 19:35:00 +01:00
|
|
|
|
|
|
|
|
const Transform rgb_to_xyz = transform_inverse(xyz_to_rgb);
|
2024-12-19 09:41:55 +01:00
|
|
|
rgb_to_y = make_float3(rgb_to_xyz.y);
|
Cycles: Add thin film iridescence to Principled BSDF
This is an implementation of thin film iridescence in the Principled BSDF based on "A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence".
There are still several open topics that are left for future work:
- Currently, the thin film only affects dielectric Fresnel, not metallic. Properly specifying thin films on metals requires a proper conductive Fresnel term with complex IOR inputs, any attempt of trying to hack it into the F82 model we currently use for the Principled BSDF is fundamentally flawed. In the future, we'll add a node for proper conductive Fresnel, including thin films.
- The F0/F90 control is not very elegantly implemented right now. It fundamentally works, but enabling thin film while using a Specular Tint causes a jump in appearance since the models integrate it differently. Then again, thin film interference is a physical effect, so of course a non-physical tweak doesn't play nicely with it.
- The white point handling is currently quite crude. In short: The code computes XYZ values of the reflectance spectrum, but we'd need the XYZ values of the product of the reflectance spectrum and the neutral illuminant of the working color space. Currently, this is addressed by just dividing by the XYZ values of the illuminant, but it would be better to do a proper chromatic adaptation transform or to use the proper reference curves for the working space instead of the XYZ curves from the paper.
Pull Request: https://projects.blender.org/blender/blender/pulls/118477
2024-05-02 14:28:44 +02:00
|
|
|
white_xyz = transform_direction(&rgb_to_xyz, one_float3());
|
2022-03-22 20:41:46 +01:00
|
|
|
|
|
|
|
|
const Transform rec709_to_rgb = xyz_to_rgb * transform_inverse(xyz_to_rec709);
|
2024-12-19 09:41:55 +01:00
|
|
|
rec709_to_r = make_float3(rec709_to_rgb.x);
|
|
|
|
|
rec709_to_g = make_float3(rec709_to_rgb.y);
|
|
|
|
|
rec709_to_b = make_float3(rec709_to_rgb.z);
|
2022-03-22 20:41:46 +01:00
|
|
|
is_rec709 = transform_equal_threshold(xyz_to_rgb, xyz_to_rec709, 0.0001f);
|
Cycles: Replace thin-film basis function approximation with accurate LUTs
Previously, we used precomputed Gaussian fits to the XYZ CMFs, performed
the spectral integration in that space, and then converted the result
to the RGB working space.
That worked because we're only supporting dielectric base layers for
the thin film code, so the inputs to the spectral integration
(reflectivity and phase) are both constant w.r.t. wavelength.
However, this will no longer work for conductive base layers.
We could handle reflectivity by converting to XYZ, but that won't work
for phase since its effect on the output is nonlinear.
Therefore, it's time to do this properly by performing the spectral
integration directly in the RGB primaries. To do this, we need to:
- Compute the RGB CMFs from the XYZ CMFs and XYZ-to-RGB matrix
- Resample the RGB CMFs to be parametrized by frequency instead of wavelength
- Compute the FFT of the CMFs
- Store it as a LUT to be used by the kernel code
However, there's two optimizations we can make:
- Both the resampling and the FFT are linear operations, as is the
XYZ-to-RGB conversion. Therefore, we can resample and Fourier-transform
the XYZ CMFs once, store the result in a precomputed table, and then just
multiply the entries by the XYZ-to-RGB matrix at runtime.
- I've included the Python script used to compute the table under
`intern/cycles/doc/precompute`.
- The reference implementation by the paper authors [1] simply stores the
real and imaginary parts in the LUT, and then computes
`cos(shift)*real + sin(shift)*imag`. However, the real and imaginary parts
are oscillating, so the LUT with linear interpolation is not particularly
good at representing them. Instead, we can convert the table to
Magnitude/Phase representation, which is much smoother, and do
`mag * cos(phase - shift)` in the kernel.
- Phase needs to be unwrapped to handle the interpolation decently,
but that's easy.
- This requires an extra trig operation in the kernel in the dielectric case,
but for the conductive case we'll actually save three.
Rendered output is mostly the same, just slightly different because we're
no longer using the Gaussian approximation.
[1] "A Practical Extension to Microfacet Theory for the Modeling of
Varying Iridescence" by Laurent Belcour and Pascal Barla,
https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html
Pull Request: https://projects.blender.org/blender/blender/pulls/140944
2025-07-09 22:10:28 +02:00
|
|
|
|
|
|
|
|
compute_thin_film_table(xyz_to_rgb);
|
OpenColorIO: upgrade to version 2.0.0
Ref T84819
Build System
============
This is an API breaking new version, and the updated code only builds with
OpenColorIO 2.0 and later. Adding backwards compatibility was too complicated.
* Tinyxml was replaced with Expat, adding a new dependency.
* Yaml-cpp is now built as a dependency on Unix, as was already done on Windows.
* Removed currently unused LCMS code.
* Pystring remains built as part of OCIO itself, since it has no good build system.
* Linux and macOS check for the OpenColorIO verison, and disable it if too old.
Ref D10270
Processors and Transforms
=========================
CPU processors now need to be created to do CPU processing. These are cached
internally, but the cache lookup is not fast enough to execute per pixel or
texture sample, so for performance these are now also exposed in the C API.
The C API for transforms will no longer be needed afer all changes, so remove
it to simplify the API and fallback implementation.
Ref D10271
Display Transforms
==================
Needs a bit more manual work constructing the transform. LegacyViewingPipeline
could also have been used, but isn't really any simpler and since it's legacy
we better not rely on it.
We moved more logic into the opencolorio module, to simplify the API. There is
no need to wrap a dozen functions just to be able to do this in C rather than C++.
It's also tightly coupled to the GPU shader logic, and so should be in the same
module.
Ref D10271
GPU Display Shader
==================
To avoid baking exposure and gamma into the GLSL shader and requiring slow
recompiles when tweaking, we manually apply them in the shader. This leads
to some logic duplicaton between the CPU and GPU display processor, but it
seems unavoidable.
Caching was also changed. Previously this was done both on the imbuf and
opencolorio module levels. Now it's all done in the opencolorio module by
simply matching color space names. We no longer use cacheIDs from OpenColorIO
since computing them is expensive, and they are unlikely to match now that
more is baked into the shader code.
Shaders can now use multiple 2D textures, 3D textures and uniforms, rather
than a single 3D texture. So allocating and binding those adds some code.
Color space conversions for blending with overlays is now hardcoded in the
shader. This was using harcoded numbers anyway, if this every becomes a
general OpenColorIO transform it can be changed, but for now there is no
point to add code complexity.
Ref D10273
CIE XYZ
=======
We need standard CIE XYZ values for rendering effects like blackbody emission.
The relation to the scene linear role is based on OpenColorIO configuration.
In OpenColorIO 2.0 configs roles can no longer have the same name as color
spaces, which means our XYZ role and colorspace in the configuration give an
error.
Instead use the new standard aces_interchange role, which relates scene linear
to a known scene referred color space. Compatibility with the old XYZ role is
preserved, if the configuration file has no conflicting names.
Also includes a non-functional change to the configuraton file to use an
XYZ-to-ACES matrix instead of REC709-to-ACES, makes debugging a little easier
since the matrix is the same one we have in the code now and that is also
found easily in the ACES specs.
Ref D10274
2021-01-31 19:35:00 +01:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
Cycles: Remove MultiGGX code, replace with albedo scaling
While the multiscattering GGX code is cool and solves the darkening problem at higher roughnesses, it's also currently buggy, hard to maintain and often impractical to use due to the higher noise and render time.
In practice, though, having the exact correct directional distribution is not that important as long as the overall albedo is correct and we a) don't get the darkening effect and b) do get the saturation effect at higher roughnesses.
This can simply be achieved by adding a second lobe (https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) or scaling the single-scattering GGX lobe (https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf). Both approaches require the same precomputation and produce outputs of comparable quality, so I went for the simple albedo scaling since it's easier to implement and more efficient.
Overall, the results are pretty good: All scenarios that I tested (Glossy BSDF, Glass BSDF, Principled BSDF with metallic or transmissive = 1) pass the white furnace test (a material with pure-white color in front of a pure-white background should be indistinguishable from the background if it preserves energy), and the overall albedo for non-white materials matches that produced by the real multi-scattering code (with the expected saturation increase as the roughness increases).
In order to produce the precomputed tables, the PR also includes a utility that computes them. This is not built by default, since there's no reason for a user to run it (it only makes sense for documentation/reproducibility purposes and when making changes to the microfacet models).
Pull Request: https://projects.blender.org/blender/blender/pulls/107958
2023-06-05 02:20:57 +02:00
|
|
|
size_t ShaderManager::ensure_bsdf_table_impl(DeviceScene *dscene,
|
|
|
|
|
Scene *scene,
|
|
|
|
|
const float *table,
|
2025-01-01 18:15:54 +01:00
|
|
|
const size_t n)
|
Cycles: Remove MultiGGX code, replace with albedo scaling
While the multiscattering GGX code is cool and solves the darkening problem at higher roughnesses, it's also currently buggy, hard to maintain and often impractical to use due to the higher noise and render time.
In practice, though, having the exact correct directional distribution is not that important as long as the overall albedo is correct and we a) don't get the darkening effect and b) do get the saturation effect at higher roughnesses.
This can simply be achieved by adding a second lobe (https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) or scaling the single-scattering GGX lobe (https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf). Both approaches require the same precomputation and produce outputs of comparable quality, so I went for the simple albedo scaling since it's easier to implement and more efficient.
Overall, the results are pretty good: All scenarios that I tested (Glossy BSDF, Glass BSDF, Principled BSDF with metallic or transmissive = 1) pass the white furnace test (a material with pure-white color in front of a pure-white background should be indistinguishable from the background if it preserves energy), and the overall albedo for non-white materials matches that produced by the real multi-scattering code (with the expected saturation increase as the roughness increases).
In order to produce the precomputed tables, the PR also includes a utility that computes them. This is not built by default, since there's no reason for a user to run it (it only makes sense for documentation/reproducibility purposes and when making changes to the microfacet models).
Pull Request: https://projects.blender.org/blender/blender/pulls/107958
2023-06-05 02:20:57 +02:00
|
|
|
{
|
|
|
|
|
/* Since the BSDF tables are static arrays, we can use their address to identify them. */
|
|
|
|
|
if (!(bsdf_tables.count(table))) {
|
|
|
|
|
vector<float> entries(table, table + n);
|
|
|
|
|
bsdf_tables[table] = scene->lookup_tables->add_table(dscene, entries);
|
|
|
|
|
}
|
|
|
|
|
return bsdf_tables[table];
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
CCL_NAMESPACE_END
|