blender/intern/cycles/render/nodes.cpp

5216 lines
141 KiB
C++
Raw Normal View History

/*
* Copyright 2011-2013 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "image.h"
#include "integrator.h"
#include "nodes.h"
#include "scene.h"
#include "svm.h"
#include "svm_math_util.h"
#include "osl.h"
#include "util_sky_model.h"
#include "util_foreach.h"
#include "util_transform.h"
CCL_NAMESPACE_BEGIN
/* Texture Mapping */
#define TEXTURE_MAPPING_DEFINE(TextureNode) \
SOCKET_POINT(tex_mapping.translation, "Translation", make_float3(0.0f, 0.0f, 0.0f)); \
SOCKET_VECTOR(tex_mapping.rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f)); \
SOCKET_VECTOR(tex_mapping.scale, "Scale", make_float3(1.0f, 1.0f, 1.0f)); \
\
SOCKET_VECTOR(tex_mapping.min, "Min", make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); \
SOCKET_VECTOR(tex_mapping.max, "Max", make_float3(FLT_MAX, FLT_MAX, FLT_MAX)); \
SOCKET_BOOLEAN(tex_mapping.use_minmax, "Use Min Max", false); \
\
static NodeEnum mapping_axis_enum; \
mapping_axis_enum.insert("none", TextureMapping::NONE); \
mapping_axis_enum.insert("x", TextureMapping::X); \
mapping_axis_enum.insert("y", TextureMapping::Y); \
mapping_axis_enum.insert("z", TextureMapping::Z); \
SOCKET_ENUM(tex_mapping.x_mapping, "x_mapping", mapping_axis_enum, TextureMapping::X); \
SOCKET_ENUM(tex_mapping.y_mapping, "y_mapping", mapping_axis_enum, TextureMapping::Y); \
SOCKET_ENUM(tex_mapping.z_mapping, "z_mapping", mapping_axis_enum, TextureMapping::Z); \
\
static NodeEnum mapping_type_enum; \
mapping_type_enum.insert("point", TextureMapping::POINT); \
mapping_type_enum.insert("texture", TextureMapping::TEXTURE); \
mapping_type_enum.insert("vector", TextureMapping::VECTOR); \
mapping_type_enum.insert("normal", TextureMapping::NORMAL); \
SOCKET_ENUM(tex_mapping.type, "Type", mapping_type_enum, TextureMapping::TEXTURE); \
\
static NodeEnum mapping_projection_enum; \
mapping_projection_enum.insert("flat", TextureMapping::FLAT); \
mapping_projection_enum.insert("cube", TextureMapping::CUBE); \
mapping_projection_enum.insert("tube", TextureMapping::TUBE); \
mapping_projection_enum.insert("sphere", TextureMapping::SPHERE); \
SOCKET_ENUM(tex_mapping.projection, "Projection", mapping_projection_enum, TextureMapping::FLAT);
TextureMapping::TextureMapping()
{
}
Transform TextureMapping::compute_transform()
{
Transform mmat = transform_scale(make_float3(0.0f, 0.0f, 0.0f));
if(x_mapping != NONE)
mmat[0][x_mapping-1] = 1.0f;
if(y_mapping != NONE)
mmat[1][y_mapping-1] = 1.0f;
if(z_mapping != NONE)
mmat[2][z_mapping-1] = 1.0f;
float3 scale_clamped = scale;
if(type == TEXTURE || type == NORMAL) {
/* keep matrix invertible */
if(fabsf(scale.x) < 1e-5f)
scale_clamped.x = signf(scale.x)*1e-5f;
if(fabsf(scale.y) < 1e-5f)
scale_clamped.y = signf(scale.y)*1e-5f;
if(fabsf(scale.z) < 1e-5f)
scale_clamped.z = signf(scale.z)*1e-5f;
}
Transform smat = transform_scale(scale_clamped);
Transform rmat = transform_euler(rotation);
Transform tmat = transform_translate(translation);
Transform mat;
switch(type) {
case TEXTURE:
/* inverse transform on texture coordinate gives
* forward transform on texture */
mat = tmat*rmat*smat;
mat = transform_inverse(mat);
break;
case POINT:
/* full transform */
mat = tmat*rmat*smat;
break;
case VECTOR:
/* no translation for vectors */
mat = rmat*smat;
break;
case NORMAL:
/* no translation for normals, and inverse transpose */
mat = rmat*smat;
mat = transform_inverse(mat);
mat = transform_transpose(mat);
break;
}
/* projection last */
mat = mat*mmat;
return mat;
}
bool TextureMapping::skip()
{
if(translation != make_float3(0.0f, 0.0f, 0.0f))
return false;
if(rotation != make_float3(0.0f, 0.0f, 0.0f))
return false;
if(scale != make_float3(1.0f, 1.0f, 1.0f))
return false;
if(x_mapping != X || y_mapping != Y || z_mapping != Z)
return false;
if(use_minmax)
return false;
return true;
}
void TextureMapping::compile(SVMCompiler& compiler, int offset_in, int offset_out)
{
compiler.add_node(NODE_MAPPING, offset_in, offset_out);
Transform tfm = compute_transform();
compiler.add_node(tfm.x);
compiler.add_node(tfm.y);
compiler.add_node(tfm.z);
compiler.add_node(tfm.w);
if(use_minmax) {
compiler.add_node(NODE_MIN_MAX, offset_out, offset_out);
compiler.add_node(float3_to_float4(min));
compiler.add_node(float3_to_float4(max));
}
if(type == NORMAL) {
compiler.add_node(NODE_VECTOR_MATH, NODE_VECTOR_MATH_NORMALIZE, offset_out, offset_out);
compiler.add_node(NODE_VECTOR_MATH, SVM_STACK_INVALID, offset_out);
}
}
/* Convenience function for texture nodes, allocating stack space to output
* a modified vector and returning its offset */
int TextureMapping::compile_begin(SVMCompiler& compiler, ShaderInput *vector_in)
{
if(!skip()) {
int offset_in = compiler.stack_assign(vector_in);
int offset_out = compiler.stack_find_offset(SocketType::VECTOR);
compile(compiler, offset_in, offset_out);
return offset_out;
}
return compiler.stack_assign(vector_in);
}
void TextureMapping::compile_end(SVMCompiler& compiler, ShaderInput *vector_in, int vector_offset)
{
if(!skip()) {
compiler.stack_clear_offset(vector_in->type(), vector_offset);
}
}
void TextureMapping::compile(OSLCompiler &compiler)
{
if(!skip()) {
Transform tfm = transform_transpose(compute_transform());
compiler.parameter("mapping", tfm);
compiler.parameter("use_mapping", 1);
}
}
/* Image Texture */
NODE_DEFINE(ImageTextureNode)
{
NodeType* type = NodeType::add("image_texture", create, NodeType::SHADER);
TEXTURE_MAPPING_DEFINE(ImageTextureNode);
SOCKET_STRING(filename, "Filename", ustring(""));
static NodeEnum color_space_enum;
color_space_enum.insert("none", NODE_COLOR_SPACE_NONE);
color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR);
SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR);
SOCKET_BOOLEAN(use_alpha, "Use Alpha", true);
static NodeEnum interpolation_enum;
interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
interpolation_enum.insert("smart", INTERPOLATION_SMART);
SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
static NodeEnum extension_enum;
extension_enum.insert("periodic", EXTENSION_REPEAT);
extension_enum.insert("clamp", EXTENSION_EXTEND);
extension_enum.insert("black", EXTENSION_CLIP);
SOCKET_ENUM(extension, "Extension", extension_enum, EXTENSION_REPEAT);
static NodeEnum projection_enum;
projection_enum.insert("flat", NODE_IMAGE_PROJ_FLAT);
projection_enum.insert("box", NODE_IMAGE_PROJ_BOX);
projection_enum.insert("sphere", NODE_IMAGE_PROJ_SPHERE);
projection_enum.insert("tube", NODE_IMAGE_PROJ_TUBE);
SOCKET_ENUM(projection, "Projection", projection_enum, NODE_IMAGE_PROJ_FLAT);
SOCKET_FLOAT(projection_blend, "Projection Blend", 0.0f);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_UV);
SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_FLOAT(alpha, "Alpha");
return type;
}
ImageTextureNode::ImageTextureNode()
: ImageSlotTextureNode(node_type)
{
image_manager = NULL;
slot = -1;
is_float = -1;
is_linear = false;
builtin_data = NULL;
animated = false;
}
ImageTextureNode::~ImageTextureNode()
{
if(image_manager) {
image_manager->remove_image(filename,
builtin_data,
interpolation,
extension);
}
}
ShaderNode *ImageTextureNode::clone() const
{
ImageTextureNode *node = new ImageTextureNode(*this);
node->image_manager = NULL;
node->slot = -1;
node->is_float = -1;
node->is_linear = false;
return node;
}
void ImageTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
#ifdef WITH_PTEX
/* todo: avoid loading other texture coordinates when using ptex,
* and hide texture coordinate socket in the UI */
if(shader->has_surface && string_endswith(filename, ".ptx")) {
/* ptex */
attributes->add(ATTR_STD_PTEX_FACE_ID);
attributes->add(ATTR_STD_PTEX_UV);
}
#endif
ShaderNode::attributes(shader, attributes);
}
void ImageTextureNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector_in = input("Vector");
ShaderOutput *color_out = output("Color");
ShaderOutput *alpha_out = output("Alpha");
image_manager = compiler.image_manager;
if(is_float == -1) {
bool is_float_bool;
slot = image_manager->add_image(filename,
builtin_data,
animated,
0,
is_float_bool,
is_linear,
interpolation,
extension,
use_alpha);
is_float = (int)is_float_bool;
}
if(slot != -1) {
int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1;
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
if(projection != NODE_IMAGE_PROJ_BOX) {
compiler.add_node(NODE_TEX_IMAGE,
slot,
compiler.encode_uchar4(
vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
srgb),
projection);
}
else {
compiler.add_node(NODE_TEX_IMAGE_BOX,
slot,
compiler.encode_uchar4(
vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
srgb),
__float_as_int(projection_blend));
}
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
else {
/* image not found */
if(!color_out->links.empty()) {
compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R,
TEX_IMAGE_MISSING_G,
TEX_IMAGE_MISSING_B));
}
if(!alpha_out->links.empty())
compiler.add_node(NODE_VALUE_F, __float_as_int(TEX_IMAGE_MISSING_A), compiler.stack_assign(alpha_out));
}
}
void ImageTextureNode::compile(OSLCompiler& compiler)
{
ShaderOutput *alpha_out = output("Alpha");
tex_mapping.compile(compiler);
image_manager = compiler.image_manager;
if(is_float == -1) {
if(builtin_data == NULL) {
ImageManager::ImageDataType type;
type = image_manager->get_image_metadata(filename, NULL, is_linear);
if(type == ImageManager::IMAGE_DATA_TYPE_FLOAT || type == ImageManager::IMAGE_DATA_TYPE_FLOAT4)
is_float = 1;
}
else {
bool is_float_bool;
slot = image_manager->add_image(filename,
builtin_data,
animated,
0,
is_float_bool,
is_linear,
interpolation,
extension,
use_alpha);
is_float = (int)is_float_bool;
}
}
if(slot == -1) {
compiler.parameter(this, "filename");
}
else {
/* TODO(sergey): It's not so simple to pass custom attribute
* to the texture() function in order to make builtin images
* support more clear. So we use special file name which is
* "@<slot_number>" and check whether file name matches this
* mask in the OSLRenderServices::texture().
*/
compiler.parameter("filename", string_printf("@%d", slot).c_str());
}
if(is_linear || color_space != NODE_COLOR_SPACE_COLOR)
compiler.parameter("color_space", "linear");
else
compiler.parameter("color_space", "sRGB");
compiler.parameter(this, "projection");
compiler.parameter(this, "projection_blend");
compiler.parameter(this, "is_float");
compiler.parameter("use_alpha", !alpha_out->links.empty());
compiler.parameter(this, "interpolation");
compiler.parameter(this, "extension");
compiler.add(this, "node_image_texture");
}
/* Environment Texture */
NODE_DEFINE(EnvironmentTextureNode)
{
NodeType* type = NodeType::add("environment_texture", create, NodeType::SHADER);
TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode);
SOCKET_STRING(filename, "Filename", ustring(""));
static NodeEnum color_space_enum;
color_space_enum.insert("none", NODE_COLOR_SPACE_NONE);
color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR);
SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR);
SOCKET_BOOLEAN(use_alpha, "Use Alpha", true);
static NodeEnum interpolation_enum;
interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
interpolation_enum.insert("smart", INTERPOLATION_SMART);
SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
static NodeEnum projection_enum;
projection_enum.insert("equirectangular", NODE_ENVIRONMENT_EQUIRECTANGULAR);
projection_enum.insert("mirror_ball", NODE_ENVIRONMENT_MIRROR_BALL);
SOCKET_ENUM(projection, "Projection", projection_enum, NODE_ENVIRONMENT_EQUIRECTANGULAR);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION);
SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_FLOAT(alpha, "Alpha");
return type;
}
EnvironmentTextureNode::EnvironmentTextureNode()
: ImageSlotTextureNode(node_type)
{
image_manager = NULL;
slot = -1;
is_float = -1;
is_linear = false;
builtin_data = NULL;
animated = false;
}
EnvironmentTextureNode::~EnvironmentTextureNode()
{
if(image_manager) {
image_manager->remove_image(filename,
builtin_data,
interpolation,
EXTENSION_REPEAT);
}
}
ShaderNode *EnvironmentTextureNode::clone() const
{
EnvironmentTextureNode *node = new EnvironmentTextureNode(*this);
node->image_manager = NULL;
node->slot = -1;
node->is_float = -1;
node->is_linear = false;
return node;
}
void EnvironmentTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
#ifdef WITH_PTEX
if(shader->has_surface && string_endswith(filename, ".ptx")) {
/* ptex */
attributes->add(ATTR_STD_PTEX_FACE_ID);
attributes->add(ATTR_STD_PTEX_UV);
}
#endif
ShaderNode::attributes(shader, attributes);
}
void EnvironmentTextureNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector_in = input("Vector");
ShaderOutput *color_out = output("Color");
ShaderOutput *alpha_out = output("Alpha");
image_manager = compiler.image_manager;
if(slot == -1) {
bool is_float_bool;
slot = image_manager->add_image(filename,
builtin_data,
animated,
0,
is_float_bool,
is_linear,
interpolation,
EXTENSION_REPEAT,
use_alpha);
is_float = (int)is_float_bool;
}
if(slot != -1) {
int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1;
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_ENVIRONMENT,
slot,
compiler.encode_uchar4(
vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
srgb),
projection);
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
else {
/* image not found */
if(!color_out->links.empty()) {
compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R,
TEX_IMAGE_MISSING_G,
TEX_IMAGE_MISSING_B));
}
if(!alpha_out->links.empty())
compiler.add_node(NODE_VALUE_F, __float_as_int(TEX_IMAGE_MISSING_A), compiler.stack_assign(alpha_out));
}
}
void EnvironmentTextureNode::compile(OSLCompiler& compiler)
{
ShaderOutput *alpha_out = output("Alpha");
tex_mapping.compile(compiler);
/* See comments in ImageTextureNode::compile about support
* of builtin images.
*/
image_manager = compiler.image_manager;
if(is_float == -1) {
if(builtin_data == NULL) {
ImageManager::ImageDataType type;
type = image_manager->get_image_metadata(filename, NULL, is_linear);
if(type == ImageManager::IMAGE_DATA_TYPE_FLOAT || type == ImageManager::IMAGE_DATA_TYPE_FLOAT4)
is_float = 1;
}
else {
bool is_float_bool;
slot = image_manager->add_image(filename,
builtin_data,
animated,
0,
is_float_bool,
is_linear,
interpolation,
EXTENSION_REPEAT,
use_alpha);
is_float = (int)is_float_bool;
}
}
if(slot == -1) {
compiler.parameter(this, "filename");
}
else {
compiler.parameter("filename", string_printf("@%d", slot).c_str());
}
compiler.parameter(this, "projection");
if(is_linear || color_space != NODE_COLOR_SPACE_COLOR)
compiler.parameter("color_space", "linear");
else
compiler.parameter("color_space", "sRGB");
compiler.parameter(this, "interpolation");
compiler.parameter(this, "is_float");
compiler.parameter("use_alpha", !alpha_out->links.empty());
compiler.add(this, "node_environment_texture");
}
/* Sky Texture */
static float2 sky_spherical_coordinates(float3 dir)
{
return make_float2(acosf(dir.z), atan2f(dir.x, dir.y));
}
typedef struct SunSky {
/* sun direction in spherical and cartesian */
float theta, phi;
/* Parameter */
float radiance_x, radiance_y, radiance_z;
float config_x[9], config_y[9], config_z[9];
} SunSky;
/* Preetham model */
static float sky_perez_function(float lam[6], float theta, float gamma)
{
return (1.0f + lam[0]*expf(lam[1]/cosf(theta))) * (1.0f + lam[2]*expf(lam[3]*gamma) + lam[4]*cosf(gamma)*cosf(gamma));
}
static void sky_texture_precompute_old(SunSky *sunsky, float3 dir, float turbidity)
{
/*
* We re-use the SunSky struct of the new model, to avoid extra variables
* zenith_Y/x/y is now radiance_x/y/z
* perez_Y/x/y is now config_x/y/z
*/
float2 spherical = sky_spherical_coordinates(dir);
float theta = spherical.x;
float phi = spherical.y;
sunsky->theta = theta;
sunsky->phi = phi;
float theta2 = theta*theta;
float theta3 = theta2*theta;
float T = turbidity;
float T2 = T * T;
float chi = (4.0f / 9.0f - T / 120.0f) * (M_PI_F - 2.0f * theta);
sunsky->radiance_x = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f;
sunsky->radiance_x *= 0.06f;
sunsky->radiance_y =
(0.00166f * theta3 - 0.00375f * theta2 + 0.00209f * theta) * T2 +
(-0.02903f * theta3 + 0.06377f * theta2 - 0.03202f * theta + 0.00394f) * T +
(0.11693f * theta3 - 0.21196f * theta2 + 0.06052f * theta + 0.25886f);
sunsky->radiance_z =
(0.00275f * theta3 - 0.00610f * theta2 + 0.00317f * theta) * T2 +
(-0.04214f * theta3 + 0.08970f * theta2 - 0.04153f * theta + 0.00516f) * T +
(0.15346f * theta3 - 0.26756f * theta2 + 0.06670f * theta + 0.26688f);
sunsky->config_x[0] = (0.1787f * T - 1.4630f);
sunsky->config_x[1] = (-0.3554f * T + 0.4275f);
sunsky->config_x[2] = (-0.0227f * T + 5.3251f);
sunsky->config_x[3] = (0.1206f * T - 2.5771f);
sunsky->config_x[4] = (-0.0670f * T + 0.3703f);
sunsky->config_y[0] = (-0.0193f * T - 0.2592f);
sunsky->config_y[1] = (-0.0665f * T + 0.0008f);
sunsky->config_y[2] = (-0.0004f * T + 0.2125f);
sunsky->config_y[3] = (-0.0641f * T - 0.8989f);
sunsky->config_y[4] = (-0.0033f * T + 0.0452f);
sunsky->config_z[0] = (-0.0167f * T - 0.2608f);
sunsky->config_z[1] = (-0.0950f * T + 0.0092f);
sunsky->config_z[2] = (-0.0079f * T + 0.2102f);
sunsky->config_z[3] = (-0.0441f * T - 1.6537f);
sunsky->config_z[4] = (-0.0109f * T + 0.0529f);
/* unused for old sky model */
for(int i = 5; i < 9; i++) {
sunsky->config_x[i] = 0.0f;
sunsky->config_y[i] = 0.0f;
sunsky->config_z[i] = 0.0f;
}
sunsky->radiance_x /= sky_perez_function(sunsky->config_x, 0, theta);
sunsky->radiance_y /= sky_perez_function(sunsky->config_y, 0, theta);
sunsky->radiance_z /= sky_perez_function(sunsky->config_z, 0, theta);
}
/* Hosek / Wilkie */
static void sky_texture_precompute_new(SunSky *sunsky, float3 dir, float turbidity, float ground_albedo)
{
/* Calculate Sun Direction and save coordinates */
float2 spherical = sky_spherical_coordinates(dir);
float theta = spherical.x;
float phi = spherical.y;
/* Clamp Turbidity */
turbidity = clamp(turbidity, 0.0f, 10.0f);
/* Clamp to Horizon */
theta = clamp(theta, 0.0f, M_PI_2_F);
sunsky->theta = theta;
sunsky->phi = phi;
float solarElevation = M_PI_2_F - theta;
/* Initialize Sky Model */
ArHosekSkyModelState *sky_state;
sky_state = arhosek_xyz_skymodelstate_alloc_init((double)turbidity, (double)ground_albedo, (double)solarElevation);
/* Copy values from sky_state to SunSky */
for(int i = 0; i < 9; ++i) {
sunsky->config_x[i] = (float)sky_state->configs[0][i];
sunsky->config_y[i] = (float)sky_state->configs[1][i];
sunsky->config_z[i] = (float)sky_state->configs[2][i];
}
sunsky->radiance_x = (float)sky_state->radiances[0];
sunsky->radiance_y = (float)sky_state->radiances[1];
sunsky->radiance_z = (float)sky_state->radiances[2];
/* Free sky_state */
arhosekskymodelstate_free(sky_state);
}
NODE_DEFINE(SkyTextureNode)
{
NodeType* type = NodeType::add("sky_texture", create, NodeType::SHADER);
TEXTURE_MAPPING_DEFINE(SkyTextureNode);
static NodeEnum type_enum;
type_enum.insert("preetham", NODE_SKY_OLD);
type_enum.insert("hosek_wilkie", NODE_SKY_NEW);
SOCKET_ENUM(type, "Type", type_enum, NODE_SKY_NEW);
SOCKET_VECTOR(sun_direction, "Sun Direction", make_float3(0.0f, 0.0f, 1.0f));
SOCKET_FLOAT(turbidity, "Turbidity", 2.2f);
SOCKET_FLOAT(ground_albedo, "Ground Albedo", 0.3f);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
SOCKET_OUT_COLOR(color, "Color");
return type;
}
SkyTextureNode::SkyTextureNode()
: TextureNode(node_type)
{
}
void SkyTextureNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector_in = input("Vector");
ShaderOutput *color_out = output("Color");
SunSky sunsky;
if(type == NODE_SKY_OLD)
sky_texture_precompute_old(&sunsky, sun_direction, turbidity);
else if(type == NODE_SKY_NEW)
sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo);
else
assert(false);
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
int sky_model = type;
compiler.stack_assign(color_out);
compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), sky_model);
compiler.add_node(__float_as_uint(sunsky.phi), __float_as_uint(sunsky.theta), __float_as_uint(sunsky.radiance_x), __float_as_uint(sunsky.radiance_y));
compiler.add_node(__float_as_uint(sunsky.radiance_z), __float_as_uint(sunsky.config_x[0]), __float_as_uint(sunsky.config_x[1]), __float_as_uint(sunsky.config_x[2]));
compiler.add_node(__float_as_uint(sunsky.config_x[3]), __float_as_uint(sunsky.config_x[4]), __float_as_uint(sunsky.config_x[5]), __float_as_uint(sunsky.config_x[6]));
compiler.add_node(__float_as_uint(sunsky.config_x[7]), __float_as_uint(sunsky.config_x[8]), __float_as_uint(sunsky.config_y[0]), __float_as_uint(sunsky.config_y[1]));
compiler.add_node(__float_as_uint(sunsky.config_y[2]), __float_as_uint(sunsky.config_y[3]), __float_as_uint(sunsky.config_y[4]), __float_as_uint(sunsky.config_y[5]));
compiler.add_node(__float_as_uint(sunsky.config_y[6]), __float_as_uint(sunsky.config_y[7]), __float_as_uint(sunsky.config_y[8]), __float_as_uint(sunsky.config_z[0]));
compiler.add_node(__float_as_uint(sunsky.config_z[1]), __float_as_uint(sunsky.config_z[2]), __float_as_uint(sunsky.config_z[3]), __float_as_uint(sunsky.config_z[4]));
compiler.add_node(__float_as_uint(sunsky.config_z[5]), __float_as_uint(sunsky.config_z[6]), __float_as_uint(sunsky.config_z[7]), __float_as_uint(sunsky.config_z[8]));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
void SkyTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
SunSky sunsky;
if(type == NODE_SKY_OLD)
sky_texture_precompute_old(&sunsky, sun_direction, turbidity);
else if(type == NODE_SKY_NEW)
sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo);
else
assert(false);
compiler.parameter(this, "type");
compiler.parameter("theta", sunsky.theta);
compiler.parameter("phi", sunsky.phi);
compiler.parameter_color("radiance", make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z));
compiler.parameter_array("config_x", sunsky.config_x, 9);
compiler.parameter_array("config_y", sunsky.config_y, 9);
compiler.parameter_array("config_z", sunsky.config_z, 9);
compiler.add(this, "node_sky_texture");
}
/* Gradient Texture */
NODE_DEFINE(GradientTextureNode)
{
NodeType* type = NodeType::add("gradient_texture", create, NodeType::SHADER);
TEXTURE_MAPPING_DEFINE(GradientTextureNode);
static NodeEnum type_enum;
type_enum.insert("linear", NODE_BLEND_LINEAR);
type_enum.insert("quadratic", NODE_BLEND_QUADRATIC);
type_enum.insert("easing", NODE_BLEND_EASING);
type_enum.insert("diagonal", NODE_BLEND_DIAGONAL);
type_enum.insert("radial", NODE_BLEND_RADIAL);
type_enum.insert("quadratic_sphere", NODE_BLEND_QUADRATIC_SPHERE);
type_enum.insert("spherical", NODE_BLEND_SPHERICAL);
SOCKET_ENUM(type, "Type", type_enum, NODE_BLEND_LINEAR);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_FLOAT(fac, "Fac");
return type;
}
GradientTextureNode::GradientTextureNode()
: TextureNode(node_type)
{
}
void GradientTextureNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector_in = input("Vector");
ShaderOutput *color_out = output("Color");
ShaderOutput *fac_out = output("Fac");
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_GRADIENT,
compiler.encode_uchar4(
type,
vector_offset,
compiler.stack_assign_if_linked(fac_out),
compiler.stack_assign_if_linked(color_out)));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
void GradientTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
compiler.parameter(this, "type");
compiler.add(this, "node_gradient_texture");
}
/* Noise Texture */
NODE_DEFINE(NoiseTextureNode)
{
NodeType* type = NodeType::add("noise_texture", create, NodeType::SHADER);
TEXTURE_MAPPING_DEFINE(NoiseTextureNode);
SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_FLOAT(fac, "Fac");
return type;
}
NoiseTextureNode::NoiseTextureNode()
: TextureNode(node_type)
{
}
void NoiseTextureNode::compile(SVMCompiler& compiler)
{
ShaderInput *distortion_in = input("Distortion");
ShaderInput *detail_in = input("Detail");
ShaderInput *scale_in = input("Scale");
ShaderInput *vector_in = input("Vector");
ShaderOutput *color_out = output("Color");
ShaderOutput *fac_out = output("Fac");
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_NOISE,
compiler.encode_uchar4(
vector_offset,
compiler.stack_assign_if_linked(scale_in),
compiler.stack_assign_if_linked(detail_in),
compiler.stack_assign_if_linked(distortion_in)),
compiler.encode_uchar4(
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out)));
compiler.add_node(
__float_as_int(scale),
__float_as_int(detail),
__float_as_int(distortion));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
void NoiseTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
compiler.add(this, "node_noise_texture");
}
/* Voronoi Texture */
NODE_DEFINE(VoronoiTextureNode)
{
NodeType* type = NodeType::add("voronoi_texture", create, NodeType::SHADER);
TEXTURE_MAPPING_DEFINE(VoronoiTextureNode);
static NodeEnum coloring_enum;
coloring_enum.insert("intensity", NODE_VORONOI_INTENSITY);
coloring_enum.insert("cells", NODE_VORONOI_CELLS);
SOCKET_ENUM(coloring, "Coloring", coloring_enum, NODE_VORONOI_INTENSITY);
SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_FLOAT(fac, "Fac");
return type;
}
VoronoiTextureNode::VoronoiTextureNode()
: TextureNode(node_type)
{
}
void VoronoiTextureNode::compile(SVMCompiler& compiler)
{
ShaderInput *scale_in = input("Scale");
ShaderInput *vector_in = input("Vector");
ShaderOutput *color_out = output("Color");
ShaderOutput *fac_out = output("Fac");
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_VORONOI,
coloring,
compiler.encode_uchar4(
compiler.stack_assign_if_linked(scale_in),
vector_offset,
compiler.stack_assign(fac_out),
compiler.stack_assign(color_out)),
__float_as_int(scale));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
void VoronoiTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
compiler.parameter(this, "coloring");
compiler.add(this, "node_voronoi_texture");
}
/* Musgrave Texture */
NODE_DEFINE(MusgraveTextureNode)
{
NodeType* type = NodeType::add("musgrave_texture", create, NodeType::SHADER);
TEXTURE_MAPPING_DEFINE(MusgraveTextureNode);
static NodeEnum type_enum;
type_enum.insert("multifractal", NODE_MUSGRAVE_MULTIFRACTAL);
type_enum.insert("fBM", NODE_MUSGRAVE_FBM);
type_enum.insert("hybrid_multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL);
type_enum.insert("ridged_multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL);
type_enum.insert("hetero_terrain", NODE_MUSGRAVE_HETERO_TERRAIN);
SOCKET_ENUM(type, "Type", type_enum, NODE_MUSGRAVE_FBM);
SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
SOCKET_IN_FLOAT(dimension, "Dimension", 2.0f);
SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 1.0f);
SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
SOCKET_IN_FLOAT(gain, "Gain", 1.0f);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_FLOAT(fac, "Fac");
return type;
}
MusgraveTextureNode::MusgraveTextureNode()
: TextureNode(node_type)
{
}
void MusgraveTextureNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector_in = input("Vector");
ShaderInput *scale_in = input("Scale");
ShaderInput *dimension_in = input("Dimension");
ShaderInput *lacunarity_in = input("Lacunarity");
ShaderInput *detail_in = input("Detail");
ShaderInput *offset_in = input("Offset");
ShaderInput *gain_in = input("Gain");
ShaderOutput *fac_out = output("Fac");
ShaderOutput *color_out = output("Color");
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_MUSGRAVE,
compiler.encode_uchar4(
type,
vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out)),
compiler.encode_uchar4(
compiler.stack_assign_if_linked(dimension_in),
compiler.stack_assign_if_linked(lacunarity_in),
compiler.stack_assign_if_linked(detail_in),
compiler.stack_assign_if_linked(offset_in)),
compiler.encode_uchar4(
compiler.stack_assign_if_linked(gain_in),
compiler.stack_assign_if_linked(scale_in)));
compiler.add_node(__float_as_int(dimension),
__float_as_int(lacunarity),
__float_as_int(detail),
__float_as_int(offset));
compiler.add_node(__float_as_int(gain),
__float_as_int(scale));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
void MusgraveTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
compiler.parameter(this, "type");
compiler.add(this, "node_musgrave_texture");
}
/* Wave Texture */
NODE_DEFINE(WaveTextureNode)
{
NodeType* type = NodeType::add("wave_texture", create, NodeType::SHADER);
TEXTURE_MAPPING_DEFINE(WaveTextureNode);
static NodeEnum type_enum;
type_enum.insert("bands", NODE_WAVE_BANDS);
type_enum.insert("rings", NODE_WAVE_RINGS);
SOCKET_ENUM(type, "Type", type_enum, NODE_WAVE_BANDS);
static NodeEnum profile_enum;
profile_enum.insert("sine", NODE_WAVE_PROFILE_SIN);
profile_enum.insert("saw", NODE_WAVE_PROFILE_SAW);
SOCKET_ENUM(profile, "Profile", profile_enum, NODE_WAVE_PROFILE_SIN);
SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f);
SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
SOCKET_IN_FLOAT(detail_scale, "Detail Scale", 0.0f);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_FLOAT(fac, "Fac");
return type;
}
WaveTextureNode::WaveTextureNode()
: TextureNode(node_type)
{
}
void WaveTextureNode::compile(SVMCompiler& compiler)
{
ShaderInput *scale_in = input("Scale");
ShaderInput *distortion_in = input("Distortion");
ShaderInput *dscale_in = input("Detail Scale");
ShaderInput *detail_in = input("Detail");
ShaderInput *vector_in = input("Vector");
ShaderOutput *fac_out = output("Fac");
ShaderOutput *color_out = output("Color");
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_WAVE,
compiler.encode_uchar4(
type,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out),
compiler.stack_assign_if_linked(dscale_in)),
compiler.encode_uchar4(
vector_offset,
compiler.stack_assign_if_linked(scale_in),
compiler.stack_assign_if_linked(detail_in),
compiler.stack_assign_if_linked(distortion_in)),
profile);
compiler.add_node(
__float_as_int(scale),
__float_as_int(detail),
__float_as_int(distortion),
__float_as_int(detail_scale));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
void WaveTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
compiler.parameter(this, "type");
compiler.parameter(this, "profile");
compiler.add(this, "node_wave_texture");
}
/* Magic Texture */
NODE_DEFINE(MagicTextureNode)
{
NodeType* type = NodeType::add("magic_texture", create, NodeType::SHADER);
TEXTURE_MAPPING_DEFINE(MagicTextureNode);
SOCKET_INT(depth, "Depth", 2);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
SOCKET_IN_FLOAT(distortion, "Distortion", 1.0f);
SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_FLOAT(fac, "Fac");
return type;
}
MagicTextureNode::MagicTextureNode()
: TextureNode(node_type)
{
}
void MagicTextureNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector_in = input("Vector");
ShaderInput *scale_in = input("Scale");
ShaderInput *distortion_in = input("Distortion");
ShaderOutput *color_out = output("Color");
ShaderOutput *fac_out = output("Fac");
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_MAGIC,
compiler.encode_uchar4(
depth,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out)),
compiler.encode_uchar4(
vector_offset,
compiler.stack_assign_if_linked(scale_in),
compiler.stack_assign_if_linked(distortion_in)));
compiler.add_node(
__float_as_int(scale),
__float_as_int(distortion));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
void MagicTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
compiler.parameter(this, "depth");
compiler.add(this, "node_magic_texture");
}
/* Checker Texture */
NODE_DEFINE(CheckerTextureNode)
{
NodeType* type = NodeType::add("checker_texture", create, NodeType::SHADER);
TEXTURE_MAPPING_DEFINE(CheckerTextureNode);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_FLOAT(fac, "Fac");
return type;
}
CheckerTextureNode::CheckerTextureNode()
: TextureNode(node_type)
{
}
void CheckerTextureNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector_in = input("Vector");
ShaderInput *color1_in = input("Color1");
ShaderInput *color2_in = input("Color2");
ShaderInput *scale_in = input("Scale");
ShaderOutput *color_out = output("Color");
ShaderOutput *fac_out = output("Fac");
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_CHECKER,
compiler.encode_uchar4(
vector_offset,
compiler.stack_assign(color1_in),
compiler.stack_assign(color2_in),
compiler.stack_assign_if_linked(scale_in)),
compiler.encode_uchar4(
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out)),
__float_as_int(scale));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
void CheckerTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
compiler.add(this, "node_checker_texture");
}
/* Brick Texture */
NODE_DEFINE(BrickTextureNode)
{
NodeType* type = NodeType::add("brick_texture", create, NodeType::SHADER);
TEXTURE_MAPPING_DEFINE(BrickTextureNode);
SOCKET_FLOAT(offset, "Offset", 0.5f);
SOCKET_INT(offset_frequency, "Offset Frequency", 2);
SOCKET_FLOAT(squash, "Squash", 1.0f);
SOCKET_INT(squash_frequency, "Squash Frequency", 2);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_COLOR(mortar, "Mortar", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
SOCKET_IN_FLOAT(mortar_size, "Mortar Size", 0.02f);
SOCKET_IN_FLOAT(bias, "Bias", 0.0f);
SOCKET_IN_FLOAT(brick_width, "Brick Width", 0.5f);
SOCKET_IN_FLOAT(row_height, "Row Height", 0.25f);
SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_FLOAT(fac, "Fac");
return type;
}
BrickTextureNode::BrickTextureNode()
: TextureNode(node_type)
{
}
void BrickTextureNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector_in = input("Vector");
ShaderInput *color1_in = input("Color1");
ShaderInput *color2_in = input("Color2");
ShaderInput *mortar_in = input("Mortar");
ShaderInput *scale_in = input("Scale");
ShaderInput *mortar_size_in = input("Mortar Size");
ShaderInput *bias_in = input("Bias");
ShaderInput *brick_width_in = input("Brick Width");
ShaderInput *row_height_in = input("Row Height");
ShaderOutput *color_out = output("Color");
ShaderOutput *fac_out = output("Fac");
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_BRICK,
compiler.encode_uchar4(
vector_offset,
compiler.stack_assign(color1_in),
compiler.stack_assign(color2_in),
compiler.stack_assign(mortar_in)),
compiler.encode_uchar4(
compiler.stack_assign_if_linked(scale_in),
compiler.stack_assign_if_linked(mortar_size_in),
compiler.stack_assign_if_linked(bias_in),
compiler.stack_assign_if_linked(brick_width_in)),
compiler.encode_uchar4(
compiler.stack_assign_if_linked(row_height_in),
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out)));
compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency),
__float_as_int(scale),
__float_as_int(mortar_size),
__float_as_int(bias));
compiler.add_node(__float_as_int(brick_width),
__float_as_int(row_height),
__float_as_int(offset),
__float_as_int(squash));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
void BrickTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
compiler.parameter(this, "offset");
compiler.parameter(this, "offset_frequency");
compiler.parameter(this, "squash");
compiler.parameter(this, "squash_frequency");
compiler.add(this, "node_brick_texture");
}
/* Point Density Texture */
NODE_DEFINE(PointDensityTextureNode)
{
NodeType* type = NodeType::add("point_density_texture", create, NodeType::SHADER);
SOCKET_STRING(filename, "Filename", ustring(""));
static NodeEnum space_enum;
space_enum.insert("object", NODE_TEX_VOXEL_SPACE_OBJECT);
space_enum.insert("world", NODE_TEX_VOXEL_SPACE_WORLD);
SOCKET_ENUM(space, "Space", space_enum, NODE_TEX_VOXEL_SPACE_OBJECT);
static NodeEnum interpolation_enum;
interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
interpolation_enum.insert("smart", INTERPOLATION_SMART);
SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION);
SOCKET_OUT_FLOAT(density, "Density");
SOCKET_OUT_COLOR(color, "Color");
return type;
}
PointDensityTextureNode::PointDensityTextureNode()
: ShaderNode(node_type)
{
image_manager = NULL;
slot = -1;
builtin_data = NULL;
}
PointDensityTextureNode::~PointDensityTextureNode()
{
if(image_manager) {
image_manager->remove_image(filename.string(),
builtin_data,
interpolation,
EXTENSION_CLIP);
}
}
ShaderNode *PointDensityTextureNode::clone() const
{
PointDensityTextureNode *node = new PointDensityTextureNode(*this);
node->image_manager = NULL;
node->slot = -1;
return node;
}
void PointDensityTextureNode::attributes(Shader *shader,
AttributeRequestSet *attributes)
{
if(shader->has_volume)
attributes->add(ATTR_STD_GENERATED_TRANSFORM);
ShaderNode::attributes(shader, attributes);
}
void PointDensityTextureNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector_in = input("Vector");
ShaderOutput *density_out = output("Density");
ShaderOutput *color_out = output("Color");
const bool use_density = !density_out->links.empty();
const bool use_color = !color_out->links.empty();
image_manager = compiler.image_manager;
if(use_density || use_color) {
if(slot == -1) {
bool is_float, is_linear;
slot = image_manager->add_image(filename.string(), builtin_data,
false, 0,
is_float, is_linear,
interpolation,
EXTENSION_CLIP,
true);
}
if(slot != -1) {
compiler.stack_assign(vector_in);
compiler.add_node(NODE_TEX_VOXEL,
slot,
compiler.encode_uchar4(compiler.stack_assign(vector_in),
compiler.stack_assign_if_linked(density_out),
compiler.stack_assign_if_linked(color_out),
space));
if(space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.add_node(tfm.x);
compiler.add_node(tfm.y);
compiler.add_node(tfm.z);
compiler.add_node(tfm.w);
}
}
else {
if(use_density) {
compiler.add_node(NODE_VALUE_F,
__float_as_int(0.0f),
compiler.stack_assign(density_out));
}
if(use_color) {
compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R,
TEX_IMAGE_MISSING_G,
TEX_IMAGE_MISSING_B));
}
}
}
}
void PointDensityTextureNode::compile(OSLCompiler& compiler)
{
ShaderOutput *density_out = output("Density");
ShaderOutput *color_out = output("Color");
const bool use_density = !density_out->links.empty();
const bool use_color = !color_out->links.empty();
image_manager = compiler.image_manager;
if(use_density || use_color) {
if(slot == -1) {
bool is_float, is_linear;
slot = image_manager->add_image(filename.string(), builtin_data,
false, 0,
is_float, is_linear,
interpolation,
EXTENSION_CLIP,
true);
}
if(slot != -1) {
compiler.parameter("filename", string_printf("@%d", slot).c_str());
}
if(space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.parameter("mapping", transform_transpose(tfm));
compiler.parameter("use_mapping", 1);
}
compiler.parameter(this, "interpolation");
compiler.add(this, "node_voxel_texture");
}
}
/* Normal */
NODE_DEFINE(NormalNode)
{
NodeType* type = NodeType::add("normal", create, NodeType::SHADER);
SOCKET_VECTOR(direction, "direction", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_NORMAL(normal, "Normal");
SOCKET_OUT_FLOAT(dot, "Dot");
return type;
}
NormalNode::NormalNode()
: ShaderNode(node_type)
{
}
void NormalNode::compile(SVMCompiler& compiler)
{
ShaderInput *normal_in = input("Normal");
ShaderOutput *normal_out = output("Normal");
ShaderOutput *dot_out = output("Dot");
compiler.add_node(NODE_NORMAL,
compiler.stack_assign(normal_in),
compiler.stack_assign(normal_out),
compiler.stack_assign(dot_out));
compiler.add_node(
__float_as_int(direction.x),
__float_as_int(direction.y),
__float_as_int(direction.z));
}
void NormalNode::compile(OSLCompiler& compiler)
{
compiler.parameter(this, "direction");
compiler.add(this, "node_normal");
}
/* Mapping */
NODE_DEFINE(MappingNode)
{
NodeType* type = NodeType::add("mapping", create, NodeType::SHADER);
TEXTURE_MAPPING_DEFINE(MappingNode);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_POINT(vector, "Vector");
return type;
}
MappingNode::MappingNode()
: ShaderNode(node_type)
{
}
void MappingNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector_in = input("Vector");
ShaderOutput *vector_out = output("Vector");
tex_mapping.compile(compiler, compiler.stack_assign(vector_in), compiler.stack_assign(vector_out));
}
void MappingNode::compile(OSLCompiler& compiler)
{
Transform tfm = transform_transpose(tex_mapping.compute_transform());
compiler.parameter("Matrix", tfm);
compiler.parameter_point("mapping_min", tex_mapping.min);
compiler.parameter_point("mapping_max", tex_mapping.max);
compiler.parameter("use_minmax", tex_mapping.use_minmax);
compiler.add(this, "node_mapping");
}
/* RGBToBW */
NODE_DEFINE(RGBToBWNode)
{
NodeType* type = NodeType::add("rgb_to_bw", create, NodeType::SHADER);
SOCKET_IN_POINT(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_POINT(val, "Val");
return type;
}
RGBToBWNode::RGBToBWNode()
: ShaderNode(node_type)
{
}
bool RGBToBWNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
{
if(inputs[0]->link == NULL) {
optimized->set(linear_rgb_to_gray(color));
return true;
}
return false;
}
void RGBToBWNode::compile(SVMCompiler& compiler)
{
compiler.add_node(NODE_CONVERT,
NODE_CONVERT_CF,
compiler.stack_assign(inputs[0]),
compiler.stack_assign(outputs[0]));
}
void RGBToBWNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_convert_from_color");
}
/* Convert */
const NodeType* ConvertNode::node_types[ConvertNode::MAX_TYPE][ConvertNode::MAX_TYPE];
bool ConvertNode::initialized = ConvertNode::register_types();
Node* ConvertNode::create(const NodeType *type)
{
return new ConvertNode(type->inputs[0].type, type->outputs[0].type);
}
bool ConvertNode::register_types()
{
const int num_types = 8;
SocketType::Type types[num_types] = {SocketType::FLOAT,
SocketType::INT,
SocketType::COLOR,
SocketType::VECTOR,
SocketType::POINT,
SocketType::NORMAL,
SocketType::STRING,
SocketType::CLOSURE};
for(size_t i = 0; i < num_types; i++) {
SocketType::Type from = types[i];
ustring from_name(SocketType::type_name(from));
ustring from_value_name("value_" + from_name.string());
for(size_t j = 0; j < num_types; j++) {
SocketType::Type to = types[j];
ustring to_name(SocketType::type_name(to));
ustring to_value_name("value_" + to_name.string());
string node_name = "convert_" + from_name.string() + "_to_" + to_name.string();
NodeType* type = NodeType::add(node_name.c_str(), create, NodeType::SHADER);
type->register_input(from_value_name, from_value_name, from,
SOCKET_OFFSETOF(ConvertNode, value_float), SocketType::zero_default_value(),
NULL, NULL, SocketType::LINKABLE);
type->register_output(to_value_name, to_value_name, to);
assert(from < MAX_TYPE);
assert(to < MAX_TYPE);
node_types[from][to] = type;
}
}
return true;
}
ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool autoconvert)
: ShaderNode(node_types[from_][to_])
{
from = from_;
to = to_;
if(from == to)
special_type = SHADER_SPECIAL_TYPE_PROXY;
else if(autoconvert)
special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
}
bool ConvertNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
{
/* proxy nodes should have been removed at this point */
assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
ShaderInput *in = inputs[0];
/* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */
if(in->link == NULL) {
if(from == SocketType::FLOAT) {
if(SocketType::is_float3(to)) {
optimized->set(make_float3(value_float, value_float, value_float));
return true;
}
}
else if(SocketType::is_float3(from)) {
if(to == SocketType::FLOAT) {
if(from == SocketType::COLOR)
/* color to float */
optimized->set(linear_rgb_to_gray(value_color));
else
/* vector/point/normal to float */
optimized->set(average(value_vector));
return true;
}
else if(SocketType::is_float3(to)) {
optimized->set(value_color);
return true;
}
}
}
return false;
}
void ConvertNode::compile(SVMCompiler& compiler)
{
/* proxy nodes should have been removed at this point */
assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
ShaderInput *in = inputs[0];
ShaderOutput *out = outputs[0];
if(from == SocketType::FLOAT) {
if(to == SocketType::INT)
/* float to int */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_FI, compiler.stack_assign(in), compiler.stack_assign(out));
else
/* float to float3 */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_FV, compiler.stack_assign(in), compiler.stack_assign(out));
}
else if(from == SocketType::INT) {
if(to == SocketType::FLOAT)
/* int to float */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_IF, compiler.stack_assign(in), compiler.stack_assign(out));
else
/* int to vector/point/normal */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_IV, compiler.stack_assign(in), compiler.stack_assign(out));
}
else if(to == SocketType::FLOAT) {
if(from == SocketType::COLOR)
/* color to float */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_CF, compiler.stack_assign(in), compiler.stack_assign(out));
else
/* vector/point/normal to float */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_VF, compiler.stack_assign(in), compiler.stack_assign(out));
}
else if(to == SocketType::INT) {
if(from == SocketType::COLOR)
/* color to int */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_CI, compiler.stack_assign(in), compiler.stack_assign(out));
else
/* vector/point/normal to int */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_VI, compiler.stack_assign(in), compiler.stack_assign(out));
}
else {
/* float3 to float3 */
if(in->link) {
/* no op in SVM */
compiler.stack_link(in, out);
}
else {
/* set 0,0,0 value */
compiler.add_node(NODE_VALUE_V, compiler.stack_assign(out));
compiler.add_node(NODE_VALUE_V, value_color);
}
}
}
void ConvertNode::compile(OSLCompiler& compiler)
{
/* proxy nodes should have been removed at this point */
assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
if(from == SocketType::FLOAT)
compiler.add(this, "node_convert_from_float");
else if(from == SocketType::INT)
compiler.add(this, "node_convert_from_int");
else if(from == SocketType::COLOR)
compiler.add(this, "node_convert_from_color");
else if(from == SocketType::VECTOR)
compiler.add(this, "node_convert_from_vector");
else if(from == SocketType::POINT)
compiler.add(this, "node_convert_from_point");
else if(from == SocketType::NORMAL)
compiler.add(this, "node_convert_from_normal");
else
assert(0);
}
/* BSDF Closure */
BsdfNode::BsdfNode(const NodeType *node_type)
: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_CLOSURE;
}
void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3, ShaderInput *param4)
{
ShaderInput *color_in = input("Color");
ShaderInput *normal_in = input("Normal");
ShaderInput *tangent_in = input("Tangent");
if(color_in->link)
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
else
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
int normal_offset = (normal_in) ? compiler.stack_assign_if_linked(normal_in) : SVM_STACK_INVALID;
int tangent_offset = (tangent_in) ? compiler.stack_assign_if_linked(tangent_in) : SVM_STACK_INVALID;
int param3_offset = (param3) ? compiler.stack_assign(param3) : SVM_STACK_INVALID;
int param4_offset = (param4) ? compiler.stack_assign(param4) : SVM_STACK_INVALID;
compiler.add_node(NODE_CLOSURE_BSDF,
compiler.encode_uchar4(closure,
(param1)? compiler.stack_assign(param1): SVM_STACK_INVALID,
(param2)? compiler.stack_assign(param2): SVM_STACK_INVALID,
compiler.closure_mix_weight_offset()),
__float_as_int((param1)? get_float(param1->socket_type): 0.0f),
__float_as_int((param2)? get_float(param2->socket_type): 0.0f));
compiler.add_node(normal_offset, tangent_offset, param3_offset, param4_offset);
}
void BsdfNode::compile(SVMCompiler& compiler)
{
compile(compiler, NULL, NULL);
}
void BsdfNode::compile(OSLCompiler& /*compiler*/)
{
assert(0);
}
/* Anisotropic BSDF Closure */
NODE_DEFINE(AnisotropicBsdfNode)
{
NodeType* type = NodeType::add("anisotropic_bsdf", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
static NodeEnum distribution_enum;
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID);
distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID);
distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID);
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID);
SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT);
SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f);
SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.5f);
SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
return type;
}
AnisotropicBsdfNode::AnisotropicBsdfNode()
: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
}
void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface) {
ShaderInput *tangent_in = input("Tangent");
if(!tangent_in->link)
attributes->add(ATTR_STD_GENERATED);
}
ShaderNode::attributes(shader, attributes);
}
void AnisotropicBsdfNode::compile(SVMCompiler& compiler)
{
closure = distribution;
BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
}
void AnisotropicBsdfNode::compile(OSLCompiler& compiler)
{
compiler.parameter(this, "distribution");
compiler.add(this, "node_anisotropic_bsdf");
}
/* Glossy BSDF Closure */
NODE_DEFINE(GlossyBsdfNode)
{
NodeType* type = NodeType::add("glossy_bsdf", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
static NodeEnum distribution_enum;
distribution_enum.insert("sharp", CLOSURE_BSDF_REFLECTION_ID);
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID);
distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
return type;
}
GlossyBsdfNode::GlossyBsdfNode()
: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
distribution_orig = NBUILTIN_CLOSURES;
}
void GlossyBsdfNode::simplify_settings(Scene *scene)
{
if(distribution_orig == NBUILTIN_CLOSURES) {
distribution_orig = distribution;
}
Integrator *integrator = scene->integrator;
if(integrator->filter_glossy == 0.0f) {
/* Fallback to Sharp closure for Roughness close to 0.
* Note: Keep the epsilon in sync with kernel!
*/
ShaderInput *roughness_input = input("Roughness");
if(!roughness_input->link && roughness <= 1e-4f) {
distribution = CLOSURE_BSDF_REFLECTION_ID;
}
}
else {
/* Rollback to original distribution when filter glossy is used. */
distribution = distribution_orig;
}
closure = distribution;
}
bool GlossyBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
return !roughness_input->link && roughness <= 1e-4f;
}
void GlossyBsdfNode::compile(SVMCompiler& compiler)
{
closure = distribution;
if(closure == CLOSURE_BSDF_REFLECTION_ID)
BsdfNode::compile(compiler, NULL, NULL);
else
BsdfNode::compile(compiler, input("Roughness"), NULL);
}
void GlossyBsdfNode::compile(OSLCompiler& compiler)
{
compiler.parameter(this, "distribution");
compiler.add(this, "node_glossy_bsdf");
}
/* Glass BSDF Closure */
NODE_DEFINE(GlassBsdfNode)
{
NodeType* type = NodeType::add("glass_bsdf", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
static NodeEnum distribution_enum;
distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID);
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
SOCKET_IN_FLOAT(IOR, "IOR", 0.3f);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
return type;
}
GlassBsdfNode::GlassBsdfNode()
: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_SHARP_GLASS_ID;
distribution_orig = NBUILTIN_CLOSURES;
}
void GlassBsdfNode::simplify_settings(Scene *scene)
{
if(distribution_orig == NBUILTIN_CLOSURES) {
distribution_orig = distribution;
}
Integrator *integrator = scene->integrator;
if(integrator->filter_glossy == 0.0f) {
/* Fallback to Sharp closure for Roughness close to 0.
* Note: Keep the epsilon in sync with kernel!
*/
ShaderInput *roughness_input = input("Roughness");
if(!roughness_input->link && roughness <= 1e-4f) {
distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
}
}
else {
/* Rollback to original distribution when filter glossy is used. */
distribution = distribution_orig;
}
closure = distribution;
}
bool GlassBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
return !roughness_input->link && roughness <= 1e-4f;
}
void GlassBsdfNode::compile(SVMCompiler& compiler)
{
closure = distribution;
if(closure == CLOSURE_BSDF_SHARP_GLASS_ID)
BsdfNode::compile(compiler, NULL, input("IOR"));
else
BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
}
void GlassBsdfNode::compile(OSLCompiler& compiler)
{
compiler.parameter(this, "distribution");
compiler.add(this, "node_glass_bsdf");
}
/* Refraction BSDF Closure */
NODE_DEFINE(RefractionBsdfNode)
{
NodeType* type = NodeType::add("refraction_bsdf", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
static NodeEnum distribution_enum;
distribution_enum.insert("sharp", CLOSURE_BSDF_REFRACTION_ID);
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
SOCKET_IN_FLOAT(IOR, "IOR", 0.3f);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
return type;
}
RefractionBsdfNode::RefractionBsdfNode()
: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_REFRACTION_ID;
distribution_orig = NBUILTIN_CLOSURES;
}
void RefractionBsdfNode::simplify_settings(Scene *scene)
{
if(distribution_orig == NBUILTIN_CLOSURES) {
distribution_orig = distribution;
}
Integrator *integrator = scene->integrator;
if(integrator->filter_glossy == 0.0f) {
/* Fallback to Sharp closure for Roughness close to 0.
* Note: Keep the epsilon in sync with kernel!
*/
ShaderInput *roughness_input = input("Roughness");
if(!roughness_input->link && roughness <= 1e-4f) {
distribution = CLOSURE_BSDF_REFRACTION_ID;
}
}
else {
/* Rollback to original distribution when filter glossy is used. */
distribution = distribution_orig;
}
closure = distribution;
}
bool RefractionBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
return !roughness_input->link && roughness <= 1e-4f;
}
void RefractionBsdfNode::compile(SVMCompiler& compiler)
{
closure = distribution;
if(closure == CLOSURE_BSDF_REFRACTION_ID)
BsdfNode::compile(compiler, NULL, input("IOR"));
else
BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
}
void RefractionBsdfNode::compile(OSLCompiler& compiler)
{
compiler.parameter(this, "distribution");
compiler.add(this, "node_refraction_bsdf");
}
/* Toon BSDF Closure */
NODE_DEFINE(ToonBsdfNode)
{
NodeType* type = NodeType::add("toon_bsdf", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
static NodeEnum component_enum;
component_enum.insert("diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID);
component_enum.insert("glossy", CLOSURE_BSDF_GLOSSY_TOON_ID);
SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_DIFFUSE_TOON_ID);
SOCKET_IN_FLOAT(size, "Size", 0.5f);
SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
return type;
}
ToonBsdfNode::ToonBsdfNode()
: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_DIFFUSE_TOON_ID;
}
void ToonBsdfNode::compile(SVMCompiler& compiler)
{
closure = component;
BsdfNode::compile(compiler, input("Size"), input("Smooth"));
}
void ToonBsdfNode::compile(OSLCompiler& compiler)
{
compiler.parameter(this, "component");
compiler.add(this, "node_toon_bsdf");
}
/* Velvet BSDF Closure */
NODE_DEFINE(VelvetBsdfNode)
{
NodeType* type = NodeType::add("velvet_bsdf", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_IN_FLOAT(sigma, "Sigma", 1.0f);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
return type;
}
VelvetBsdfNode::VelvetBsdfNode()
: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
}
void VelvetBsdfNode::compile(SVMCompiler& compiler)
{
BsdfNode::compile(compiler, input("Sigma"), NULL);
}
void VelvetBsdfNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_velvet_bsdf");
}
/* Diffuse BSDF Closure */
NODE_DEFINE(DiffuseBsdfNode)
{
NodeType* type = NodeType::add("diffuse_bsdf", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
return type;
}
DiffuseBsdfNode::DiffuseBsdfNode()
: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_DIFFUSE_ID;
}
void DiffuseBsdfNode::compile(SVMCompiler& compiler)
{
BsdfNode::compile(compiler, input("Roughness"), NULL);
}
void DiffuseBsdfNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_diffuse_bsdf");
}
/* Translucent BSDF Closure */
NODE_DEFINE(TranslucentBsdfNode)
{
NodeType* type = NodeType::add("translucent_bsdf", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
return type;
}
TranslucentBsdfNode::TranslucentBsdfNode()
: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_TRANSLUCENT_ID;
}
void TranslucentBsdfNode::compile(SVMCompiler& compiler)
{
BsdfNode::compile(compiler, NULL, NULL);
}
void TranslucentBsdfNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_translucent_bsdf");
}
/* Transparent BSDF Closure */
NODE_DEFINE(TransparentBsdfNode)
{
NodeType* type = NodeType::add("transparent_bsdf", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
return type;
}
TransparentBsdfNode::TransparentBsdfNode()
: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_TRANSPARENT_ID;
}
void TransparentBsdfNode::compile(SVMCompiler& compiler)
{
BsdfNode::compile(compiler, NULL, NULL);
}
void TransparentBsdfNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_transparent_bsdf");
}
/* Subsurface Scattering Closure */
NODE_DEFINE(SubsurfaceScatteringNode)
{
NodeType* type = NodeType::add("subsurface_scattering", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
static NodeEnum falloff_enum;
falloff_enum.insert("cubic", CLOSURE_BSSRDF_CUBIC_ID);
falloff_enum.insert("gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID);
falloff_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID);
SOCKET_ENUM(falloff, "Falloff", falloff_enum, CLOSURE_BSSRDF_BURLEY_ID);
SOCKET_IN_FLOAT(scale, "Scale", 0.01f);
SOCKET_IN_VECTOR(radius, "Radius", make_float3(0.1f, 0.1f, 0.1f));
SOCKET_IN_FLOAT(sharpness, "Sharpness", 0.0f);
SOCKET_IN_FLOAT(texture_blur, "Texture Blur", 1.0f);
SOCKET_OUT_CLOSURE(BSSRDF, "BSSRDF");
return type;
}
SubsurfaceScatteringNode::SubsurfaceScatteringNode()
: BsdfNode(node_type)
{
}
void SubsurfaceScatteringNode::compile(SVMCompiler& compiler)
{
closure = falloff;
BsdfNode::compile(compiler, input("Scale"), input("Texture Blur"), input("Radius"), input("Sharpness"));
}
void SubsurfaceScatteringNode::compile(OSLCompiler& compiler)
{
compiler.parameter(this, "falloff");
compiler.add(this, "node_subsurface_scattering");
}
bool SubsurfaceScatteringNode::has_bssrdf_bump()
{
/* detect if anything is plugged into the normal input besides the default */
ShaderInput *normal_in = input("Normal");
return (normal_in->link && normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY);
}
/* Emissive Closure */
NODE_DEFINE(EmissionNode)
{
NodeType* type = NodeType::add("emission", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_OUT_CLOSURE(emission, "Emission");
return type;
}
EmissionNode::EmissionNode()
: ShaderNode(node_type)
{
}
void EmissionNode::compile(SVMCompiler& compiler)
{
ShaderInput *color_in = input("Color");
ShaderInput *strength_in = input("Strength");
if(color_in->link || strength_in->link) {
compiler.add_node(NODE_EMISSION_WEIGHT,
compiler.stack_assign(color_in),
compiler.stack_assign(strength_in));
}
else
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength);
compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset());
}
void EmissionNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_emission");
}
bool EmissionNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *)
{
ShaderInput *color_in = input("Color");
ShaderInput *strength_in = input("Strength");
return ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) ||
(!strength_in->link && strength == 0.0f));
}
/* Background Closure */
NODE_DEFINE(BackgroundNode)
{
NodeType* type = NodeType::add("background_shader", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_OUT_CLOSURE(background, "Background");
return type;
}
BackgroundNode::BackgroundNode()
: ShaderNode(node_type)
{
}
void BackgroundNode::compile(SVMCompiler& compiler)
{
ShaderInput *color_in = input("Color");
ShaderInput *strength_in = input("Strength");
if(color_in->link || strength_in->link) {
compiler.add_node(NODE_EMISSION_WEIGHT,
compiler.stack_assign(color_in),
compiler.stack_assign(strength_in));
}
else
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color*strength);
compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset());
}
void BackgroundNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_background");
}
bool BackgroundNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *)
{
ShaderInput *color_in = input("Color");
ShaderInput *strength_in = input("Strength");
return ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) ||
(!strength_in->link && strength == 0.0f));
}
/* Holdout Closure */
NODE_DEFINE(HoldoutNode)
{
NodeType* type = NodeType::add("holdout", create, NodeType::SHADER);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_OUT_CLOSURE(holdout, "Holdout");
return type;
}
HoldoutNode::HoldoutNode()
: ShaderNode(node_type)
{
}
void HoldoutNode::compile(SVMCompiler& compiler)
{
float3 value = make_float3(1.0f, 1.0f, 1.0f);
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, value);
compiler.add_node(NODE_CLOSURE_HOLDOUT, compiler.closure_mix_weight_offset());
}
void HoldoutNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_holdout");
}
/* Ambient Occlusion */
NODE_DEFINE(AmbientOcclusionNode)
{
NodeType* type = NodeType::add("ambient_occlusion", create, NodeType::SHADER);
SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_OUT_CLOSURE(AO, "AO");
return type;
}
AmbientOcclusionNode::AmbientOcclusionNode()
: ShaderNode(node_type)
{
}
void AmbientOcclusionNode::compile(SVMCompiler& compiler)
{
ShaderInput *color_in = input("Color");
if(color_in->link)
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
else
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
compiler.add_node(NODE_CLOSURE_AMBIENT_OCCLUSION, compiler.closure_mix_weight_offset());
}
void AmbientOcclusionNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_ambient_occlusion");
}
/* Volume Closure */
VolumeNode::VolumeNode(const NodeType *node_type)
: ShaderNode(node_type)
{
closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
}
void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2)
{
ShaderInput *color_in = input("Color");
if(color_in->link)
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
else
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
compiler.add_node(NODE_CLOSURE_VOLUME,
compiler.encode_uchar4(closure,
(param1)? compiler.stack_assign(param1): SVM_STACK_INVALID,
(param2)? compiler.stack_assign(param2): SVM_STACK_INVALID,
compiler.closure_mix_weight_offset()),
__float_as_int((param1)? get_float(param1->socket_type): 0.0f),
__float_as_int((param2)? get_float(param2->socket_type): 0.0f));
}
void VolumeNode::compile(SVMCompiler& compiler)
{
compile(compiler, NULL, NULL);
}
void VolumeNode::compile(OSLCompiler& /*compiler*/)
{
assert(0);
}
/* Absorption Volume Closure */
NODE_DEFINE(AbsorptionVolumeNode)
{
NodeType* type = NodeType::add("absorption_volume", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_FLOAT(density, "Density", 1.0f);
SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_OUT_CLOSURE(volume, "Volume");
return type;
}
AbsorptionVolumeNode::AbsorptionVolumeNode()
: VolumeNode(node_type)
{
closure = CLOSURE_VOLUME_ABSORPTION_ID;
}
void AbsorptionVolumeNode::compile(SVMCompiler& compiler)
{
VolumeNode::compile(compiler, input("Density"), NULL);
}
void AbsorptionVolumeNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_absorption_volume");
}
/* Scatter Volume Closure */
NODE_DEFINE(ScatterVolumeNode)
{
NodeType* type = NodeType::add("scatter_volume", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_FLOAT(density, "Density", 1.0f);
SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f);
SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_OUT_CLOSURE(volume, "Volume");
return type;
}
ScatterVolumeNode::ScatterVolumeNode()
: VolumeNode(node_type)
{
closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
}
void ScatterVolumeNode::compile(SVMCompiler& compiler)
{
VolumeNode::compile(compiler, input("Density"), input("Anisotropy"));
}
void ScatterVolumeNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_scatter_volume");
}
/* Hair BSDF Closure */
NODE_DEFINE(HairBsdfNode)
{
NodeType* type = NodeType::add("hair_bsdf", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
static NodeEnum component_enum;
component_enum.insert("reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID);
component_enum.insert("transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_HAIR_REFLECTION_ID);
SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
SOCKET_IN_FLOAT(roughness_u, "RoughnessU", 0.2f);
SOCKET_IN_FLOAT(roughness_v, "RoughnessV", 0.2f);
SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
return type;
}
HairBsdfNode::HairBsdfNode()
: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_HAIR_REFLECTION_ID;
}
void HairBsdfNode::compile(SVMCompiler& compiler)
{
closure = component;
BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset"));
}
void HairBsdfNode::compile(OSLCompiler& compiler)
{
compiler.parameter(this, "component");
compiler.add(this, "node_hair_bsdf");
}
/* Geometry */
NODE_DEFINE(GeometryNode)
{
NodeType* type = NodeType::add("geometry", create, NodeType::SHADER);
SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
SOCKET_OUT_POINT(position, "Position");
SOCKET_OUT_NORMAL(normal, "Normal");
SOCKET_OUT_NORMAL(tangent, "Tangent");
SOCKET_OUT_NORMAL(true_normal, "True Normal");
SOCKET_OUT_VECTOR(incoming, "Incoming");
SOCKET_OUT_POINT(parametric, "Parametric");
SOCKET_OUT_FLOAT(backfacing, "Backfacing");
SOCKET_OUT_FLOAT(pointiness, "Pointiness");
return type;
}
GeometryNode::GeometryNode()
: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_GEOMETRY;
}
void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface) {
if(!output("Tangent")->links.empty()) {
attributes->add(ATTR_STD_GENERATED);
}
if(!output("Pointiness")->links.empty()) {
attributes->add(ATTR_STD_POINTINESS);
}
}
ShaderNode::attributes(shader, attributes);
}
void GeometryNode::compile(SVMCompiler& compiler)
{
ShaderOutput *out;
ShaderNodeType geom_node = NODE_GEOMETRY;
ShaderNodeType attr_node = NODE_ATTR;
if(bump == SHADER_BUMP_DX) {
geom_node = NODE_GEOMETRY_BUMP_DX;
attr_node = NODE_ATTR_BUMP_DX;
}
else if(bump == SHADER_BUMP_DY) {
geom_node = NODE_GEOMETRY_BUMP_DY;
attr_node = NODE_ATTR_BUMP_DY;
}
out = output("Position");
if(!out->links.empty()) {
compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out));
}
out = output("Normal");
if(!out->links.empty()) {
compiler.add_node(geom_node, NODE_GEOM_N, compiler.stack_assign(out));
}
out = output("Tangent");
if(!out->links.empty()) {
compiler.add_node(geom_node, NODE_GEOM_T, compiler.stack_assign(out));
}
out = output("True Normal");
if(!out->links.empty()) {
compiler.add_node(geom_node, NODE_GEOM_Ng, compiler.stack_assign(out));
}
out = output("Incoming");
if(!out->links.empty()) {
compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out));
}
out = output("Parametric");
if(!out->links.empty()) {
compiler.add_node(geom_node, NODE_GEOM_uv, compiler.stack_assign(out));
}
out = output("Backfacing");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_backfacing, compiler.stack_assign(out));
}
out = output("Pointiness");
if(!out->links.empty()) {
if(compiler.output_type() != SHADER_TYPE_VOLUME) {
compiler.add_node(attr_node,
ATTR_STD_POINTINESS,
compiler.stack_assign(out),
NODE_ATTR_FLOAT);
}
else {
compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(out));
}
}
}
void GeometryNode::compile(OSLCompiler& compiler)
{
if(bump == SHADER_BUMP_DX)
compiler.parameter("bump_offset", "dx");
else if(bump == SHADER_BUMP_DY)
compiler.parameter("bump_offset", "dy");
else
compiler.parameter("bump_offset", "center");
compiler.add(this, "node_geometry");
}
/* TextureCoordinate */
NODE_DEFINE(TextureCoordinateNode)
{
NodeType* type = NodeType::add("texture_coordinate", create, NodeType::SHADER);
SOCKET_BOOLEAN(from_dupli, "From Dupli", false);
SOCKET_BOOLEAN(use_transform, "Use Transform", false);
SOCKET_TRANSFORM(ob_tfm, "Object Transform", transform_identity());
SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
SOCKET_OUT_POINT(generated, "Generated");
SOCKET_OUT_NORMAL(normal, "Normal");
SOCKET_OUT_POINT(UV, "UV");
SOCKET_OUT_POINT(object, "Object");
SOCKET_OUT_POINT(camera, "Camera");
SOCKET_OUT_POINT(window, "Window");
SOCKET_OUT_NORMAL(reflection, "Reflection");
return type;
}
TextureCoordinateNode::TextureCoordinateNode()
: ShaderNode(node_type)
{
}
void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface) {
if(!from_dupli) {
if(!output("Generated")->links.empty())
attributes->add(ATTR_STD_GENERATED);
if(!output("UV")->links.empty())
attributes->add(ATTR_STD_UV);
}
}
if(shader->has_volume) {
if(!from_dupli) {
if(!output("Generated")->links.empty()) {
attributes->add(ATTR_STD_GENERATED_TRANSFORM);
}
}
}
ShaderNode::attributes(shader, attributes);
}
void TextureCoordinateNode::compile(SVMCompiler& compiler)
{
ShaderOutput *out;
ShaderNodeType texco_node = NODE_TEX_COORD;
ShaderNodeType attr_node = NODE_ATTR;
ShaderNodeType geom_node = NODE_GEOMETRY;
if(bump == SHADER_BUMP_DX) {
texco_node = NODE_TEX_COORD_BUMP_DX;
attr_node = NODE_ATTR_BUMP_DX;
geom_node = NODE_GEOMETRY_BUMP_DX;
}
else if(bump == SHADER_BUMP_DY) {
texco_node = NODE_TEX_COORD_BUMP_DY;
attr_node = NODE_ATTR_BUMP_DY;
geom_node = NODE_GEOMETRY_BUMP_DY;
}
out = output("Generated");
if(!out->links.empty()) {
if(compiler.background) {
compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out));
}
else {
if(from_dupli) {
compiler.add_node(texco_node, NODE_TEXCO_DUPLI_GENERATED, compiler.stack_assign(out));
}
else if(compiler.output_type() == SHADER_TYPE_VOLUME) {
compiler.add_node(texco_node, NODE_TEXCO_VOLUME_GENERATED, compiler.stack_assign(out));
}
else {
int attr = compiler.attribute(ATTR_STD_GENERATED);
compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT3);
}
}
}
Cycles: merging features from tomato branch. === BVH build time optimizations === * BVH building was multithreaded. Not all building is multithreaded, packing and the initial bounding/splitting is still single threaded, but recursive splitting is, which was the main bottleneck. * Object splitting now uses binning rather than sorting of all elements, using code from the Embree raytracer from Intel. http://software.intel.com/en-us/articles/embree-photo-realistic-ray-tracing-kernels/ * Other small changes to avoid allocations, pack memory more tightly, avoid some unnecessary operations, ... These optimizations do not work yet when Spatial Splits are enabled, for that more work is needed. There's also other optimizations still needed, in particular for the case of many low poly objects, the packing step and node memory allocation. BVH raytracing time should remain about the same, but BVH build time should be significantly reduced, test here show speedup of about 5x to 10x on a dual core and 5x to 25x on an 8-core machine, depending on the scene. === Threads === Centralized task scheduler for multithreading, which is basically the CPU device threading code wrapped into something reusable. Basic idea is that there is a single TaskScheduler that keeps a pool of threads, one for each core. Other places in the code can then create a TaskPool that they can drop Tasks in to be executed by the scheduler, and wait for them to complete or cancel them early. === Normal ==== Added a Normal output to the texture coordinate node. This currently gives the object space normal, which is the same under object animation. In the future this might become a "generated" normal so it's also stable for deforming objects, but for now it's already useful for non-deforming objects. === Render Layers === Per render layer Samples control, leaving it to 0 will use the common scene setting. Environment pass will now render environment even if film is set to transparent. Exclude Layers" added. Scene layers (all object that influence the render, directly or indirectly) are shared between all render layers. However sometimes it's useful to leave out some object influence for a particular render layer. That's what this option allows you to do. === Filter Glossy === When using a value higher than 0.0, this will blur glossy reflections after blurry bounces, to reduce noise at the cost of accuracy. 1.0 is a good starting value to tweak. Some light paths have a low probability of being found while contributing much light to the pixel. As a result these light paths will be found in some pixels and not in others, causing fireflies. An example of such a difficult path might be a small light that is causing a small specular highlight on a sharp glossy material, which we are seeing through a rough glossy material. With path tracing it is difficult to find the specular highlight, but if we increase the roughness on the material the highlight gets bigger and softer, and so easier to find. Often this blurring will be hardly noticeable, because we are seeing it through a blurry material anyway, but there are also cases where this will lead to a loss of detail in lighting.
2012-04-28 08:53:59 +00:00
out = output("Normal");
if(!out->links.empty()) {
compiler.add_node(texco_node, NODE_TEXCO_NORMAL, compiler.stack_assign(out));
Cycles: merging features from tomato branch. === BVH build time optimizations === * BVH building was multithreaded. Not all building is multithreaded, packing and the initial bounding/splitting is still single threaded, but recursive splitting is, which was the main bottleneck. * Object splitting now uses binning rather than sorting of all elements, using code from the Embree raytracer from Intel. http://software.intel.com/en-us/articles/embree-photo-realistic-ray-tracing-kernels/ * Other small changes to avoid allocations, pack memory more tightly, avoid some unnecessary operations, ... These optimizations do not work yet when Spatial Splits are enabled, for that more work is needed. There's also other optimizations still needed, in particular for the case of many low poly objects, the packing step and node memory allocation. BVH raytracing time should remain about the same, but BVH build time should be significantly reduced, test here show speedup of about 5x to 10x on a dual core and 5x to 25x on an 8-core machine, depending on the scene. === Threads === Centralized task scheduler for multithreading, which is basically the CPU device threading code wrapped into something reusable. Basic idea is that there is a single TaskScheduler that keeps a pool of threads, one for each core. Other places in the code can then create a TaskPool that they can drop Tasks in to be executed by the scheduler, and wait for them to complete or cancel them early. === Normal ==== Added a Normal output to the texture coordinate node. This currently gives the object space normal, which is the same under object animation. In the future this might become a "generated" normal so it's also stable for deforming objects, but for now it's already useful for non-deforming objects. === Render Layers === Per render layer Samples control, leaving it to 0 will use the common scene setting. Environment pass will now render environment even if film is set to transparent. Exclude Layers" added. Scene layers (all object that influence the render, directly or indirectly) are shared between all render layers. However sometimes it's useful to leave out some object influence for a particular render layer. That's what this option allows you to do. === Filter Glossy === When using a value higher than 0.0, this will blur glossy reflections after blurry bounces, to reduce noise at the cost of accuracy. 1.0 is a good starting value to tweak. Some light paths have a low probability of being found while contributing much light to the pixel. As a result these light paths will be found in some pixels and not in others, causing fireflies. An example of such a difficult path might be a small light that is causing a small specular highlight on a sharp glossy material, which we are seeing through a rough glossy material. With path tracing it is difficult to find the specular highlight, but if we increase the roughness on the material the highlight gets bigger and softer, and so easier to find. Often this blurring will be hardly noticeable, because we are seeing it through a blurry material anyway, but there are also cases where this will lead to a loss of detail in lighting.
2012-04-28 08:53:59 +00:00
}
out = output("UV");
if(!out->links.empty()) {
if(from_dupli) {
compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out));
}
else {
int attr = compiler.attribute(ATTR_STD_UV);
compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT3);
}
}
out = output("Object");
if(!out->links.empty()) {
compiler.add_node(texco_node, NODE_TEXCO_OBJECT, compiler.stack_assign(out), use_transform);
if(use_transform) {
Transform ob_itfm = transform_inverse(ob_tfm);
compiler.add_node(ob_itfm.x);
compiler.add_node(ob_itfm.y);
compiler.add_node(ob_itfm.z);
compiler.add_node(ob_itfm.w);
}
}
out = output("Camera");
if(!out->links.empty()) {
compiler.add_node(texco_node, NODE_TEXCO_CAMERA, compiler.stack_assign(out));
}
out = output("Window");
if(!out->links.empty()) {
compiler.add_node(texco_node, NODE_TEXCO_WINDOW, compiler.stack_assign(out));
}
out = output("Reflection");
if(!out->links.empty()) {
if(compiler.background) {
compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out));
}
else {
compiler.add_node(texco_node, NODE_TEXCO_REFLECTION, compiler.stack_assign(out));
}
}
}
void TextureCoordinateNode::compile(OSLCompiler& compiler)
{
if(bump == SHADER_BUMP_DX)
compiler.parameter("bump_offset", "dx");
else if(bump == SHADER_BUMP_DY)
compiler.parameter("bump_offset", "dy");
else
compiler.parameter("bump_offset", "center");
if(compiler.background)
compiler.parameter("is_background", true);
if(compiler.output_type() == SHADER_TYPE_VOLUME)
compiler.parameter("is_volume", true);
compiler.parameter(this, "use_transform");
Transform ob_itfm = transform_transpose(transform_inverse(ob_tfm));
compiler.parameter("object_itfm", ob_itfm);
compiler.parameter(this, "from_dupli");
compiler.add(this, "node_texture_coordinate");
}
/* UV Map */
NODE_DEFINE(UVMapNode)
{
NodeType* type = NodeType::add("uvmap", create, NodeType::SHADER);
SOCKET_IN_STRING(attribute, "attribute", ustring(""));
SOCKET_IN_BOOLEAN(from_dupli, "from dupli", false);
SOCKET_OUT_POINT(UV, "UV");
return type;
}
UVMapNode::UVMapNode()
: ShaderNode(node_type)
{
}
void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface) {
if(!from_dupli) {
if(!output("UV")->links.empty()) {
if(attribute != "")
attributes->add(attribute);
else
attributes->add(ATTR_STD_UV);
}
}
}
ShaderNode::attributes(shader, attributes);
}
void UVMapNode::compile(SVMCompiler& compiler)
{
ShaderOutput *out = output("UV");
ShaderNodeType texco_node = NODE_TEX_COORD;
ShaderNodeType attr_node = NODE_ATTR;
int attr;
if(bump == SHADER_BUMP_DX) {
texco_node = NODE_TEX_COORD_BUMP_DX;
attr_node = NODE_ATTR_BUMP_DX;
}
else if(bump == SHADER_BUMP_DY) {
texco_node = NODE_TEX_COORD_BUMP_DY;
attr_node = NODE_ATTR_BUMP_DY;
}
if(!out->links.empty()) {
if(from_dupli) {
compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out));
}
else {
if(attribute != "")
attr = compiler.attribute(attribute);
else
attr = compiler.attribute(ATTR_STD_UV);
compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT3);
}
}
}
void UVMapNode::compile(OSLCompiler& compiler)
{
if(bump == SHADER_BUMP_DX)
compiler.parameter("bump_offset", "dx");
else if(bump == SHADER_BUMP_DY)
compiler.parameter("bump_offset", "dy");
else
compiler.parameter("bump_offset", "center");
compiler.parameter(this, "from_dupli");
compiler.parameter(this, "attribute");
compiler.add(this, "node_uv_map");
}
/* Light Path */
NODE_DEFINE(LightPathNode)
{
NodeType* type = NodeType::add("light_path", create, NodeType::SHADER);
SOCKET_OUT_FLOAT(is_camera_ray, "Is Camera Ray");
SOCKET_OUT_FLOAT(is_shadow_ray, "Is Shadow Ray");
SOCKET_OUT_FLOAT(is_diffus_ray, "Is Diffus Ray");
SOCKET_OUT_FLOAT(is_glossy_ray, "Is Glossy Ray");
SOCKET_OUT_FLOAT(is_singular_ray, "Is Singular Ray");
SOCKET_OUT_FLOAT(is_reflection_ray, "Is Reflection Ray");
SOCKET_OUT_FLOAT(is_transmission_ray, "Is Transmission Ray");
SOCKET_OUT_FLOAT(is_volume_scatter_ray, "Is Volume Scatter Ray");
SOCKET_OUT_FLOAT(ray_length, "Ray Length");
SOCKET_OUT_FLOAT(ray_depth, "Ray Depth");
SOCKET_OUT_FLOAT(transparent_depth, "Transparent Depth");
SOCKET_OUT_FLOAT(transmission_depth, "Transmission Depth");
return type;
}
LightPathNode::LightPathNode()
: ShaderNode(node_type)
{
}
void LightPathNode::compile(SVMCompiler& compiler)
{
ShaderOutput *out;
out = output("Is Camera Ray");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_camera, compiler.stack_assign(out));
}
out = output("Is Shadow Ray");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_shadow, compiler.stack_assign(out));
}
out = output("Is Diffuse Ray");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_diffuse, compiler.stack_assign(out));
}
out = output("Is Glossy Ray");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_glossy, compiler.stack_assign(out));
}
out = output("Is Singular Ray");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_singular, compiler.stack_assign(out));
}
out = output("Is Reflection Ray");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_reflection, compiler.stack_assign(out));
}
out = output("Is Transmission Ray");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_transmission, compiler.stack_assign(out));
}
out = output("Is Volume Scatter Ray");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_volume_scatter, compiler.stack_assign(out));
}
out = output("Ray Length");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_length, compiler.stack_assign(out));
}
out = output("Ray Depth");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_depth, compiler.stack_assign(out));
}
out = output("Transparent Depth");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transparent, compiler.stack_assign(out));
}
out = output("Transmission Depth");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transmission, compiler.stack_assign(out));
}
}
void LightPathNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_light_path");
}
/* Light Falloff */
NODE_DEFINE(LightFalloffNode)
{
NodeType* type = NodeType::add("light_fallof", create, NodeType::SHADER);
SOCKET_IN_FLOAT(strength, "Strength", 100.0f);
SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f);
SOCKET_OUT_FLOAT(quadratic, "Quadratic");
SOCKET_OUT_FLOAT(linear, "Linear");
SOCKET_OUT_FLOAT(constant, "Constant");
return type;
}
LightFalloffNode::LightFalloffNode()
: ShaderNode(node_type)
{
}
void LightFalloffNode::compile(SVMCompiler& compiler)
{
ShaderInput *strength_in = input("Strength");
ShaderInput *smooth_in = input("Smooth");
ShaderOutput *out = output("Quadratic");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_FALLOFF, NODE_LIGHT_FALLOFF_QUADRATIC,
compiler.encode_uchar4(
compiler.stack_assign(strength_in),
compiler.stack_assign(smooth_in),
compiler.stack_assign(out)));
}
out = output("Linear");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_FALLOFF, NODE_LIGHT_FALLOFF_LINEAR,
compiler.encode_uchar4(
compiler.stack_assign(strength_in),
compiler.stack_assign(smooth_in),
compiler.stack_assign(out)));
}
out = output("Constant");
if(!out->links.empty()) {
compiler.add_node(NODE_LIGHT_FALLOFF, NODE_LIGHT_FALLOFF_CONSTANT,
compiler.encode_uchar4(
compiler.stack_assign(strength_in),
compiler.stack_assign(smooth_in),
compiler.stack_assign(out)));
}
}
void LightFalloffNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_light_falloff");
}
/* Object Info */
NODE_DEFINE(ObjectInfoNode)
{
NodeType* type = NodeType::add("object_info", create, NodeType::SHADER);
SOCKET_OUT_VECTOR(location, "Location");
SOCKET_OUT_FLOAT(object_index, "Object Index");
SOCKET_OUT_FLOAT(material_index, "Material Index");
SOCKET_OUT_FLOAT(random, "Random");
return type;
}
ObjectInfoNode::ObjectInfoNode()
: ShaderNode(node_type)
{
}
void ObjectInfoNode::compile(SVMCompiler& compiler)
{
ShaderOutput *out = output("Location");
if(!out->links.empty()) {
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_LOCATION, compiler.stack_assign(out));
}
out = output("Object Index");
if(!out->links.empty()) {
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_INDEX, compiler.stack_assign(out));
}
out = output("Material Index");
if(!out->links.empty()) {
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_MAT_INDEX, compiler.stack_assign(out));
}
out = output("Random");
if(!out->links.empty()) {
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_RANDOM, compiler.stack_assign(out));
}
}
void ObjectInfoNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_object_info");
}
/* Particle Info */
NODE_DEFINE(ParticleInfoNode)
{
NodeType* type = NodeType::add("particle_info", create, NodeType::SHADER);
SOCKET_OUT_FLOAT(index, "Index");
SOCKET_OUT_FLOAT(age, "Age");
SOCKET_OUT_FLOAT(lifetime, "Lifetime");
SOCKET_OUT_POINT(location, "Location");
#if 0 /* not yet supported */
SOCKET_OUT_QUATERNION(rotation, "Rotation");
#endif
SOCKET_OUT_FLOAT(size, "Size");
SOCKET_OUT_VECTOR(velocity, "Velocity");
SOCKET_OUT_VECTOR(angular_velocity, "Angular Velocity");
return type;
}
ParticleInfoNode::ParticleInfoNode()
: ShaderNode(node_type)
{
}
void ParticleInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(!output("Index")->links.empty())
attributes->add(ATTR_STD_PARTICLE);
if(!output("Age")->links.empty())
attributes->add(ATTR_STD_PARTICLE);
if(!output("Lifetime")->links.empty())
attributes->add(ATTR_STD_PARTICLE);
if(!output("Location")->links.empty())
attributes->add(ATTR_STD_PARTICLE);
#if 0 /* not yet supported */
if(!output("Rotation")->links.empty())
attributes->add(ATTR_STD_PARTICLE);
#endif
if(!output("Size")->links.empty())
attributes->add(ATTR_STD_PARTICLE);
if(!output("Velocity")->links.empty())
attributes->add(ATTR_STD_PARTICLE);
if(!output("Angular Velocity")->links.empty())
attributes->add(ATTR_STD_PARTICLE);
ShaderNode::attributes(shader, attributes);
}
void ParticleInfoNode::compile(SVMCompiler& compiler)
{
ShaderOutput *out;
out = output("Index");
if(!out->links.empty()) {
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_INDEX, compiler.stack_assign(out));
}
out = output("Age");
if(!out->links.empty()) {
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_AGE, compiler.stack_assign(out));
}
out = output("Lifetime");
if(!out->links.empty()) {
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LIFETIME, compiler.stack_assign(out));
}
out = output("Location");
if(!out->links.empty()) {
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LOCATION, compiler.stack_assign(out));
}
/* quaternion data is not yet supported by Cycles */
#if 0
out = output("Rotation");
if(!out->links.empty()) {
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_ROTATION, compiler.stack_assign(out));
}
#endif
out = output("Size");
if(!out->links.empty()) {
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_SIZE, compiler.stack_assign(out));
}
out = output("Velocity");
if(!out->links.empty()) {
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_VELOCITY, compiler.stack_assign(out));
}
out = output("Angular Velocity");
if(!out->links.empty()) {
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_ANGULAR_VELOCITY, compiler.stack_assign(out));
}
}
void ParticleInfoNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_particle_info");
}
/* Hair Info */
NODE_DEFINE(HairInfoNode)
{
NodeType* type = NodeType::add("hair_info", create, NodeType::SHADER);
SOCKET_OUT_FLOAT(is_strand, "Is Strand");
SOCKET_OUT_FLOAT(intercept, "Intercept");
SOCKET_OUT_FLOAT(thickness, "Thickness");
SOCKET_OUT_NORMAL(tangent Normal, "Tangent Normal");
#if 0 /*output for minimum hair width transparency - deactivated */
SOCKET_OUT_FLOAT(fade, "Fade");
#endif
return type;
}
HairInfoNode::HairInfoNode()
: ShaderNode(node_type)
{
}
void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface) {
ShaderOutput *intercept_out = output("Intercept");
if(!intercept_out->links.empty())
attributes->add(ATTR_STD_CURVE_INTERCEPT);
}
ShaderNode::attributes(shader, attributes);
}
void HairInfoNode::compile(SVMCompiler& compiler)
{
ShaderOutput *out;
out = output("Is Strand");
if(!out->links.empty()) {
compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_IS_STRAND, compiler.stack_assign(out));
}
out = output("Intercept");
if(!out->links.empty()) {
int attr = compiler.attribute(ATTR_STD_CURVE_INTERCEPT);
compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT);
}
out = output("Thickness");
if(!out->links.empty()) {
compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_THICKNESS, compiler.stack_assign(out));
}
out = output("Tangent Normal");
if(!out->links.empty()) {
compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_TANGENT_NORMAL, compiler.stack_assign(out));
}
/*out = output("Fade");
if(!out->links.empty()) {
compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_FADE, compiler.stack_assign(out));
}*/
}
void HairInfoNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_hair_info");
}
/* Value */
NODE_DEFINE(ValueNode)
{
NodeType* type = NodeType::add("value", create, NodeType::SHADER);
SOCKET_FLOAT(value, "Value", 0.0f);
SOCKET_OUT_FLOAT(value, "Value");
return type;
}
ValueNode::ValueNode()
: ShaderNode(node_type)
{
}
bool ValueNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
{
optimized->set(value);
return true;
}
void ValueNode::compile(SVMCompiler& compiler)
{
ShaderOutput *val_out = output("Value");
compiler.add_node(NODE_VALUE_F, __float_as_int(value), compiler.stack_assign(val_out));
}
void ValueNode::compile(OSLCompiler& compiler)
{
compiler.parameter("value_value", value);
compiler.add(this, "node_value");
}
/* Color */
NODE_DEFINE(ColorNode)
{
NodeType* type = NodeType::add("color", create, NodeType::SHADER);
SOCKET_COLOR(value, "Value", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_COLOR(color, "Color");
return type;
}
ColorNode::ColorNode()
: ShaderNode(node_type)
{
}
bool ColorNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
{
optimized->set(value);
return true;
}
void ColorNode::compile(SVMCompiler& compiler)
{
ShaderOutput *color_out = output("Color");
if(!color_out->links.empty()) {
compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
compiler.add_node(NODE_VALUE_V, value);
}
}
void ColorNode::compile(OSLCompiler& compiler)
{
compiler.parameter_color("color_value", value);
compiler.add(this, "node_value");
}
/* Add Closure */
NODE_DEFINE(AddClosureNode)
{
NodeType* type = NodeType::add("add_closure", create, NodeType::SHADER);
SOCKET_IN_CLOSURE(closure1, "Closure1");
SOCKET_IN_CLOSURE(closure2, "Closure2");
SOCKET_OUT_CLOSURE(closure, "Closure");
return type;
}
AddClosureNode::AddClosureNode()
: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
}
void AddClosureNode::compile(SVMCompiler& /*compiler*/)
{
/* handled in the SVM compiler */
}
void AddClosureNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_add_closure");
}
/* Mix Closure */
NODE_DEFINE(MixClosureNode)
{
NodeType* type = NodeType::add("mix_closure", create, NodeType::SHADER);
SOCKET_IN_FLOAT(fac, "Fac", 0.5f);
SOCKET_IN_CLOSURE(closure1, "Closure1");
SOCKET_IN_CLOSURE(closure2, "Closure2");
SOCKET_OUT_CLOSURE(closure, "Closure");
return type;
}
MixClosureNode::MixClosureNode()
: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
}
void MixClosureNode::compile(SVMCompiler& /*compiler*/)
{
/* handled in the SVM compiler */
}
void MixClosureNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_mix_closure");
}
bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *)
{
ShaderInput *fac_in = input("Fac");
ShaderInput *closure1_in = input("Closure1");
ShaderInput *closure2_in = input("Closure2");
ShaderOutput *closure_out = output("Closure");
/* remove useless mix closures nodes */
if(closure1_in->link == closure2_in->link) {
graph->relink(this, closure_out, closure1_in->link);
return true;
}
/* remove unused mix closure input when factor is 0.0 or 1.0 */
/* check for closure links and make sure factor link is disconnected */
if(closure1_in->link && closure2_in->link && !fac_in->link) {
/* factor 0.0 */
if(fac == 0.0f) {
graph->relink(this, closure_out, closure1_in->link);
return true;
}
/* factor 1.0 */
else if(fac == 1.0f) {
graph->relink(this, closure_out, closure2_in->link);
return true;
}
}
return false;
}
/* Mix Closure */
NODE_DEFINE(MixClosureWeightNode)
{
NodeType* type = NodeType::add("mix_closure_weight", create, NodeType::SHADER);
SOCKET_IN_FLOAT(weight, "Weight", 1.0f);
SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
SOCKET_OUT_FLOAT(weight1, "Weight1");
SOCKET_OUT_FLOAT(weight2, "Weight2");
return type;
}
MixClosureWeightNode::MixClosureWeightNode()
: ShaderNode(node_type)
{
}
void MixClosureWeightNode::compile(SVMCompiler& compiler)
{
ShaderInput *weight_in = input("Weight");
ShaderInput *fac_in = input("Fac");
ShaderOutput *weight1_out = output("Weight1");
ShaderOutput *weight2_out = output("Weight2");
compiler.add_node(NODE_MIX_CLOSURE,
compiler.encode_uchar4(
compiler.stack_assign(fac_in),
compiler.stack_assign(weight_in),
compiler.stack_assign(weight1_out),
compiler.stack_assign(weight2_out)));
}
void MixClosureWeightNode::compile(OSLCompiler& /*compiler*/)
{
assert(0);
}
/* Invert */
NODE_DEFINE(InvertNode)
{
NodeType* type = NodeType::add("invert", create, NodeType::SHADER);
SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_COLOR(color, "Color");
return type;
}
InvertNode::InvertNode()
: ShaderNode(node_type)
{
}
void InvertNode::compile(SVMCompiler& compiler)
{
ShaderInput *fac_in = input("Fac");
ShaderInput *color_in = input("Color");
ShaderOutput *color_out = output("Color");
compiler.add_node(NODE_INVERT,
compiler.stack_assign(fac_in),
compiler.stack_assign(color_in),
compiler.stack_assign(color_out));
}
void InvertNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_invert");
}
/* Mix */
NODE_DEFINE(MixNode)
{
NodeType* type = NodeType::add("mix", create, NodeType::SHADER);
static NodeEnum type_enum;
type_enum.insert("mix", NODE_MIX_BLEND);
type_enum.insert("add", NODE_MIX_ADD);
type_enum.insert("multiply", NODE_MIX_MUL);
type_enum.insert("screen", NODE_MIX_SCREEN);
type_enum.insert("overlay", NODE_MIX_OVERLAY);
type_enum.insert("subtract", NODE_MIX_SUB);
type_enum.insert("divide", NODE_MIX_DIV);
type_enum.insert("difference", NODE_MIX_DIFF);
type_enum.insert("darken", NODE_MIX_DARK);
type_enum.insert("lighten", NODE_MIX_LIGHT);
type_enum.insert("dodge", NODE_MIX_DODGE);
type_enum.insert("burn", NODE_MIX_BURN);
type_enum.insert("hue", NODE_MIX_HUE);
type_enum.insert("saturation", NODE_MIX_SAT);
type_enum.insert("value", NODE_MIX_VAL);
type_enum.insert("color", NODE_MIX_COLOR);
type_enum.insert("soft_light", NODE_MIX_SOFT);
type_enum.insert("linear_light", NODE_MIX_LINEAR);
SOCKET_ENUM(type, "Type", type_enum, NODE_MIX_BLEND);
SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
SOCKET_IN_FLOAT(fac, "Fac", 0.5f);
SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_COLOR(color, "Color");
return type;
}
MixNode::MixNode()
: ShaderNode(node_type)
{
}
void MixNode::compile(SVMCompiler& compiler)
{
ShaderInput *fac_in = input("Fac");
ShaderInput *color1_in = input("Color1");
ShaderInput *color2_in = input("Color2");
ShaderOutput *color_out = output("Color");
compiler.add_node(NODE_MIX,
compiler.stack_assign(fac_in),
compiler.stack_assign(color1_in),
compiler.stack_assign(color2_in));
compiler.add_node(NODE_MIX, type, compiler.stack_assign(color_out));
if(use_clamp) {
compiler.add_node(NODE_MIX, 0, compiler.stack_assign(color_out));
compiler.add_node(NODE_MIX, NODE_MIX_CLAMP, compiler.stack_assign(color_out));
}
}
void MixNode::compile(OSLCompiler& compiler)
{
compiler.parameter(this, "type");
compiler.parameter(this, "use_clamp");
compiler.add(this, "node_mix");
}
bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *optimized)
{
if(type != NODE_MIX_BLEND) {
return false;
}
ShaderInput *fac_in = input("Fac");
ShaderInput *color1_in = input("Color1");
ShaderInput *color2_in = input("Color2");
ShaderOutput *color_out = output("Color");
/* remove useless mix colors nodes */
if(color1_in->link && color1_in->link == color2_in->link) {
graph->relink(this, color_out, color1_in->link);
return true;
}
/* remove unused mix color input when factor is 0.0 or 1.0 */
if(!fac_in->link) {
/* factor 0.0 */
if(fac == 0.0f) {
if(color1_in->link)
graph->relink(this, color_out, color1_in->link);
else
optimized->set(color1);
return true;
}
/* factor 1.0 */
else if(fac == 1.0f) {
if(color2_in->link)
graph->relink(this, color_out, color2_in->link);
else
optimized->set(color2);
return true;
}
}
return false;
}
/* Combine RGB */
NODE_DEFINE(CombineRGBNode)
{
NodeType* type = NodeType::add("combine_rgb", create, NodeType::SHADER);
SOCKET_IN_FLOAT(r, "R", 0.0f);
SOCKET_IN_FLOAT(g, "G", 0.0f);
SOCKET_IN_FLOAT(b, "B", 0.0f);
SOCKET_OUT_COLOR(image, "Image");
return type;
}
CombineRGBNode::CombineRGBNode()
: ShaderNode(node_type)
{
}
void CombineRGBNode::compile(SVMCompiler& compiler)
{
ShaderInput *red_in = input("R");
ShaderInput *green_in = input("G");
ShaderInput *blue_in = input("B");
ShaderOutput *color_out = output("Image");
compiler.add_node(NODE_COMBINE_VECTOR,
compiler.stack_assign(red_in), 0,
compiler.stack_assign(color_out));
compiler.add_node(NODE_COMBINE_VECTOR,
compiler.stack_assign(green_in), 1,
compiler.stack_assign(color_out));
compiler.add_node(NODE_COMBINE_VECTOR,
compiler.stack_assign(blue_in), 2,
compiler.stack_assign(color_out));
}
void CombineRGBNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_combine_rgb");
}
/* Combine XYZ */
NODE_DEFINE(CombineXYZNode)
{
NodeType* type = NodeType::add("combine_xyz", create, NodeType::SHADER);
SOCKET_IN_FLOAT(x, "X", 0.0f);
SOCKET_IN_FLOAT(y, "Y", 0.0f);
SOCKET_IN_FLOAT(z, "Z", 0.0f);
SOCKET_OUT_COLOR(color, "Image");
return type;
}
CombineXYZNode::CombineXYZNode()
: ShaderNode(node_type)
{
}
void CombineXYZNode::compile(SVMCompiler& compiler)
{
ShaderInput *x_in = input("X");
ShaderInput *y_in = input("Y");
ShaderInput *z_in = input("Z");
ShaderOutput *vector_out = output("Vector");
compiler.add_node(NODE_COMBINE_VECTOR,
compiler.stack_assign(x_in), 0,
compiler.stack_assign(vector_out));
compiler.add_node(NODE_COMBINE_VECTOR,
compiler.stack_assign(y_in), 1,
compiler.stack_assign(vector_out));
compiler.add_node(NODE_COMBINE_VECTOR,
compiler.stack_assign(z_in), 2,
compiler.stack_assign(vector_out));
}
void CombineXYZNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_combine_xyz");
}
/* Combine HSV */
NODE_DEFINE(CombineHSVNode)
{
NodeType* type = NodeType::add("combine_hsv", create, NodeType::SHADER);
SOCKET_IN_FLOAT(h, "H", 0.0f);
SOCKET_IN_FLOAT(s, "S", 0.0f);
SOCKET_IN_FLOAT(v, "V", 0.0f);
SOCKET_OUT_COLOR(color, "Color");
return type;
}
CombineHSVNode::CombineHSVNode()
: ShaderNode(node_type)
{
}
void CombineHSVNode::compile(SVMCompiler& compiler)
{
ShaderInput *hue_in = input("H");
ShaderInput *saturation_in = input("S");
ShaderInput *value_in = input("V");
ShaderOutput *color_out = output("Color");
compiler.add_node(NODE_COMBINE_HSV,
compiler.stack_assign(hue_in),
compiler.stack_assign(saturation_in),
compiler.stack_assign(value_in));
compiler.add_node(NODE_COMBINE_HSV,
compiler.stack_assign(color_out));
}
void CombineHSVNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_combine_hsv");
}
/* Gamma */
NODE_DEFINE(GammaNode)
{
NodeType* type = NodeType::add("gamma", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_FLOAT(gamma, "Gamma", 1.0f);
SOCKET_OUT_COLOR(color, "Color");
return type;
}
GammaNode::GammaNode()
: ShaderNode(node_type)
{
}
bool GammaNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized)
{
ShaderInput *color_in = input("Color");
ShaderInput *gamma_in = input("Gamma");
if(color_in->link == NULL && gamma_in->link == NULL) {
optimized->set(svm_math_gamma_color(color, gamma));
return true;
}
return false;
}
void GammaNode::compile(SVMCompiler& compiler)
{
ShaderInput *color_in = input("Color");
ShaderInput *gamma_in = input("Gamma");
ShaderOutput *color_out = output("Color");
compiler.add_node(NODE_GAMMA,
compiler.stack_assign(gamma_in),
compiler.stack_assign(color_in),
compiler.stack_assign(color_out));
}
void GammaNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_gamma");
}
/* Bright Contrast */
NODE_DEFINE(BrightContrastNode)
{
NodeType* type = NodeType::add("brightness_contrast", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_FLOAT(bright, "Bright", 0.0f);
SOCKET_IN_FLOAT(contrast, "Contrast", 0.0f);
SOCKET_OUT_COLOR(color, "Color");
return type;
}
BrightContrastNode::BrightContrastNode()
: ShaderNode(node_type)
{
}
void BrightContrastNode::compile(SVMCompiler& compiler)
{
ShaderInput *color_in = input("Color");
ShaderInput *bright_in = input("Bright");
ShaderInput *contrast_in = input("Contrast");
ShaderOutput *color_out = output("Color");
compiler.add_node(NODE_BRIGHTCONTRAST,
compiler.stack_assign(color_in),
compiler.stack_assign(color_out),
compiler.encode_uchar4(
compiler.stack_assign(bright_in),
compiler.stack_assign(contrast_in)));
}
void BrightContrastNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_brightness");
}
/* Separate RGB */
NODE_DEFINE(SeparateRGBNode)
{
NodeType* type = NodeType::add("separate_rgb", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Image", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_FLOAT(g, "R");
SOCKET_OUT_FLOAT(g, "G");
SOCKET_OUT_FLOAT(b, "B");
return type;
}
SeparateRGBNode::SeparateRGBNode()
: ShaderNode(node_type)
{
}
void SeparateRGBNode::compile(SVMCompiler& compiler)
{
ShaderInput *color_in = input("Image");
ShaderOutput *red_out = output("R");
ShaderOutput *green_out = output("G");
ShaderOutput *blue_out = output("B");
compiler.add_node(NODE_SEPARATE_VECTOR,
compiler.stack_assign(color_in), 0,
compiler.stack_assign(red_out));
compiler.add_node(NODE_SEPARATE_VECTOR,
compiler.stack_assign(color_in), 1,
compiler.stack_assign(green_out));
compiler.add_node(NODE_SEPARATE_VECTOR,
compiler.stack_assign(color_in), 2,
compiler.stack_assign(blue_out));
}
void SeparateRGBNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_separate_rgb");
}
/* Separate XYZ */
NODE_DEFINE(SeparateXYZNode)
{
NodeType* type = NodeType::add("separate_xyz", create, NodeType::SHADER);
SOCKET_IN_COLOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_FLOAT(x, "X");
SOCKET_OUT_FLOAT(y, "Y");
SOCKET_OUT_FLOAT(z, "Z");
return type;
}
SeparateXYZNode::SeparateXYZNode()
: ShaderNode(node_type)
{
}
void SeparateXYZNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector_in = input("Vector");
ShaderOutput *x_out = output("X");
ShaderOutput *y_out = output("Y");
ShaderOutput *z_out = output("Z");
compiler.add_node(NODE_SEPARATE_VECTOR,
compiler.stack_assign(vector_in), 0,
compiler.stack_assign(x_out));
compiler.add_node(NODE_SEPARATE_VECTOR,
compiler.stack_assign(vector_in), 1,
compiler.stack_assign(y_out));
compiler.add_node(NODE_SEPARATE_VECTOR,
compiler.stack_assign(vector_in), 2,
compiler.stack_assign(z_out));
}
void SeparateXYZNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_separate_xyz");
}
/* Separate HSV */
NODE_DEFINE(SeparateHSVNode)
{
NodeType* type = NodeType::add("separate_hsv", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_FLOAT(h, "H");
SOCKET_OUT_FLOAT(s, "S");
SOCKET_OUT_FLOAT(v, "V");
return type;
}
SeparateHSVNode::SeparateHSVNode()
: ShaderNode(node_type)
{
}
void SeparateHSVNode::compile(SVMCompiler& compiler)
{
ShaderInput *color_in = input("Color");
ShaderOutput *hue_out = output("H");
ShaderOutput *saturation_out = output("S");
ShaderOutput *value_out = output("V");
compiler.add_node(NODE_SEPARATE_HSV,
compiler.stack_assign(color_in),
compiler.stack_assign(hue_out),
compiler.stack_assign(saturation_out));
compiler.add_node(NODE_SEPARATE_HSV,
compiler.stack_assign(value_out));
}
void SeparateHSVNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_separate_hsv");
}
/* Hue Saturation Value */
NODE_DEFINE(HSVNode)
{
NodeType* type = NodeType::add("hsv", create, NodeType::SHADER);
SOCKET_IN_FLOAT(hue, "Hue", 0.5f);
SOCKET_IN_FLOAT(saturation, "Saturation", 1.0f);
SOCKET_IN_FLOAT(value, "Value", 1.0f);
SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_COLOR(color, "Color");
return type;
}
HSVNode::HSVNode()
: ShaderNode(node_type)
{
}
void HSVNode::compile(SVMCompiler& compiler)
{
ShaderInput *hue_in = input("Hue");
ShaderInput *saturation_in = input("Saturation");
ShaderInput *value_in = input("Value");
ShaderInput *fac_in = input("Fac");
ShaderInput *color_in = input("Color");
ShaderOutput *color_out = output("Color");
compiler.add_node(NODE_HSV,
compiler.encode_uchar4(
compiler.stack_assign(color_in),
compiler.stack_assign(fac_in),
compiler.stack_assign(color_out)),
compiler.encode_uchar4(
compiler.stack_assign(hue_in),
compiler.stack_assign(saturation_in),
compiler.stack_assign(value_in)));
}
void HSVNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_hsv");
}
/* Attribute */
NODE_DEFINE(AttributeNode)
{
NodeType* type = NodeType::add("attribute", create, NodeType::SHADER);
SOCKET_STRING(attribute, "Attribute", ustring(""));
SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_VECTOR(vector, "Vector");
SOCKET_OUT_FLOAT(fac, "Fac");
return type;
}
AttributeNode::AttributeNode()
: ShaderNode(node_type)
{
}
void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
ShaderOutput *color_out = output("Color");
ShaderOutput *vector_out = output("Vector");
ShaderOutput *fac_out = output("Fac");
if(!color_out->links.empty() || !vector_out->links.empty() || !fac_out->links.empty()) {
AttributeStandard std = Attribute::name_standard(attribute.c_str());
if(std != ATTR_STD_NONE)
attributes->add(std);
else
attributes->add(attribute);
}
if(shader->has_volume)
attributes->add(ATTR_STD_GENERATED_TRANSFORM);
ShaderNode::attributes(shader, attributes);
}
void AttributeNode::compile(SVMCompiler& compiler)
{
ShaderOutput *color_out = output("Color");
ShaderOutput *vector_out = output("Vector");
ShaderOutput *fac_out = output("Fac");
ShaderNodeType attr_node = NODE_ATTR;
AttributeStandard std = Attribute::name_standard(attribute.c_str());
int attr;
if(std != ATTR_STD_NONE)
attr = compiler.attribute(std);
else
attr = compiler.attribute(attribute);
if(bump == SHADER_BUMP_DX)
attr_node = NODE_ATTR_BUMP_DX;
else if(bump == SHADER_BUMP_DY)
attr_node = NODE_ATTR_BUMP_DY;
if(!color_out->links.empty() || !vector_out->links.empty()) {
if(!color_out->links.empty()) {
compiler.add_node(attr_node, attr, compiler.stack_assign(color_out), NODE_ATTR_FLOAT3);
}
if(!vector_out->links.empty()) {
compiler.add_node(attr_node, attr, compiler.stack_assign(vector_out), NODE_ATTR_FLOAT3);
}
}
if(!fac_out->links.empty()) {
compiler.add_node(attr_node, attr, compiler.stack_assign(fac_out), NODE_ATTR_FLOAT);
}
}
void AttributeNode::compile(OSLCompiler& compiler)
{
if(bump == SHADER_BUMP_DX)
compiler.parameter("bump_offset", "dx");
else if(bump == SHADER_BUMP_DY)
compiler.parameter("bump_offset", "dy");
else
compiler.parameter("bump_offset", "center");
if(Attribute::name_standard(attribute.c_str()) != ATTR_STD_NONE)
compiler.parameter("name", (string("geom:") + attribute.c_str()).c_str());
else
compiler.parameter("name", attribute.c_str());
compiler.add(this, "node_attribute");
}
/* Camera */
NODE_DEFINE(CameraNode)
{
NodeType* type = NodeType::add("camera_info", create, NodeType::SHADER);
SOCKET_OUT_VECTOR(view_vector, "View Vector");
SOCKET_OUT_FLOAT(view_z_depth, "View Z Depth");
SOCKET_OUT_FLOAT(view_distance, "View Distance");
return type;
}
CameraNode::CameraNode()
: ShaderNode(node_type)
{
}
void CameraNode::compile(SVMCompiler& compiler)
{
ShaderOutput *vector_out = output("View Vector");
ShaderOutput *z_depth_out = output("View Z Depth");
ShaderOutput *distance_out = output("View Distance");
compiler.add_node(NODE_CAMERA,
compiler.stack_assign(vector_out),
compiler.stack_assign(z_depth_out),
compiler.stack_assign(distance_out));
}
void CameraNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_camera");
}
/* Fresnel */
NODE_DEFINE(FresnelNode)
{
NodeType* type = NodeType::add("fresnel", create, NodeType::SHADER);
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
SOCKET_IN_FLOAT(IOR, "IOR", 1.45f);
SOCKET_OUT_FLOAT(fac, "Fac");
return type;
}
FresnelNode::FresnelNode()
: ShaderNode(node_type)
{
}
void FresnelNode::compile(SVMCompiler& compiler)
{
ShaderInput *normal_in = input("Normal");
ShaderInput *IOR_in = input("IOR");
ShaderOutput *fac_out = output("Fac");
compiler.add_node(NODE_FRESNEL,
compiler.stack_assign(IOR_in),
__float_as_int(IOR),
compiler.encode_uchar4(
compiler.stack_assign_if_linked(normal_in),
compiler.stack_assign(fac_out)));
}
void FresnelNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_fresnel");
}
/* Layer Weight */
NODE_DEFINE(LayerWeightNode)
{
NodeType* type = NodeType::add("layer_weight", create, NodeType::SHADER);
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
SOCKET_IN_FLOAT(blend, "Blend", 0.5f);
SOCKET_OUT_FLOAT(fresnel, "Fresnel");
SOCKET_OUT_FLOAT(facing, "Facing");
return type;
}
LayerWeightNode::LayerWeightNode()
: ShaderNode(node_type)
{
}
void LayerWeightNode::compile(SVMCompiler& compiler)
{
ShaderInput *normal_in = input("Normal");
ShaderInput *blend_in = input("Blend");
ShaderOutput *fresnel_out = output("Fresnel");
ShaderOutput *facing_out = output("Facing");
if(!fresnel_out->links.empty()) {
compiler.add_node(NODE_LAYER_WEIGHT,
compiler.stack_assign_if_linked(blend_in),
__float_as_int(blend),
compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL,
compiler.stack_assign_if_linked(normal_in),
compiler.stack_assign(fresnel_out)));
}
if(!facing_out->links.empty()) {
compiler.add_node(NODE_LAYER_WEIGHT,
compiler.stack_assign_if_linked(blend_in),
__float_as_int(blend),
compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING,
compiler.stack_assign_if_linked(normal_in),
compiler.stack_assign(facing_out)));
}
}
void LayerWeightNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_layer_weight");
}
/* Wireframe */
NODE_DEFINE(WireframeNode)
{
NodeType* type = NodeType::add("wireframe", create, NodeType::SHADER);
SOCKET_BOOLEAN(use_pixel_size, "Use Pixel Size", false);
SOCKET_IN_FLOAT(size, "Size", 0.01f);
SOCKET_OUT_FLOAT(fac, "Fac");
return type;
}
WireframeNode::WireframeNode()
: ShaderNode(node_type)
{
}
void WireframeNode::compile(SVMCompiler& compiler)
{
ShaderInput *size_in = input("Size");
ShaderOutput *fac_out = output("Fac");
NodeBumpOffset bump_offset = NODE_BUMP_OFFSET_CENTER;
if(bump == SHADER_BUMP_DX) {
bump_offset = NODE_BUMP_OFFSET_DX;
}
else if(bump == SHADER_BUMP_DY) {
bump_offset = NODE_BUMP_OFFSET_DY;
}
compiler.add_node(NODE_WIREFRAME,
compiler.stack_assign(size_in),
compiler.stack_assign(fac_out),
compiler.encode_uchar4(use_pixel_size,
bump_offset,
0, 0));
}
void WireframeNode::compile(OSLCompiler& compiler)
{
if(bump == SHADER_BUMP_DX) {
compiler.parameter("bump_offset", "dx");
}
else if(bump == SHADER_BUMP_DY) {
compiler.parameter("bump_offset", "dy");
}
else {
compiler.parameter("bump_offset", "center");
}
compiler.parameter(this, "use_pixel_size");
compiler.add(this, "node_wireframe");
}
/* Wavelength */
NODE_DEFINE(WavelengthNode)
{
NodeType* type = NodeType::add("wavelength", create, NodeType::SHADER);
SOCKET_IN_FLOAT(wavelength, "Wavelength", 500.0f);
SOCKET_OUT_COLOR(color, "Color");
return type;
}
WavelengthNode::WavelengthNode()
: ShaderNode(node_type)
{
}
void WavelengthNode::compile(SVMCompiler& compiler)
{
ShaderInput *wavelength_in = input("Wavelength");
ShaderOutput *color_out = output("Color");
compiler.add_node(NODE_WAVELENGTH,
compiler.stack_assign(wavelength_in),
compiler.stack_assign(color_out));
}
void WavelengthNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_wavelength");
}
/* Blackbody */
NODE_DEFINE(BlackbodyNode)
{
NodeType* type = NodeType::add("blackbody", create, NodeType::SHADER);
SOCKET_IN_FLOAT(temperature, "Temperature", 1200.0f);
SOCKET_OUT_COLOR(color, "Color");
return type;
}
BlackbodyNode::BlackbodyNode()
: ShaderNode(node_type)
{
}
bool BlackbodyNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized)
{
ShaderInput *temperature_in = input("Temperature");
if(temperature_in->link == NULL) {
optimized->set(svm_math_blackbody_color(temperature));
return true;
}
return false;
}
void BlackbodyNode::compile(SVMCompiler& compiler)
{
ShaderInput *temperature_in = input("Temperature");
ShaderOutput *color_out = output("Color");
compiler.add_node(NODE_BLACKBODY,
compiler.stack_assign(temperature_in),
compiler.stack_assign(color_out));
}
void BlackbodyNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_blackbody");
}
/* Output */
NODE_DEFINE(OutputNode)
{
NodeType* type = NodeType::add("output", create, NodeType::SHADER);
SOCKET_IN_CLOSURE(surface, "Surface");
SOCKET_IN_CLOSURE(volume, "Volume");
SOCKET_IN_FLOAT(displacement, "Displacement", 0.0f);
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f));
return type;
}
OutputNode::OutputNode()
: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_OUTPUT;
}
void OutputNode::compile(SVMCompiler& compiler)
{
if(compiler.output_type() == SHADER_TYPE_DISPLACEMENT) {
ShaderInput *displacement_in = input("Displacement");
if(displacement_in->link) {
compiler.add_node(NODE_SET_DISPLACEMENT, compiler.stack_assign(displacement_in));
}
}
}
void OutputNode::compile(OSLCompiler& compiler)
{
if(compiler.output_type() == SHADER_TYPE_SURFACE)
compiler.add(this, "node_output_surface");
else if(compiler.output_type() == SHADER_TYPE_VOLUME)
compiler.add(this, "node_output_volume");
else if(compiler.output_type() == SHADER_TYPE_DISPLACEMENT)
compiler.add(this, "node_output_displacement");
}
/* Math */
NODE_DEFINE(MathNode)
{
NodeType* type = NodeType::add("math", create, NodeType::SHADER);
static NodeEnum type_enum;
type_enum.insert("add", NODE_MATH_ADD);
type_enum.insert("subtract", NODE_MATH_SUBTRACT);
type_enum.insert("multiply", NODE_MATH_MULTIPLY);
type_enum.insert("divide", NODE_MATH_DIVIDE);
type_enum.insert("sine", NODE_MATH_SINE);
type_enum.insert("cosine", NODE_MATH_COSINE);
type_enum.insert("tangent", NODE_MATH_TANGENT);
type_enum.insert("arcsine", NODE_MATH_ARCSINE);
type_enum.insert("arccosine", NODE_MATH_ARCCOSINE);
type_enum.insert("arctangent", NODE_MATH_ARCTANGENT);
type_enum.insert("power", NODE_MATH_POWER);
type_enum.insert("logarithm", NODE_MATH_LOGARITHM);
type_enum.insert("minimum", NODE_MATH_MINIMUM);
type_enum.insert("maximum", NODE_MATH_MAXIMUM);
type_enum.insert("round", NODE_MATH_ROUND);
type_enum.insert("less_than", NODE_MATH_LESS_THAN);
type_enum.insert("greater_than", NODE_MATH_GREATER_THAN);
type_enum.insert("modulo", NODE_MATH_MODULO);
type_enum.insert("absolute", NODE_MATH_ABSOLUTE);
SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD);
SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
SOCKET_IN_FLOAT(value1, "Value1", 0.0f);
SOCKET_IN_FLOAT(value2, "Value2", 0.0f);
SOCKET_OUT_FLOAT(value, "Value");
return type;
}
MathNode::MathNode()
: ShaderNode(node_type)
{
}
bool MathNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized)
{
ShaderInput *value1_in = input("Value1");
ShaderInput *value2_in = input("Value2");
if(value1_in->link == NULL && value2_in->link == NULL) {
float value = svm_math(type, value1, value2);
if(use_clamp) {
value = saturate(value);
}
optimized->set(value);
return true;
}
return false;
}
void MathNode::compile(SVMCompiler& compiler)
{
ShaderInput *value1_in = input("Value1");
ShaderInput *value2_in = input("Value2");
ShaderOutput *value_out = output("Value");
compiler.add_node(NODE_MATH, type, compiler.stack_assign(value1_in), compiler.stack_assign(value2_in));
compiler.add_node(NODE_MATH, compiler.stack_assign(value_out));
if(use_clamp) {
compiler.add_node(NODE_MATH, NODE_MATH_CLAMP, compiler.stack_assign(value_out));
compiler.add_node(NODE_MATH, compiler.stack_assign(value_out));
}
}
void MathNode::compile(OSLCompiler& compiler)
{
compiler.parameter(this, "type");
compiler.parameter(this, "use_clamp");
compiler.add(this, "node_math");
}
/* VectorMath */
NODE_DEFINE(VectorMathNode)
{
NodeType* type = NodeType::add("vector_math", create, NodeType::SHADER);
static NodeEnum type_enum;
type_enum.insert("add", NODE_VECTOR_MATH_ADD);
type_enum.insert("subtract", NODE_VECTOR_MATH_SUBTRACT);
type_enum.insert("average", NODE_VECTOR_MATH_AVERAGE);
type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT);
type_enum.insert("cross_product", NODE_VECTOR_MATH_CROSS_PRODUCT);
type_enum.insert("normalize", NODE_VECTOR_MATH_NORMALIZE);
SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_MATH_ADD);
SOCKET_IN_VECTOR(vector1, "Vector1", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_VECTOR(vector2, "Vector2", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_FLOAT(value, "Value");
SOCKET_OUT_VECTOR(vector, "Vector");
return type;
}
VectorMathNode::VectorMathNode()
: ShaderNode(node_type)
{
}
bool VectorMathNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized)
{
ShaderInput *vector1_in = input("Vector1");
ShaderInput *vector2_in = input("Vector2");
float value;
float3 vector;
if(vector1_in->link == NULL && vector2_in->link == NULL) {
svm_vector_math(&value,
&vector,
type,
vector1,
vector2);
if(socket == output("Value")) {
optimized->set(value);
return true;
}
else if(socket == output("Vector")) {
optimized->set(vector);
return true;
}
}
return false;
}
void VectorMathNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector1_in = input("Vector1");
ShaderInput *vector2_in = input("Vector2");
ShaderOutput *value_out = output("Value");
ShaderOutput *vector_out = output("Vector");
compiler.add_node(NODE_VECTOR_MATH,
type,
compiler.stack_assign(vector1_in),
compiler.stack_assign(vector2_in));
compiler.add_node(NODE_VECTOR_MATH,
compiler.stack_assign(value_out),
compiler.stack_assign(vector_out));
}
void VectorMathNode::compile(OSLCompiler& compiler)
{
compiler.parameter(this, "type");
compiler.add(this, "node_vector_math");
}
/* VectorTransform */
NODE_DEFINE(VectorTransformNode)
{
NodeType* type = NodeType::add("vector_transform", create, NodeType::SHADER);
static NodeEnum type_enum;
type_enum.insert("vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
type_enum.insert("point", NODE_VECTOR_TRANSFORM_TYPE_POINT);
type_enum.insert("normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
static NodeEnum space_enum;
space_enum.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
space_enum.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
space_enum.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA);
SOCKET_ENUM(convert_from, "Convert From", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
SOCKET_ENUM(convert_to, "Convert To", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
SOCKET_IN_VECTOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_VECTOR(vector, "Vector");
return type;
}
VectorTransformNode::VectorTransformNode()
: ShaderNode(node_type)
{
}
void VectorTransformNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector_in = input("Vector");
ShaderOutput *vector_out = output("Vector");
compiler.add_node(NODE_VECTOR_TRANSFORM,
compiler.encode_uchar4(type, convert_from, convert_to),
compiler.encode_uchar4(compiler.stack_assign(vector_in),
compiler.stack_assign(vector_out)));
}
void VectorTransformNode::compile(OSLCompiler& compiler)
{
compiler.parameter(this, "type");
compiler.parameter(this, "convert_from");
compiler.parameter(this, "convert_to");
compiler.add(this, "node_vector_transform");
}
/* BumpNode */
NODE_DEFINE(BumpNode)
{
NodeType* type = NodeType::add("bump", create, NodeType::SHADER);
SOCKET_BOOLEAN(invert, "Invert", false);
/* this input is used by the user, but after graph transform it is no longer
* used and moved to sampler center/x/y instead */
SOCKET_IN_FLOAT(height, "Height", 1.0f);
SOCKET_IN_FLOAT(sample_center, "SampleCenter", 0.0f);
SOCKET_IN_FLOAT(sample_x, "SampleX", 0.0f);
SOCKET_IN_FLOAT(sample_y, "SampleY", 0.0f);
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
SOCKET_IN_FLOAT(distance, "Distance", 0.1f);
SOCKET_OUT_NORMAL(normal, "Normal");
return type;
}
BumpNode::BumpNode()
: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_BUMP;
}
void BumpNode::compile(SVMCompiler& compiler)
{
ShaderInput *center_in = input("SampleCenter");
ShaderInput *dx_in = input("SampleX");
ShaderInput *dy_in = input("SampleY");
ShaderInput *normal_in = input("Normal");
ShaderInput *strength_in = input("Strength");
ShaderInput *distance_in = input("Distance");
ShaderOutput *normal_out = output("Normal");
/* pack all parameters in the node */
compiler.add_node(NODE_SET_BUMP,
compiler.encode_uchar4(
compiler.stack_assign_if_linked(normal_in),
compiler.stack_assign(distance_in),
invert),
compiler.encode_uchar4(
compiler.stack_assign(center_in),
compiler.stack_assign(dx_in),
compiler.stack_assign(dy_in),
compiler.stack_assign(strength_in)),
compiler.stack_assign(normal_out));
}
void BumpNode::compile(OSLCompiler& compiler)
{
compiler.parameter(this, "invert");
compiler.add(this, "node_bump");
}
bool BumpNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *)
{
ShaderInput *height_in = input("Height");
ShaderInput *normal_in = input("Normal");
if(height_in->link == NULL) {
if(normal_in->link == NULL) {
GeometryNode *geom = new GeometryNode();
graph->add(geom);
graph->relink(this, outputs[0], geom->output("Normal"));
}
else {
graph->relink(this, outputs[0], normal_in->link);
}
return true;
}
/* TODO(sergey): Ignore bump with zero strength. */
return false;
}
2012-03-26 12:45:14 +00:00
/* RGBCurvesNode */
NODE_DEFINE(RGBCurvesNode)
2012-03-26 12:45:14 +00:00
{
NodeType* type = NodeType::add("rgb_curves", create, NodeType::SHADER);
SOCKET_COLOR_ARRAY(curves, "Curves", array<float3>());
SOCKET_FLOAT(min_x, "Min X", 0.0f);
SOCKET_FLOAT(max_x, "Max X", 1.0f);
SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_COLOR(color, "Color");
return type;
}
RGBCurvesNode::RGBCurvesNode()
: ShaderNode(node_type)
{
2012-03-26 12:45:14 +00:00
}
void RGBCurvesNode::compile(SVMCompiler& compiler)
{
if(curves.size() == 0)
return;
2012-03-26 12:45:14 +00:00
ShaderInput *fac_in = input("Fac");
ShaderInput *color_in = input("Color");
ShaderOutput *color_out = output("Color");
compiler.add_node(NODE_RGB_CURVES,
compiler.encode_uchar4(compiler.stack_assign(fac_in),
compiler.stack_assign(color_in),
compiler.stack_assign(color_out)),
__float_as_int(min_x),
__float_as_int(max_x));
compiler.add_node(curves.size());
for(int i = 0; i < curves.size(); i++)
compiler.add_node(float3_to_float4(curves[i]));
2012-03-26 12:45:14 +00:00
}
void RGBCurvesNode::compile(OSLCompiler& compiler)
{
if(curves.size() == 0)
return;
compiler.parameter_color_array("ramp", curves);
compiler.parameter(this, "min_x");
compiler.parameter(this, "max_x");
2012-03-26 12:45:14 +00:00
compiler.add(this, "node_rgb_curves");
}
/* VectorCurvesNode */
NODE_DEFINE(VectorCurvesNode)
{
NodeType* type = NodeType::add("vector_curves", create, NodeType::SHADER);
SOCKET_VECTOR_ARRAY(curves, "Curves", array<float3>());
SOCKET_FLOAT(min_x, "Min X", 0.0f);
SOCKET_FLOAT(max_x, "Max X", 1.0f);
SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
SOCKET_IN_VECTOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_VECTOR(vector, "Vector");
return type;
}
VectorCurvesNode::VectorCurvesNode()
: ShaderNode(node_type)
{
}
void VectorCurvesNode::compile(SVMCompiler& compiler)
{
if(curves.size() == 0)
return;
ShaderInput *fac_in = input("Fac");
ShaderInput *vector_in = input("Vector");
ShaderOutput *vector_out = output("Vector");
compiler.add_node(NODE_VECTOR_CURVES,
compiler.encode_uchar4(compiler.stack_assign(fac_in),
compiler.stack_assign(vector_in),
compiler.stack_assign(vector_out)),
__float_as_int(min_x),
__float_as_int(max_x));
compiler.add_node(curves.size());
for(int i = 0; i < curves.size(); i++)
compiler.add_node(float3_to_float4(curves[i]));
}
void VectorCurvesNode::compile(OSLCompiler& compiler)
{
if(curves.size() == 0)
return;
compiler.parameter_color_array("ramp", curves);
compiler.parameter(this, "min_x");
compiler.parameter(this, "max_x");
compiler.add(this, "node_vector_curves");
}
2012-03-26 12:45:14 +00:00
/* RGBRampNode */
NODE_DEFINE(RGBRampNode)
2012-03-26 12:45:14 +00:00
{
NodeType* type = NodeType::add("rgb_ramp", create, NodeType::SHADER);
SOCKET_COLOR_ARRAY(ramp, "Ramp", array<float3>());
SOCKET_FLOAT_ARRAY(ramp_alpha, "Ramp Alpha", array<float>());
SOCKET_BOOLEAN(interpolate, "Interpolate", true);
SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_FLOAT(alpha, "Alpha");
return type;
}
RGBRampNode::RGBRampNode()
: ShaderNode(node_type)
{
2012-03-26 12:45:14 +00:00
}
void RGBRampNode::compile(SVMCompiler& compiler)
{
if(ramp.size() == 0 || ramp.size() != ramp_alpha.size())
return;
2012-03-26 12:45:14 +00:00
ShaderInput *fac_in = input("Fac");
ShaderOutput *color_out = output("Color");
ShaderOutput *alpha_out = output("Alpha");
2012-03-26 12:45:14 +00:00
compiler.add_node(NODE_RGB_RAMP,
compiler.encode_uchar4(
compiler.stack_assign(fac_in),
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out)),
interpolate);
compiler.add_node(ramp.size());
for(int i = 0; i < ramp.size(); i++)
compiler.add_node(make_float4(ramp[i].x, ramp[i].y, ramp[i].z, ramp_alpha[i]));
2012-03-26 12:45:14 +00:00
}
void RGBRampNode::compile(OSLCompiler& compiler)
{
if(ramp.size() == 0 || ramp.size() != ramp_alpha.size())
return;
compiler.parameter_color_array("ramp_color", ramp);
compiler.parameter_array("ramp_alpha", ramp_alpha.data(), ramp_alpha.size());
compiler.parameter(this, "interpolate");
2012-03-26 12:45:14 +00:00
compiler.add(this, "node_rgb_ramp");
}
/* Set Normal Node */
NODE_DEFINE(SetNormalNode)
{
NodeType* type = NodeType::add("set_normal", create, NodeType::SHADER);
SOCKET_IN_VECTOR(direction, "Direction", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_NORMAL(normal, "Normal");
return type;
}
SetNormalNode::SetNormalNode()
: ShaderNode(node_type)
{
}
void SetNormalNode::compile(SVMCompiler& compiler)
{
ShaderInput *direction_in = input("Direction");
ShaderOutput *normal_out = output("Normal");
compiler.add_node(NODE_CLOSURE_SET_NORMAL,
compiler.stack_assign(direction_in),
compiler.stack_assign(normal_out));
}
void SetNormalNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_set_normal");
}
/* OSLNode */
OSLNode::OSLNode()
: ShaderNode(new NodeType(NodeType::SHADER))
{
special_type = SHADER_SPECIAL_TYPE_SCRIPT;
}
OSLNode::~OSLNode()
{
delete type;
}
OSLNode* OSLNode::create(size_t num_inputs)
{
/* allocate space for the node itself and parameters, aligned to 16 bytes
* assuming that's the most parameter types need */
size_t node_size = align_up(sizeof(OSLNode), 16);
size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs;
char *node_memory = (char*) operator new(node_size + inputs_size);
memset(node_memory, 0, node_size + inputs_size);
return new(node_memory) OSLNode();
}
char* OSLNode::input_default_value()
{
/* pointer to default value storage, which is the same as our actual value */
size_t num_inputs = type->inputs.size();
size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs;
return (char*)this + align_up(sizeof(OSLNode), 16) + inputs_size;
}
void OSLNode::add_input(ustring name, SocketType::Type socket_type)
{
char *memory = input_default_value();
size_t offset = memory - (char*)this;
const_cast<NodeType*>(type)->register_input(name, name, socket_type, offset, memory, NULL, NULL, SocketType::LINKABLE);
}
void OSLNode::add_output(ustring name, SocketType::Type socket_type)
{
const_cast<NodeType*>(type)->register_output(name, name, socket_type);
}
void OSLNode::compile(SVMCompiler&)
{
/* doesn't work for SVM, obviously ... */
}
void OSLNode::compile(OSLCompiler& compiler)
{
if(!filepath.empty())
compiler.add(this, filepath.c_str(), true);
else
compiler.add(this, bytecode_hash.c_str(), false);
}
/* Normal Map */
NODE_DEFINE(NormalMapNode)
{
NodeType* type = NodeType::add("normal_map", create, NodeType::SHADER);
static NodeEnum space_enum;
space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT);
space_enum.insert("object", NODE_NORMAL_MAP_OBJECT);
space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
space_enum.insert("blender_object", NODE_NORMAL_MAP_BLENDER_OBJECT);
space_enum.insert("blender_world", NODE_NORMAL_MAP_BLENDER_WORLD);
SOCKET_ENUM(space, "Space", space_enum, NODE_TANGENT_RADIAL);
SOCKET_STRING(attribute, "Attribute", ustring(""));
SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 1.0f));
SOCKET_OUT_NORMAL(normal, "Normal");
return type;
}
NormalMapNode::NormalMapNode()
: ShaderNode(node_type)
{
}
void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
attributes->add(ATTR_STD_UV_TANGENT);
attributes->add(ATTR_STD_UV_TANGENT_SIGN);
}
else {
attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
}
attributes->add(ATTR_STD_VERTEX_NORMAL);
}
ShaderNode::attributes(shader, attributes);
}
void NormalMapNode::compile(SVMCompiler& compiler)
{
ShaderInput *color_in = input("Color");
ShaderInput *strength_in = input("Strength");
ShaderOutput *normal_out = output("Normal");
int attr = 0, attr_sign = 0;
if(space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
}
else {
attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
attr_sign = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
}
}
compiler.add_node(NODE_NORMAL_MAP,
compiler.encode_uchar4(
compiler.stack_assign(color_in),
compiler.stack_assign(strength_in),
compiler.stack_assign(normal_out),
space),
attr, attr_sign);
}
void NormalMapNode::compile(OSLCompiler& compiler)
{
if(space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
compiler.parameter("attr_name", ustring("geom:tangent"));
compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
}
else {
compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
compiler.parameter("attr_sign_name", ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
}
}
compiler.parameter(this, "space");
compiler.add(this, "node_normal_map");
}
/* Tangent */
NODE_DEFINE(TangentNode)
{
NodeType* type = NodeType::add("tangent", create, NodeType::SHADER);
static NodeEnum direction_type_enum;
direction_type_enum.insert("radial", NODE_TANGENT_RADIAL);
direction_type_enum.insert("uv_map", NODE_TANGENT_UVMAP);
SOCKET_ENUM(direction_type, "Direction Type", direction_type_enum, NODE_TANGENT_RADIAL);
static NodeEnum axis_enum;
axis_enum.insert("x", NODE_TANGENT_AXIS_X);
axis_enum.insert("y", NODE_TANGENT_AXIS_Y);
axis_enum.insert("z", NODE_TANGENT_AXIS_Z);
SOCKET_ENUM(axis, "Axis", axis_enum, NODE_TANGENT_AXIS_X);
SOCKET_STRING(attribute, "Attribute", ustring(""));
SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
SOCKET_OUT_NORMAL(tangent, "Tangent");
return type;
}
TangentNode::TangentNode()
: ShaderNode(node_type)
{
}
void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface) {
if(direction_type == NODE_TANGENT_UVMAP) {
if(attribute == ustring(""))
attributes->add(ATTR_STD_UV_TANGENT);
else
attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
}
else
attributes->add(ATTR_STD_GENERATED);
}
ShaderNode::attributes(shader, attributes);
}
void TangentNode::compile(SVMCompiler& compiler)
{
ShaderOutput *tangent_out = output("Tangent");
int attr;
if(direction_type == NODE_TANGENT_UVMAP) {
if(attribute == ustring(""))
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
else
attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
}
else
attr = compiler.attribute(ATTR_STD_GENERATED);
compiler.add_node(NODE_TANGENT,
compiler.encode_uchar4(
compiler.stack_assign(tangent_out),
direction_type,
axis), attr);
}
void TangentNode::compile(OSLCompiler& compiler)
{
if(direction_type == NODE_TANGENT_UVMAP) {
if(attribute == ustring(""))
compiler.parameter("attr_name", ustring("geom:tangent"));
else
compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
}
compiler.parameter(this, "direction_type");
compiler.parameter(this, "axis");
compiler.add(this, "node_tangent");
}
CCL_NAMESPACE_END