This encapsulates Node socket members behind a set of specific methods; as such it is no longer possible to directly access Node class members from exporters and parts of Cycles. The methods are defined via the NODE_SOCKET_API macros in `graph/ node.h`, and are for getting or setting a specific socket's value, as well as querying or modifying the state of its update flag. The setters will check whether the value has changed and tag the socket as modified appropriately. This will let us know how a Node has changed and what to update, which is the first concrete step toward a more granular scene update system. Since the setters will tag the Node sockets as modified when passed different data, this patch also removes the various modified methods on Nodes in favor of Node::is_modified which checks the sockets' update flags status. Reviewed By: brecht Maniphest Tasks: T79174 Differential Revision: https://developer.blender.org/D8544
1586 lines
59 KiB
C++
1586 lines
59 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)
|
|
{
|
|
BL::Node::outputs_iterator b_out;
|
|
|
|
for (b_node.outputs.begin(b_out); b_out != b_node.outputs.end(); ++b_out)
|
|
if (b_out->name() == name)
|
|
return *b_out;
|
|
|
|
assert(0);
|
|
|
|
return *b_out;
|
|
}
|
|
|
|
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;
|
|
BL::Image::tiles_iterator b_iter;
|
|
for (b_image.tiles.begin(b_iter); b_iter != b_image.tiles.end(); ++b_iter) {
|
|
tiles.push_back_slow(b_iter->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(1000.0f * 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)) {
|
|
BL::Node::inputs_iterator b_input;
|
|
bool found = false;
|
|
int counter = 0, total = 0;
|
|
|
|
for (b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
|
|
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)) {
|
|
BL::Node::outputs_iterator b_output;
|
|
bool found = false;
|
|
int counter = 0, total = 0;
|
|
|
|
for (b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
|
|
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 */
|
|
BL::ShaderNodeTree::nodes_iterator b_node;
|
|
PtrInputMap input_map;
|
|
PtrOutputMap output_map;
|
|
|
|
BL::Node::inputs_iterator b_input;
|
|
BL::Node::outputs_iterator b_output;
|
|
|
|
/* 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 (b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
|
|
if (b_node->mute() || b_node->is_a(&RNA_NodeReroute)) {
|
|
/* replace muted node with internal links */
|
|
BL::Node::internal_links_iterator b_link;
|
|
for (b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end();
|
|
++b_link) {
|
|
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 (b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
|
|
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 (b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
|
|
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 (b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
|
|
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 (b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
|
|
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 (b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
|
|
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 (b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
|
|
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 */
|
|
BL::NodeTree::links_iterator b_link;
|
|
|
|
for (b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) {
|
|
/* 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())) {
|
|
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;
|
|
|
|
BL::Depsgraph::ids_iterator b_id;
|
|
for (b_depsgraph.ids.begin(b_id); b_id != b_depsgraph.ids.end(); ++b_id) {
|
|
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.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 = make_float3(0.0f, 0.0f, 0.0f);
|
|
}
|
|
|
|
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);
|
|
background->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.custom_viewport_parameters());
|
|
background->set_use_ao(background->get_use_ao() && view_layer.use_background_ao);
|
|
|
|
if (background->is_modified())
|
|
background->tag_update(scene);
|
|
}
|
|
|
|
/* Sync Lights */
|
|
|
|
void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
|
|
{
|
|
shader_map.set_default(scene->default_light);
|
|
|
|
BL::Depsgraph::ids_iterator b_id;
|
|
for (b_depsgraph.ids.begin(b_id); b_id != b_depsgraph.ids.end(); ++b_id) {
|
|
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(make_float3(1.0f, 1.0f, 1.0f));
|
|
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 */
|
|
bool auto_refresh_update = false;
|
|
|
|
if (preview) {
|
|
ImageManager *image_manager = scene->image_manager;
|
|
int frame = b_scene.frame_current();
|
|
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
|