Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/scene/shader.cpp
| Show First 20 Lines • Show All 141 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /* Shader */ | /* Shader */ | ||||
| NODE_DEFINE(Shader) | NODE_DEFINE(Shader) | ||||
| { | { | ||||
| NodeType *type = NodeType::add("shader", create); | NodeType *type = NodeType::add("shader", create); | ||||
| SOCKET_BOOLEAN(use_mis, "Use MIS", true); | 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); | |||||
| SOCKET_BOOLEAN(use_transparent_shadow, "Use Transparent Shadow", true); | SOCKET_BOOLEAN(use_transparent_shadow, "Use Transparent Shadow", true); | ||||
| SOCKET_BOOLEAN(heterogeneous_volume, "Heterogeneous Volume", true); | SOCKET_BOOLEAN(heterogeneous_volume, "Heterogeneous Volume", true); | ||||
| static NodeEnum volume_sampling_method_enum; | static NodeEnum volume_sampling_method_enum; | ||||
| volume_sampling_method_enum.insert("distance", VOLUME_SAMPLING_DISTANCE); | volume_sampling_method_enum.insert("distance", VOLUME_SAMPLING_DISTANCE); | ||||
| volume_sampling_method_enum.insert("equiangular", VOLUME_SAMPLING_EQUIANGULAR); | volume_sampling_method_enum.insert("equiangular", VOLUME_SAMPLING_EQUIANGULAR); | ||||
| volume_sampling_method_enum.insert("multiple_importance", VOLUME_SAMPLING_MULTIPLE_IMPORTANCE); | volume_sampling_method_enum.insert("multiple_importance", VOLUME_SAMPLING_MULTIPLE_IMPORTANCE); | ||||
| SOCKET_ENUM(volume_sampling_method, | SOCKET_ENUM(volume_sampling_method, | ||||
| Show All 25 Lines | |||||
| Shader::Shader() : Node(get_node_type()) | Shader::Shader() : Node(get_node_type()) | ||||
| { | { | ||||
| pass_id = 0; | pass_id = 0; | ||||
| graph = NULL; | graph = NULL; | ||||
| has_surface = false; | has_surface = false; | ||||
| has_surface_transparent = false; | has_surface_transparent = false; | ||||
| has_surface_emission = false; | |||||
| has_surface_raytrace = false; | has_surface_raytrace = false; | ||||
| has_surface_bssrdf = false; | has_surface_bssrdf = false; | ||||
| has_volume = false; | has_volume = false; | ||||
| has_displacement = false; | has_displacement = false; | ||||
| has_bump = false; | has_bump = false; | ||||
| has_bssrdf_bump = false; | has_bssrdf_bump = false; | ||||
| has_surface_spatial_varying = false; | has_surface_spatial_varying = false; | ||||
| has_volume_spatial_varying = false; | has_volume_spatial_varying = false; | ||||
| has_volume_attribute_dependency = false; | has_volume_attribute_dependency = false; | ||||
| has_integrator_dependency = false; | has_integrator_dependency = false; | ||||
| has_volume_connected = false; | has_volume_connected = false; | ||||
| prev_volume_step_rate = 0.0f; | prev_volume_step_rate = 0.0f; | ||||
| emission_estimate = zero_float3(); | |||||
| emission_sampling = EMISSION_SAMPLING_NONE; | |||||
| emission_is_constant = true; | |||||
| displacement_method = DISPLACE_BUMP; | displacement_method = DISPLACE_BUMP; | ||||
| id = -1; | id = -1; | ||||
| need_update_uvs = true; | need_update_uvs = true; | ||||
| need_update_attribute = true; | need_update_attribute = true; | ||||
| need_update_displacement = true; | need_update_displacement = true; | ||||
| } | } | ||||
| Shader::~Shader() | Shader::~Shader() | ||||
| { | { | ||||
| delete graph; | delete graph; | ||||
| } | } | ||||
| bool Shader::is_constant_emission(float3 *emission) | static float3 output_estimate_emission(ShaderOutput *output, bool &is_constant) | ||||
| { | { | ||||
| /* If the shader has AOVs, they need to be evaluated, so we can't skip the shader. */ | /* Only supports a few nodes for now, not arbitrary shader graphs. */ | ||||
| foreach (ShaderNode *node, graph->nodes) { | ShaderNode *node = (output) ? output->parent : nullptr; | ||||
| if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) { | |||||
| return false; | if (node == nullptr) { | ||||
| } | return zero_float3(); | ||||
| } | } | ||||
| else if (node->type == EmissionNode::get_node_type() || | |||||
| node->type == BackgroundNode::get_node_type()) { | |||||
| /* Emission and Background node. */ | |||||
| ShaderInput *color_in = node->input("Color"); | |||||
| ShaderInput *strength_in = node->input("Strength"); | |||||
| ShaderInput *surf = graph->output()->input("Surface"); | float3 estimate = one_float3(); | ||||
| if (surf->link == NULL) { | if (color_in->link) { | ||||
| return false; | is_constant = false; | ||||
| } | |||||
| else { | |||||
| estimate *= node->get_float3(color_in->socket_type); | |||||
| } | } | ||||
| if (surf->link->parent->type == EmissionNode::get_node_type()) { | if (strength_in->link) { | ||||
| EmissionNode *node = (EmissionNode *)surf->link->parent; | is_constant = false; | ||||
| estimate *= output_estimate_emission(strength_in->link, is_constant); | |||||
| } | |||||
| else { | |||||
| estimate *= node->get_float(strength_in->socket_type); | |||||
| } | |||||
| assert(node->input("Color")); | return estimate; | ||||
| assert(node->input("Strength")); | } | ||||
| else if (node->type == LightFalloffNode::get_node_type()) { | |||||
| /* Light Falloff node. */ | |||||
| ShaderInput *strength_in = node->input("Strength"); | |||||
| is_constant = false; | |||||
| return (strength_in->link) ? output_estimate_emission(strength_in->link, is_constant) : | |||||
| make_float3(node->get_float(strength_in->socket_type)); | |||||
| } | |||||
| else if (node->type == AddClosureNode::get_node_type()) { | |||||
| /* 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; | |||||
| } | |||||
| else if (node->type == MixClosureNode::get_node_type()) { | |||||
| /* 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; | |||||
| } | |||||
| else { | |||||
| const float fac = node->get_float(fac_in->socket_type); | |||||
| return (1.0f - fac) * estimate1 + fac * estimate2; | |||||
| } | |||||
| } | |||||
| else { | |||||
| /* 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) { | |||||
| estimate = one_float3(); | |||||
| is_constant = false; | |||||
| } | |||||
| else { | |||||
| estimate = zero_float3(); | |||||
| } | |||||
| if (node->input("Color")->link || node->input("Strength")->link) { | foreach (const ShaderInput *in, node->inputs) { | ||||
| return false; | if (in->type() == SocketType::CLOSURE && in->link) { | ||||
| estimate += output_estimate_emission(in->link, is_constant); | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| estimate = one_float3(); | |||||
| is_constant = false; | |||||
| } | } | ||||
| *emission = node->get_color() * node->get_strength(); | return estimate; | ||||
| } | |||||
| } | } | ||||
| else if (surf->link->parent->type == BackgroundNode::get_node_type()) { | |||||
| BackgroundNode *node = (BackgroundNode *)surf->link->parent; | |||||
| assert(node->input("Color")); | void Shader::estimate_emission() | ||||
| assert(node->input("Strength")); | { | ||||
| /* If the shader has AOVs, they need to be evaluated, so we can't skip the shader. */ | |||||
| emission_is_constant = true; | |||||
| if (node->input("Color")->link || node->input("Strength")->link) { | foreach (ShaderNode *node, graph->nodes) { | ||||
| return false; | if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) { | ||||
| emission_is_constant = false; | |||||
| } | } | ||||
| } | |||||
| ShaderInput *surf = graph->output()->input("Surface"); | |||||
| emission_estimate = output_estimate_emission(surf->link, emission_is_constant); | |||||
| *emission = node->get_color() * node->get_strength(); | 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. */ | |||||
| emission_sampling = (reduce_max(emission_estimate) > 0.5f) ? EMISSION_SAMPLING_FRONT_BACK : | |||||
| EMISSION_SAMPLING_NONE; | |||||
| } | } | ||||
| else { | else { | ||||
| return false; | emission_sampling = emission_sampling_method; | ||||
| } | } | ||||
| return true; | |||||
| } | } | ||||
| void Shader::set_graph(ShaderGraph *graph_) | void Shader::set_graph(ShaderGraph *graph_) | ||||
| { | { | ||||
| /* do this here already so that we can detect if mesh or object attributes | /* 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 needed, since the node attribute callbacks check if their sockets | ||||
| * are connected but proxy nodes should not count */ | * are connected but proxy nodes should not count */ | ||||
| if (graph_) { | if (graph_) { | ||||
| Show All 28 Lines | void Shader::tag_update(Scene *scene) | ||||
| /* update tag */ | /* update tag */ | ||||
| tag_modified(); | tag_modified(); | ||||
| scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED); | scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED); | ||||
| /* if the shader previously was emissive, update light distribution, | /* if the shader previously was emissive, update light distribution, | ||||
| * if the new shader is emissive, a light manager update tag will be | * if the new shader is emissive, a light manager update tag will be | ||||
| * done in the shader manager device update. */ | * done in the shader manager device update. */ | ||||
| if (use_mis && has_surface_emission) | if (emission_sampling != EMISSION_SAMPLING_NONE) | ||||
| scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED); | scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED); | ||||
| /* Special handle of background MIS light for now: for some reason it | /* 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 | * has use_mis set to false. We are quite close to release now, so | ||||
| * better to be safe. | * better to be safe. | ||||
| */ | */ | ||||
| if (this == scene->background->get_shader(scene)) { | if (this == scene->background->get_shader(scene)) { | ||||
| scene->light_manager->need_update_background = true; | scene->light_manager->need_update_background = true; | ||||
| ▲ Show 20 Lines • Show All 169 Lines • ▼ Show 20 Lines | void ShaderManager::device_update_common(Device * /*device*/, | ||||
| KernelShader *kshader = dscene->shaders.alloc(scene->shaders.size()); | KernelShader *kshader = dscene->shaders.alloc(scene->shaders.size()); | ||||
| bool has_volumes = false; | bool has_volumes = false; | ||||
| bool has_transparent_shadow = false; | bool has_transparent_shadow = false; | ||||
| foreach (Shader *shader, scene->shaders) { | foreach (Shader *shader, scene->shaders) { | ||||
| uint flag = 0; | uint flag = 0; | ||||
| if (shader->get_use_mis()) | if (shader->emission_sampling == EMISSION_SAMPLING_FRONT) { | ||||
| flag |= SD_USE_MIS; | flag |= SD_MIS_FRONT; | ||||
| if (shader->has_surface_emission) | } | ||||
| 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; | |||||
| } | |||||
| if (!is_zero(shader->emission_estimate)) | |||||
| flag |= SD_HAS_EMISSION; | flag |= SD_HAS_EMISSION; | ||||
| if (shader->has_surface_transparent && shader->get_use_transparent_shadow()) | if (shader->has_surface_transparent && shader->get_use_transparent_shadow()) | ||||
| flag |= SD_HAS_TRANSPARENT_SHADOW; | flag |= SD_HAS_TRANSPARENT_SHADOW; | ||||
| if (shader->has_surface_raytrace) | if (shader->has_surface_raytrace) | ||||
| flag |= SD_HAS_RAYTRACE; | flag |= SD_HAS_RAYTRACE; | ||||
| if (shader->has_volume) { | if (shader->has_volume) { | ||||
| flag |= SD_HAS_VOLUME; | flag |= SD_HAS_VOLUME; | ||||
| has_volumes = true; | has_volumes = true; | ||||
| Show All 21 Lines | foreach (Shader *shader, scene->shaders) { | ||||
| if (shader->get_volume_interpolation_method() == VOLUME_INTERPOLATION_CUBIC) | if (shader->get_volume_interpolation_method() == VOLUME_INTERPOLATION_CUBIC) | ||||
| flag |= SD_VOLUME_CUBIC; | flag |= SD_VOLUME_CUBIC; | ||||
| if (shader->has_bump) | if (shader->has_bump) | ||||
| flag |= SD_HAS_BUMP; | flag |= SD_HAS_BUMP; | ||||
| if (shader->get_displacement_method() != DISPLACE_BUMP) | if (shader->get_displacement_method() != DISPLACE_BUMP) | ||||
| flag |= SD_HAS_DISPLACEMENT; | flag |= SD_HAS_DISPLACEMENT; | ||||
| /* constant emission check */ | /* constant emission check */ | ||||
| float3 constant_emission = zero_float3(); | if (shader->emission_is_constant) | ||||
| if (shader->is_constant_emission(&constant_emission)) | |||||
| flag |= SD_HAS_CONSTANT_EMISSION; | flag |= SD_HAS_CONSTANT_EMISSION; | ||||
| uint32_t cryptomatte_id = util_murmur_hash3(shader->name.c_str(), shader->name.length(), 0); | uint32_t cryptomatte_id = util_murmur_hash3(shader->name.c_str(), shader->name.length(), 0); | ||||
| /* regular shader */ | /* regular shader */ | ||||
| kshader->flags = flag; | kshader->flags = flag; | ||||
| kshader->pass_id = shader->get_pass_id(); | kshader->pass_id = shader->get_pass_id(); | ||||
| kshader->constant_emission[0] = constant_emission.x; | kshader->constant_emission[0] = shader->emission_estimate.x; | ||||
| kshader->constant_emission[1] = constant_emission.y; | kshader->constant_emission[1] = shader->emission_estimate.y; | ||||
| kshader->constant_emission[2] = constant_emission.z; | kshader->constant_emission[2] = shader->emission_estimate.z; | ||||
| kshader->cryptomatte_id = util_hash_to_float(cryptomatte_id); | kshader->cryptomatte_id = util_hash_to_float(cryptomatte_id); | ||||
| kshader++; | kshader++; | ||||
| has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0; | has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0; | ||||
| } | } | ||||
| dscene->shaders.copy_to_device(); | dscene->shaders.copy_to_device(); | ||||
| ▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | /* default volume */ | ||||
| graph->connect(principled->output("Volume"), graph->output()->input("Volume")); | graph->connect(principled->output("Volume"), graph->output()->input("Volume")); | ||||
| Shader *shader = scene->create_node<Shader>(); | Shader *shader = scene->create_node<Shader>(); | ||||
| shader->name = "default_volume"; | shader->name = "default_volume"; | ||||
| shader->set_graph(graph); | shader->set_graph(graph); | ||||
| scene->default_volume = shader; | scene->default_volume = shader; | ||||
| shader->tag_update(scene); | shader->tag_update(scene); | ||||
| /* No default reference for the volume to avoid compiling volume kernels if there are no actual | /* No default reference for the volume to avoid compiling volume kernels if there are no | ||||
| * volumes in the scene */ | * actual volumes in the scene */ | ||||
| } | } | ||||
| /* default light */ | /* default light */ | ||||
| { | { | ||||
| ShaderGraph *graph = new ShaderGraph(); | ShaderGraph *graph = new ShaderGraph(); | ||||
| EmissionNode *emission = graph->create_node<EmissionNode>(); | EmissionNode *emission = graph->create_node<EmissionNode>(); | ||||
| emission->set_color(make_float3(0.8f, 0.8f, 0.8f)); | emission->set_color(make_float3(0.8f, 0.8f, 0.8f)); | ||||
| ▲ Show 20 Lines • Show All 259 Lines • Show Last 20 Lines | |||||