Blender V5.0
scene/shader.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "device/device.h"
6
7#include "scene/background.h"
8#include "scene/camera.h"
9#include "scene/integrator.h"
10#include "scene/light.h"
11#include "scene/mesh.h"
12#include "scene/object.h"
13#include "scene/osl.h"
14#include "scene/procedural.h"
15#include "scene/scene.h"
16#include "scene/shader.h"
17#include "scene/shader_graph.h"
18#include "scene/shader_nodes.h"
19#include "scene/svm.h"
20#include "scene/tables.h"
21#include "scene/volume.h"
22
23#include "util/log.h"
24#include "util/murmurhash.h"
25#include "util/transform.h"
26
27#ifdef WITH_OCIO
28# include <OpenColorIO/OpenColorIO.h>
29namespace OCIO = OCIO_NAMESPACE;
30#endif
31
32#include "scene/shader.tables"
33
35
37
38/* Shader */
39
41{
42 NodeType *type = NodeType::add("shader", create);
43
44 static NodeEnum emission_sampling_method_enum;
45 emission_sampling_method_enum.insert("none", EMISSION_SAMPLING_NONE);
46 emission_sampling_method_enum.insert("auto", EMISSION_SAMPLING_AUTO);
47 emission_sampling_method_enum.insert("front", EMISSION_SAMPLING_FRONT);
48 emission_sampling_method_enum.insert("back", EMISSION_SAMPLING_BACK);
49 emission_sampling_method_enum.insert("front_back", EMISSION_SAMPLING_FRONT_BACK);
50 SOCKET_ENUM(emission_sampling_method,
51 "Emission Sampling Method",
52 emission_sampling_method_enum,
54
55 SOCKET_BOOLEAN(use_transparent_shadow, "Use Transparent Shadow", true);
56 SOCKET_BOOLEAN(use_bump_map_correction, "Bump Map Correction", true);
57
58 static NodeEnum volume_sampling_method_enum;
59 volume_sampling_method_enum.insert("distance", VOLUME_SAMPLING_DISTANCE);
60 volume_sampling_method_enum.insert("equiangular", VOLUME_SAMPLING_EQUIANGULAR);
61 volume_sampling_method_enum.insert("multiple_importance", VOLUME_SAMPLING_MULTIPLE_IMPORTANCE);
62 SOCKET_ENUM(volume_sampling_method,
63 "Volume Sampling Method",
64 volume_sampling_method_enum,
66
67 static NodeEnum volume_interpolation_method_enum;
68 volume_interpolation_method_enum.insert("linear", VOLUME_INTERPOLATION_LINEAR);
69 volume_interpolation_method_enum.insert("cubic", VOLUME_INTERPOLATION_CUBIC);
70 SOCKET_ENUM(volume_interpolation_method,
71 "Volume Interpolation Method",
72 volume_interpolation_method_enum,
74
75 SOCKET_FLOAT(volume_step_rate, "Volume Step Rate", 1.0f);
76
77 static NodeEnum displacement_method_enum;
78 displacement_method_enum.insert("bump", DISPLACE_BUMP);
79 displacement_method_enum.insert("true", DISPLACE_TRUE);
80 displacement_method_enum.insert("both", DISPLACE_BOTH);
81 SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP);
82
83 SOCKET_INT(pass_id, "Pass ID", 0);
84
85 return type;
86}
87
88Shader::Shader() : Node(get_node_type())
89{
90 pass_id = 0;
91
92 graph = nullptr;
93
94 has_surface = false;
97 has_surface_bssrdf = false;
98 has_volume = false;
99 has_displacement = false;
100 has_bump = false;
101 has_bssrdf_bump = false;
105 has_volume_connected = false;
108 has_light_path_node = false;
109
113
114 displacement_method = DISPLACE_BUMP;
115
116 id = -1;
117
118 need_update_uvs = true;
122}
123
125{
126 /* Only supports a few nodes for now, not arbitrary shader graphs. */
127 ShaderNode *node = (output) ? output->parent : nullptr;
128
129 if (node == nullptr) {
130 return zero_float3();
131 }
132 if (node->type == EmissionNode::get_node_type() ||
133 node->type == BackgroundNode::get_node_type() ||
134 node->type == PrincipledBsdfNode::get_node_type())
135 {
136 const bool is_principled = (node->type == PrincipledBsdfNode::get_node_type());
137 /* Emission and Background node. */
138 ShaderInput *color_in = node->input(is_principled ? "Emission Color" : "Color");
139 ShaderInput *strength_in = node->input(is_principled ? "Emission Strength" : "Strength");
140
141 if (is_principled) {
142 /* Too many parameters (coat, sheen, alpha) influence Emission for the Principled BSDF. */
143 is_constant = false;
144 }
145
146 float3 estimate = one_float3();
147
148 if (color_in->link) {
149 is_constant = false;
150 }
151 else {
152 estimate *= node->get_float3(color_in->socket_type);
153 }
154
155 if (strength_in->link) {
156 is_constant = false;
157 estimate *= output_estimate_emission(strength_in->link, is_constant);
158 }
159 else {
160 estimate *= node->get_float(strength_in->socket_type);
161 }
162
163 return estimate;
164 }
165 if (node->type == LightFalloffNode::get_node_type() ||
166 node->type == IESLightNode::get_node_type())
167 {
168 /* Get strength from Light Falloff and IES texture node. */
169 ShaderInput *strength_in = node->input("Strength");
170 is_constant = false;
171
172 return (strength_in->link) ? output_estimate_emission(strength_in->link, is_constant) :
173 make_float3(node->get_float(strength_in->socket_type));
174 }
175 if (node->type == AddClosureNode::get_node_type()) {
176 /* Add Closure. */
177 ShaderInput *closure1_in = node->input("Closure1");
178 ShaderInput *closure2_in = node->input("Closure2");
179
180 const float3 estimate1 = (closure1_in->link) ?
181 output_estimate_emission(closure1_in->link, is_constant) :
182 zero_float3();
183 const float3 estimate2 = (closure2_in->link) ?
184 output_estimate_emission(closure2_in->link, is_constant) :
185 zero_float3();
186
187 return estimate1 + estimate2;
188 }
189 if (node->type == MixClosureNode::get_node_type()) {
190 /* Mix Closure. */
191 ShaderInput *fac_in = node->input("Fac");
192 ShaderInput *closure1_in = node->input("Closure1");
193 ShaderInput *closure2_in = node->input("Closure2");
194
195 const float3 estimate1 = (closure1_in->link) ?
196 output_estimate_emission(closure1_in->link, is_constant) :
197 zero_float3();
198 const float3 estimate2 = (closure2_in->link) ?
199 output_estimate_emission(closure2_in->link, is_constant) :
200 zero_float3();
201
202 if (fac_in->link) {
203 is_constant = false;
204 return estimate1 + estimate2;
205 }
206
207 const float fac = node->get_float(fac_in->socket_type);
208 return (1.0f - fac) * estimate1 + fac * estimate2;
209 }
210
211 /* Other nodes, potentially OSL nodes with arbitrary code for which all we can
212 * determine is if it has emission or not. */
213 const bool has_emission = node->has_surface_emission();
214 float3 estimate;
215
216 if (output->type() == SocketType::CLOSURE) {
217 if (has_emission) {
218 estimate = one_float3();
219 is_constant = false;
220 }
221 else {
222 estimate = zero_float3();
223 }
224
225 for (const ShaderInput *in : node->inputs) {
226 if (in->type() == SocketType::CLOSURE && in->link) {
227 estimate += output_estimate_emission(in->link, is_constant);
228 }
229 }
230 }
231 else {
232 estimate = one_float3();
233 is_constant = false;
234 }
235
236 return estimate;
237}
238
240{
241 /* If the shader has AOVs, they need to be evaluated, so we can't skip the shader. */
243
244 for (ShaderNode *node : graph->nodes) {
246 emission_is_constant = false;
247 }
248 }
249
250 ShaderInput *surf = graph->output()->input("Surface");
252
255 }
256 else if (emission_sampling_method == EMISSION_SAMPLING_AUTO) {
257 /* Automatically disable MIS when emission is low, to avoid weakly emitting
258 * using a lot of memory in the light tree and potentially wasting samples
259 * where indirect light samples are sufficient.
260 * Possible optimization: estimate front and back emission separately. */
261
262 /* Lower importance of emission nodes from automatic value/color to shader conversion, as these
263 * are likely used for previewing and can be slow to build a light tree for on dense meshes. */
264 float scale = 1.0f;
265 const ShaderOutput *output = surf->link;
266 if (output && output->parent->type == EmissionNode::get_node_type()) {
267 const EmissionNode *emission_node = static_cast<const EmissionNode *>(output->parent);
268 if (emission_node->from_auto_conversion) {
269 scale = 0.1f;
270 }
271 }
272
276 }
277 else {
278 emission_sampling = emission_sampling_method;
279 }
280}
281
283{
284 /* do this here already so that we can detect if mesh or object attributes
285 * are needed, since the node attribute callbacks check if their sockets
286 * are connected but proxy nodes should not count */
287 if (graph_) {
288 graph_->remove_proxy_nodes();
289
290 if (displacement_method != DISPLACE_BUMP) {
291 graph_->compute_displacement_hash();
292 }
293 }
294
295 /* update geometry if displacement changed */
296 if (displacement_method != DISPLACE_BUMP) {
297 const char *old_hash = (graph) ? graph->displacement_hash.c_str() : "";
298 const char *new_hash = (graph_) ? graph_->displacement_hash.c_str() : "";
299
300 if (strcmp(old_hash, new_hash) != 0) {
302 }
303 }
304
305 /* assign graph */
306 graph = std::move(graph_);
307
308 /* Store info here before graph optimization to make sure that
309 * nodes that get optimized away still count. */
310 has_volume_connected = (graph->output()->input("Volume")->link != nullptr);
311}
312
314{
315 if (!use_transparent_shadow) {
316 return false;
317 }
318
319 for (ShaderNode *node : graph->nodes) {
320 if (node->has_surface_transparent()) {
321 return true;
322 }
323 }
324
325 return false;
326}
327
329{
330 /* update tag */
331 tag_modified();
332
333 scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED);
334
335 /* if the shader previously was emissive, update light distribution,
336 * if the new shader is emissive, a light manager update tag will be
337 * done in the shader manager device update. */
339 scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED);
340 }
341
342 /* Special handle of background MIS light for now: for some reason it
343 * has use_mis set to false. We are quite close to release now, so
344 * better to be safe.
345 */
346 if (this == scene->background->get_shader(scene)) {
347 scene->light_manager->need_update_background = true;
348 if (scene->light_manager->has_background_light(scene)) {
349 scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED);
350 }
351 }
352
353 /* quick detection of which kind of shaders we have to avoid loading
354 * e.g. surface attributes when there is only a volume shader. this could
355 * be more fine grained but it's better than nothing */
356 OutputNode *output = graph->output();
357 const bool prev_has_volume = has_volume;
358 has_surface = has_surface || output->input("Surface")->link;
359 has_volume = has_volume || output->input("Volume")->link;
360 has_displacement = has_displacement || output->input("Displacement")->link;
361
362 if (!has_surface && !has_volume) {
363 /* If we need to output surface AOVs, add a Transparent BSDF so that the
364 * surface shader runs. */
365 for (ShaderNode *node : graph->nodes) {
367 for (const ShaderInput *in : node->inputs) {
368 if (in->link) {
369 TransparentBsdfNode *transparent = graph->create_node<TransparentBsdfNode>();
370 graph->connect(transparent->output("BSDF"), output->input("Surface"));
371 has_surface = true;
372 break;
373 }
374 }
375 if (has_surface) {
376 break;
377 }
378 }
379 }
380 }
381
382 /* get requested attributes. this could be optimized by pruning unused
383 * nodes here already, but that's the job of the shader manager currently,
384 * and may not be so great for interactive rendering where you temporarily
385 * disconnect a node */
386
387 const AttributeRequestSet prev_attributes = attributes;
388
389 attributes.clear();
390 for (ShaderNode *node : graph->nodes) {
391 node->attributes(this, &attributes);
392 }
393
394 if (has_displacement) {
395 if (displacement_method == DISPLACE_BOTH) {
398 }
399 if (displacement_method_is_modified()) {
402 scene->object_manager->need_flags_update = true;
403 }
404 }
405
406 /* compare if the attributes changed, mesh manager will check
407 * need_update_attribute, update the relevant meshes and clear it. */
408 if (attributes.modified(prev_attributes)) {
411 scene->procedural_manager->tag_update();
412 }
413
417 }
418
419 if (has_volume != prev_has_volume || volume_step_rate != prev_volume_step_rate) {
420 scene->geometry_manager->need_flags_update = true;
421 scene->object_manager->need_flags_update = true;
422 prev_volume_step_rate = volume_step_rate;
423 }
424
425 if (has_volume || prev_has_volume) {
426 scene->volume_manager->tag_update(this);
427 }
428}
429
431{
432 /* if an unused shader suddenly gets used somewhere, it needs to be
433 * recompiled because it was skipped for compilation before */
434 if (!reference_count()) {
435 tag_modified();
436 /* We do not reference here as the shader will be referenced when added to a socket. */
437 scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED);
438 }
439}
440
445
446/* Shader Manager */
447
454
456
458{
460
461 (void)shadingsystem; /* Ignored when built without OSL. */
462
463#ifdef WITH_OSL
464 if (shadingsystem == SHADINGSYSTEM_OSL) {
465 manager = make_unique<OSLShaderManager>();
466 }
467 else
468#endif
469 {
470 manager = make_unique<SVMShaderManager>();
471 }
472
473 return manager;
474}
475
477{
479
480 /* get a unique id for each name, for SVM attribute lookup */
481 const AttributeIDMap::iterator it = unique_attribute_id.find(name);
482
483 if (it != unique_attribute_id.end()) {
484 return it->second;
485 }
486
487 const uint64_t id = ATTR_STD_NUM + unique_attribute_id.size();
489 return id;
490}
491
496
497int ShaderManager::get_shader_id(Shader *shader, bool smooth)
498{
499 /* get a shader id to pass to the kernel */
500 int id = shader->id;
501
502 /* smooth flag */
503 if (smooth) {
505 }
506
507 /* default flags */
509
510 return id;
511}
512
514 DeviceScene *dscene,
515 Scene *scene,
516 Progress & /*progress*/)
517{
518 /* This optimizes the shader graphs, but does not update anything on the device yet.
519 * After this we'll know the kernel features actually used, to load the kernels. */
520 if (!need_update()) {
521 return;
522 }
523
524 uint id = 0;
525 for (Shader *shader : scene->shaders) {
526 shader->id = id++;
527 }
528
529 /* Those shaders should always be compiled as they are used as a fallback if a shader cannot be
530 * found, e.g. bad shader index for the triangle shaders on a Mesh. */
531 assert(scene->default_surface->reference_count() != 0);
532 assert(scene->default_light->reference_count() != 0);
534 assert(scene->default_empty->reference_count() != 0);
535
536 /* Preprocess shader graph. */
537 bool has_volumes = false;
538
539 for (Shader *shader : scene->shaders) {
540 if (shader->is_modified()) {
541 ShaderNode *output = shader->graph->output();
542 shader->has_bump = (shader->get_displacement_method() != DISPLACE_TRUE) &&
543 output->input("Surface")->link && output->input("Displacement")->link;
544 shader->has_bssrdf_bump = shader->has_bump;
545
546 shader->graph->finalize(
547 scene, shader->has_bump, shader->get_displacement_method() == DISPLACE_BOTH);
548
549 shader->has_surface = output->input("Surface")->link != nullptr;
550 shader->has_surface_transparent = false;
551 shader->has_surface_raytrace = false;
552 shader->has_surface_bssrdf = false;
553 shader->has_surface_spatial_varying = false;
554 shader->has_volume = output->input("Volume")->link != nullptr;
555 shader->has_volume_spatial_varying = false;
556 shader->has_volume_attribute_dependency = false;
557 shader->has_displacement = output->input("Displacement")->link != nullptr;
558
559 shader->has_light_path_node = false;
560 for (ShaderNode *node : shader->graph->nodes) {
562 /* TODO: check if the light path node is linked to the volume output. */
563 shader->has_light_path_node = true;
564 break;
565 }
566 }
567 }
568
569 if (shader->reference_count()) {
570 has_volumes |= shader->has_volume;
571 }
572 }
573
574 /* Set this early as it is needed by volume rendering passes. */
575 KernelIntegrator *kintegrator = &dscene->data.integrator;
576 if (bool(kintegrator->use_volumes) != has_volumes) {
578 kintegrator->use_volumes = has_volumes;
579 }
580}
581
583 DeviceScene *dscene,
584 Scene *scene,
585 Progress &progress)
586{
587 device_update_specific(device, dscene, scene, progress);
588
589 /* This runs after kernels have been loaded, so can copy to device. */
592}
593
595 DeviceScene *dscene,
596 Scene *scene,
597 Progress & /*progress*/)
598{
599 dscene->shaders.free();
600
601 if (scene->shaders.empty()) {
602 return;
603 }
604
605 KernelShader *kshader = dscene->shaders.alloc(scene->shaders.size());
606 bool has_transparent_shadow = false;
607
608 for (Shader *shader : scene->shaders) {
609 uint flag = 0;
610
613 }
614 else if (shader->emission_sampling == EMISSION_SAMPLING_BACK) {
615 flag |= SD_MIS_BACK;
616 }
619 }
620
621 if (!is_zero(shader->emission_estimate)) {
623 }
624 if (shader->has_surface_transparent && shader->get_use_transparent_shadow()) {
626 }
627 if (shader->has_surface_raytrace) {
629 }
630 if (shader->has_volume) {
632 /* todo: this could check more fine grained, to skip useless volumes
633 * enclosed inside an opaque bsdf.
634 */
636 }
637 /* in this case we can assume transparent surface */
638 if (shader->has_volume_connected && !shader->has_surface) {
640 }
641 if (shader->has_volume && shader->has_volume_spatial_varying) {
643 }
646 }
647 if (shader->has_bssrdf_bump) {
649 }
650 if (shader->get_volume_sampling_method() == VOLUME_SAMPLING_EQUIANGULAR) {
652 }
653 if (shader->get_volume_sampling_method() == VOLUME_SAMPLING_MULTIPLE_IMPORTANCE) {
655 }
656 if (shader->get_volume_interpolation_method() == VOLUME_INTERPOLATION_CUBIC) {
658 }
659 if (shader->has_bump) {
660 flag |= SD_HAS_BUMP;
661 }
662 if (shader->get_displacement_method() != DISPLACE_BUMP) {
664 }
665 if (shader->get_use_bump_map_correction()) {
667 }
668
669 /* constant emission check */
670 if (shader->emission_is_constant) {
672 }
673
674 if (shader->has_light_path_node) {
676 }
677
678 const uint32_t cryptomatte_id = util_murmur_hash3(
679 shader->name.c_str(), shader->name.length(), 0);
680
681 /* regular shader */
682 kshader->flags = flag;
683 kshader->pass_id = shader->get_pass_id();
684 kshader->constant_emission[0] = shader->emission_estimate.x;
685 kshader->constant_emission[1] = shader->emission_estimate.y;
686 kshader->constant_emission[2] = shader->emission_estimate.z;
687 kshader->cryptomatte_id = util_hash_to_float(cryptomatte_id);
688 kshader++;
689
690 has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
691 }
692
693 /* lookup tables */
694 KernelTables *ktables = &dscene->data.tables;
695 ktables->ggx_E = ensure_bsdf_table(dscene, scene, table_ggx_E);
696 ktables->ggx_Eavg = ensure_bsdf_table(dscene, scene, table_ggx_Eavg);
697 ktables->ggx_glass_E = ensure_bsdf_table(dscene, scene, table_ggx_glass_E);
698 ktables->ggx_glass_Eavg = ensure_bsdf_table(dscene, scene, table_ggx_glass_Eavg);
699 ktables->ggx_glass_inv_E = ensure_bsdf_table(dscene, scene, table_ggx_glass_inv_E);
700 ktables->ggx_glass_inv_Eavg = ensure_bsdf_table(dscene, scene, table_ggx_glass_inv_Eavg);
701 ktables->sheen_ltc = ensure_bsdf_table(dscene, scene, table_sheen_ltc);
702 ktables->ggx_gen_schlick_ior_s = ensure_bsdf_table(dscene, scene, table_ggx_gen_schlick_ior_s);
703 ktables->ggx_gen_schlick_s = ensure_bsdf_table(dscene, scene, table_ggx_gen_schlick_s);
704
706 thin_film_table_offset_ = scene->lookup_tables->add_table(dscene, thin_film_table);
707 }
708 dscene->data.tables.thin_film_table = (int)thin_film_table_offset_;
709
710 /* integrator */
711 KernelIntegrator *kintegrator = &dscene->data.integrator;
712 /* TODO(sergey): De-duplicate with flags set in integrator.cpp. */
713 kintegrator->transparent_shadows = has_transparent_shadow;
714
715 /* film */
716 KernelFilm *kfilm = &dscene->data.film;
717 /* color space, needs to be here because e.g. displacement shaders could depend on it */
718 kfilm->xyz_to_r = make_float4(xyz_to_r);
719 kfilm->xyz_to_g = make_float4(xyz_to_g);
720 kfilm->xyz_to_b = make_float4(xyz_to_b);
721 kfilm->rgb_to_y = make_float4(rgb_to_y);
722 kfilm->white_xyz = make_float4(white_xyz);
723 kfilm->rec709_to_r = make_float4(rec709_to_r);
724 kfilm->rec709_to_g = make_float4(rec709_to_g);
725 kfilm->rec709_to_b = make_float4(rec709_to_b);
726 kfilm->is_rec709 = scene_linear_space == SceneLinearSpace::Rec709;
727}
728
730{
731 for (auto &entry : bsdf_tables) {
732 scene->lookup_tables->remove_table(&entry.second);
733 }
734 bsdf_tables.clear();
735 scene->lookup_tables->remove_table(&thin_film_table_offset_);
737
738 dscene->shaders.free();
739}
740
742{
743 /* default surface */
744 {
745 unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
746
747 PrincipledBsdfNode *bsdf = graph->create_node<PrincipledBsdfNode>();
748 graph->connect(bsdf->output("BSDF"), graph->output()->input("Surface"));
749
750 Shader *shader = scene->create_node<Shader>();
751 shader->name = "default_surface";
752 shader->set_graph(std::move(graph));
753 shader->reference();
754 scene->default_surface = shader;
755 shader->tag_update(scene);
756 }
757
758 /* default volume */
759 {
760 unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
761
762 PrincipledVolumeNode *principled = graph->create_node<PrincipledVolumeNode>();
763
764 graph->connect(principled->output("Volume"), graph->output()->input("Volume"));
765
766 Shader *shader = scene->create_node<Shader>();
767 shader->name = "default_volume";
768 shader->set_graph(std::move(graph));
769 scene->default_volume = shader;
770 shader->tag_update(scene);
771 /* No default reference for the volume to avoid compiling volume kernels if there are no
772 * actual volumes in the scene */
773 }
774
775 /* default light */
776 {
777 unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
778
779 EmissionNode *emission = graph->create_node<EmissionNode>();
780 emission->set_color(make_float3(0.8f, 0.8f, 0.8f));
781 emission->set_strength(0.0f);
782
783 graph->connect(emission->output("Emission"), graph->output()->input("Surface"));
784
785 Shader *shader = scene->create_node<Shader>();
786 shader->name = "default_light";
787 shader->set_graph(std::move(graph));
788 shader->reference();
789 scene->default_light = shader;
790 shader->tag_update(scene);
791 }
792
793 /* default background */
794 {
795 unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
796
797 Shader *shader = scene->create_node<Shader>();
798 shader->name = "default_background";
799 shader->set_graph(std::move(graph));
800 shader->reference();
801 scene->default_background = shader;
802 shader->tag_update(scene);
803 }
804
805 /* default empty */
806 {
807 unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
808
809 Shader *shader = scene->create_node<Shader>();
810 shader->name = "default_empty";
811 shader->set_graph(std::move(graph));
812 shader->reference();
813 scene->default_empty = shader;
814 shader->tag_update(scene);
815 }
816}
817
819{
820 uint kernel_features = 0;
821
822 for (ShaderNode *node : graph->nodes) {
823 kernel_features |= node->get_feature();
825 BsdfBaseNode *bsdf_node = static_cast<BsdfBaseNode *>(node);
826 if (CLOSURE_IS_VOLUME(bsdf_node->get_closure_type())) {
827 kernel_features |= KERNEL_FEATURE_NODE_VOLUME;
828 }
829 }
830 if (node->has_surface_bssrdf()) {
831 kernel_features |= KERNEL_FEATURE_SUBSURFACE;
832 }
833 if (node->has_surface_transparent()) {
834 kernel_features |= KERNEL_FEATURE_TRANSPARENT;
835 }
836 }
837
838 return kernel_features;
839}
840
842{
844 for (int i = 0; i < scene->shaders.size(); i++) {
845 Shader *shader = scene->shaders[i];
846 if (!shader->reference_count()) {
847 continue;
848 }
849
850 /* Gather requested features from all the nodes from the graph nodes. */
851 kernel_features |= get_graph_kernel_features(shader->graph.get());
852 ShaderNode *output_node = shader->graph->output();
853 if (output_node->input("Displacement")->link != nullptr) {
854 kernel_features |= KERNEL_FEATURE_NODE_BUMP;
855 if (shader->get_displacement_method() == DISPLACE_BOTH) {
856 kernel_features |= KERNEL_FEATURE_NODE_BUMP_STATE;
857 }
858 }
859 /* On top of volume nodes, also check if we need volume sampling because
860 * e.g. an Emission node would slip through the KERNEL_FEATURE_NODE_VOLUME check */
861 if (shader->has_volume_connected) {
862 kernel_features |= KERNEL_FEATURE_VOLUME;
863 }
864 }
865
866 if (use_osl()) {
867 kernel_features |= KERNEL_FEATURE_OSL_SHADING;
868 }
869
870 return kernel_features;
871}
872
874{
875 return dot(c, rgb_to_y);
876}
877
882
884{
885 string manifest = "{";
886 unordered_set<ustring> materials;
887 for (Shader *shader : scene->shaders) {
888 if (materials.count(shader->name)) {
889 continue;
890 }
891 materials.insert(shader->name);
892 const uint32_t cryptomatte_id = util_murmur_hash3(
893 shader->name.c_str(), shader->name.length(), 0);
894 manifest += string_printf("\"%s\":\"%08x\",", shader->name.c_str(), cryptomatte_id);
895 }
896 manifest[manifest.size() - 1] = '}';
897 return manifest;
898}
899
900void ShaderManager::tag_update(Scene * /*scene*/, uint32_t /*flag*/)
901{
902 /* update everything for now */
904}
905
907{
908 return update_flags != UPDATE_NONE;
909}
910
911#ifdef WITH_OCIO
912static bool to_scene_linear_transform(OCIO::ConstConfigRcPtr &config,
913 const char *colorspace,
914 Transform &to_scene_linear)
915{
916 OCIO::ConstProcessorRcPtr processor;
917 try {
918 processor = config->getProcessor("scene_linear", colorspace);
919 }
920 catch (OCIO::Exception &) {
921 return false;
922 }
923
924 if (!processor) {
925 return false;
926 }
927
928 const OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
929 if (!device_processor) {
930 return false;
931 }
932
934 device_processor->applyRGB(&to_scene_linear.x.x);
935 device_processor->applyRGB(&to_scene_linear.y.x);
936 device_processor->applyRGB(&to_scene_linear.z.x);
938 return true;
939}
940#endif
941
943{
944 /* Our implementation of Thin Film Fresnel is based on
945 * "A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence"
946 * by Laurent Belcour and Pascal Barla
947 * (https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html).
948 *
949 * The idea there is that for a naive implementation of Thin Film interference, you'd compute
950 * the reflectivity for a given wavelength using Airy summation, and then numerically integrate
951 * the product of this reflectivity function and the Color Matching Functions of the colorspace
952 * you're working in to obtain the RGB (or XYZ) values.
953 * However, this integration would require too many evaluations to be practical.
954 * Therefore, they reformulate the computation as a rapidly converging series involving the
955 * Fourier transform of the CMFs.
956 *
957 * Specifically, we need to:
958 * - Compute the RGB CMFs from the XYZ CMFs using the working color space's XYZ-to-RGB matrix
959 * - Resample the RGB CMFs to be parametrized by frequency instead of wavelength as usual
960 * - Compute the FFT of the CMFs
961 * - Store the result as a LUT
962 * - Look up the values for each channel at runtime based on the optical path difference and
963 * phase shift.
964 *
965 * Computing an FFT here would be annoying, so we'd like to precompute it, but we only know
966 * the XYZ-to-RGB matrix at runtime. Luckily, both resampling and FFT are linear operations,
967 * so we can precompute the FFT of the resampled XYZ CMFs and then multiply each entry with
968 * the XYZ-to-RGB matrix to get the RGB LUT.
969 *
970 * That's what this function does: We load the precomputed values, convert to RGB, normalize
971 * the result to make the DC term equal to 1, and then store that into the final table that's
972 * used by the kernel.
973 */
974 assert(sizeof(table_thin_film_cmf) == 6 * THIN_FILM_TABLE_SIZE * sizeof(float));
976
977 float3 normalization;
978 for (int i = 0; i < THIN_FILM_TABLE_SIZE; i++) {
979 const float *table_row = table_thin_film_cmf[i];
980 /* Load precomputed resampled Fourier-transformed XYZ CMFs. */
981 const float3 xyzReal = make_float3(table_row[0], table_row[1], table_row[2]);
982 const float3 xyzImag = make_float3(table_row[3], table_row[4], table_row[5]);
983
984 /* Linearly combine precomputed data to produce the RGB equivalents. Works since both
985 * resampling and Fourier transformation are linear operations. */
986 const float3 rgbReal = transform_direction(&xyz_to_rgb, xyzReal);
987 const float3 rgbImag = transform_direction(&xyz_to_rgb, xyzImag);
988
989 /* We normalize all entries by the first element. Since that is the DC component, it normalizes
990 * the CMF (in non-Fourier space) to an area of 1. */
991 if (i == 0) {
992 normalization = 1.0f / rgbReal;
993 }
994
995 /* Store in lookup table. */
996 thin_film_table[i + 0 * THIN_FILM_TABLE_SIZE] = rgbReal.x * normalization.x;
997 thin_film_table[i + 1 * THIN_FILM_TABLE_SIZE] = rgbReal.y * normalization.y;
998 thin_film_table[i + 2 * THIN_FILM_TABLE_SIZE] = rgbReal.z * normalization.z;
999 thin_film_table[i + 3 * THIN_FILM_TABLE_SIZE] = rgbImag.x * normalization.x;
1000 thin_film_table[i + 4 * THIN_FILM_TABLE_SIZE] = rgbImag.y * normalization.y;
1001 thin_film_table[i + 5 * THIN_FILM_TABLE_SIZE] = rgbImag.z * normalization.z;
1002 }
1003}
1004
1006{
1007 /* Default to ITU-BT.709 in case no appropriate transform found.
1008 * Note XYZ here is defined as having a D65 white point. */
1009 const Transform xyz_to_rec709 = make_transform(3.2404542f,
1010 -1.5371385f,
1011 -0.4985314f,
1012 0.0f,
1013 -0.9692660f,
1014 1.8760108f,
1015 0.0415560f,
1016 0.0f,
1017 0.0556434f,
1018 -0.2040259f,
1019 1.0572252f,
1020 0.0f);
1021
1022 xyz_to_r = make_float3(xyz_to_rec709.x);
1023 xyz_to_g = make_float3(xyz_to_rec709.y);
1024 xyz_to_b = make_float3(xyz_to_rec709.z);
1025 rgb_to_y = make_float3(0.2126729f, 0.7151522f, 0.0721750f);
1026 white_xyz = make_float3(0.95047f, 1.0f, 1.08883f);
1027
1028 rec709_to_r = make_float3(1.0f, 0.0f, 0.0f);
1029 rec709_to_g = make_float3(0.0f, 1.0f, 0.0f);
1030 rec709_to_b = make_float3(0.0f, 0.0f, 1.0f);
1032
1033 compute_thin_film_table(xyz_to_rec709);
1034
1035#ifdef WITH_OCIO
1036 /* Get from OpenColorO config if it has the required roles. */
1037 OCIO::ConstConfigRcPtr config = nullptr;
1038 try {
1039 config = OCIO::GetCurrentConfig();
1040 }
1041 catch (OCIO::Exception &exception) {
1042 LOG_WARNING << "OCIO config error: " << exception.what();
1043 return;
1044 }
1045
1046 if (!(config && config->hasRole("scene_linear"))) {
1047 return;
1048 }
1049
1051
1052 if (config->hasRole("aces_interchange")) {
1053 /* Standard OpenColorIO role, defined as ACES AP0 (ACES2065-1). */
1054 Transform aces_to_rgb;
1055 if (!to_scene_linear_transform(config, "aces_interchange", aces_to_rgb)) {
1056 return;
1057 }
1058
1059 /* This is the OpenColorIO builtin transform:
1060 * UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD. */
1061 const Transform ACES_AP0_to_xyz_D65 = make_transform(0.938280f,
1062 -0.004451f,
1063 0.016628f,
1064 0.000000f,
1065 0.337369f,
1066 0.729522f,
1067 -0.066890f,
1068 0.000000f,
1069 0.001174f,
1070 -0.003711f,
1071 1.091595f,
1072 0.000000f);
1073 const Transform xyz_to_aces = transform_inverse(ACES_AP0_to_xyz_D65);
1074 xyz_to_rgb = aces_to_rgb * xyz_to_aces;
1075 }
1076 else if (config->hasRole("XYZ")) {
1077 /* Custom role used before the standard existed. */
1078 if (!to_scene_linear_transform(config, "XYZ", xyz_to_rgb)) {
1079 return;
1080 }
1081 }
1082 else {
1083 /* No reference role found to determine XYZ. */
1084 return;
1085 }
1086
1090
1091 const Transform rgb_to_xyz = transform_inverse(xyz_to_rgb);
1092 rgb_to_y = make_float3(rgb_to_xyz.y);
1093 white_xyz = transform_direction(&rgb_to_xyz, one_float3());
1094
1095 const Transform rec709_to_rgb = xyz_to_rgb * transform_inverse(xyz_to_rec709);
1099
1101
1102 const Transform xyz_to_rec2020 = make_transform(1.7166512f,
1103 -0.3556708f,
1104 -0.2533663f,
1105 0.0f,
1106 -0.6666844,
1107 1.6164812f,
1108 0.0157685f,
1109 0.0f,
1110 0.0176399f,
1111 -0.0427706f,
1112 0.9421031f,
1113 0.0f);
1114 const Transform acescg_to_xyz = make_transform(0.652238f,
1115 0.128237f,
1116 0.169983f,
1117 0.0f,
1118 0.267672f,
1119 0.674340f,
1120 0.057988f,
1121 0.0f,
1122 -0.005382f,
1123 0.001369f,
1124 1.093071f,
1125 0.0f);
1126
1127 if (transform_equal_threshold(xyz_to_rgb, xyz_to_rec709, 0.001f)) {
1129 }
1130 else if (transform_equal_threshold(xyz_to_rgb, xyz_to_rec2020, 0.001f)) {
1132 }
1133 else if (transform_equal_threshold(rgb_to_xyz, acescg_to_xyz, 0.001f)) {
1135 }
1136 else {
1138 }
1139#endif
1140}
1141
1143 Scene *scene,
1144 const float *table,
1145 const size_t n)
1146{
1147 /* Since the BSDF tables are static arrays, we can use their address to identify them. */
1148 if (!(bsdf_tables.count(table))) {
1149 vector<float> entries(table, table + n);
1150 bsdf_tables[table] = scene->lookup_tables->add_table(dscene, entries);
1151 }
1152 return bsdf_tables[table];
1153}
1154
unsigned int uint
volatile int lock
unsigned long long int uint64_t
Shader * get_shader(const Scene *scene)
ClosureType get_closure_type() override
device_vector< KernelShader > shaders
Definition devicescene.h:77
device_vector< int4 > svm_nodes
Definition devicescene.h:76
KernelData data
Definition devicescene.h:94
bool from_auto_conversion
unique_ptr_vector< ShaderNode > nodes
ShaderOutput * link
const SocketType & socket_type
string get_cryptomatte_materials(Scene *scene)
size_t thin_film_table_offset_
float3 rec709_to_scene_linear(const float3 c)
static unique_ptr< ShaderManager > create(const int shadingsystem)
void device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress)
SceneLinearSpace scene_linear_space
size_t ensure_bsdf_table_impl(DeviceScene *dscene, Scene *scene, const float *table, const size_t n)
void device_update_pre(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress)
AttributeIDMap unique_attribute_id
float linear_rgb_to_gray(const float3 c)
virtual uint64_t get_attribute_id(ustring name)
void init_xyz_transforms()
virtual void device_update_specific(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress)=0
thread_spin_lock attribute_lock_
virtual ~ShaderManager()
void compute_thin_film_table(const Transform &xyz_to_rgb)
int get_shader_id(Shader *shader, bool smooth=false)
unordered_map< const float *, size_t > bsdf_tables
void device_update_post(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress)
bool need_update() const
void tag_update(Scene *scene, const uint32_t flag)
void device_free_common(Device *device, DeviceScene *dscene, Scene *scene)
static thread_mutex lookup_table_mutex
uint get_kernel_features(Scene *scene)
size_t ensure_bsdf_table(DeviceScene *dscene, Scene *scene, const float(&table)[n])
static void add_default(Scene *scene)
uint32_t update_flags
virtual bool use_osl()
uint get_graph_kernel_features(ShaderGraph *graph)
vector< float > thin_film_table
ShaderInput * input(const char *name)
virtual bool has_surface_transparent()
virtual bool has_surface_emission()
virtual uint get_feature()
ShaderNodeSpecialType special_type
unique_ptr_vector< ShaderInput > inputs
ShaderOutput * output(const char *name)
virtual bool has_surface_bssrdf()
virtual void attributes(Shader *shader, AttributeRequestSet *attributes)
bool has_surface_spatial_varying
bool has_surface_bssrdf
void estimate_emission()
bool need_update_attribute
bool has_volume_attribute_dependency
bool need_update_geometry() const
void set_graph(unique_ptr< ShaderGraph > &&graph)
bool has_volume
bool emission_is_constant
float3 emission_estimate
bool has_surface
bool has_light_path_node
bool has_bssrdf_bump
float prev_volume_step_rate
bool need_update_displacement
EmissionSampling emission_sampling
bool shadow_transparency_needs_realloc
bool has_surface_raytrace
bool need_update_uvs
bool has_displacement
bool has_bump
AttributeRequestSet attributes
bool has_surface_transparent
void tag_update(Scene *scene)
NODE_DECLARE unique_ptr< ShaderGraph > graph
bool prev_has_surface_shadow_transparency
bool has_surface_shadow_transparency() const
bool has_volume_connected
void tag_used(Scene *scene)
bool has_volume_spatial_varying
T * alloc(const size_t width, const size_t height=0)
size_t size() const
reduce_max(value.rgb)") DEFINE_VALUE("REDUCE(lhs
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
ccl_device_inline float2 to_local(const T p, const T X, const T Y)
#define KERNEL_FEATURE_VOLUME
#define CLOSURE_IS_VOLUME(type)
#define KERNEL_FEATURE_NODE_BUMP_STATE
#define KERNEL_FEATURE_TRANSPARENT
#define KERNEL_FEATURE_OSL_SHADING
#define KERNEL_FEATURE_SUBSURFACE
#define KERNEL_FEATURE_NODE_BSDF
#define THIN_FILM_TABLE_SIZE
#define KERNEL_FEATURE_NODE_VOLUME
#define KERNEL_FEATURE_NODE_EMISSION
#define KERNEL_FEATURE_NODE_BUMP
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define input
#define assert(assertion)
#define in
#define output
@ SD_VOLUME_MIS
@ SD_MIS_BACK
@ SD_HAS_TRANSPARENT_SHADOW
@ SD_VOLUME_EQUIANGULAR
@ SD_HAS_BUMP
@ SD_HAS_CONSTANT_EMISSION
@ SD_HAS_DISPLACEMENT
@ SD_HAS_EMISSION
@ SD_MIS_FRONT
@ SD_HAS_BSSRDF_BUMP
@ SD_HAS_ONLY_VOLUME
@ SD_HAS_LIGHT_PATH_NODE
@ SD_HAS_RAYTRACE
@ SD_VOLUME_CUBIC
@ SD_HAS_VOLUME
@ SD_NEED_VOLUME_ATTRIBUTES
@ SD_USE_BUMP_MAP_CORRECTION
@ SD_HETEROGENEOUS_VOLUME
AttributeStandard
@ ATTR_STD_NUM
@ ATTR_STD_POSITION_UNDISPLACED
@ ATTR_STD_NORMAL_UNDISPLACED
@ EMISSION_SAMPLING_NONE
@ EMISSION_SAMPLING_AUTO
@ EMISSION_SAMPLING_BACK
@ EMISSION_SAMPLING_FRONT_BACK
@ EMISSION_SAMPLING_FRONT
@ SHADER_AREA_LIGHT
@ SHADER_SMOOTH_NORMAL
@ SHADER_CAST_SHADOW
ccl_device float3 rec709_to_rgb(KernelGlobals kg, const float3 rec709)
#define LOG_WARNING
Definition log.h:103
ccl_device_inline bool is_zero(const float2 a)
ccl_device_inline float2 fabs(const float2 a)
ccl_device_inline float3 one_float3()
Definition math_float3.h:26
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
Definition math_float3.h:17
uint32_t util_murmur_hash3(const void *key, const int len, const uint32_t seed)
float util_hash_to_float(const uint32_t hash)
BLI_INLINE ColorSceneLinear4f< eAlpha::Straight > to_scene_linear(const ColorTheme4f &theme4f)
Definition BLI_color.hh:126
color xyz_to_rgb(float x, float y, float z)
Definition node_color.h:73
#define SOCKET_FLOAT(name, ui_name, default_value,...)
Definition node_type.h:211
#define SOCKET_INT(name, ui_name, default_value,...)
Definition node_type.h:205
#define NODE_DEFINE(structname)
Definition node_type.h:152
#define SOCKET_BOOLEAN(name, ui_name, default_value,...)
Definition node_type.h:203
#define SOCKET_ENUM(name, ui_name, values, default_value,...)
Definition node_type.h:227
const char * name
#define make_float4
static float3 output_estimate_emission(ShaderOutput *output, bool &is_constant)
@ VOLUME_INTERPOLATION_LINEAR
@ VOLUME_INTERPOLATION_CUBIC
@ DISPLACE_BUMP
@ DISPLACE_TRUE
@ DISPLACE_BOTH
@ SHADINGSYSTEM_OSL
@ VOLUME_SAMPLING_DISTANCE
@ VOLUME_SAMPLING_EQUIANGULAR
@ VOLUME_SAMPLING_MULTIPLE_IMPORTANCE
@ TABLE_OFFSET_INVALID
@ SHADER_SPECIAL_TYPE_LIGHT_PATH
@ SHADER_SPECIAL_TYPE_OUTPUT_AOV
@ SHADER_SPECIAL_TYPE_CLOSURE
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition string.cpp:23
float constant_emission[3]
int ggx_gen_schlick_ior_s
void insert(const char *x, const int y)
Definition node_enum.h:21
static NodeType * add(const char *name, CreateFunc create, Type type=NONE, const NodeType *base=nullptr)
float get_float(const SocketType &input) const
const NodeType * type
Definition graph/node.h:178
float3 get_float3(const SocketType &input) const
ustring name
Definition graph/node.h:177
int reference_count() const
Definition graph/node.h:183
void reference()
Definition graph/node.h:188
void tag_modified()
bool is_modified() const
Node(const NodeType *type, ustring name=ustring())
unique_ptr< ObjectManager > object_manager
Definition scene.h:150
unique_ptr< LightManager > light_manager
Definition scene.h:146
Shader * default_volume
Definition scene.h:158
Shader * default_surface
Definition scene.h:157
Shader * default_empty
Definition scene.h:161
Shader * default_background
Definition scene.h:160
T * create_node(Args &&...)=delete
Background * background
Definition scene.h:129
void tag_has_volume_modified()
Definition scene.cpp:812
unique_ptr_vector< Shader > shaders
Definition scene.h:137
unique_ptr< ShaderManager > shader_manager
Definition scene.h:148
unique_ptr< GeometryManager > geometry_manager
Definition scene.h:149
unique_ptr< ProceduralManager > procedural_manager
Definition scene.h:153
Shader * default_light
Definition scene.h:159
unique_ptr< VolumeManager > volume_manager
Definition scene.h:154
unique_ptr< LookupTables > lookup_tables
Definition scene.h:124
float4 y
Definition transform.h:23
float4 x
Definition transform.h:23
float4 z
Definition transform.h:23
float z
Definition sky_math.h:136
float y
Definition sky_math.h:136
float x
Definition sky_math.h:136
i
Definition text_draw.cc:230
std::mutex thread_mutex
Definition thread.h:27
CCL_NAMESPACE_BEGIN Transform transform_transposed_inverse(const Transform &tfm)
Definition transform.cpp:15
ccl_device_inline Transform transform_identity()
Definition transform.h:322
ccl_device_inline bool transform_equal_threshold(const Transform &A, const Transform &B, const float threshold)
Definition transform.h:339
ccl_device_inline Transform transform_inverse(const Transform tfm)
Definition transform.h:525
ccl_device_inline Transform make_transform(const float a, const float b, const float c, const float d, const float e, const float f, const float g, const float h, const float i, const float j, const float k, const float l)
Definition transform.h:159
ccl_device_inline float3 transform_direction(const ccl_private Transform *t, const float3 a)
Definition transform.h:127
uint8_t flag
Definition wm_window.cc:145