forked from bartvdbraak/blender
5552e83b53
Our Python API is not ready for such things at all. Better be slower but more correct for until we improve our API.
1364 lines
44 KiB
C++
1364 lines
44 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 "background.h"
|
|
#include "graph.h"
|
|
#include "light.h"
|
|
#include "nodes.h"
|
|
#include "osl.h"
|
|
#include "scene.h"
|
|
#include "shader.h"
|
|
|
|
#include "blender_texture.h"
|
|
#include "blender_sync.h"
|
|
#include "blender_util.h"
|
|
|
|
#include "util_debug.h"
|
|
#include "util_string.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,
|
|
vector<Shader*>& used_shaders,
|
|
Shader *default_shader)
|
|
{
|
|
Shader *shader = (id)? shader_map.find(id): default_shader;
|
|
|
|
used_shaders.push_back(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);
|
|
}
|
|
|
|
/* 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(TextureMapping *mapping, BL::TexMapping& b_mapping)
|
|
{
|
|
if(!b_mapping)
|
|
return;
|
|
|
|
mapping->translation = get_float3(b_mapping.translation());
|
|
mapping->rotation = get_float3(b_mapping.rotation());
|
|
mapping->scale = get_float3(b_mapping.scale());
|
|
mapping->type = (TextureMapping::Type)b_mapping.vector_type();
|
|
|
|
mapping->x_mapping = (TextureMapping::Mapping)b_mapping.mapping_x();
|
|
mapping->y_mapping = (TextureMapping::Mapping)b_mapping.mapping_y();
|
|
mapping->z_mapping = (TextureMapping::Mapping)b_mapping.mapping_z();
|
|
}
|
|
|
|
static void get_tex_mapping(TextureMapping *mapping,
|
|
BL::ShaderNodeMapping& b_mapping)
|
|
{
|
|
if(!b_mapping)
|
|
return;
|
|
|
|
mapping->translation = get_float3(b_mapping.translation());
|
|
mapping->rotation = get_float3(b_mapping.rotation());
|
|
mapping->scale = get_float3(b_mapping.scale());
|
|
mapping->type = (TextureMapping::Type)b_mapping.vector_type();
|
|
|
|
mapping->use_minmax = b_mapping.use_min() || b_mapping.use_max();
|
|
|
|
if(b_mapping.use_min())
|
|
mapping->min = get_float3(b_mapping.min());
|
|
if(b_mapping.use_max())
|
|
mapping->max = get_float3(b_mapping.max());
|
|
}
|
|
|
|
static bool is_output_node(BL::Node& b_node)
|
|
{
|
|
return (b_node.is_a(&RNA_ShaderNodeOutputMaterial)
|
|
|| b_node.is_a(&RNA_ShaderNodeOutputWorld)
|
|
|| b_node.is_a(&RNA_ShaderNodeOutputLamp));
|
|
}
|
|
|
|
static ShaderNode *add_node(Scene *scene,
|
|
BL::RenderEngine& b_engine,
|
|
BL::BlendData& b_data,
|
|
BL::Scene& b_scene,
|
|
const bool background,
|
|
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 = new RGBCurvesNode();
|
|
curvemapping_color_to_array(mapping,
|
|
curves->curves,
|
|
RAMP_TABLE_SIZE,
|
|
true);
|
|
curvemapping_minmax(mapping, true, &curves->min_x, &curves->max_x);
|
|
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 = new VectorCurvesNode();
|
|
curvemapping_color_to_array(mapping,
|
|
curves->curves,
|
|
RAMP_TABLE_SIZE,
|
|
false);
|
|
curvemapping_minmax(mapping, false, &curves->min_x, &curves->max_x);
|
|
node = curves;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeValToRGB)) {
|
|
RGBRampNode *ramp = new RGBRampNode();
|
|
BL::ShaderNodeValToRGB b_ramp_node(b_node);
|
|
BL::ColorRamp b_color_ramp(b_ramp_node.color_ramp());
|
|
colorramp_to_array(b_color_ramp, ramp->ramp, ramp->ramp_alpha, RAMP_TABLE_SIZE);
|
|
ramp->interpolate = b_color_ramp.interpolation() != BL::ColorRamp::interpolation_CONSTANT;
|
|
node = ramp;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeRGB)) {
|
|
ColorNode *color = new ColorNode();
|
|
color->value = get_node_output_rgba(b_node, "Color");
|
|
node = color;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeValue)) {
|
|
ValueNode *value = new ValueNode();
|
|
value->value = get_node_output_value(b_node, "Value");
|
|
node = value;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeCameraData)) {
|
|
node = new CameraNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeInvert)) {
|
|
node = new InvertNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeGamma)) {
|
|
node = new GammaNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeBrightContrast)) {
|
|
node = new BrightContrastNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeMixRGB)) {
|
|
BL::ShaderNodeMixRGB b_mix_node(b_node);
|
|
MixNode *mix = new MixNode();
|
|
mix->type = (NodeMix)b_mix_node.blend_type();
|
|
mix->use_clamp = b_mix_node.use_clamp();
|
|
node = mix;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeSeparateRGB)) {
|
|
node = new SeparateRGBNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeCombineRGB)) {
|
|
node = new CombineRGBNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeSeparateHSV)) {
|
|
node = new SeparateHSVNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeCombineHSV)) {
|
|
node = new CombineHSVNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeSeparateXYZ)) {
|
|
node = new SeparateXYZNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeCombineXYZ)) {
|
|
node = new CombineXYZNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeHueSaturation)) {
|
|
node = new HSVNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeRGBToBW)) {
|
|
node = new RGBToBWNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeMath)) {
|
|
BL::ShaderNodeMath b_math_node(b_node);
|
|
MathNode *math = new MathNode();
|
|
math->type = (NodeMath)b_math_node.operation();
|
|
math->use_clamp = b_math_node.use_clamp();
|
|
node = math;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeVectorMath)) {
|
|
BL::ShaderNodeVectorMath b_vector_math_node(b_node);
|
|
VectorMathNode *vmath = new VectorMathNode();
|
|
vmath->type = (NodeVectorMath)b_vector_math_node.operation();
|
|
node = vmath;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeVectorTransform)) {
|
|
BL::ShaderNodeVectorTransform b_vector_transform_node(b_node);
|
|
VectorTransformNode *vtransform = new VectorTransformNode();
|
|
vtransform->type = (NodeVectorTransformType)b_vector_transform_node.vector_type();
|
|
vtransform->convert_from = (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_from();
|
|
vtransform->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 = new NormalNode();
|
|
norm->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 = new MappingNode();
|
|
|
|
get_tex_mapping(&mapping->tex_mapping, b_mapping_node);
|
|
|
|
node = mapping;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeFresnel)) {
|
|
node = new FresnelNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeLayerWeight)) {
|
|
node = new LayerWeightNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeAddShader)) {
|
|
node = new AddClosureNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeMixShader)) {
|
|
node = new MixClosureNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeAttribute)) {
|
|
BL::ShaderNodeAttribute b_attr_node(b_node);
|
|
AttributeNode *attr = new AttributeNode();
|
|
attr->attribute = b_attr_node.attribute_name();
|
|
node = attr;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeBackground)) {
|
|
node = new BackgroundNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeHoldout)) {
|
|
node = new HoldoutNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) {
|
|
BL::ShaderNodeBsdfAnisotropic b_aniso_node(b_node);
|
|
AnisotropicBsdfNode *aniso = new AnisotropicBsdfNode();
|
|
|
|
switch(b_aniso_node.distribution()) {
|
|
case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN:
|
|
aniso->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID;
|
|
break;
|
|
case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
|
|
aniso->distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
|
|
break;
|
|
case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX:
|
|
aniso->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID;
|
|
break;
|
|
case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
|
|
aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID;
|
|
break;
|
|
}
|
|
|
|
node = aniso;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) {
|
|
node = new DiffuseBsdfNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeSubsurfaceScattering)) {
|
|
BL::ShaderNodeSubsurfaceScattering b_subsurface_node(b_node);
|
|
|
|
SubsurfaceScatteringNode *subsurface = new SubsurfaceScatteringNode();
|
|
|
|
switch(b_subsurface_node.falloff()) {
|
|
case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC:
|
|
subsurface->falloff = CLOSURE_BSSRDF_CUBIC_ID;
|
|
break;
|
|
case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN:
|
|
subsurface->falloff = CLOSURE_BSSRDF_GAUSSIAN_ID;
|
|
break;
|
|
case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY:
|
|
subsurface->falloff = CLOSURE_BSSRDF_BURLEY_ID;
|
|
break;
|
|
}
|
|
|
|
node = subsurface;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) {
|
|
BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
|
|
GlossyBsdfNode *glossy = new GlossyBsdfNode();
|
|
|
|
switch(b_glossy_node.distribution()) {
|
|
case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
|
|
glossy->distribution = CLOSURE_BSDF_REFLECTION_ID;
|
|
break;
|
|
case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
|
|
glossy->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
|
|
break;
|
|
case BL::ShaderNodeBsdfGlossy::distribution_GGX:
|
|
glossy->distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
|
|
break;
|
|
case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY:
|
|
glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID;
|
|
break;
|
|
case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX:
|
|
glossy->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 = new GlassBsdfNode();
|
|
switch(b_glass_node.distribution()) {
|
|
case BL::ShaderNodeBsdfGlass::distribution_SHARP:
|
|
glass->distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
|
|
break;
|
|
case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
|
|
glass->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID;
|
|
break;
|
|
case BL::ShaderNodeBsdfGlass::distribution_GGX:
|
|
glass->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
|
|
break;
|
|
case BL::ShaderNodeBsdfGlass::distribution_MULTI_GGX:
|
|
glass->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 = new RefractionBsdfNode();
|
|
switch(b_refraction_node.distribution()) {
|
|
case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
|
|
refraction->distribution = CLOSURE_BSDF_REFRACTION_ID;
|
|
break;
|
|
case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
|
|
refraction->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
|
|
break;
|
|
case BL::ShaderNodeBsdfRefraction::distribution_GGX:
|
|
refraction->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 = new ToonBsdfNode();
|
|
switch(b_toon_node.component()) {
|
|
case BL::ShaderNodeBsdfToon::component_DIFFUSE:
|
|
toon->component = CLOSURE_BSDF_DIFFUSE_TOON_ID;
|
|
break;
|
|
case BL::ShaderNodeBsdfToon::component_GLOSSY:
|
|
toon->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 = new HairBsdfNode();
|
|
switch(b_hair_node.component()) {
|
|
case BL::ShaderNodeBsdfHair::component_Reflection:
|
|
hair->component = CLOSURE_BSDF_HAIR_REFLECTION_ID;
|
|
break;
|
|
case BL::ShaderNodeBsdfHair::component_Transmission:
|
|
hair->component = CLOSURE_BSDF_HAIR_TRANSMISSION_ID;
|
|
break;
|
|
}
|
|
node = hair;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) {
|
|
node = new TranslucentBsdfNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeBsdfTransparent)) {
|
|
node = new TransparentBsdfNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeBsdfVelvet)) {
|
|
node = new VelvetBsdfNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeEmission)) {
|
|
node = new EmissionNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) {
|
|
node = new AmbientOcclusionNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeVolumeScatter)) {
|
|
node = new ScatterVolumeNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeVolumeAbsorption)) {
|
|
node = new AbsorptionVolumeNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeNewGeometry)) {
|
|
node = new GeometryNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeWireframe)) {
|
|
BL::ShaderNodeWireframe b_wireframe_node(b_node);
|
|
WireframeNode *wire = new WireframeNode();
|
|
wire->use_pixel_size = b_wireframe_node.use_pixel_size();
|
|
node = wire;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeWavelength)) {
|
|
node = new WavelengthNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeBlackbody)) {
|
|
node = new BlackbodyNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeLightPath)) {
|
|
node = new LightPathNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeLightFalloff)) {
|
|
node = new LightFalloffNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeObjectInfo)) {
|
|
node = new ObjectInfoNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeParticleInfo)) {
|
|
node = new ParticleInfoNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeHairInfo)) {
|
|
node = new HairInfoNode();
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeBump)) {
|
|
BL::ShaderNodeBump b_bump_node(b_node);
|
|
BumpNode *bump = new BumpNode();
|
|
bump->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);
|
|
|
|
OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager;
|
|
string bytecode_hash = b_script_node.bytecode_hash();
|
|
|
|
if(!bytecode_hash.empty()) {
|
|
node = manager->osl_node("", bytecode_hash, b_script_node.bytecode());
|
|
}
|
|
else {
|
|
string absolute_filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath());
|
|
node = manager->osl_node(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 = new ImageTextureNode();
|
|
if(b_image) {
|
|
/* 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,
|
|
scene_frame);
|
|
image->filename = b_image.name() + "@" + string_printf("%d", image_frame);
|
|
image->builtin_data = b_image.ptr.data;
|
|
}
|
|
else {
|
|
image->filename = image_user_file_path(b_image_user,
|
|
b_image,
|
|
b_scene.frame_current());
|
|
image->builtin_data = NULL;
|
|
}
|
|
|
|
image->animated = b_image_node.image_user().use_auto_refresh();
|
|
image->use_alpha = b_image.use_alpha();
|
|
|
|
/* TODO(sergey): Does not work properly when we change builtin type. */
|
|
if(b_image.is_updated()) {
|
|
scene->image_manager->tag_reload_image(
|
|
image->filename.string(),
|
|
image->builtin_data,
|
|
get_image_interpolation(b_image_node),
|
|
get_image_extension(b_image_node),
|
|
image->use_alpha);
|
|
}
|
|
}
|
|
image->color_space = (NodeImageColorSpace)b_image_node.color_space();
|
|
image->projection = (NodeImageProjection)b_image_node.projection();
|
|
image->interpolation = get_image_interpolation(b_image_node);
|
|
image->extension = get_image_extension(b_image_node);
|
|
image->projection_blend = b_image_node.projection_blend();
|
|
BL::TexMapping b_texture_mapping(b_image_node.texture_mapping());
|
|
get_tex_mapping(&image->tex_mapping, b_texture_mapping);
|
|
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 = new EnvironmentTextureNode();
|
|
if(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,
|
|
scene_frame);
|
|
env->filename = b_image.name() + "@" + string_printf("%d", image_frame);
|
|
env->builtin_data = b_image.ptr.data;
|
|
}
|
|
else {
|
|
env->filename = image_user_file_path(b_image_user,
|
|
b_image,
|
|
b_scene.frame_current());
|
|
env->builtin_data = NULL;
|
|
}
|
|
|
|
env->animated = b_env_node.image_user().use_auto_refresh();
|
|
env->use_alpha = b_image.use_alpha();
|
|
|
|
/* TODO(sergey): Does not work properly when we change builtin type. */
|
|
if(b_image.is_updated()) {
|
|
scene->image_manager->tag_reload_image(
|
|
env->filename.string(),
|
|
env->builtin_data,
|
|
get_image_interpolation(b_env_node),
|
|
EXTENSION_REPEAT,
|
|
env->use_alpha);
|
|
}
|
|
}
|
|
env->color_space = (NodeImageColorSpace)b_env_node.color_space();
|
|
env->interpolation = get_image_interpolation(b_env_node);
|
|
env->projection = (NodeEnvironmentProjection)b_env_node.projection();
|
|
BL::TexMapping b_texture_mapping(b_env_node.texture_mapping());
|
|
get_tex_mapping(&env->tex_mapping, b_texture_mapping);
|
|
node = env;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeTexGradient)) {
|
|
BL::ShaderNodeTexGradient b_gradient_node(b_node);
|
|
GradientTextureNode *gradient = new GradientTextureNode();
|
|
gradient->type = (NodeGradientType)b_gradient_node.gradient_type();
|
|
BL::TexMapping b_texture_mapping(b_gradient_node.texture_mapping());
|
|
get_tex_mapping(&gradient->tex_mapping, b_texture_mapping);
|
|
node = gradient;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
|
|
BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
|
|
VoronoiTextureNode *voronoi = new VoronoiTextureNode();
|
|
voronoi->coloring = (NodeVoronoiColoring)b_voronoi_node.coloring();
|
|
BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping());
|
|
get_tex_mapping(&voronoi->tex_mapping, b_texture_mapping);
|
|
node = voronoi;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeTexMagic)) {
|
|
BL::ShaderNodeTexMagic b_magic_node(b_node);
|
|
MagicTextureNode *magic = new MagicTextureNode();
|
|
magic->depth = b_magic_node.turbulence_depth();
|
|
BL::TexMapping b_texture_mapping(b_magic_node.texture_mapping());
|
|
get_tex_mapping(&magic->tex_mapping, b_texture_mapping);
|
|
node = magic;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeTexWave)) {
|
|
BL::ShaderNodeTexWave b_wave_node(b_node);
|
|
WaveTextureNode *wave = new WaveTextureNode();
|
|
wave->type = (NodeWaveType)b_wave_node.wave_type();
|
|
wave->profile = (NodeWaveProfile)b_wave_node.wave_profile();
|
|
BL::TexMapping b_texture_mapping(b_wave_node.texture_mapping());
|
|
get_tex_mapping(&wave->tex_mapping, b_texture_mapping);
|
|
node = wave;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeTexChecker)) {
|
|
BL::ShaderNodeTexChecker b_checker_node(b_node);
|
|
CheckerTextureNode *checker = new CheckerTextureNode();
|
|
BL::TexMapping b_texture_mapping(b_checker_node.texture_mapping());
|
|
get_tex_mapping(&checker->tex_mapping, b_texture_mapping);
|
|
node = checker;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeTexBrick)) {
|
|
BL::ShaderNodeTexBrick b_brick_node(b_node);
|
|
BrickTextureNode *brick = new BrickTextureNode();
|
|
brick->offset = b_brick_node.offset();
|
|
brick->offset_frequency = b_brick_node.offset_frequency();
|
|
brick->squash = b_brick_node.squash();
|
|
brick->squash_frequency = b_brick_node.squash_frequency();
|
|
BL::TexMapping b_texture_mapping(b_brick_node.texture_mapping());
|
|
get_tex_mapping(&brick->tex_mapping, b_texture_mapping);
|
|
node = brick;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeTexNoise)) {
|
|
BL::ShaderNodeTexNoise b_noise_node(b_node);
|
|
NoiseTextureNode *noise = new NoiseTextureNode();
|
|
BL::TexMapping b_texture_mapping(b_noise_node.texture_mapping());
|
|
get_tex_mapping(&noise->tex_mapping, b_texture_mapping);
|
|
node = noise;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
|
|
BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
|
|
MusgraveTextureNode *musgrave = new MusgraveTextureNode();
|
|
musgrave->type = (NodeMusgraveType)b_musgrave_node.musgrave_type();
|
|
BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping());
|
|
get_tex_mapping(&musgrave->tex_mapping, b_texture_mapping);
|
|
node = musgrave;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeTexCoord)) {
|
|
BL::ShaderNodeTexCoord b_tex_coord_node(b_node);
|
|
TextureCoordinateNode *tex_coord = new TextureCoordinateNode();
|
|
tex_coord->from_dupli = b_tex_coord_node.from_dupli();
|
|
if(b_tex_coord_node.object()) {
|
|
tex_coord->use_transform = true;
|
|
tex_coord->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 = new SkyTextureNode();
|
|
sky->type = (NodeSkyType)b_sky_node.sky_type();
|
|
sky->sun_direction = normalize(get_float3(b_sky_node.sun_direction()));
|
|
sky->turbidity = b_sky_node.turbidity();
|
|
sky->ground_albedo = b_sky_node.ground_albedo();
|
|
BL::TexMapping b_texture_mapping(b_sky_node.texture_mapping());
|
|
get_tex_mapping(&sky->tex_mapping, b_texture_mapping);
|
|
node = sky;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeNormalMap)) {
|
|
BL::ShaderNodeNormalMap b_normal_map_node(b_node);
|
|
NormalMapNode *nmap = new NormalMapNode();
|
|
nmap->space = (NodeNormalMapSpace)b_normal_map_node.space();
|
|
nmap->attribute = 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 = new TangentNode();
|
|
tangent->direction_type = (NodeTangentDirectionType)b_tangent_node.direction_type();
|
|
tangent->axis = (NodeTangentAxis)b_tangent_node.axis();
|
|
tangent->attribute = b_tangent_node.uv_map();
|
|
node = tangent;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeUVMap)) {
|
|
BL::ShaderNodeUVMap b_uvmap_node(b_node);
|
|
UVMapNode *uvm = new UVMapNode();
|
|
uvm->attribute = b_uvmap_node.uv_map();
|
|
uvm->from_dupli = b_uvmap_node.from_dupli();
|
|
node = uvm;
|
|
}
|
|
else if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
|
|
BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
|
|
PointDensityTextureNode *point_density = new PointDensityTextureNode();
|
|
point_density->filename = b_point_density_node.name();
|
|
point_density->space = (NodeTexVoxelSpace)b_point_density_node.space();
|
|
point_density->interpolation = get_image_interpolation(b_point_density_node);
|
|
point_density->builtin_data = b_point_density_node.ptr.data;
|
|
|
|
/* 1 - render settings, 0 - vewport settings. */
|
|
int settings = background ? 1 : 0;
|
|
|
|
/* TODO(sergey): Use more proper update flag. */
|
|
if(true) {
|
|
b_point_density_node.cache_point_density(b_scene, settings);
|
|
scene->image_manager->tag_reload_image(
|
|
point_density->filename.string(),
|
|
point_density->builtin_data,
|
|
point_density->interpolation,
|
|
EXTENSION_CLIP,
|
|
true);
|
|
}
|
|
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_scene,
|
|
b_point_density_node,
|
|
settings,
|
|
loc,
|
|
size);
|
|
point_density->tfm =
|
|
transform_translate(-loc) * transform_scale(size) *
|
|
transform_inverse(get_transform(b_ob.matrix_world()));
|
|
}
|
|
}
|
|
|
|
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_SCRIPT)
|
|
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::Scene& b_scene,
|
|
const bool background,
|
|
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 */
|
|
bool found_active_output = false;
|
|
BL::ShaderNode output_node(PointerRNA_NULL);
|
|
|
|
for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
|
|
if(is_output_node(*b_node)) {
|
|
BL::ShaderNodeOutputMaterial b_output_node(*b_node);
|
|
|
|
if(b_output_node.is_active_output()) {
|
|
output_node = b_output_node;
|
|
found_active_output = true;
|
|
break;
|
|
}
|
|
else if(!output_node.ptr.data && !found_active_output) {
|
|
output_node = b_output_node;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 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);
|
|
ConvertNode *proxy = new 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)) {
|
|
|
|
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
|
|
b_group_ntree = BL::ShaderNodeTree(((BL::NodeCustomGroup)(*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);
|
|
ConvertNode *proxy = new 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);
|
|
ConvertNode *proxy = new 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_scene,
|
|
background,
|
|
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(is_output_node(*b_node)) {
|
|
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_scene,
|
|
background,
|
|
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. */
|
|
if(!b_link->is_valid()) {
|
|
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::Scene& b_scene,
|
|
const bool background,
|
|
ShaderGraph *graph,
|
|
BL::ShaderNodeTree& b_ntree)
|
|
{
|
|
static const ProxyMap empty_proxy_map;
|
|
add_nodes(scene,
|
|
b_engine,
|
|
b_data,
|
|
b_scene,
|
|
background,
|
|
graph,
|
|
b_ntree,
|
|
empty_proxy_map,
|
|
empty_proxy_map);
|
|
}
|
|
|
|
/* Sync Materials */
|
|
|
|
void BlenderSync::sync_materials(bool update_all)
|
|
{
|
|
shader_map.set_default(scene->default_surface);
|
|
|
|
/* material loop */
|
|
BL::BlendData::materials_iterator b_mat;
|
|
|
|
for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat) {
|
|
Shader *shader;
|
|
|
|
/* test if we need to sync */
|
|
if(shader_map.sync(&shader, *b_mat) || update_all) {
|
|
ShaderGraph *graph = new ShaderGraph();
|
|
|
|
shader->name = b_mat->name().c_str();
|
|
shader->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_scene, !preview, graph, b_ntree);
|
|
}
|
|
else {
|
|
DiffuseBsdfNode *diffuse = new DiffuseBsdfNode();
|
|
diffuse->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->use_mis = get_boolean(cmat, "sample_as_light");
|
|
shader->use_transparent_shadow = get_boolean(cmat, "use_transparent_shadow");
|
|
shader->heterogeneous_volume = !get_boolean(cmat, "homogeneous_volume");
|
|
shader->volume_sampling_method = get_volume_sampling(cmat);
|
|
shader->volume_interpolation_method = get_volume_interpolation(cmat);
|
|
shader->displacement_method = (experimental) ? get_displacement_method(cmat) : DISPLACE_BUMP;
|
|
|
|
shader->set_graph(graph);
|
|
shader->tag_update(scene);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Sync World */
|
|
|
|
void BlenderSync::sync_world(bool update_all)
|
|
{
|
|
Background *background = scene->background;
|
|
Background prevbackground = *background;
|
|
|
|
BL::World b_world = b_scene.world();
|
|
|
|
if(world_recalc || update_all || b_world.ptr.data != world_map) {
|
|
Shader *shader = scene->default_background;
|
|
ShaderGraph *graph = new ShaderGraph();
|
|
|
|
/* create nodes */
|
|
if(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_scene, !preview, graph, b_ntree);
|
|
|
|
/* volume */
|
|
PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
|
|
shader->heterogeneous_volume = !get_boolean(cworld, "homogeneous_volume");
|
|
shader->volume_sampling_method = get_volume_sampling(cworld);
|
|
shader->volume_interpolation_method = get_volume_interpolation(cworld);
|
|
}
|
|
else if(b_world) {
|
|
BackgroundNode *background = new BackgroundNode();
|
|
background->color = get_float3(b_world.horizon_color());
|
|
graph->add(background);
|
|
|
|
ShaderNode *out = graph->output();
|
|
graph->connect(background->output("Background"), out->input("Surface"));
|
|
}
|
|
|
|
if(b_world) {
|
|
/* AO */
|
|
BL::WorldLighting b_light = b_world.light_settings();
|
|
|
|
if(b_light.use_ambient_occlusion())
|
|
background->ao_factor = b_light.ao_factor();
|
|
else
|
|
background->ao_factor = 0.0f;
|
|
|
|
background->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->visibility = visibility;
|
|
}
|
|
else {
|
|
background->ao_factor = 0.0f;
|
|
background->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");
|
|
|
|
/* when doing preview render check for BI's transparency settings,
|
|
* this is so because Blender's preview render routines are not able
|
|
* to tweak all cycles's settings depending on different circumstances
|
|
*/
|
|
if(b_engine.is_preview() == false)
|
|
background->transparent = get_boolean(cscene, "film_transparent");
|
|
else
|
|
background->transparent = b_scene.render().alpha_mode() == BL::RenderSettings::alpha_mode_TRANSPARENT;
|
|
|
|
background->use_shader = render_layer.use_background_shader;
|
|
background->use_ao = render_layer.use_background_ao;
|
|
|
|
if(background->modified(prevbackground))
|
|
background->tag_update(scene);
|
|
}
|
|
|
|
/* Sync Lamps */
|
|
|
|
void BlenderSync::sync_lamps(bool update_all)
|
|
{
|
|
shader_map.set_default(scene->default_light);
|
|
|
|
/* lamp loop */
|
|
BL::BlendData::lamps_iterator b_lamp;
|
|
|
|
for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp) {
|
|
Shader *shader;
|
|
|
|
/* test if we need to sync */
|
|
if(shader_map.sync(&shader, *b_lamp) || update_all) {
|
|
ShaderGraph *graph = new ShaderGraph();
|
|
|
|
/* create nodes */
|
|
if(b_lamp->use_nodes() && b_lamp->node_tree()) {
|
|
shader->name = b_lamp->name().c_str();
|
|
|
|
BL::ShaderNodeTree b_ntree(b_lamp->node_tree());
|
|
|
|
add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree);
|
|
}
|
|
else {
|
|
float strength = 1.0f;
|
|
|
|
if(b_lamp->type() == BL::Lamp::type_POINT ||
|
|
b_lamp->type() == BL::Lamp::type_SPOT ||
|
|
b_lamp->type() == BL::Lamp::type_AREA)
|
|
{
|
|
strength = 100.0f;
|
|
}
|
|
|
|
EmissionNode *emission = new EmissionNode();
|
|
emission->color = get_float3(b_lamp->color());
|
|
emission->strength = strength;
|
|
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()
|
|
{
|
|
/* 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(auto_refresh_update);
|
|
sync_lamps(auto_refresh_update);
|
|
sync_materials(auto_refresh_update);
|
|
|
|
/* false = don't delete unused shaders, not supported */
|
|
shader_map.post_sync(false);
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|
|
|