Makes it more explicit they operate on shading/light. Gives room to move more viewport related settings into this class and cover with specific or generic modification checks.
1568 lines
58 KiB
C++
1568 lines
58 KiB
C++
/*
|
|
* Copyright 2011-2013 Blender Foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "render/background.h"
|
|
#include "render/colorspace.h"
|
|
#include "render/graph.h"
|
|
#include "render/light.h"
|
|
#include "render/nodes.h"
|
|
#include "render/osl.h"
|
|
#include "render/scene.h"
|
|
#include "render/shader.h"
|
|
|
|
#include "blender/blender_image.h"
|
|
#include "blender/blender_sync.h"
|
|
#include "blender/blender_texture.h"
|
|
#include "blender/blender_util.h"
|
|
|
|
#include "util/util_debug.h"
|
|
#include "util/util_foreach.h"
|
|
#include "util/util_set.h"
|
|
#include "util/util_string.h"
|
|
#include "util/util_task.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
typedef map<void *, ShaderInput *> PtrInputMap;
|
|
typedef map<void *, ShaderOutput *> PtrOutputMap;
|
|
typedef map<string, ConvertNode *> ProxyMap;
|
|
|
|
/* Find */
|
|
|
|
void BlenderSync::find_shader(BL::ID &id, array<Node *> &used_shaders, Shader *default_shader)
|
|
{
|
|
Shader *shader = (id) ? shader_map.find(id) : default_shader;
|
|
|
|
used_shaders.push_back_slow(shader);
|
|
shader->tag_used(scene);
|
|
}
|
|
|
|
/* RNA translation utilities */
|
|
|
|
static VolumeSampling get_volume_sampling(PointerRNA &ptr)
|
|
{
|
|
return (VolumeSampling)get_enum(
|
|
ptr, "volume_sampling", VOLUME_NUM_SAMPLING, VOLUME_SAMPLING_DISTANCE);
|
|
}
|
|
|
|
static VolumeInterpolation get_volume_interpolation(PointerRNA &ptr)
|
|
{
|
|
return (VolumeInterpolation)get_enum(
|
|
ptr, "volume_interpolation", VOLUME_NUM_INTERPOLATION, VOLUME_INTERPOLATION_LINEAR);
|
|
}
|
|
|
|
static DisplacementMethod get_displacement_method(PointerRNA &ptr)
|
|
{
|
|
return (DisplacementMethod)get_enum(
|
|
ptr, "displacement_method", DISPLACE_NUM_METHODS, DISPLACE_BUMP);
|
|
}
|
|
|
|
static int validate_enum_value(int value, int num_values, int default_value)
|
|
{
|
|
if (value >= num_values) {
|
|
return default_value;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
template<typename NodeType> static InterpolationType get_image_interpolation(NodeType &b_node)
|
|
{
|
|
int value = b_node.interpolation();
|
|
return (InterpolationType)validate_enum_value(
|
|
value, INTERPOLATION_NUM_TYPES, INTERPOLATION_LINEAR);
|
|
}
|
|
|
|
template<typename NodeType> static ExtensionType get_image_extension(NodeType &b_node)
|
|
{
|
|
int value = b_node.extension();
|
|
return (ExtensionType)validate_enum_value(value, EXTENSION_NUM_TYPES, EXTENSION_REPEAT);
|
|
}
|
|
|
|
static ImageAlphaType get_image_alpha_type(BL::Image &b_image)
|
|
{
|
|
int value = b_image.alpha_mode();
|
|
return (ImageAlphaType)validate_enum_value(value, IMAGE_ALPHA_NUM_TYPES, IMAGE_ALPHA_AUTO);
|
|
}
|
|
|
|
/* Attribute name translation utilities */
|
|
|
|
/* Since Eevee needs to know whether the attribute is uniform or varying
|
|
* at the time it compiles the shader for the material, Blender had to
|
|
* introduce different namespaces (types) in its attribute node. However,
|
|
* Cycles already has object attributes that form a uniform namespace with
|
|
* the more common varying attributes. Without completely reworking the
|
|
* attribute handling in Cycles to introduce separate namespaces (this could
|
|
* be especially hard for OSL which directly uses the name string), the
|
|
* space identifier has to be added to the attribute name as a prefix.
|
|
*
|
|
* The prefixes include a control character to ensure the user specified
|
|
* name can't accidentally include a special prefix.
|
|
*/
|
|
|
|
static const string_view object_attr_prefix("\x01object:");
|
|
static const string_view instancer_attr_prefix("\x01instancer:");
|
|
|
|
static ustring blender_attribute_name_add_type(const string &name, BlenderAttributeType type)
|
|
{
|
|
switch (type) {
|
|
case BL::ShaderNodeAttribute::attribute_type_OBJECT:
|
|
return ustring::concat(object_attr_prefix, name);
|
|
case BL::ShaderNodeAttribute::attribute_type_INSTANCER:
|
|
return ustring::concat(instancer_attr_prefix, name);
|
|
default:
|
|
return ustring(name);
|
|
}
|
|
}
|
|
|
|
BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name)
|
|
{
|
|
string_view sname(name);
|
|
|
|
if (sname.substr(0, object_attr_prefix.size()) == object_attr_prefix) {
|
|
*r_real_name = sname.substr(object_attr_prefix.size());
|
|
return BL::ShaderNodeAttribute::attribute_type_OBJECT;
|
|
}
|
|
|
|
if (sname.substr(0, instancer_attr_prefix.size()) == instancer_attr_prefix) {
|
|
*r_real_name = sname.substr(instancer_attr_prefix.size());
|
|
return BL::ShaderNodeAttribute::attribute_type_INSTANCER;
|
|
}
|
|
|
|
return BL::ShaderNodeAttribute::attribute_type_GEOMETRY;
|
|
}
|
|
|
|
/* Graph */
|
|
|
|
static BL::NodeSocket get_node_output(BL::Node &b_node, const string &name)
|
|
{
|
|
for (BL::NodeSocket &b_out : b_node.outputs) {
|
|
if (b_out.name() == name) {
|
|
return b_out;
|
|
}
|
|
}
|
|
assert(0);
|
|
return *b_node.outputs.begin();
|
|
}
|
|
|
|
static float3 get_node_output_rgba(BL::Node &b_node, const string &name)
|
|
{
|
|
BL::NodeSocket b_sock = get_node_output(b_node, name);
|
|
float value[4];
|
|
RNA_float_get_array(&b_sock.ptr, "default_value", value);
|
|
return make_float3(value[0], value[1], value[2]);
|
|
}
|
|
|
|
static float get_node_output_value(BL::Node &b_node, const string &name)
|
|
{
|
|
BL::NodeSocket b_sock = get_node_output(b_node, name);
|
|
return RNA_float_get(&b_sock.ptr, "default_value");
|
|
}
|
|
|
|
static float3 get_node_output_vector(BL::Node &b_node, const string &name)
|
|
{
|
|
BL::NodeSocket b_sock = get_node_output(b_node, name);
|
|
float value[3];
|
|
RNA_float_get_array(&b_sock.ptr, "default_value", value);
|
|
return make_float3(value[0], value[1], value[2]);
|
|
}
|
|
|
|
static SocketType::Type convert_socket_type(BL::NodeSocket &b_socket)
|
|
{
|
|
switch (b_socket.type()) {
|
|
case BL::NodeSocket::type_VALUE:
|
|
return SocketType::FLOAT;
|
|
case BL::NodeSocket::type_INT:
|
|
return SocketType::INT;
|
|
case BL::NodeSocket::type_VECTOR:
|
|
return SocketType::VECTOR;
|
|
case BL::NodeSocket::type_RGBA:
|
|
return SocketType::COLOR;
|
|
case BL::NodeSocket::type_STRING:
|
|
return SocketType::STRING;
|
|
case BL::NodeSocket::type_SHADER:
|
|
return SocketType::CLOSURE;
|
|
|
|
default:
|
|
return SocketType::UNDEFINED;
|
|
}
|
|
}
|
|
|
|
static void set_default_value(ShaderInput *input,
|
|
BL::NodeSocket &b_sock,
|
|
BL::BlendData &b_data,
|
|
BL::ID &b_id)
|
|
{
|
|
Node *node = input->parent;
|
|
const SocketType &socket = input->socket_type;
|
|
|
|
/* copy values for non linked inputs */
|
|
switch (input->type()) {
|
|
case SocketType::FLOAT: {
|
|
node->set(socket, get_float(b_sock.ptr, "default_value"));
|
|
break;
|
|
}
|
|
case SocketType::INT: {
|
|
node->set(socket, get_int(b_sock.ptr, "default_value"));
|
|
break;
|
|
}
|
|
case SocketType::COLOR: {
|
|
node->set(socket, float4_to_float3(get_float4(b_sock.ptr, "default_value")));
|
|
break;
|
|
}
|
|
case SocketType::NORMAL:
|
|
case SocketType::POINT:
|
|
case SocketType::VECTOR: {
|
|
node->set(socket, get_float3(b_sock.ptr, "default_value"));
|
|
break;
|
|
}
|
|
case SocketType::STRING: {
|
|
node->set(
|
|
socket,
|
|
(ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value")));
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void get_tex_mapping(TextureNode *mapping, BL::TexMapping &b_mapping)
|
|
{
|
|
if (!b_mapping)
|
|
return;
|
|
|
|
mapping->set_tex_mapping_translation(get_float3(b_mapping.translation()));
|
|
mapping->set_tex_mapping_rotation(get_float3(b_mapping.rotation()));
|
|
mapping->set_tex_mapping_scale(get_float3(b_mapping.scale()));
|
|
mapping->set_tex_mapping_type((TextureMapping::Type)b_mapping.vector_type());
|
|
|
|
mapping->set_tex_mapping_x_mapping((TextureMapping::Mapping)b_mapping.mapping_x());
|
|
mapping->set_tex_mapping_y_mapping((TextureMapping::Mapping)b_mapping.mapping_y());
|
|
mapping->set_tex_mapping_z_mapping((TextureMapping::Mapping)b_mapping.mapping_z());
|
|
}
|
|
|
|
static ShaderNode *add_node(Scene *scene,
|
|
BL::RenderEngine &b_engine,
|
|
BL::BlendData &b_data,
|
|
BL::Depsgraph &b_depsgraph,
|
|
BL::Scene &b_scene,
|
|
ShaderGraph *graph,
|
|
BL::ShaderNodeTree &b_ntree,
|
|
BL::ShaderNode &b_node)
|
|
{
|
|
ShaderNode *node = NULL;
|
|
|
|
/* existing blender nodes */
|
|
if (b_node.is_a(&RNA_ShaderNodeRGBCurve)) {
|
|
BL::ShaderNodeRGBCurve b_curve_node(b_node);
|
|
BL::CurveMapping mapping(b_curve_node.mapping());
|
|
RGBCurvesNode *curves = graph->create_node<RGBCurvesNode>();
|
|
array<float3> curve_mapping_curves;
|
|
float min_x, max_x;
|
|
curvemapping_color_to_array(mapping, curve_mapping_curves, RAMP_TABLE_SIZE, true);
|
|
curvemapping_minmax(mapping, true, &min_x, &max_x);
|
|
curves->set_min_x(min_x);
|
|
curves->set_max_x(max_x);
|
|
curves->set_curves(curve_mapping_curves);
|
|
node = curves;
|
|
}
|
|
if (b_node.is_a(&RNA_ShaderNodeVectorCurve)) {
|
|
BL::ShaderNodeVectorCurve b_curve_node(b_node);
|
|
BL::CurveMapping mapping(b_curve_node.mapping());
|
|
VectorCurvesNode *curves = graph->create_node<VectorCurvesNode>();
|
|
array<float3> curve_mapping_curves;
|
|
float min_x, max_x;
|
|
curvemapping_color_to_array(mapping, curve_mapping_curves, RAMP_TABLE_SIZE, false);
|
|
curvemapping_minmax(mapping, false, &min_x, &max_x);
|
|
curves->set_min_x(min_x);
|
|
curves->set_max_x(max_x);
|
|
curves->set_curves(curve_mapping_curves);
|
|
node = curves;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeValToRGB)) {
|
|
RGBRampNode *ramp = graph->create_node<RGBRampNode>();
|
|
BL::ShaderNodeValToRGB b_ramp_node(b_node);
|
|
BL::ColorRamp b_color_ramp(b_ramp_node.color_ramp());
|
|
array<float3> ramp_values;
|
|
array<float> ramp_alpha;
|
|
colorramp_to_array(b_color_ramp, ramp_values, ramp_alpha, RAMP_TABLE_SIZE);
|
|
ramp->set_ramp(ramp_values);
|
|
ramp->set_ramp_alpha(ramp_alpha);
|
|
ramp->set_interpolate(b_color_ramp.interpolation() != BL::ColorRamp::interpolation_CONSTANT);
|
|
node = ramp;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeRGB)) {
|
|
ColorNode *color = graph->create_node<ColorNode>();
|
|
color->set_value(get_node_output_rgba(b_node, "Color"));
|
|
node = color;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeValue)) {
|
|
ValueNode *value = graph->create_node<ValueNode>();
|
|
value->set_value(get_node_output_value(b_node, "Value"));
|
|
node = value;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeCameraData)) {
|
|
node = graph->create_node<CameraNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeInvert)) {
|
|
node = graph->create_node<InvertNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeGamma)) {
|
|
node = graph->create_node<GammaNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBrightContrast)) {
|
|
node = graph->create_node<BrightContrastNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeMixRGB)) {
|
|
BL::ShaderNodeMixRGB b_mix_node(b_node);
|
|
MixNode *mix = graph->create_node<MixNode>();
|
|
mix->set_mix_type((NodeMix)b_mix_node.blend_type());
|
|
mix->set_use_clamp(b_mix_node.use_clamp());
|
|
node = mix;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeSeparateRGB)) {
|
|
node = graph->create_node<SeparateRGBNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeCombineRGB)) {
|
|
node = graph->create_node<CombineRGBNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeSeparateHSV)) {
|
|
node = graph->create_node<SeparateHSVNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeCombineHSV)) {
|
|
node = graph->create_node<CombineHSVNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeSeparateXYZ)) {
|
|
node = graph->create_node<SeparateXYZNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeCombineXYZ)) {
|
|
node = graph->create_node<CombineXYZNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeHueSaturation)) {
|
|
node = graph->create_node<HSVNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeRGBToBW)) {
|
|
node = graph->create_node<RGBToBWNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeMapRange)) {
|
|
BL::ShaderNodeMapRange b_map_range_node(b_node);
|
|
MapRangeNode *map_range_node = graph->create_node<MapRangeNode>();
|
|
map_range_node->set_clamp(b_map_range_node.clamp());
|
|
map_range_node->set_range_type((NodeMapRangeType)b_map_range_node.interpolation_type());
|
|
node = map_range_node;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeClamp)) {
|
|
BL::ShaderNodeClamp b_clamp_node(b_node);
|
|
ClampNode *clamp_node = graph->create_node<ClampNode>();
|
|
clamp_node->set_clamp_type((NodeClampType)b_clamp_node.clamp_type());
|
|
node = clamp_node;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeMath)) {
|
|
BL::ShaderNodeMath b_math_node(b_node);
|
|
MathNode *math_node = graph->create_node<MathNode>();
|
|
math_node->set_math_type((NodeMathType)b_math_node.operation());
|
|
math_node->set_use_clamp(b_math_node.use_clamp());
|
|
node = math_node;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeVectorMath)) {
|
|
BL::ShaderNodeVectorMath b_vector_math_node(b_node);
|
|
VectorMathNode *vector_math_node = graph->create_node<VectorMathNode>();
|
|
vector_math_node->set_math_type((NodeVectorMathType)b_vector_math_node.operation());
|
|
node = vector_math_node;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeVectorRotate)) {
|
|
BL::ShaderNodeVectorRotate b_vector_rotate_node(b_node);
|
|
VectorRotateNode *vector_rotate_node = graph->create_node<VectorRotateNode>();
|
|
vector_rotate_node->set_rotate_type(
|
|
(NodeVectorRotateType)b_vector_rotate_node.rotation_type());
|
|
vector_rotate_node->set_invert(b_vector_rotate_node.invert());
|
|
node = vector_rotate_node;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeVectorTransform)) {
|
|
BL::ShaderNodeVectorTransform b_vector_transform_node(b_node);
|
|
VectorTransformNode *vtransform = graph->create_node<VectorTransformNode>();
|
|
vtransform->set_transform_type((NodeVectorTransformType)b_vector_transform_node.vector_type());
|
|
vtransform->set_convert_from(
|
|
(NodeVectorTransformConvertSpace)b_vector_transform_node.convert_from());
|
|
vtransform->set_convert_to(
|
|
(NodeVectorTransformConvertSpace)b_vector_transform_node.convert_to());
|
|
node = vtransform;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeNormal)) {
|
|
BL::Node::outputs_iterator out_it;
|
|
b_node.outputs.begin(out_it);
|
|
|
|
NormalNode *norm = graph->create_node<NormalNode>();
|
|
norm->set_direction(get_node_output_vector(b_node, "Normal"));
|
|
node = norm;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeMapping)) {
|
|
BL::ShaderNodeMapping b_mapping_node(b_node);
|
|
MappingNode *mapping = graph->create_node<MappingNode>();
|
|
mapping->set_mapping_type((NodeMappingType)b_mapping_node.vector_type());
|
|
node = mapping;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeFresnel)) {
|
|
node = graph->create_node<FresnelNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeLayerWeight)) {
|
|
node = graph->create_node<LayerWeightNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeAddShader)) {
|
|
node = graph->create_node<AddClosureNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeMixShader)) {
|
|
node = graph->create_node<MixClosureNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeAttribute)) {
|
|
BL::ShaderNodeAttribute b_attr_node(b_node);
|
|
AttributeNode *attr = graph->create_node<AttributeNode>();
|
|
attr->set_attribute(blender_attribute_name_add_type(b_attr_node.attribute_name(),
|
|
b_attr_node.attribute_type()));
|
|
node = attr;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBackground)) {
|
|
node = graph->create_node<BackgroundNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeHoldout)) {
|
|
node = graph->create_node<HoldoutNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) {
|
|
BL::ShaderNodeBsdfAnisotropic b_aniso_node(b_node);
|
|
AnisotropicBsdfNode *aniso = graph->create_node<AnisotropicBsdfNode>();
|
|
|
|
switch (b_aniso_node.distribution()) {
|
|
case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN:
|
|
aniso->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
|
|
aniso->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX:
|
|
aniso->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
|
|
aniso->set_distribution(CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
|
|
break;
|
|
}
|
|
|
|
node = aniso;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) {
|
|
node = graph->create_node<DiffuseBsdfNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeSubsurfaceScattering)) {
|
|
BL::ShaderNodeSubsurfaceScattering b_subsurface_node(b_node);
|
|
|
|
SubsurfaceScatteringNode *subsurface = graph->create_node<SubsurfaceScatteringNode>();
|
|
|
|
switch (b_subsurface_node.falloff()) {
|
|
case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC:
|
|
subsurface->set_falloff(CLOSURE_BSSRDF_CUBIC_ID);
|
|
break;
|
|
case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN:
|
|
subsurface->set_falloff(CLOSURE_BSSRDF_GAUSSIAN_ID);
|
|
break;
|
|
case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY:
|
|
subsurface->set_falloff(CLOSURE_BSSRDF_BURLEY_ID);
|
|
break;
|
|
case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK:
|
|
subsurface->set_falloff(CLOSURE_BSSRDF_RANDOM_WALK_ID);
|
|
break;
|
|
}
|
|
|
|
node = subsurface;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) {
|
|
BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
|
|
GlossyBsdfNode *glossy = graph->create_node<GlossyBsdfNode>();
|
|
|
|
switch (b_glossy_node.distribution()) {
|
|
case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
|
|
glossy->set_distribution(CLOSURE_BSDF_REFLECTION_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
|
|
glossy->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfGlossy::distribution_GGX:
|
|
glossy->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY:
|
|
glossy->set_distribution(CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX:
|
|
glossy->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
|
|
break;
|
|
}
|
|
node = glossy;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBsdfGlass)) {
|
|
BL::ShaderNodeBsdfGlass b_glass_node(b_node);
|
|
GlassBsdfNode *glass = graph->create_node<GlassBsdfNode>();
|
|
switch (b_glass_node.distribution()) {
|
|
case BL::ShaderNodeBsdfGlass::distribution_SHARP:
|
|
glass->set_distribution(CLOSURE_BSDF_SHARP_GLASS_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
|
|
glass->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfGlass::distribution_GGX:
|
|
glass->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfGlass::distribution_MULTI_GGX:
|
|
glass->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
|
|
break;
|
|
}
|
|
node = glass;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBsdfRefraction)) {
|
|
BL::ShaderNodeBsdfRefraction b_refraction_node(b_node);
|
|
RefractionBsdfNode *refraction = graph->create_node<RefractionBsdfNode>();
|
|
switch (b_refraction_node.distribution()) {
|
|
case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
|
|
refraction->set_distribution(CLOSURE_BSDF_REFRACTION_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
|
|
refraction->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfRefraction::distribution_GGX:
|
|
refraction->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
|
|
break;
|
|
}
|
|
node = refraction;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBsdfToon)) {
|
|
BL::ShaderNodeBsdfToon b_toon_node(b_node);
|
|
ToonBsdfNode *toon = graph->create_node<ToonBsdfNode>();
|
|
switch (b_toon_node.component()) {
|
|
case BL::ShaderNodeBsdfToon::component_DIFFUSE:
|
|
toon->set_component(CLOSURE_BSDF_DIFFUSE_TOON_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfToon::component_GLOSSY:
|
|
toon->set_component(CLOSURE_BSDF_GLOSSY_TOON_ID);
|
|
break;
|
|
}
|
|
node = toon;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBsdfHair)) {
|
|
BL::ShaderNodeBsdfHair b_hair_node(b_node);
|
|
HairBsdfNode *hair = graph->create_node<HairBsdfNode>();
|
|
switch (b_hair_node.component()) {
|
|
case BL::ShaderNodeBsdfHair::component_Reflection:
|
|
hair->set_component(CLOSURE_BSDF_HAIR_REFLECTION_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfHair::component_Transmission:
|
|
hair->set_component(CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
|
|
break;
|
|
}
|
|
node = hair;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBsdfHairPrincipled)) {
|
|
BL::ShaderNodeBsdfHairPrincipled b_principled_hair_node(b_node);
|
|
PrincipledHairBsdfNode *principled_hair = graph->create_node<PrincipledHairBsdfNode>();
|
|
principled_hair->set_parametrization(
|
|
(NodePrincipledHairParametrization)get_enum(b_principled_hair_node.ptr,
|
|
"parametrization",
|
|
NODE_PRINCIPLED_HAIR_NUM,
|
|
NODE_PRINCIPLED_HAIR_REFLECTANCE));
|
|
node = principled_hair;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBsdfPrincipled)) {
|
|
BL::ShaderNodeBsdfPrincipled b_principled_node(b_node);
|
|
PrincipledBsdfNode *principled = graph->create_node<PrincipledBsdfNode>();
|
|
switch (b_principled_node.distribution()) {
|
|
case BL::ShaderNodeBsdfPrincipled::distribution_GGX:
|
|
principled->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfPrincipled::distribution_MULTI_GGX:
|
|
principled->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
|
|
break;
|
|
}
|
|
switch (b_principled_node.subsurface_method()) {
|
|
case BL::ShaderNodeBsdfPrincipled::subsurface_method_BURLEY:
|
|
principled->set_subsurface_method(CLOSURE_BSSRDF_PRINCIPLED_ID);
|
|
break;
|
|
case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK:
|
|
principled->set_subsurface_method(CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID);
|
|
break;
|
|
}
|
|
node = principled;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) {
|
|
node = graph->create_node<TranslucentBsdfNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBsdfTransparent)) {
|
|
node = graph->create_node<TransparentBsdfNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBsdfVelvet)) {
|
|
node = graph->create_node<VelvetBsdfNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeEmission)) {
|
|
node = graph->create_node<EmissionNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) {
|
|
BL::ShaderNodeAmbientOcclusion b_ao_node(b_node);
|
|
AmbientOcclusionNode *ao = graph->create_node<AmbientOcclusionNode>();
|
|
ao->set_samples(b_ao_node.samples());
|
|
ao->set_inside(b_ao_node.inside());
|
|
ao->set_only_local(b_ao_node.only_local());
|
|
node = ao;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeVolumeScatter)) {
|
|
node = graph->create_node<ScatterVolumeNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeVolumeAbsorption)) {
|
|
node = graph->create_node<AbsorptionVolumeNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeVolumePrincipled)) {
|
|
PrincipledVolumeNode *principled = graph->create_node<PrincipledVolumeNode>();
|
|
node = principled;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeNewGeometry)) {
|
|
node = graph->create_node<GeometryNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeWireframe)) {
|
|
BL::ShaderNodeWireframe b_wireframe_node(b_node);
|
|
WireframeNode *wire = graph->create_node<WireframeNode>();
|
|
wire->set_use_pixel_size(b_wireframe_node.use_pixel_size());
|
|
node = wire;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeWavelength)) {
|
|
node = graph->create_node<WavelengthNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBlackbody)) {
|
|
node = graph->create_node<BlackbodyNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeLightPath)) {
|
|
node = graph->create_node<LightPathNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeLightFalloff)) {
|
|
node = graph->create_node<LightFalloffNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeObjectInfo)) {
|
|
node = graph->create_node<ObjectInfoNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeParticleInfo)) {
|
|
node = graph->create_node<ParticleInfoNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeHairInfo)) {
|
|
node = graph->create_node<HairInfoNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeVolumeInfo)) {
|
|
node = graph->create_node<VolumeInfoNode>();
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeVertexColor)) {
|
|
BL::ShaderNodeVertexColor b_vertex_color_node(b_node);
|
|
VertexColorNode *vertex_color_node = graph->create_node<VertexColorNode>();
|
|
vertex_color_node->set_layer_name(ustring(b_vertex_color_node.layer_name()));
|
|
node = vertex_color_node;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBump)) {
|
|
BL::ShaderNodeBump b_bump_node(b_node);
|
|
BumpNode *bump = graph->create_node<BumpNode>();
|
|
bump->set_invert(b_bump_node.invert());
|
|
node = bump;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeScript)) {
|
|
#ifdef WITH_OSL
|
|
if (scene->shader_manager->use_osl()) {
|
|
/* create script node */
|
|
BL::ShaderNodeScript b_script_node(b_node);
|
|
|
|
ShaderManager *manager = scene->shader_manager;
|
|
string bytecode_hash = b_script_node.bytecode_hash();
|
|
|
|
if (!bytecode_hash.empty()) {
|
|
node = OSLShaderManager::osl_node(
|
|
graph, manager, "", bytecode_hash, b_script_node.bytecode());
|
|
}
|
|
else {
|
|
string absolute_filepath = blender_absolute_path(
|
|
b_data, b_ntree, b_script_node.filepath());
|
|
node = OSLShaderManager::osl_node(graph, manager, absolute_filepath, "");
|
|
}
|
|
}
|
|
#else
|
|
(void)b_data;
|
|
(void)b_ntree;
|
|
#endif
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexImage)) {
|
|
BL::ShaderNodeTexImage b_image_node(b_node);
|
|
BL::Image b_image(b_image_node.image());
|
|
BL::ImageUser b_image_user(b_image_node.image_user());
|
|
ImageTextureNode *image = graph->create_node<ImageTextureNode>();
|
|
|
|
image->set_interpolation(get_image_interpolation(b_image_node));
|
|
image->set_extension(get_image_extension(b_image_node));
|
|
image->set_projection((NodeImageProjection)b_image_node.projection());
|
|
image->set_projection_blend(b_image_node.projection_blend());
|
|
BL::TexMapping b_texture_mapping(b_image_node.texture_mapping());
|
|
get_tex_mapping(image, b_texture_mapping);
|
|
|
|
if (b_image) {
|
|
PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
|
|
image->set_colorspace(ustring(get_enum_identifier(colorspace_ptr, "name")));
|
|
|
|
image->set_animated(b_image_node.image_user().use_auto_refresh());
|
|
image->set_alpha_type(get_image_alpha_type(b_image));
|
|
|
|
array<int> tiles;
|
|
for (BL::UDIMTile &b_tile : b_image.tiles) {
|
|
tiles.push_back_slow(b_tile.number());
|
|
}
|
|
image->set_tiles(tiles);
|
|
|
|
/* builtin images will use callback-based reading because
|
|
* they could only be loaded correct from blender side
|
|
*/
|
|
bool is_builtin = b_image.packed_file() || b_image.source() == BL::Image::source_GENERATED ||
|
|
b_image.source() == BL::Image::source_MOVIE ||
|
|
(b_engine.is_preview() && b_image.source() != BL::Image::source_SEQUENCE);
|
|
|
|
if (is_builtin) {
|
|
/* for builtin images we're using image datablock name to find an image to
|
|
* read pixels from later
|
|
*
|
|
* also store frame number as well, so there's no differences in handling
|
|
* builtin names for packed images and movies
|
|
*/
|
|
int scene_frame = b_scene.frame_current();
|
|
int image_frame = image_user_frame_number(b_image_user, b_image, scene_frame);
|
|
image->handle = scene->image_manager->add_image(
|
|
new BlenderImageLoader(b_image, image_frame), image->image_params());
|
|
}
|
|
else {
|
|
ustring filename = ustring(
|
|
image_user_file_path(b_image_user, b_image, b_scene.frame_current(), true));
|
|
image->set_filename(filename);
|
|
}
|
|
}
|
|
node = image;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexEnvironment)) {
|
|
BL::ShaderNodeTexEnvironment b_env_node(b_node);
|
|
BL::Image b_image(b_env_node.image());
|
|
BL::ImageUser b_image_user(b_env_node.image_user());
|
|
EnvironmentTextureNode *env = graph->create_node<EnvironmentTextureNode>();
|
|
|
|
env->set_interpolation(get_image_interpolation(b_env_node));
|
|
env->set_projection((NodeEnvironmentProjection)b_env_node.projection());
|
|
BL::TexMapping b_texture_mapping(b_env_node.texture_mapping());
|
|
get_tex_mapping(env, b_texture_mapping);
|
|
|
|
if (b_image) {
|
|
PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
|
|
env->set_colorspace(ustring(get_enum_identifier(colorspace_ptr, "name")));
|
|
|
|
env->set_animated(b_env_node.image_user().use_auto_refresh());
|
|
env->set_alpha_type(get_image_alpha_type(b_image));
|
|
|
|
bool is_builtin = b_image.packed_file() || b_image.source() == BL::Image::source_GENERATED ||
|
|
b_image.source() == BL::Image::source_MOVIE ||
|
|
(b_engine.is_preview() && b_image.source() != BL::Image::source_SEQUENCE);
|
|
|
|
if (is_builtin) {
|
|
int scene_frame = b_scene.frame_current();
|
|
int image_frame = image_user_frame_number(b_image_user, b_image, scene_frame);
|
|
env->handle = scene->image_manager->add_image(new BlenderImageLoader(b_image, image_frame),
|
|
env->image_params());
|
|
}
|
|
else {
|
|
env->set_filename(
|
|
ustring(image_user_file_path(b_image_user, b_image, b_scene.frame_current(), false)));
|
|
}
|
|
}
|
|
node = env;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexGradient)) {
|
|
BL::ShaderNodeTexGradient b_gradient_node(b_node);
|
|
GradientTextureNode *gradient = graph->create_node<GradientTextureNode>();
|
|
gradient->set_gradient_type((NodeGradientType)b_gradient_node.gradient_type());
|
|
BL::TexMapping b_texture_mapping(b_gradient_node.texture_mapping());
|
|
get_tex_mapping(gradient, b_texture_mapping);
|
|
node = gradient;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
|
|
BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
|
|
VoronoiTextureNode *voronoi = graph->create_node<VoronoiTextureNode>();
|
|
voronoi->set_dimensions(b_voronoi_node.voronoi_dimensions());
|
|
voronoi->set_feature((NodeVoronoiFeature)b_voronoi_node.feature());
|
|
voronoi->set_metric((NodeVoronoiDistanceMetric)b_voronoi_node.distance());
|
|
BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping());
|
|
get_tex_mapping(voronoi, b_texture_mapping);
|
|
node = voronoi;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexMagic)) {
|
|
BL::ShaderNodeTexMagic b_magic_node(b_node);
|
|
MagicTextureNode *magic = graph->create_node<MagicTextureNode>();
|
|
magic->set_depth(b_magic_node.turbulence_depth());
|
|
BL::TexMapping b_texture_mapping(b_magic_node.texture_mapping());
|
|
get_tex_mapping(magic, b_texture_mapping);
|
|
node = magic;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexWave)) {
|
|
BL::ShaderNodeTexWave b_wave_node(b_node);
|
|
WaveTextureNode *wave = graph->create_node<WaveTextureNode>();
|
|
wave->set_wave_type((NodeWaveType)b_wave_node.wave_type());
|
|
wave->set_bands_direction((NodeWaveBandsDirection)b_wave_node.bands_direction());
|
|
wave->set_rings_direction((NodeWaveRingsDirection)b_wave_node.rings_direction());
|
|
wave->set_profile((NodeWaveProfile)b_wave_node.wave_profile());
|
|
BL::TexMapping b_texture_mapping(b_wave_node.texture_mapping());
|
|
get_tex_mapping(wave, b_texture_mapping);
|
|
node = wave;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexChecker)) {
|
|
BL::ShaderNodeTexChecker b_checker_node(b_node);
|
|
CheckerTextureNode *checker = graph->create_node<CheckerTextureNode>();
|
|
BL::TexMapping b_texture_mapping(b_checker_node.texture_mapping());
|
|
get_tex_mapping(checker, b_texture_mapping);
|
|
node = checker;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexBrick)) {
|
|
BL::ShaderNodeTexBrick b_brick_node(b_node);
|
|
BrickTextureNode *brick = graph->create_node<BrickTextureNode>();
|
|
brick->set_offset(b_brick_node.offset());
|
|
brick->set_offset_frequency(b_brick_node.offset_frequency());
|
|
brick->set_squash(b_brick_node.squash());
|
|
brick->set_squash_frequency(b_brick_node.squash_frequency());
|
|
BL::TexMapping b_texture_mapping(b_brick_node.texture_mapping());
|
|
get_tex_mapping(brick, b_texture_mapping);
|
|
node = brick;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexNoise)) {
|
|
BL::ShaderNodeTexNoise b_noise_node(b_node);
|
|
NoiseTextureNode *noise = graph->create_node<NoiseTextureNode>();
|
|
noise->set_dimensions(b_noise_node.noise_dimensions());
|
|
BL::TexMapping b_texture_mapping(b_noise_node.texture_mapping());
|
|
get_tex_mapping(noise, b_texture_mapping);
|
|
node = noise;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
|
|
BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
|
|
MusgraveTextureNode *musgrave_node = graph->create_node<MusgraveTextureNode>();
|
|
musgrave_node->set_musgrave_type((NodeMusgraveType)b_musgrave_node.musgrave_type());
|
|
musgrave_node->set_dimensions(b_musgrave_node.musgrave_dimensions());
|
|
BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping());
|
|
get_tex_mapping(musgrave_node, b_texture_mapping);
|
|
node = musgrave_node;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexCoord)) {
|
|
BL::ShaderNodeTexCoord b_tex_coord_node(b_node);
|
|
TextureCoordinateNode *tex_coord = graph->create_node<TextureCoordinateNode>();
|
|
tex_coord->set_from_dupli(b_tex_coord_node.from_instancer());
|
|
if (b_tex_coord_node.object()) {
|
|
tex_coord->set_use_transform(true);
|
|
tex_coord->set_ob_tfm(get_transform(b_tex_coord_node.object().matrix_world()));
|
|
}
|
|
node = tex_coord;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexSky)) {
|
|
BL::ShaderNodeTexSky b_sky_node(b_node);
|
|
SkyTextureNode *sky = graph->create_node<SkyTextureNode>();
|
|
sky->set_sky_type((NodeSkyType)b_sky_node.sky_type());
|
|
sky->set_sun_direction(normalize(get_float3(b_sky_node.sun_direction())));
|
|
sky->set_turbidity(b_sky_node.turbidity());
|
|
sky->set_ground_albedo(b_sky_node.ground_albedo());
|
|
sky->set_sun_disc(b_sky_node.sun_disc());
|
|
sky->set_sun_size(b_sky_node.sun_size());
|
|
sky->set_sun_intensity(b_sky_node.sun_intensity());
|
|
sky->set_sun_elevation(b_sky_node.sun_elevation());
|
|
sky->set_sun_rotation(b_sky_node.sun_rotation());
|
|
sky->set_altitude(b_sky_node.altitude());
|
|
sky->set_air_density(b_sky_node.air_density());
|
|
sky->set_dust_density(b_sky_node.dust_density());
|
|
sky->set_ozone_density(b_sky_node.ozone_density());
|
|
BL::TexMapping b_texture_mapping(b_sky_node.texture_mapping());
|
|
get_tex_mapping(sky, b_texture_mapping);
|
|
node = sky;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexIES)) {
|
|
BL::ShaderNodeTexIES b_ies_node(b_node);
|
|
IESLightNode *ies = graph->create_node<IESLightNode>();
|
|
switch (b_ies_node.mode()) {
|
|
case BL::ShaderNodeTexIES::mode_EXTERNAL:
|
|
ies->set_filename(ustring(blender_absolute_path(b_data, b_ntree, b_ies_node.filepath())));
|
|
break;
|
|
case BL::ShaderNodeTexIES::mode_INTERNAL:
|
|
ustring ies_content = ustring(get_text_datablock_content(b_ies_node.ies().ptr));
|
|
if (ies_content.empty()) {
|
|
ies_content = "\n";
|
|
}
|
|
ies->set_ies(ies_content);
|
|
break;
|
|
}
|
|
node = ies;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexWhiteNoise)) {
|
|
BL::ShaderNodeTexWhiteNoise b_tex_white_noise_node(b_node);
|
|
WhiteNoiseTextureNode *white_noise_node = graph->create_node<WhiteNoiseTextureNode>();
|
|
white_noise_node->set_dimensions(b_tex_white_noise_node.noise_dimensions());
|
|
node = white_noise_node;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeNormalMap)) {
|
|
BL::ShaderNodeNormalMap b_normal_map_node(b_node);
|
|
NormalMapNode *nmap = graph->create_node<NormalMapNode>();
|
|
nmap->set_space((NodeNormalMapSpace)b_normal_map_node.space());
|
|
nmap->set_attribute(ustring(b_normal_map_node.uv_map()));
|
|
node = nmap;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTangent)) {
|
|
BL::ShaderNodeTangent b_tangent_node(b_node);
|
|
TangentNode *tangent = graph->create_node<TangentNode>();
|
|
tangent->set_direction_type((NodeTangentDirectionType)b_tangent_node.direction_type());
|
|
tangent->set_axis((NodeTangentAxis)b_tangent_node.axis());
|
|
tangent->set_attribute(ustring(b_tangent_node.uv_map()));
|
|
node = tangent;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeUVMap)) {
|
|
BL::ShaderNodeUVMap b_uvmap_node(b_node);
|
|
UVMapNode *uvm = graph->create_node<UVMapNode>();
|
|
uvm->set_attribute(ustring(b_uvmap_node.uv_map()));
|
|
uvm->set_from_dupli(b_uvmap_node.from_instancer());
|
|
node = uvm;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
|
|
BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
|
|
PointDensityTextureNode *point_density = graph->create_node<PointDensityTextureNode>();
|
|
point_density->set_space((NodeTexVoxelSpace)b_point_density_node.space());
|
|
point_density->set_interpolation(get_image_interpolation(b_point_density_node));
|
|
point_density->handle = scene->image_manager->add_image(
|
|
new BlenderPointDensityLoader(b_depsgraph, b_point_density_node),
|
|
point_density->image_params());
|
|
|
|
b_point_density_node.cache_point_density(b_depsgraph);
|
|
node = point_density;
|
|
|
|
/* Transformation form world space to texture space.
|
|
*
|
|
* NOTE: Do this after the texture is cached, this is because getting
|
|
* min/max will need to access this cache.
|
|
*/
|
|
BL::Object b_ob(b_point_density_node.object());
|
|
if (b_ob) {
|
|
float3 loc, size;
|
|
point_density_texture_space(b_depsgraph, b_point_density_node, loc, size);
|
|
point_density->set_tfm(transform_translate(-loc) * transform_scale(size) *
|
|
transform_inverse(get_transform(b_ob.matrix_world())));
|
|
}
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeBevel)) {
|
|
BL::ShaderNodeBevel b_bevel_node(b_node);
|
|
BevelNode *bevel = graph->create_node<BevelNode>();
|
|
bevel->set_samples(b_bevel_node.samples());
|
|
node = bevel;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeDisplacement)) {
|
|
BL::ShaderNodeDisplacement b_disp_node(b_node);
|
|
DisplacementNode *disp = graph->create_node<DisplacementNode>();
|
|
disp->set_space((NodeNormalMapSpace)b_disp_node.space());
|
|
node = disp;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeVectorDisplacement)) {
|
|
BL::ShaderNodeVectorDisplacement b_disp_node(b_node);
|
|
VectorDisplacementNode *disp = graph->create_node<VectorDisplacementNode>();
|
|
disp->set_space((NodeNormalMapSpace)b_disp_node.space());
|
|
disp->set_attribute(ustring(""));
|
|
node = disp;
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeOutputAOV)) {
|
|
BL::ShaderNodeOutputAOV b_aov_node(b_node);
|
|
OutputAOVNode *aov = graph->create_node<OutputAOVNode>();
|
|
aov->set_name(ustring(b_aov_node.name()));
|
|
node = aov;
|
|
}
|
|
|
|
if (node) {
|
|
node->name = b_node.name();
|
|
graph->add(node);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
static bool node_use_modified_socket_name(ShaderNode *node)
|
|
{
|
|
if (node->special_type == SHADER_SPECIAL_TYPE_OSL)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static ShaderInput *node_find_input_by_name(ShaderNode *node,
|
|
BL::Node &b_node,
|
|
BL::NodeSocket &b_socket)
|
|
{
|
|
string name = b_socket.name();
|
|
|
|
if (node_use_modified_socket_name(node)) {
|
|
bool found = false;
|
|
int counter = 0, total = 0;
|
|
|
|
for (BL::NodeSocket &b_input : b_node.inputs) {
|
|
if (b_input.name() == name) {
|
|
if (!found) {
|
|
counter++;
|
|
}
|
|
total++;
|
|
}
|
|
|
|
if (b_input.ptr.data == b_socket.ptr.data)
|
|
found = true;
|
|
}
|
|
|
|
/* rename if needed */
|
|
if (name == "Shader")
|
|
name = "Closure";
|
|
|
|
if (total > 1)
|
|
name = string_printf("%s%d", name.c_str(), counter);
|
|
}
|
|
|
|
return node->input(name.c_str());
|
|
}
|
|
|
|
static ShaderOutput *node_find_output_by_name(ShaderNode *node,
|
|
BL::Node &b_node,
|
|
BL::NodeSocket &b_socket)
|
|
{
|
|
string name = b_socket.name();
|
|
|
|
if (node_use_modified_socket_name(node)) {
|
|
bool found = false;
|
|
int counter = 0, total = 0;
|
|
|
|
for (BL::NodeSocket &b_output : b_node.outputs) {
|
|
if (b_output.name() == name) {
|
|
if (!found) {
|
|
counter++;
|
|
}
|
|
total++;
|
|
}
|
|
|
|
if (b_output.ptr.data == b_socket.ptr.data) {
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
/* rename if needed */
|
|
if (name == "Shader")
|
|
name = "Closure";
|
|
|
|
if (total > 1)
|
|
name = string_printf("%s%d", name.c_str(), counter);
|
|
}
|
|
|
|
return node->output(name.c_str());
|
|
}
|
|
|
|
static void add_nodes(Scene *scene,
|
|
BL::RenderEngine &b_engine,
|
|
BL::BlendData &b_data,
|
|
BL::Depsgraph &b_depsgraph,
|
|
BL::Scene &b_scene,
|
|
ShaderGraph *graph,
|
|
BL::ShaderNodeTree &b_ntree,
|
|
const ProxyMap &proxy_input_map,
|
|
const ProxyMap &proxy_output_map)
|
|
{
|
|
/* add nodes */
|
|
PtrInputMap input_map;
|
|
PtrOutputMap output_map;
|
|
|
|
/* find the node to use for output if there are multiple */
|
|
BL::ShaderNode output_node = b_ntree.get_output_node(
|
|
BL::ShaderNodeOutputMaterial::target_CYCLES);
|
|
|
|
/* add nodes */
|
|
for (BL::Node &b_node : b_ntree.nodes) {
|
|
if (b_node.mute() || b_node.is_a(&RNA_NodeReroute)) {
|
|
/* replace muted node with internal links */
|
|
for (BL::NodeLink &b_link : b_node.internal_links) {
|
|
BL::NodeSocket to_socket(b_link.to_socket());
|
|
SocketType::Type to_socket_type = convert_socket_type(to_socket);
|
|
if (to_socket_type == SocketType::UNDEFINED) {
|
|
continue;
|
|
}
|
|
|
|
ConvertNode *proxy = graph->create_node<ConvertNode>(to_socket_type, to_socket_type, true);
|
|
|
|
input_map[b_link.from_socket().ptr.data] = proxy->inputs[0];
|
|
output_map[b_link.to_socket().ptr.data] = proxy->outputs[0];
|
|
|
|
graph->add(proxy);
|
|
}
|
|
}
|
|
else if (b_node.is_a(&RNA_ShaderNodeGroup) || b_node.is_a(&RNA_NodeCustomGroup) ||
|
|
b_node.is_a(&RNA_ShaderNodeCustomGroup)) {
|
|
|
|
BL::ShaderNodeTree b_group_ntree(PointerRNA_NULL);
|
|
if (b_node.is_a(&RNA_ShaderNodeGroup))
|
|
b_group_ntree = BL::ShaderNodeTree(((BL::NodeGroup)(b_node)).node_tree());
|
|
else if (b_node.is_a(&RNA_NodeCustomGroup))
|
|
b_group_ntree = BL::ShaderNodeTree(((BL::NodeCustomGroup)(b_node)).node_tree());
|
|
else
|
|
b_group_ntree = BL::ShaderNodeTree(((BL::ShaderNodeCustomGroup)(b_node)).node_tree());
|
|
|
|
ProxyMap group_proxy_input_map, group_proxy_output_map;
|
|
|
|
/* Add a proxy node for each socket
|
|
* Do this even if the node group has no internal tree,
|
|
* so that links have something to connect to and assert won't fail.
|
|
*/
|
|
for (BL::NodeSocket &b_input : b_node.inputs) {
|
|
SocketType::Type input_type = convert_socket_type(b_input);
|
|
if (input_type == SocketType::UNDEFINED) {
|
|
continue;
|
|
}
|
|
|
|
ConvertNode *proxy = graph->create_node<ConvertNode>(input_type, input_type, true);
|
|
graph->add(proxy);
|
|
|
|
/* register the proxy node for internal binding */
|
|
group_proxy_input_map[b_input.identifier()] = proxy;
|
|
|
|
input_map[b_input.ptr.data] = proxy->inputs[0];
|
|
|
|
set_default_value(proxy->inputs[0], b_input, b_data, b_ntree);
|
|
}
|
|
for (BL::NodeSocket &b_output : b_node.outputs) {
|
|
SocketType::Type output_type = convert_socket_type(b_output);
|
|
if (output_type == SocketType::UNDEFINED) {
|
|
continue;
|
|
}
|
|
|
|
ConvertNode *proxy = graph->create_node<ConvertNode>(output_type, output_type, true);
|
|
graph->add(proxy);
|
|
|
|
/* register the proxy node for internal binding */
|
|
group_proxy_output_map[b_output.identifier()] = proxy;
|
|
|
|
output_map[b_output.ptr.data] = proxy->outputs[0];
|
|
}
|
|
|
|
if (b_group_ntree) {
|
|
add_nodes(scene,
|
|
b_engine,
|
|
b_data,
|
|
b_depsgraph,
|
|
b_scene,
|
|
graph,
|
|
b_group_ntree,
|
|
group_proxy_input_map,
|
|
group_proxy_output_map);
|
|
}
|
|
}
|
|
else if (b_node.is_a(&RNA_NodeGroupInput)) {
|
|
/* map each socket to a proxy node */
|
|
for (BL::NodeSocket &b_output : b_node.outputs) {
|
|
ProxyMap::const_iterator proxy_it = proxy_input_map.find(b_output.identifier());
|
|
if (proxy_it != proxy_input_map.end()) {
|
|
ConvertNode *proxy = proxy_it->second;
|
|
|
|
output_map[b_output.ptr.data] = proxy->outputs[0];
|
|
}
|
|
}
|
|
}
|
|
else if (b_node.is_a(&RNA_NodeGroupOutput)) {
|
|
BL::NodeGroupOutput b_output_node(b_node);
|
|
/* only the active group output is used */
|
|
if (b_output_node.is_active_output()) {
|
|
/* map each socket to a proxy node */
|
|
for (BL::NodeSocket &b_input : b_node.inputs) {
|
|
ProxyMap::const_iterator proxy_it = proxy_output_map.find(b_input.identifier());
|
|
if (proxy_it != proxy_output_map.end()) {
|
|
ConvertNode *proxy = proxy_it->second;
|
|
|
|
input_map[b_input.ptr.data] = proxy->inputs[0];
|
|
|
|
set_default_value(proxy->inputs[0], b_input, b_data, b_ntree);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
ShaderNode *node = NULL;
|
|
|
|
if (b_node.ptr.data == output_node.ptr.data) {
|
|
node = graph->output();
|
|
}
|
|
else {
|
|
BL::ShaderNode b_shader_node(b_node);
|
|
node = add_node(
|
|
scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree, b_shader_node);
|
|
}
|
|
|
|
if (node) {
|
|
/* map node sockets for linking */
|
|
for (BL::NodeSocket &b_input : b_node.inputs) {
|
|
ShaderInput *input = node_find_input_by_name(node, b_node, b_input);
|
|
if (!input) {
|
|
/* XXX should not happen, report error? */
|
|
continue;
|
|
}
|
|
input_map[b_input.ptr.data] = input;
|
|
|
|
set_default_value(input, b_input, b_data, b_ntree);
|
|
}
|
|
for (BL::NodeSocket &b_output : b_node.outputs) {
|
|
ShaderOutput *output = node_find_output_by_name(node, b_node, b_output);
|
|
if (!output) {
|
|
/* XXX should not happen, report error? */
|
|
continue;
|
|
}
|
|
output_map[b_output.ptr.data] = output;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* connect nodes */
|
|
for (BL::NodeLink &b_link : b_ntree.links) {
|
|
/* Ignore invalid links to avoid unwanted cycles created in graph.
|
|
* Also ignore links with unavailable sockets. */
|
|
if (!(b_link.is_valid() && b_link.from_socket().enabled() && b_link.to_socket().enabled()) ||
|
|
b_link.is_muted()) {
|
|
continue;
|
|
}
|
|
/* get blender link data */
|
|
BL::NodeSocket b_from_sock = b_link.from_socket();
|
|
BL::NodeSocket b_to_sock = b_link.to_socket();
|
|
|
|
ShaderOutput *output = 0;
|
|
ShaderInput *input = 0;
|
|
|
|
PtrOutputMap::iterator output_it = output_map.find(b_from_sock.ptr.data);
|
|
if (output_it != output_map.end())
|
|
output = output_it->second;
|
|
PtrInputMap::iterator input_it = input_map.find(b_to_sock.ptr.data);
|
|
if (input_it != input_map.end())
|
|
input = input_it->second;
|
|
|
|
/* either node may be NULL when the node was not exported, typically
|
|
* because the node type is not supported */
|
|
if (output && input)
|
|
graph->connect(output, input);
|
|
}
|
|
}
|
|
|
|
static void add_nodes(Scene *scene,
|
|
BL::RenderEngine &b_engine,
|
|
BL::BlendData &b_data,
|
|
BL::Depsgraph &b_depsgraph,
|
|
BL::Scene &b_scene,
|
|
ShaderGraph *graph,
|
|
BL::ShaderNodeTree &b_ntree)
|
|
{
|
|
static const ProxyMap empty_proxy_map;
|
|
add_nodes(scene,
|
|
b_engine,
|
|
b_data,
|
|
b_depsgraph,
|
|
b_scene,
|
|
graph,
|
|
b_ntree,
|
|
empty_proxy_map,
|
|
empty_proxy_map);
|
|
}
|
|
|
|
/* Sync Materials */
|
|
|
|
void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
|
|
{
|
|
shader_map.set_default(scene->default_surface);
|
|
|
|
TaskPool pool;
|
|
set<Shader *> updated_shaders;
|
|
|
|
for (BL::ID &b_id : b_depsgraph.ids) {
|
|
if (!b_id.is_a(&RNA_Material)) {
|
|
continue;
|
|
}
|
|
|
|
BL::Material b_mat(b_id);
|
|
Shader *shader;
|
|
|
|
/* test if we need to sync */
|
|
if (shader_map.add_or_update(&shader, b_mat) || update_all) {
|
|
ShaderGraph *graph = new ShaderGraph();
|
|
|
|
shader->name = b_mat.name().c_str();
|
|
shader->set_pass_id(b_mat.pass_index());
|
|
|
|
/* create nodes */
|
|
if (b_mat.use_nodes() && b_mat.node_tree()) {
|
|
BL::ShaderNodeTree b_ntree(b_mat.node_tree());
|
|
|
|
add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree);
|
|
}
|
|
else {
|
|
DiffuseBsdfNode *diffuse = graph->create_node<DiffuseBsdfNode>();
|
|
diffuse->set_color(get_float3(b_mat.diffuse_color()));
|
|
graph->add(diffuse);
|
|
|
|
ShaderNode *out = graph->output();
|
|
graph->connect(diffuse->output("BSDF"), out->input("Surface"));
|
|
}
|
|
|
|
/* settings */
|
|
PointerRNA cmat = RNA_pointer_get(&b_mat.ptr, "cycles");
|
|
shader->set_use_mis(get_boolean(cmat, "sample_as_light"));
|
|
shader->set_use_transparent_shadow(get_boolean(cmat, "use_transparent_shadow"));
|
|
shader->set_heterogeneous_volume(!get_boolean(cmat, "homogeneous_volume"));
|
|
shader->set_volume_sampling_method(get_volume_sampling(cmat));
|
|
shader->set_volume_interpolation_method(get_volume_interpolation(cmat));
|
|
shader->set_volume_step_rate(get_float(cmat, "volume_step_rate"));
|
|
shader->set_displacement_method(get_displacement_method(cmat));
|
|
|
|
shader->set_graph(graph);
|
|
|
|
/* By simplifying the shader graph as soon as possible, some
|
|
* redundant shader nodes might be removed which prevents loading
|
|
* unnecessary attributes later.
|
|
*
|
|
* However, since graph simplification also accounts for e.g. mix
|
|
* weight, this would cause frequent expensive resyncs in interactive
|
|
* sessions, so for those sessions optimization is only performed
|
|
* right before compiling.
|
|
*/
|
|
if (!preview) {
|
|
pool.push(function_bind(&ShaderGraph::simplify, graph, scene));
|
|
/* NOTE: Update shaders out of the threads since those routines
|
|
* are accessing and writing to a global context.
|
|
*/
|
|
updated_shaders.insert(shader);
|
|
}
|
|
else {
|
|
/* NOTE: Update tagging can access links which are being
|
|
* optimized out.
|
|
*/
|
|
shader->tag_update(scene);
|
|
}
|
|
}
|
|
}
|
|
|
|
pool.wait_work();
|
|
|
|
foreach (Shader *shader, updated_shaders) {
|
|
shader->tag_update(scene);
|
|
}
|
|
}
|
|
|
|
/* Sync World */
|
|
|
|
void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all)
|
|
{
|
|
Background *background = scene->background;
|
|
|
|
BL::World b_world = b_scene.world();
|
|
|
|
BlenderViewportParameters new_viewport_parameters(b_v3d);
|
|
|
|
if (world_recalc || update_all || b_world.ptr.data != world_map ||
|
|
viewport_parameters.shader_modified(new_viewport_parameters)) {
|
|
Shader *shader = scene->default_background;
|
|
ShaderGraph *graph = new ShaderGraph();
|
|
|
|
/* create nodes */
|
|
if (new_viewport_parameters.use_scene_world && b_world && b_world.use_nodes() &&
|
|
b_world.node_tree()) {
|
|
BL::ShaderNodeTree b_ntree(b_world.node_tree());
|
|
|
|
add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree);
|
|
|
|
/* volume */
|
|
PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
|
|
shader->set_heterogeneous_volume(!get_boolean(cworld, "homogeneous_volume"));
|
|
shader->set_volume_sampling_method(get_volume_sampling(cworld));
|
|
shader->set_volume_interpolation_method(get_volume_interpolation(cworld));
|
|
shader->set_volume_step_rate(get_float(cworld, "volume_step_size"));
|
|
}
|
|
else if (new_viewport_parameters.use_scene_world && b_world) {
|
|
BackgroundNode *background = graph->create_node<BackgroundNode>();
|
|
background->set_color(get_float3(b_world.color()));
|
|
graph->add(background);
|
|
|
|
ShaderNode *out = graph->output();
|
|
graph->connect(background->output("Background"), out->input("Surface"));
|
|
}
|
|
else if (!new_viewport_parameters.use_scene_world) {
|
|
float3 world_color;
|
|
if (b_world) {
|
|
world_color = get_float3(b_world.color());
|
|
}
|
|
else {
|
|
world_color = zero_float3();
|
|
}
|
|
|
|
BackgroundNode *background = graph->create_node<BackgroundNode>();
|
|
graph->add(background);
|
|
|
|
LightPathNode *light_path = graph->create_node<LightPathNode>();
|
|
graph->add(light_path);
|
|
|
|
MixNode *mix_scene_with_background = graph->create_node<MixNode>();
|
|
mix_scene_with_background->set_color2(world_color);
|
|
graph->add(mix_scene_with_background);
|
|
|
|
EnvironmentTextureNode *texture_environment = graph->create_node<EnvironmentTextureNode>();
|
|
texture_environment->set_tex_mapping_type(TextureMapping::VECTOR);
|
|
float3 rotation_z = texture_environment->get_tex_mapping_rotation();
|
|
rotation_z[2] = new_viewport_parameters.studiolight_rotate_z;
|
|
texture_environment->set_tex_mapping_rotation(rotation_z);
|
|
texture_environment->set_filename(new_viewport_parameters.studiolight_path);
|
|
graph->add(texture_environment);
|
|
|
|
MixNode *mix_intensity = graph->create_node<MixNode>();
|
|
mix_intensity->set_mix_type(NODE_MIX_MUL);
|
|
mix_intensity->set_fac(1.0f);
|
|
mix_intensity->set_color2(make_float3(new_viewport_parameters.studiolight_intensity,
|
|
new_viewport_parameters.studiolight_intensity,
|
|
new_viewport_parameters.studiolight_intensity));
|
|
graph->add(mix_intensity);
|
|
|
|
TextureCoordinateNode *texture_coordinate = graph->create_node<TextureCoordinateNode>();
|
|
graph->add(texture_coordinate);
|
|
|
|
MixNode *mix_background_with_environment = graph->create_node<MixNode>();
|
|
mix_background_with_environment->set_fac(
|
|
new_viewport_parameters.studiolight_background_alpha);
|
|
mix_background_with_environment->set_color1(world_color);
|
|
graph->add(mix_background_with_environment);
|
|
|
|
ShaderNode *out = graph->output();
|
|
|
|
graph->connect(texture_coordinate->output("Generated"),
|
|
texture_environment->input("Vector"));
|
|
graph->connect(texture_environment->output("Color"), mix_intensity->input("Color1"));
|
|
graph->connect(light_path->output("Is Camera Ray"), mix_scene_with_background->input("Fac"));
|
|
graph->connect(mix_intensity->output("Color"), mix_scene_with_background->input("Color1"));
|
|
graph->connect(mix_intensity->output("Color"),
|
|
mix_background_with_environment->input("Color2"));
|
|
graph->connect(mix_background_with_environment->output("Color"),
|
|
mix_scene_with_background->input("Color2"));
|
|
graph->connect(mix_scene_with_background->output("Color"), background->input("Color"));
|
|
graph->connect(background->output("Background"), out->input("Surface"));
|
|
}
|
|
|
|
if (b_world) {
|
|
/* AO */
|
|
BL::WorldLighting b_light = b_world.light_settings();
|
|
|
|
background->set_use_ao(b_light.use_ambient_occlusion());
|
|
background->set_ao_factor(b_light.ao_factor());
|
|
background->set_ao_distance(b_light.distance());
|
|
|
|
/* visibility */
|
|
PointerRNA cvisibility = RNA_pointer_get(&b_world.ptr, "cycles_visibility");
|
|
uint visibility = 0;
|
|
|
|
visibility |= get_boolean(cvisibility, "camera") ? PATH_RAY_CAMERA : 0;
|
|
visibility |= get_boolean(cvisibility, "diffuse") ? PATH_RAY_DIFFUSE : 0;
|
|
visibility |= get_boolean(cvisibility, "glossy") ? PATH_RAY_GLOSSY : 0;
|
|
visibility |= get_boolean(cvisibility, "transmission") ? PATH_RAY_TRANSMIT : 0;
|
|
visibility |= get_boolean(cvisibility, "scatter") ? PATH_RAY_VOLUME_SCATTER : 0;
|
|
|
|
background->set_visibility(visibility);
|
|
}
|
|
else {
|
|
background->set_use_ao(false);
|
|
background->set_ao_factor(0.0f);
|
|
background->set_ao_distance(FLT_MAX);
|
|
}
|
|
|
|
shader->set_graph(graph);
|
|
shader->tag_update(scene);
|
|
}
|
|
|
|
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
|
background->set_transparent(b_scene.render().film_transparent());
|
|
|
|
if (background->get_transparent()) {
|
|
background->set_transparent_glass(get_boolean(cscene, "film_transparent_glass"));
|
|
background->set_transparent_roughness_threshold(
|
|
get_float(cscene, "film_transparent_roughness"));
|
|
}
|
|
else {
|
|
background->set_transparent_glass(false);
|
|
background->set_transparent_roughness_threshold(0.0f);
|
|
}
|
|
|
|
background->set_use_shader(view_layer.use_background_shader ||
|
|
viewport_parameters.use_custom_shader());
|
|
background->set_use_ao(background->get_use_ao() && view_layer.use_background_ao);
|
|
|
|
background->tag_update(scene);
|
|
}
|
|
|
|
/* Sync Lights */
|
|
|
|
void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
|
|
{
|
|
shader_map.set_default(scene->default_light);
|
|
|
|
for (BL::ID &b_id : b_depsgraph.ids) {
|
|
if (!b_id.is_a(&RNA_Light)) {
|
|
continue;
|
|
}
|
|
|
|
BL::Light b_light(b_id);
|
|
Shader *shader;
|
|
|
|
/* test if we need to sync */
|
|
if (shader_map.add_or_update(&shader, b_light) || update_all) {
|
|
ShaderGraph *graph = new ShaderGraph();
|
|
|
|
/* create nodes */
|
|
if (b_light.use_nodes() && b_light.node_tree()) {
|
|
shader->name = b_light.name().c_str();
|
|
|
|
BL::ShaderNodeTree b_ntree(b_light.node_tree());
|
|
|
|
add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree);
|
|
}
|
|
else {
|
|
EmissionNode *emission = graph->create_node<EmissionNode>();
|
|
emission->set_color(one_float3());
|
|
emission->set_strength(1.0f);
|
|
graph->add(emission);
|
|
|
|
ShaderNode *out = graph->output();
|
|
graph->connect(emission->output("Emission"), out->input("Surface"));
|
|
}
|
|
|
|
shader->set_graph(graph);
|
|
shader->tag_update(scene);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BlenderSync::sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d)
|
|
{
|
|
/* for auto refresh images */
|
|
ImageManager *image_manager = scene->image_manager;
|
|
const int frame = b_scene.frame_current();
|
|
const bool auto_refresh_update = image_manager->set_animation_frame_update(frame);
|
|
|
|
shader_map.pre_sync();
|
|
|
|
sync_world(b_depsgraph, b_v3d, auto_refresh_update);
|
|
sync_lights(b_depsgraph, auto_refresh_update);
|
|
sync_materials(b_depsgraph, auto_refresh_update);
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|