2011-04-27 11:58:34 +00:00
|
|
|
/*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Copyright 2011-2013 Blender Foundation
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* 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
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* 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
|
2014-12-25 02:50:24 +01:00
|
|
|
* limitations under the License.
|
2011-04-27 11:58:34 +00:00
|
|
|
*/
|
|
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 20:39:14 +02:00
|
|
|
#include "render/background.h"
|
2019-05-02 15:45:31 +02:00
|
|
|
#include "render/colorspace.h"
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 20:39:14 +02:00
|
|
|
#include "render/graph.h"
|
|
|
|
|
#include "render/light.h"
|
|
|
|
|
#include "render/nodes.h"
|
|
|
|
|
#include "render/osl.h"
|
|
|
|
|
#include "render/scene.h"
|
|
|
|
|
#include "render/shader.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2020-03-08 14:21:29 +01:00
|
|
|
#include "blender/blender_image.h"
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 20:39:14 +02:00
|
|
|
#include "blender/blender_sync.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "blender/blender_texture.h"
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 20:39:14 +02:00
|
|
|
#include "blender/blender_util.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 20:39:14 +02:00
|
|
|
#include "util/util_debug.h"
|
2017-04-04 13:36:58 +02:00
|
|
|
#include "util/util_foreach.h"
|
|
|
|
|
#include "util/util_set.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "util/util_string.h"
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 20:39:14 +02:00
|
|
|
#include "util/util_task.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
typedef map<void *, ShaderInput *> PtrInputMap;
|
|
|
|
|
typedef map<void *, ShaderOutput *> PtrOutputMap;
|
|
|
|
|
typedef map<string, ConvertNode *> ProxyMap;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
/* Find */
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
void BlenderSync::find_shader(BL::ID &id, vector<Shader *> &used_shaders, Shader *default_shader)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Shader *shader = (id) ? shader_map.find(id) : default_shader;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
used_shaders.push_back(shader);
|
|
|
|
|
shader->tag_used(scene);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2016-02-10 15:09:45 +01:00
|
|
|
/* RNA translation utilities */
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static VolumeSampling get_volume_sampling(PointerRNA &ptr)
|
2016-02-10 15:09:45 +01:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return (VolumeSampling)get_enum(
|
|
|
|
|
ptr, "volume_sampling", VOLUME_NUM_SAMPLING, VOLUME_SAMPLING_DISTANCE);
|
2016-02-10 15:09:45 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static VolumeInterpolation get_volume_interpolation(PointerRNA &ptr)
|
2016-02-10 15:09:45 +01:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return (VolumeInterpolation)get_enum(
|
|
|
|
|
ptr, "volume_interpolation", VOLUME_NUM_INTERPOLATION, VOLUME_INTERPOLATION_LINEAR);
|
2016-02-10 15:09:45 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static DisplacementMethod get_displacement_method(PointerRNA &ptr)
|
2016-08-02 05:13:58 -04:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return (DisplacementMethod)get_enum(
|
|
|
|
|
ptr, "displacement_method", DISPLACE_NUM_METHODS, DISPLACE_BUMP);
|
2016-08-02 05:13:58 -04:00
|
|
|
}
|
|
|
|
|
|
2016-02-10 15:09:45 +01:00
|
|
|
static int validate_enum_value(int value, int num_values, int default_value)
|
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (value >= num_values) {
|
|
|
|
|
return default_value;
|
|
|
|
|
}
|
|
|
|
|
return value;
|
2016-02-10 15:09:45 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
template<typename NodeType> static InterpolationType get_image_interpolation(NodeType &b_node)
|
2016-02-10 15:09:45 +01:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
int value = b_node.interpolation();
|
|
|
|
|
return (InterpolationType)validate_enum_value(
|
|
|
|
|
value, INTERPOLATION_NUM_TYPES, INTERPOLATION_LINEAR);
|
2016-02-10 15:09:45 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
template<typename NodeType> static ExtensionType get_image_extension(NodeType &b_node)
|
2016-02-10 15:09:45 +01:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
int value = b_node.extension();
|
|
|
|
|
return (ExtensionType)validate_enum_value(value, EXTENSION_NUM_TYPES, EXTENSION_REPEAT);
|
2016-02-10 15:09:45 +01:00
|
|
|
}
|
|
|
|
|
|
2019-05-18 20:52:20 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Graph */
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static BL::NodeSocket get_node_output(BL::Node &b_node, const string &name)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
BL::Node::outputs_iterator b_out;
|
2014-09-19 12:57:09 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
for (b_node.outputs.begin(b_out); b_out != b_node.outputs.end(); ++b_out)
|
|
|
|
|
if (b_out->name() == name)
|
|
|
|
|
return *b_out;
|
2014-09-19 12:57:09 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
assert(0);
|
2014-09-19 12:57:09 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return *b_out;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static float3 get_node_output_rgba(BL::Node &b_node, const string &name)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
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]);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static float get_node_output_value(BL::Node &b_node, const string &name)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
BL::NodeSocket b_sock = get_node_output(b_node, name);
|
|
|
|
|
return RNA_float_get(&b_sock.ptr, "default_value");
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static float3 get_node_output_vector(BL::Node &b_node, const string &name)
|
2012-06-12 07:27:50 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
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]);
|
2013-03-18 16:34:57 +00:00
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static SocketType::Type convert_socket_type(BL::NodeSocket &b_socket)
|
2013-03-18 16:34:57 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
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;
|
|
|
|
|
}
|
2012-06-12 07:27:50 +00:00
|
|
|
}
|
|
|
|
|
|
2016-01-30 14:18:29 +01:00
|
|
|
static void set_default_value(ShaderInput *input,
|
2019-04-17 06:17:24 +02:00
|
|
|
BL::NodeSocket &b_sock,
|
|
|
|
|
BL::BlendData &b_data,
|
|
|
|
|
BL::ID &b_id)
|
2012-06-12 07:27:50 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
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;
|
|
|
|
|
}
|
2012-06-12 07:27:50 +00:00
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping &b_mapping)
|
2011-11-04 20:58:00 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (!b_mapping)
|
|
|
|
|
return;
|
2011-11-21 16:28:19 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
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();
|
2011-11-04 20:58:00 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
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();
|
2011-11-04 20:58:00 +00:00
|
|
|
}
|
|
|
|
|
|
Cycles: Experiment with making previews more interactive
There were two major problems with the interactivity of material previews:
- Beckmann tables were re-generated on every material tweak.
This is because preview scene is not set to be persistent, so re-triggering
the render leads to the full scene re-sync.
- Images could take rather noticeable time to load with OIIO from the disk
on every tweak.
This patch addressed this two issues in the following way:
- Beckmann tables are now static on CPU memory.
They're couple of hundred kilobytes only, so wouldn't expect this to be
an issue. And they're needed for almost every render anyway.
This actually also makes blackbody table to be static, but it's even smaller
than beckmann table.
Not totally happy with this approach, but others seems to complicate things
quite a bit with all this render engine life time and so..
- For preview rendering all images are considered to be built-in. This means
instead of OIIO which re-loads images on every re-render they're coming
from ImBuf cache which is fully manageable from blender side and unused
images gets freed later.
This would make it impossible to have mipmapping with OSL for now, but we'll
be working on that later anyway and don't think mipmaps are really so crucial
for the material preview.
This seems to be a better alternative to making preview scene persistent,
because of much optimal memory control from blender side.
Reviewers: brecht, juicyfruit, campbellbarton, dingto
Subscribers: eyecandy, venomgfx
Differential Revision: https://developer.blender.org/D1132
2015-02-21 21:55:24 +05:00
|
|
|
static ShaderNode *add_node(Scene *scene,
|
2019-04-17 06:17:24 +02:00
|
|
|
BL::RenderEngine &b_engine,
|
|
|
|
|
BL::BlendData &b_data,
|
|
|
|
|
BL::Depsgraph &b_depsgraph,
|
|
|
|
|
BL::Scene &b_scene,
|
Cycles: Experiment with making previews more interactive
There were two major problems with the interactivity of material previews:
- Beckmann tables were re-generated on every material tweak.
This is because preview scene is not set to be persistent, so re-triggering
the render leads to the full scene re-sync.
- Images could take rather noticeable time to load with OIIO from the disk
on every tweak.
This patch addressed this two issues in the following way:
- Beckmann tables are now static on CPU memory.
They're couple of hundred kilobytes only, so wouldn't expect this to be
an issue. And they're needed for almost every render anyway.
This actually also makes blackbody table to be static, but it's even smaller
than beckmann table.
Not totally happy with this approach, but others seems to complicate things
quite a bit with all this render engine life time and so..
- For preview rendering all images are considered to be built-in. This means
instead of OIIO which re-loads images on every re-render they're coming
from ImBuf cache which is fully manageable from blender side and unused
images gets freed later.
This would make it impossible to have mipmapping with OSL for now, but we'll
be working on that later anyway and don't think mipmaps are really so crucial
for the material preview.
This seems to be a better alternative to making preview scene persistent,
because of much optimal memory control from blender side.
Reviewers: brecht, juicyfruit, campbellbarton, dingto
Subscribers: eyecandy, venomgfx
Differential Revision: https://developer.blender.org/D1132
2015-02-21 21:55:24 +05:00
|
|
|
ShaderGraph *graph,
|
2019-04-17 06:17:24 +02:00
|
|
|
BL::ShaderNodeTree &b_ntree,
|
|
|
|
|
BL::ShaderNode &b_node)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
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();
|
|
|
|
|
}
|
2019-08-13 16:29:32 +02:00
|
|
|
else if (b_node.is_a(&RNA_ShaderNodeMapRange)) {
|
2019-08-14 10:53:19 +02:00
|
|
|
BL::ShaderNodeMapRange b_map_range_node(b_node);
|
|
|
|
|
MapRangeNode *map_range_node = new MapRangeNode();
|
|
|
|
|
map_range_node->clamp = b_map_range_node.clamp();
|
2019-12-07 12:35:07 +00:00
|
|
|
map_range_node->type = (NodeMapRangeType)b_map_range_node.interpolation_type();
|
2019-08-14 10:53:19 +02:00
|
|
|
node = map_range_node;
|
2019-08-13 16:29:32 +02:00
|
|
|
}
|
2019-08-13 22:22:15 +02:00
|
|
|
else if (b_node.is_a(&RNA_ShaderNodeClamp)) {
|
2019-12-07 12:35:07 +00:00
|
|
|
BL::ShaderNodeClamp b_clamp_node(b_node);
|
|
|
|
|
ClampNode *clamp_node = new ClampNode();
|
|
|
|
|
clamp_node->type = (NodeClampType)b_clamp_node.clamp_type();
|
|
|
|
|
node = clamp_node;
|
2019-08-13 22:22:15 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
else if (b_node.is_a(&RNA_ShaderNodeMath)) {
|
|
|
|
|
BL::ShaderNodeMath b_math_node(b_node);
|
2019-08-18 11:16:04 +02:00
|
|
|
MathNode *math_node = new MathNode();
|
|
|
|
|
math_node->type = (NodeMathType)b_math_node.operation();
|
|
|
|
|
math_node->use_clamp = b_math_node.use_clamp();
|
|
|
|
|
node = math_node;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
else if (b_node.is_a(&RNA_ShaderNodeVectorMath)) {
|
|
|
|
|
BL::ShaderNodeVectorMath b_vector_math_node(b_node);
|
Shading: Add more operators to Vector Math node.
Add Multiply, Divide, Project, Reflect, Distance, Length, Scale, Snap,
Floor, Ceil, Modulo, Fraction, Absolute, Minimum, and Maximum operators
to the Vector Math node. The Value output has been removed from operators
whose output is a vector, and the other way around. All of those removals
has been handled properly in versioning code.
The patch doesn't include tests for the new operators. Tests will be added
in a later patch.
Reviewers: brecht, JacquesLucke
Differential Revision: https://developer.blender.org/D5523
2019-08-21 19:36:33 +02:00
|
|
|
VectorMathNode *vector_math_node = new VectorMathNode();
|
|
|
|
|
vector_math_node->type = (NodeVectorMathType)b_vector_math_node.operation();
|
|
|
|
|
node = vector_math_node;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2020-02-17 15:15:46 +00:00
|
|
|
else if (b_node.is_a(&RNA_ShaderNodeVectorRotate)) {
|
|
|
|
|
BL::ShaderNodeVectorRotate b_vector_rotate_node(b_node);
|
|
|
|
|
VectorRotateNode *vector_rotate_node = new VectorRotateNode();
|
|
|
|
|
vector_rotate_node->type = (NodeVectorRotateType)b_vector_rotate_node.rotation_type();
|
2020-02-25 14:52:01 +00:00
|
|
|
vector_rotate_node->invert = b_vector_rotate_node.invert();
|
2020-02-17 15:15:46 +00:00
|
|
|
node = vector_rotate_node;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
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();
|
2019-09-04 23:17:13 +02:00
|
|
|
mapping->type = (NodeMappingType)b_mapping_node.vector_type();
|
2019-04-17 06:17:24 +02:00
|
|
|
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:
|
2020-05-14 22:12:29 +02:00
|
|
|
aniso->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
|
2019-04-17 06:17:24 +02:00
|
|
|
break;
|
|
|
|
|
case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
|
2020-05-14 22:12:29 +02:00
|
|
|
aniso->distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
|
2019-04-17 06:17:24 +02:00
|
|
|
break;
|
|
|
|
|
case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX:
|
2020-05-14 22:12:29 +02:00
|
|
|
aniso->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
|
2019-04-17 06:17:24 +02:00
|
|
|
break;
|
|
|
|
|
case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
|
2020-05-14 22:12:29 +02:00
|
|
|
aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID;
|
2019-04-17 06:17:24 +02:00
|
|
|
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;
|
|
|
|
|
case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK:
|
|
|
|
|
subsurface->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 = 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_ShaderNodeBsdfHairPrincipled)) {
|
|
|
|
|
BL::ShaderNodeBsdfHairPrincipled b_principled_hair_node(b_node);
|
|
|
|
|
PrincipledHairBsdfNode *principled_hair = new PrincipledHairBsdfNode();
|
|
|
|
|
principled_hair->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 = new PrincipledBsdfNode();
|
|
|
|
|
switch (b_principled_node.distribution()) {
|
|
|
|
|
case BL::ShaderNodeBsdfPrincipled::distribution_GGX:
|
|
|
|
|
principled->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
|
|
|
|
|
break;
|
|
|
|
|
case BL::ShaderNodeBsdfPrincipled::distribution_MULTI_GGX:
|
|
|
|
|
principled->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
switch (b_principled_node.subsurface_method()) {
|
|
|
|
|
case BL::ShaderNodeBsdfPrincipled::subsurface_method_BURLEY:
|
|
|
|
|
principled->subsurface_method = CLOSURE_BSSRDF_PRINCIPLED_ID;
|
|
|
|
|
break;
|
|
|
|
|
case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK:
|
|
|
|
|
principled->subsurface_method = CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
node = principled;
|
|
|
|
|
}
|
|
|
|
|
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)) {
|
|
|
|
|
BL::ShaderNodeAmbientOcclusion b_ao_node(b_node);
|
|
|
|
|
AmbientOcclusionNode *ao = new AmbientOcclusionNode();
|
|
|
|
|
ao->samples = b_ao_node.samples();
|
|
|
|
|
ao->inside = b_ao_node.inside();
|
|
|
|
|
ao->only_local = b_ao_node.only_local();
|
|
|
|
|
node = ao;
|
|
|
|
|
}
|
|
|
|
|
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_ShaderNodeVolumePrincipled)) {
|
|
|
|
|
PrincipledVolumeNode *principled = new PrincipledVolumeNode();
|
|
|
|
|
node = principled;
|
|
|
|
|
}
|
|
|
|
|
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();
|
|
|
|
|
}
|
2019-08-21 20:22:24 +02:00
|
|
|
else if (b_node.is_a(&RNA_ShaderNodeVolumeInfo)) {
|
|
|
|
|
node = new VolumeInfoNode();
|
|
|
|
|
}
|
2019-09-12 17:42:13 +02:00
|
|
|
else if (b_node.is_a(&RNA_ShaderNodeVertexColor)) {
|
|
|
|
|
BL::ShaderNodeVertexColor b_vertex_color_node(b_node);
|
|
|
|
|
VertexColorNode *vertex_color_node = new VertexColorNode();
|
|
|
|
|
vertex_color_node->layer_name = b_vertex_color_node.layer_name();
|
|
|
|
|
node = vertex_color_node;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
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)) {
|
2012-11-03 14:32:35 +00:00
|
|
|
#ifdef WITH_OSL
|
2019-04-17 06:17:24 +02:00
|
|
|
if (scene->shader_manager->use_osl()) {
|
|
|
|
|
/* create script node */
|
|
|
|
|
BL::ShaderNodeScript b_script_node(b_node);
|
|
|
|
|
|
2020-03-11 16:51:42 +01:00
|
|
|
ShaderManager *manager = scene->shader_manager;
|
2019-04-17 06:17:24 +02:00
|
|
|
string bytecode_hash = b_script_node.bytecode_hash();
|
|
|
|
|
|
|
|
|
|
if (!bytecode_hash.empty()) {
|
2020-03-11 16:51:42 +01:00
|
|
|
node = OSLShaderManager::osl_node(manager, "", bytecode_hash, b_script_node.bytecode());
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
string absolute_filepath = blender_absolute_path(
|
|
|
|
|
b_data, b_ntree, b_script_node.filepath());
|
2020-03-11 16:51:42 +01:00
|
|
|
node = OSLShaderManager::osl_node(manager, absolute_filepath, "");
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2015-03-27 19:09:41 +05:00
|
|
|
#else
|
2019-04-17 06:17:24 +02:00
|
|
|
(void)b_data;
|
|
|
|
|
(void)b_ntree;
|
2013-03-18 16:34:57 +00:00
|
|
|
#endif
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
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();
|
2020-02-20 00:52:50 +01:00
|
|
|
|
|
|
|
|
image->interpolation = get_image_interpolation(b_image_node);
|
|
|
|
|
image->extension = get_image_extension(b_image_node);
|
|
|
|
|
image->projection = (NodeImageProjection)b_image_node.projection();
|
|
|
|
|
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);
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (b_image) {
|
2020-03-08 14:21:29 +01:00
|
|
|
PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
|
|
|
|
|
image->colorspace = get_enum_identifier(colorspace_ptr, "name");
|
|
|
|
|
|
|
|
|
|
image->animated = b_image_node.image_user().use_auto_refresh();
|
|
|
|
|
image->alpha_type = get_image_alpha_type(b_image);
|
|
|
|
|
|
|
|
|
|
image->tiles.clear();
|
|
|
|
|
BL::Image::tiles_iterator b_iter;
|
|
|
|
|
for (b_image.tiles.begin(b_iter); b_iter != b_image.tiles.end(); ++b_iter) {
|
|
|
|
|
image->tiles.push_back(b_iter->number());
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* 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();
|
2020-07-31 15:00:42 +02:00
|
|
|
int image_frame = image_user_frame_number(b_image_user, b_image, scene_frame);
|
2020-03-08 14:21:29 +01:00
|
|
|
image->handle = scene->image_manager->add_image(
|
|
|
|
|
new BlenderImageLoader(b_image, image_frame), image->image_params());
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2019-12-16 03:58:01 +01:00
|
|
|
image->filename = image_user_file_path(
|
2019-12-26 18:55:36 +01:00
|
|
|
b_image_user, b_image, b_scene.frame_current(), true);
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
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();
|
2020-02-20 00:52:50 +01:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (b_image) {
|
2020-03-08 14:21:29 +01:00
|
|
|
PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
|
|
|
|
|
env->colorspace = get_enum_identifier(colorspace_ptr, "name");
|
|
|
|
|
|
|
|
|
|
env->animated = b_env_node.image_user().use_auto_refresh();
|
|
|
|
|
env->alpha_type = get_image_alpha_type(b_image);
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
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();
|
2020-07-31 15:00:42 +02:00
|
|
|
int image_frame = image_user_frame_number(b_image_user, b_image, scene_frame);
|
2020-03-08 14:21:29 +01:00
|
|
|
env->handle = scene->image_manager->add_image(new BlenderImageLoader(b_image, image_frame),
|
|
|
|
|
env->image_params());
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2019-12-26 18:55:36 +01:00
|
|
|
env->filename = image_user_file_path(
|
|
|
|
|
b_image_user, b_image, b_scene.frame_current(), false);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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();
|
2019-09-12 13:09:31 +02:00
|
|
|
voronoi->dimensions = b_voronoi_node.voronoi_dimensions();
|
2019-04-17 06:17:24 +02:00
|
|
|
voronoi->feature = (NodeVoronoiFeature)b_voronoi_node.feature();
|
2019-09-12 13:09:31 +02:00
|
|
|
voronoi->metric = (NodeVoronoiDistanceMetric)b_voronoi_node.distance();
|
2019-04-17 06:17:24 +02:00
|
|
|
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();
|
2020-02-17 12:31:38 +01:00
|
|
|
wave->bands_direction = (NodeWaveBandsDirection)b_wave_node.bands_direction();
|
|
|
|
|
wave->rings_direction = (NodeWaveRingsDirection)b_wave_node.rings_direction();
|
2019-04-17 06:17:24 +02:00
|
|
|
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();
|
2019-09-06 16:06:02 +02:00
|
|
|
noise->dimensions = b_noise_node.noise_dimensions();
|
2019-04-17 06:17:24 +02:00
|
|
|
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);
|
2019-09-09 21:06:55 +02:00
|
|
|
MusgraveTextureNode *musgrave_node = new MusgraveTextureNode();
|
|
|
|
|
musgrave_node->type = (NodeMusgraveType)b_musgrave_node.musgrave_type();
|
|
|
|
|
musgrave_node->dimensions = b_musgrave_node.musgrave_dimensions();
|
2019-04-17 06:17:24 +02:00
|
|
|
BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping());
|
2019-09-09 21:06:55 +02:00
|
|
|
get_tex_mapping(&musgrave_node->tex_mapping, b_texture_mapping);
|
|
|
|
|
node = musgrave_node;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
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_instancer();
|
|
|
|
|
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();
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
sky->sun_disc = b_sky_node.sun_disc();
|
|
|
|
|
sky->sun_size = b_sky_node.sun_size();
|
2020-07-13 01:49:25 +02:00
|
|
|
sky->sun_intensity = b_sky_node.sun_intensity();
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
sky->sun_elevation = b_sky_node.sun_elevation();
|
|
|
|
|
sky->sun_rotation = b_sky_node.sun_rotation();
|
2020-07-13 01:49:25 +02:00
|
|
|
sky->altitude = 1000.0f * b_sky_node.altitude();
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
sky->air_density = b_sky_node.air_density();
|
|
|
|
|
sky->dust_density = b_sky_node.dust_density();
|
|
|
|
|
sky->ozone_density = b_sky_node.ozone_density();
|
2019-04-17 06:17:24 +02:00
|
|
|
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_ShaderNodeTexIES)) {
|
|
|
|
|
BL::ShaderNodeTexIES b_ies_node(b_node);
|
|
|
|
|
IESLightNode *ies = new IESLightNode();
|
|
|
|
|
switch (b_ies_node.mode()) {
|
|
|
|
|
case BL::ShaderNodeTexIES::mode_EXTERNAL:
|
|
|
|
|
ies->filename = blender_absolute_path(b_data, b_ntree, b_ies_node.filepath());
|
|
|
|
|
break;
|
|
|
|
|
case BL::ShaderNodeTexIES::mode_INTERNAL:
|
|
|
|
|
ies->ies = get_text_datablock_content(b_ies_node.ies().ptr);
|
|
|
|
|
if (ies->ies.empty()) {
|
|
|
|
|
ies->ies = "\n";
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
node = ies;
|
|
|
|
|
}
|
2019-08-21 20:04:09 +02:00
|
|
|
else if (b_node.is_a(&RNA_ShaderNodeTexWhiteNoise)) {
|
|
|
|
|
BL::ShaderNodeTexWhiteNoise b_tex_white_noise_node(b_node);
|
|
|
|
|
WhiteNoiseTextureNode *white_noise_node = new WhiteNoiseTextureNode();
|
2019-09-06 16:06:02 +02:00
|
|
|
white_noise_node->dimensions = b_tex_white_noise_node.noise_dimensions();
|
2019-08-21 20:04:09 +02:00
|
|
|
node = white_noise_node;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
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_instancer();
|
|
|
|
|
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->space = (NodeTexVoxelSpace)b_point_density_node.space();
|
|
|
|
|
point_density->interpolation = get_image_interpolation(b_point_density_node);
|
2020-03-08 14:21:29 +01:00
|
|
|
point_density->handle = scene->image_manager->add_image(
|
|
|
|
|
new BlenderPointDensityLoader(b_depsgraph, b_point_density_node),
|
|
|
|
|
point_density->image_params());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-08 10:42:11 +01:00
|
|
|
b_point_density_node.cache_point_density(b_depsgraph);
|
2019-04-17 06:17:24 +02:00
|
|
|
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->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 = new BevelNode();
|
|
|
|
|
bevel->samples = b_bevel_node.samples();
|
|
|
|
|
node = bevel;
|
|
|
|
|
}
|
|
|
|
|
else if (b_node.is_a(&RNA_ShaderNodeDisplacement)) {
|
|
|
|
|
BL::ShaderNodeDisplacement b_disp_node(b_node);
|
|
|
|
|
DisplacementNode *disp = new DisplacementNode();
|
|
|
|
|
disp->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 = new VectorDisplacementNode();
|
|
|
|
|
disp->space = (NodeNormalMapSpace)b_disp_node.space();
|
|
|
|
|
disp->attribute = "";
|
|
|
|
|
node = disp;
|
|
|
|
|
}
|
2019-12-04 19:57:28 +01:00
|
|
|
else if (b_node.is_a(&RNA_ShaderNodeOutputAOV)) {
|
|
|
|
|
BL::ShaderNodeOutputAOV b_aov_node(b_node);
|
|
|
|
|
OutputAOVNode *aov = new OutputAOVNode();
|
|
|
|
|
aov->name = b_aov_node.name();
|
|
|
|
|
node = aov;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
if (node) {
|
|
|
|
|
node->name = b_node.name();
|
|
|
|
|
graph->add(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return node;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-30 11:21:31 +00:00
|
|
|
static bool node_use_modified_socket_name(ShaderNode *node)
|
|
|
|
|
{
|
2019-04-21 02:18:19 +02:00
|
|
|
if (node->special_type == SHADER_SPECIAL_TYPE_OSL)
|
2019-04-17 06:17:24 +02:00
|
|
|
return false;
|
2014-09-19 12:57:09 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return true;
|
2013-10-30 11:21:31 +00:00
|
|
|
}
|
|
|
|
|
|
2016-01-30 14:18:29 +01:00
|
|
|
static ShaderInput *node_find_input_by_name(ShaderNode *node,
|
2019-04-17 06:17:24 +02:00
|
|
|
BL::Node &b_node,
|
|
|
|
|
BL::NodeSocket &b_socket)
|
2011-09-16 13:14:02 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
string name = b_socket.name();
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (node_use_modified_socket_name(node)) {
|
|
|
|
|
BL::Node::inputs_iterator b_input;
|
|
|
|
|
bool found = false;
|
|
|
|
|
int counter = 0, total = 0;
|
2014-09-19 12:57:09 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
for (b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
|
|
|
|
|
if (b_input->name() == name) {
|
|
|
|
|
if (!found)
|
|
|
|
|
counter++;
|
|
|
|
|
total++;
|
|
|
|
|
}
|
2014-09-19 12:57:09 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (b_input->ptr.data == b_socket.ptr.data)
|
|
|
|
|
found = true;
|
|
|
|
|
}
|
2014-09-19 12:57:09 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* rename if needed */
|
|
|
|
|
if (name == "Shader")
|
|
|
|
|
name = "Closure";
|
2014-09-19 12:57:09 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (total > 1)
|
|
|
|
|
name = string_printf("%s%d", name.c_str(), counter);
|
|
|
|
|
}
|
2014-09-19 12:57:09 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return node->input(name.c_str());
|
2013-03-18 16:34:57 +00:00
|
|
|
}
|
2011-09-16 13:14:02 +00:00
|
|
|
|
2016-01-30 14:18:29 +01:00
|
|
|
static ShaderOutput *node_find_output_by_name(ShaderNode *node,
|
2019-04-17 06:17:24 +02:00
|
|
|
BL::Node &b_node,
|
|
|
|
|
BL::NodeSocket &b_socket)
|
2013-03-18 16:34:57 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
string name = b_socket.name();
|
2014-09-19 12:57:09 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (node_use_modified_socket_name(node)) {
|
|
|
|
|
BL::Node::outputs_iterator b_output;
|
|
|
|
|
bool found = false;
|
|
|
|
|
int counter = 0, total = 0;
|
2014-09-19 12:57:09 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
for (b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
|
|
|
|
|
if (b_output->name() == name) {
|
|
|
|
|
if (!found)
|
|
|
|
|
counter++;
|
|
|
|
|
total++;
|
|
|
|
|
}
|
2014-09-19 12:57:09 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (b_output->ptr.data == b_socket.ptr.data)
|
|
|
|
|
found = true;
|
|
|
|
|
}
|
2014-09-19 12:57:09 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* rename if needed */
|
|
|
|
|
if (name == "Shader")
|
|
|
|
|
name = "Closure";
|
2014-09-19 12:57:09 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (total > 1)
|
|
|
|
|
name = string_printf("%s%d", name.c_str(), counter);
|
|
|
|
|
}
|
2014-09-19 12:57:09 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return node->output(name.c_str());
|
2011-09-16 13:14:02 +00:00
|
|
|
}
|
|
|
|
|
|
Cycles: Experiment with making previews more interactive
There were two major problems with the interactivity of material previews:
- Beckmann tables were re-generated on every material tweak.
This is because preview scene is not set to be persistent, so re-triggering
the render leads to the full scene re-sync.
- Images could take rather noticeable time to load with OIIO from the disk
on every tweak.
This patch addressed this two issues in the following way:
- Beckmann tables are now static on CPU memory.
They're couple of hundred kilobytes only, so wouldn't expect this to be
an issue. And they're needed for almost every render anyway.
This actually also makes blackbody table to be static, but it's even smaller
than beckmann table.
Not totally happy with this approach, but others seems to complicate things
quite a bit with all this render engine life time and so..
- For preview rendering all images are considered to be built-in. This means
instead of OIIO which re-loads images on every re-render they're coming
from ImBuf cache which is fully manageable from blender side and unused
images gets freed later.
This would make it impossible to have mipmapping with OSL for now, but we'll
be working on that later anyway and don't think mipmaps are really so crucial
for the material preview.
This seems to be a better alternative to making preview scene persistent,
because of much optimal memory control from blender side.
Reviewers: brecht, juicyfruit, campbellbarton, dingto
Subscribers: eyecandy, venomgfx
Differential Revision: https://developer.blender.org/D1132
2015-02-21 21:55:24 +05:00
|
|
|
static void add_nodes(Scene *scene,
|
2019-04-17 06:17:24 +02:00
|
|
|
BL::RenderEngine &b_engine,
|
|
|
|
|
BL::BlendData &b_data,
|
|
|
|
|
BL::Depsgraph &b_depsgraph,
|
|
|
|
|
BL::Scene &b_scene,
|
Cycles: Experiment with making previews more interactive
There were two major problems with the interactivity of material previews:
- Beckmann tables were re-generated on every material tweak.
This is because preview scene is not set to be persistent, so re-triggering
the render leads to the full scene re-sync.
- Images could take rather noticeable time to load with OIIO from the disk
on every tweak.
This patch addressed this two issues in the following way:
- Beckmann tables are now static on CPU memory.
They're couple of hundred kilobytes only, so wouldn't expect this to be
an issue. And they're needed for almost every render anyway.
This actually also makes blackbody table to be static, but it's even smaller
than beckmann table.
Not totally happy with this approach, but others seems to complicate things
quite a bit with all this render engine life time and so..
- For preview rendering all images are considered to be built-in. This means
instead of OIIO which re-loads images on every re-render they're coming
from ImBuf cache which is fully manageable from blender side and unused
images gets freed later.
This would make it impossible to have mipmapping with OSL for now, but we'll
be working on that later anyway and don't think mipmaps are really so crucial
for the material preview.
This seems to be a better alternative to making preview scene persistent,
because of much optimal memory control from blender side.
Reviewers: brecht, juicyfruit, campbellbarton, dingto
Subscribers: eyecandy, venomgfx
Differential Revision: https://developer.blender.org/D1132
2015-02-21 21:55:24 +05:00
|
|
|
ShaderGraph *graph,
|
2019-04-17 06:17:24 +02:00
|
|
|
BL::ShaderNodeTree &b_ntree,
|
Cycles: Experiment with making previews more interactive
There were two major problems with the interactivity of material previews:
- Beckmann tables were re-generated on every material tweak.
This is because preview scene is not set to be persistent, so re-triggering
the render leads to the full scene re-sync.
- Images could take rather noticeable time to load with OIIO from the disk
on every tweak.
This patch addressed this two issues in the following way:
- Beckmann tables are now static on CPU memory.
They're couple of hundred kilobytes only, so wouldn't expect this to be
an issue. And they're needed for almost every render anyway.
This actually also makes blackbody table to be static, but it's even smaller
than beckmann table.
Not totally happy with this approach, but others seems to complicate things
quite a bit with all this render engine life time and so..
- For preview rendering all images are considered to be built-in. This means
instead of OIIO which re-loads images on every re-render they're coming
from ImBuf cache which is fully manageable from blender side and unused
images gets freed later.
This would make it impossible to have mipmapping with OSL for now, but we'll
be working on that later anyway and don't think mipmaps are really so crucial
for the material preview.
This seems to be a better alternative to making preview scene persistent,
because of much optimal memory control from blender side.
Reviewers: brecht, juicyfruit, campbellbarton, dingto
Subscribers: eyecandy, venomgfx
Differential Revision: https://developer.blender.org/D1132
2015-02-21 21:55:24 +05:00
|
|
|
const ProxyMap &proxy_input_map,
|
|
|
|
|
const ProxyMap &proxy_output_map)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* 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 = 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) ||
|
|
|
|
|
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 = 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);
|
|
|
|
|
if (output_type == SocketType::UNDEFINED) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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_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) {
|
2019-09-11 18:32:50 +02:00
|
|
|
/* 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())) {
|
2019-04-17 06:17:24 +02:00
|
|
|
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);
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
Cycles: Experiment with making previews more interactive
There were two major problems with the interactivity of material previews:
- Beckmann tables were re-generated on every material tweak.
This is because preview scene is not set to be persistent, so re-triggering
the render leads to the full scene re-sync.
- Images could take rather noticeable time to load with OIIO from the disk
on every tweak.
This patch addressed this two issues in the following way:
- Beckmann tables are now static on CPU memory.
They're couple of hundred kilobytes only, so wouldn't expect this to be
an issue. And they're needed for almost every render anyway.
This actually also makes blackbody table to be static, but it's even smaller
than beckmann table.
Not totally happy with this approach, but others seems to complicate things
quite a bit with all this render engine life time and so..
- For preview rendering all images are considered to be built-in. This means
instead of OIIO which re-loads images on every re-render they're coming
from ImBuf cache which is fully manageable from blender side and unused
images gets freed later.
This would make it impossible to have mipmapping with OSL for now, but we'll
be working on that later anyway and don't think mipmaps are really so crucial
for the material preview.
This seems to be a better alternative to making preview scene persistent,
because of much optimal memory control from blender side.
Reviewers: brecht, juicyfruit, campbellbarton, dingto
Subscribers: eyecandy, venomgfx
Differential Revision: https://developer.blender.org/D1132
2015-02-21 21:55:24 +05:00
|
|
|
static void add_nodes(Scene *scene,
|
2019-04-17 06:17:24 +02:00
|
|
|
BL::RenderEngine &b_engine,
|
|
|
|
|
BL::BlendData &b_data,
|
|
|
|
|
BL::Depsgraph &b_depsgraph,
|
|
|
|
|
BL::Scene &b_scene,
|
Cycles: Experiment with making previews more interactive
There were two major problems with the interactivity of material previews:
- Beckmann tables were re-generated on every material tweak.
This is because preview scene is not set to be persistent, so re-triggering
the render leads to the full scene re-sync.
- Images could take rather noticeable time to load with OIIO from the disk
on every tweak.
This patch addressed this two issues in the following way:
- Beckmann tables are now static on CPU memory.
They're couple of hundred kilobytes only, so wouldn't expect this to be
an issue. And they're needed for almost every render anyway.
This actually also makes blackbody table to be static, but it's even smaller
than beckmann table.
Not totally happy with this approach, but others seems to complicate things
quite a bit with all this render engine life time and so..
- For preview rendering all images are considered to be built-in. This means
instead of OIIO which re-loads images on every re-render they're coming
from ImBuf cache which is fully manageable from blender side and unused
images gets freed later.
This would make it impossible to have mipmapping with OSL for now, but we'll
be working on that later anyway and don't think mipmaps are really so crucial
for the material preview.
This seems to be a better alternative to making preview scene persistent,
because of much optimal memory control from blender side.
Reviewers: brecht, juicyfruit, campbellbarton, dingto
Subscribers: eyecandy, venomgfx
Differential Revision: https://developer.blender.org/D1132
2015-02-21 21:55:24 +05:00
|
|
|
ShaderGraph *graph,
|
2019-04-17 06:17:24 +02:00
|
|
|
BL::ShaderNodeTree &b_ntree)
|
2013-04-11 09:16:36 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
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);
|
2013-04-11 09:16:36 +00:00
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Sync Materials */
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
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 */
|
2020-05-14 17:26:04 +02:00
|
|
|
if (shader_map.add_or_update(&shader, b_mat) || update_all) {
|
2019-04-17 06:17:24 +02:00
|
|
|
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_depsgraph, b_scene, 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);
|
2020-03-07 14:38:52 +01:00
|
|
|
shader->volume_step_rate = get_float(cmat, "volume_step_rate");
|
2019-04-17 06:17:24 +02:00
|
|
|
shader->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);
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Sync World */
|
|
|
|
|
|
2019-08-27 15:47:30 +02:00
|
|
|
void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Background *background = scene->background;
|
|
|
|
|
Background prevbackground = *background;
|
|
|
|
|
|
|
|
|
|
BL::World b_world = b_scene.world();
|
|
|
|
|
|
2019-08-27 15:47:30 +02:00
|
|
|
BlenderViewportParameters new_viewport_parameters(b_v3d);
|
|
|
|
|
|
|
|
|
|
if (world_recalc || update_all || b_world.ptr.data != world_map ||
|
|
|
|
|
viewport_parameters.modified(new_viewport_parameters)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
Shader *shader = scene->default_background;
|
|
|
|
|
ShaderGraph *graph = new ShaderGraph();
|
|
|
|
|
|
|
|
|
|
/* create nodes */
|
2019-08-27 15:47:30 +02:00
|
|
|
if (new_viewport_parameters.use_scene_world && b_world && b_world.use_nodes() &&
|
|
|
|
|
b_world.node_tree()) {
|
2019-04-17 06:17:24 +02:00
|
|
|
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->heterogeneous_volume = !get_boolean(cworld, "homogeneous_volume");
|
|
|
|
|
shader->volume_sampling_method = get_volume_sampling(cworld);
|
|
|
|
|
shader->volume_interpolation_method = get_volume_interpolation(cworld);
|
2020-03-07 14:38:52 +01:00
|
|
|
shader->volume_step_rate = get_float(cworld, "volume_step_size");
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-08-27 15:47:30 +02:00
|
|
|
else if (new_viewport_parameters.use_scene_world && b_world) {
|
2019-04-17 06:17:24 +02:00
|
|
|
BackgroundNode *background = new BackgroundNode();
|
|
|
|
|
background->color = get_float3(b_world.color());
|
|
|
|
|
graph->add(background);
|
|
|
|
|
|
|
|
|
|
ShaderNode *out = graph->output();
|
|
|
|
|
graph->connect(background->output("Background"), out->input("Surface"));
|
|
|
|
|
}
|
2019-08-27 15:47:30 +02:00
|
|
|
else if (!new_viewport_parameters.use_scene_world) {
|
2019-10-07 11:31:47 +02:00
|
|
|
float3 world_color;
|
|
|
|
|
if (b_world) {
|
|
|
|
|
world_color = get_float3(b_world.color());
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
world_color = make_float3(0.0f, 0.0f, 0.0f);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-27 15:47:30 +02:00
|
|
|
BackgroundNode *background = new BackgroundNode();
|
|
|
|
|
graph->add(background);
|
|
|
|
|
|
|
|
|
|
LightPathNode *light_path = new LightPathNode();
|
|
|
|
|
graph->add(light_path);
|
|
|
|
|
|
|
|
|
|
MixNode *mix_scene_with_background = new MixNode();
|
2019-10-07 11:31:47 +02:00
|
|
|
mix_scene_with_background->color2 = world_color;
|
2019-08-27 15:47:30 +02:00
|
|
|
graph->add(mix_scene_with_background);
|
|
|
|
|
|
|
|
|
|
EnvironmentTextureNode *texture_environment = new EnvironmentTextureNode();
|
|
|
|
|
texture_environment->tex_mapping.type = TextureMapping::VECTOR;
|
|
|
|
|
texture_environment->tex_mapping.rotation[2] = new_viewport_parameters.studiolight_rotate_z;
|
|
|
|
|
texture_environment->filename = new_viewport_parameters.studiolight_path;
|
|
|
|
|
graph->add(texture_environment);
|
|
|
|
|
|
2019-09-04 16:22:47 +02:00
|
|
|
MixNode *mix_intensity = new MixNode();
|
|
|
|
|
mix_intensity->type = NODE_MIX_MUL;
|
|
|
|
|
mix_intensity->fac = 1.0f;
|
|
|
|
|
mix_intensity->color2 = make_float3(new_viewport_parameters.studiolight_intensity,
|
|
|
|
|
new_viewport_parameters.studiolight_intensity,
|
|
|
|
|
new_viewport_parameters.studiolight_intensity);
|
|
|
|
|
graph->add(mix_intensity);
|
|
|
|
|
|
2019-08-27 15:47:30 +02:00
|
|
|
TextureCoordinateNode *texture_coordinate = new TextureCoordinateNode();
|
|
|
|
|
graph->add(texture_coordinate);
|
|
|
|
|
|
|
|
|
|
MixNode *mix_background_with_environment = new MixNode();
|
|
|
|
|
mix_background_with_environment->fac = new_viewport_parameters.studiolight_background_alpha;
|
2019-10-07 11:31:47 +02:00
|
|
|
mix_background_with_environment->color1 = world_color;
|
2019-08-27 15:47:30 +02:00
|
|
|
graph->add(mix_background_with_environment);
|
|
|
|
|
|
|
|
|
|
ShaderNode *out = graph->output();
|
|
|
|
|
|
|
|
|
|
graph->connect(texture_coordinate->output("Generated"),
|
|
|
|
|
texture_environment->input("Vector"));
|
2019-09-04 16:22:47 +02:00
|
|
|
graph->connect(texture_environment->output("Color"), mix_intensity->input("Color1"));
|
2019-08-27 15:47:30 +02:00
|
|
|
graph->connect(light_path->output("Is Camera Ray"), mix_scene_with_background->input("Fac"));
|
2019-09-04 16:22:47 +02:00
|
|
|
graph->connect(mix_intensity->output("Color"), mix_scene_with_background->input("Color1"));
|
|
|
|
|
graph->connect(mix_intensity->output("Color"),
|
2019-08-27 15:47:30 +02:00
|
|
|
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"));
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
if (b_world) {
|
|
|
|
|
/* AO */
|
|
|
|
|
BL::WorldLighting b_light = b_world.light_settings();
|
|
|
|
|
|
|
|
|
|
background->use_ao = b_light.use_ambient_occlusion();
|
|
|
|
|
background->ao_factor = b_light.ao_factor();
|
|
|
|
|
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->use_ao = false;
|
|
|
|
|
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");
|
2019-05-16 17:03:16 +02:00
|
|
|
background->transparent = b_scene.render().film_transparent();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
if (background->transparent) {
|
|
|
|
|
background->transparent_glass = get_boolean(cscene, "film_transparent_glass");
|
|
|
|
|
background->transparent_roughness_threshold = get_float(cscene, "film_transparent_roughness");
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
background->transparent_glass = false;
|
|
|
|
|
background->transparent_roughness_threshold = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-27 15:47:30 +02:00
|
|
|
background->use_shader = view_layer.use_background_shader |
|
|
|
|
|
viewport_parameters.custom_viewport_parameters();
|
2019-04-17 06:17:24 +02:00
|
|
|
background->use_ao = background->use_ao && view_layer.use_background_ao;
|
|
|
|
|
|
|
|
|
|
if (background->modified(prevbackground))
|
|
|
|
|
background->tag_update(scene);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2018-06-27 14:41:53 +02:00
|
|
|
/* Sync Lights */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
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 */
|
2020-02-02 12:04:19 +01:00
|
|
|
if (shader_map.add_or_update(&shader, b_light) || update_all) {
|
2019-04-17 06:17:24 +02:00
|
|
|
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 = new EmissionNode();
|
2019-05-12 13:41:23 +02:00
|
|
|
emission->color = make_float3(1.0f, 1.0f, 1.0f);
|
|
|
|
|
emission->strength = 1.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
graph->add(emission);
|
|
|
|
|
|
|
|
|
|
ShaderNode *out = graph->output();
|
|
|
|
|
graph->connect(emission->output("Emission"), out->input("Surface"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
shader->set_graph(graph);
|
|
|
|
|
shader->tag_update(scene);
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2019-08-27 15:47:30 +02:00
|
|
|
void BlenderSync::sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* for auto refresh images */
|
|
|
|
|
bool auto_refresh_update = false;
|
2012-11-21 13:00:51 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (preview) {
|
|
|
|
|
ImageManager *image_manager = scene->image_manager;
|
|
|
|
|
int frame = b_scene.frame_current();
|
|
|
|
|
auto_refresh_update = image_manager->set_animation_frame_update(frame);
|
|
|
|
|
}
|
2012-11-21 13:00:51 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
shader_map.pre_sync();
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-08-27 15:47:30 +02:00
|
|
|
sync_world(b_depsgraph, b_v3d, auto_refresh_update);
|
2019-04-17 06:17:24 +02:00
|
|
|
sync_lights(b_depsgraph, auto_refresh_update);
|
|
|
|
|
sync_materials(b_depsgraph, auto_refresh_update);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CCL_NAMESPACE_END
|