Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles/scene')
-rw-r--r--intern/cycles/scene/osl.cpp284
-rw-r--r--intern/cycles/scene/osl.h18
-rw-r--r--intern/cycles/scene/scene.cpp7
-rw-r--r--intern/cycles/scene/shader.cpp9
-rw-r--r--intern/cycles/scene/shader.h2
-rw-r--r--intern/cycles/scene/shader_nodes.cpp10
-rw-r--r--intern/cycles/scene/shader_nodes.h9
7 files changed, 179 insertions, 160 deletions
diff --git a/intern/cycles/scene/osl.cpp b/intern/cycles/scene/osl.cpp
index 93839facdbe..4dc5fb4edf7 100644
--- a/intern/cycles/scene/osl.cpp
+++ b/intern/cycles/scene/osl.cpp
@@ -38,16 +38,17 @@ OSL::TextureSystem *OSLShaderManager::ts_shared = NULL;
int OSLShaderManager::ts_shared_users = 0;
thread_mutex OSLShaderManager::ts_shared_mutex;
-OSL::ShadingSystem *OSLShaderManager::ss_shared = NULL;
-OSLRenderServices *OSLShaderManager::services_shared = NULL;
+OSL::ErrorHandler OSLShaderManager::errhandler;
+map<int, OSL::ShadingSystem *> OSLShaderManager::ss_shared;
int OSLShaderManager::ss_shared_users = 0;
thread_mutex OSLShaderManager::ss_shared_mutex;
thread_mutex OSLShaderManager::ss_mutex;
+
int OSLCompiler::texture_shared_unique_id = 0;
/* Shader Manager */
-OSLShaderManager::OSLShaderManager()
+OSLShaderManager::OSLShaderManager(Device *device) : device_(device)
{
texture_system_init();
shading_system_init();
@@ -107,11 +108,12 @@ void OSLShaderManager::device_update_specific(Device *device,
device_free(device, dscene, scene);
- /* set texture system */
- scene->image_manager->set_osl_texture_system((void *)ts);
+ /* set texture system (only on CPU devices, since GPU devices cannot use OIIO) */
+ if (device->info.type == DEVICE_CPU) {
+ scene->image_manager->set_osl_texture_system((void *)ts_shared);
+ }
/* create shaders */
- OSLGlobals *og = (OSLGlobals *)device->get_cpu_osl_memory();
Shader *background_shader = scene->background->get_shader(scene);
foreach (Shader *shader, scene->shaders) {
@@ -125,22 +127,34 @@ void OSLShaderManager::device_update_specific(Device *device,
* compile shaders alternating */
thread_scoped_lock lock(ss_mutex);
- OSLCompiler compiler(this, services, ss, scene);
- compiler.background = (shader == background_shader);
- compiler.compile(og, shader);
+ device->foreach_device(
+ [this, scene, shader, background = (shader == background_shader)](Device *sub_device) {
+ OSLGlobals *og = (OSLGlobals *)sub_device->get_cpu_osl_memory();
+ OSL::ShadingSystem *ss = ss_shared[sub_device->info.type];
+
+ OSLCompiler compiler(this, ss, scene);
+ compiler.background = background;
+ compiler.compile(og, shader);
+ });
if (shader->get_use_mis() && shader->has_surface_emission)
scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED);
}
/* setup shader engine */
- og->ss = ss;
- og->ts = ts;
- og->services = services;
-
int background_id = scene->shader_manager->get_shader_id(background_shader);
- og->background_state = og->surface_state[background_id & SHADER_MASK];
- og->use = true;
+
+ device->foreach_device([background_id](Device *sub_device) {
+ OSLGlobals *og = (OSLGlobals *)sub_device->get_cpu_osl_memory();
+ OSL::ShadingSystem *ss = ss_shared[sub_device->info.type];
+
+ og->ss = ss;
+ og->ts = ts_shared;
+ og->services = static_cast<OSLRenderServices *>(ss->renderer());
+
+ og->background_state = og->surface_state[background_id & SHADER_MASK];
+ og->use = true;
+ });
foreach (Shader *shader, scene->shaders)
shader->clear_modified();
@@ -148,8 +162,12 @@ void OSLShaderManager::device_update_specific(Device *device,
update_flags = UPDATE_NONE;
/* add special builtin texture types */
- services->textures.insert(ustring("@ao"), new OSLTextureHandle(OSLTextureHandle::AO));
- services->textures.insert(ustring("@bevel"), new OSLTextureHandle(OSLTextureHandle::BEVEL));
+ for (const auto &[device_type, ss] : ss_shared) {
+ OSLRenderServices *services = static_cast<OSLRenderServices *>(ss->renderer());
+
+ services->textures.insert(ustring("@ao"), new OSLTextureHandle(OSLTextureHandle::AO));
+ services->textures.insert(ustring("@bevel"), new OSLTextureHandle(OSLTextureHandle::BEVEL));
+ }
device_update_common(device, dscene, scene, progress);
@@ -166,26 +184,35 @@ void OSLShaderManager::device_update_specific(Device *device,
* is being freed after the Session is freed.
*/
thread_scoped_lock lock(ss_shared_mutex);
- ss->optimize_all_groups();
+ for (const auto &[device_type, ss] : ss_shared) {
+ ss->optimize_all_groups();
+ }
+ }
+
+ /* load kernels */
+ if (!device->load_osl_kernels()) {
+ progress.set_error(device->error_message());
}
}
void OSLShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
{
- OSLGlobals *og = (OSLGlobals *)device->get_cpu_osl_memory();
-
device_free_common(device, dscene, scene);
/* clear shader engine */
- og->use = false;
- og->ss = NULL;
- og->ts = NULL;
-
- og->surface_state.clear();
- og->volume_state.clear();
- og->displacement_state.clear();
- og->bump_state.clear();
- og->background_state.reset();
+ device->foreach_device([](Device *sub_device) {
+ OSLGlobals *og = (OSLGlobals *)sub_device->get_cpu_osl_memory();
+
+ og->use = false;
+ og->ss = NULL;
+ og->ts = NULL;
+
+ og->surface_state.clear();
+ og->volume_state.clear();
+ og->displacement_state.clear();
+ og->bump_state.clear();
+ og->background_state.reset();
+ });
}
void OSLShaderManager::texture_system_init()
@@ -193,7 +220,7 @@ void OSLShaderManager::texture_system_init()
/* create texture system, shared between different renders to reduce memory usage */
thread_scoped_lock lock(ts_shared_mutex);
- if (ts_shared_users == 0) {
+ if (ts_shared_users++ == 0) {
ts_shared = TextureSystem::create(true);
ts_shared->attribute("automip", 1);
@@ -203,24 +230,18 @@ void OSLShaderManager::texture_system_init()
/* effectively unlimited for now, until we support proper mipmap lookups */
ts_shared->attribute("max_memory_MB", 16384);
}
-
- ts = ts_shared;
- ts_shared_users++;
}
void OSLShaderManager::texture_system_free()
{
/* shared texture system decrease users and destroy if no longer used */
thread_scoped_lock lock(ts_shared_mutex);
- ts_shared_users--;
- if (ts_shared_users == 0) {
+ if (--ts_shared_users == 0) {
ts_shared->invalidate_all(true);
OSL::TextureSystem::destroy(ts_shared);
ts_shared = NULL;
}
-
- ts = NULL;
}
void OSLShaderManager::shading_system_init()
@@ -228,101 +249,105 @@ void OSLShaderManager::shading_system_init()
/* create shading system, shared between different renders to reduce memory usage */
thread_scoped_lock lock(ss_shared_mutex);
- if (ss_shared_users == 0) {
- /* Must use aligned new due to concurrent hash map. */
- services_shared = util_aligned_new<OSLRenderServices>(ts_shared);
+ device_->foreach_device([](Device *sub_device) {
+ const DeviceType device_type = sub_device->info.type;
- string shader_path = path_get("shader");
+ if (ss_shared_users++ == 0 || ss_shared.find(device_type) == ss_shared.end()) {
+ /* Must use aligned new due to concurrent hash map. */
+ OSLRenderServices *services = util_aligned_new<OSLRenderServices>(ts_shared, device_type);
+
+ string shader_path = path_get("shader");
# ifdef _WIN32
- /* Annoying thing, Cycles stores paths in UTF-8 codepage, so it can
- * operate with file paths with any character. This requires to use wide
- * char functions, but OSL uses old fashioned ANSI functions which means:
- *
- * - We have to convert our paths to ANSI before passing to OSL
- * - OSL can't be used when there's a multi-byte character in the path
- * to the shaders folder.
- */
- shader_path = string_to_ansi(shader_path);
+ /* Annoying thing, Cycles stores paths in UTF-8 codepage, so it can
+ * operate with file paths with any character. This requires to use wide
+ * char functions, but OSL uses old fashioned ANSI functions which means:
+ *
+ * - We have to convert our paths to ANSI before passing to OSL
+ * - OSL can't be used when there's a multi-byte character in the path
+ * to the shaders folder.
+ */
+ shader_path = string_to_ansi(shader_path);
# endif
- ss_shared = new OSL::ShadingSystem(services_shared, ts_shared, &errhandler);
- ss_shared->attribute("lockgeom", 1);
- ss_shared->attribute("commonspace", "world");
- ss_shared->attribute("searchpath:shader", shader_path);
- ss_shared->attribute("greedyjit", 1);
-
- VLOG_INFO << "Using shader search path: " << shader_path;
-
- /* our own ray types */
- static const char *raytypes[] = {
- "camera", /* PATH_RAY_CAMERA */
- "reflection", /* PATH_RAY_REFLECT */
- "refraction", /* PATH_RAY_TRANSMIT */
- "diffuse", /* PATH_RAY_DIFFUSE */
- "glossy", /* PATH_RAY_GLOSSY */
- "singular", /* PATH_RAY_SINGULAR */
- "transparent", /* PATH_RAY_TRANSPARENT */
- "volume_scatter", /* PATH_RAY_VOLUME_SCATTER */
-
- "shadow", /* PATH_RAY_SHADOW_OPAQUE */
- "shadow", /* PATH_RAY_SHADOW_TRANSPARENT */
-
- "__unused__", /* PATH_RAY_NODE_UNALIGNED */
- "__unused__", /* PATH_RAY_MIS_SKIP */
-
- "diffuse_ancestor", /* PATH_RAY_DIFFUSE_ANCESTOR */
-
- /* Remaining irrelevant bits up to 32. */
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- "__unused__",
- };
-
- const int nraytypes = sizeof(raytypes) / sizeof(raytypes[0]);
- ss_shared->attribute("raytypes", TypeDesc(TypeDesc::STRING, nraytypes), raytypes);
-
- OSLRenderServices::register_closures(ss_shared);
-
- loaded_shaders.clear();
- }
+ OSL::ShadingSystem *ss = new OSL::ShadingSystem(services, ts_shared, &errhandler);
+ ss->attribute("lockgeom", 1);
+ ss->attribute("commonspace", "world");
+ ss->attribute("searchpath:shader", shader_path);
+ ss->attribute("greedyjit", 1);
+
+ VLOG_INFO << "Using shader search path: " << shader_path;
+
+ /* our own ray types */
+ static const char *raytypes[] = {
+ "camera", /* PATH_RAY_CAMERA */
+ "reflection", /* PATH_RAY_REFLECT */
+ "refraction", /* PATH_RAY_TRANSMIT */
+ "diffuse", /* PATH_RAY_DIFFUSE */
+ "glossy", /* PATH_RAY_GLOSSY */
+ "singular", /* PATH_RAY_SINGULAR */
+ "transparent", /* PATH_RAY_TRANSPARENT */
+ "volume_scatter", /* PATH_RAY_VOLUME_SCATTER */
+
+ "shadow", /* PATH_RAY_SHADOW_OPAQUE */
+ "shadow", /* PATH_RAY_SHADOW_TRANSPARENT */
+
+ "__unused__", /* PATH_RAY_NODE_UNALIGNED */
+ "__unused__", /* PATH_RAY_MIS_SKIP */
+
+ "diffuse_ancestor", /* PATH_RAY_DIFFUSE_ANCESTOR */
+
+ /* Remaining irrelevant bits up to 32. */
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ };
+
+ const int nraytypes = sizeof(raytypes) / sizeof(raytypes[0]);
+ ss->attribute("raytypes", TypeDesc(TypeDesc::STRING, nraytypes), raytypes);
+
+ OSLRenderServices::register_closures(ss);
+
+ ss_shared[device_type] = ss;
+ }
+ });
- ss = ss_shared;
- services = services_shared;
- ss_shared_users++;
+ loaded_shaders.clear();
}
void OSLShaderManager::shading_system_free()
{
/* shared shading system decrease users and destroy if no longer used */
thread_scoped_lock lock(ss_shared_mutex);
- ss_shared_users--;
- if (ss_shared_users == 0) {
- delete ss_shared;
- ss_shared = NULL;
+ device_->foreach_device([](Device * /*sub_device*/) {
+ if (--ss_shared_users == 0) {
+ for (const auto &[device_type, ss] : ss_shared) {
+ OSLRenderServices *services = static_cast<OSLRenderServices *>(ss->renderer());
- util_aligned_delete(services_shared);
- services_shared = NULL;
- }
+ delete ss;
+
+ util_aligned_delete(services);
+ }
- ss = NULL;
- services = NULL;
+ ss_shared.clear();
+ }
+ });
}
bool OSLShaderManager::osl_compile(const string &inputfile, const string &outputfile)
@@ -447,7 +472,9 @@ const char *OSLShaderManager::shader_load_filepath(string filepath)
const char *OSLShaderManager::shader_load_bytecode(const string &hash, const string &bytecode)
{
- ss->LoadMemoryCompiledShader(hash.c_str(), bytecode.c_str());
+ for (const auto &[device_type, ss] : ss_shared) {
+ ss->LoadMemoryCompiledShader(hash.c_str(), bytecode.c_str());
+ }
OSLShaderInfo info;
@@ -599,11 +626,11 @@ OSLNode *OSLShaderManager::osl_node(ShaderGraph *graph,
/* Graph Compiler */
-OSLCompiler::OSLCompiler(OSLShaderManager *manager,
- OSLRenderServices *services,
- OSL::ShadingSystem *ss,
- Scene *scene)
- : scene(scene), manager(manager), services(services), ss(ss)
+OSLCompiler::OSLCompiler(OSLShaderManager *manager, OSL::ShadingSystem *ss, Scene *scene)
+ : scene(scene),
+ manager(manager),
+ services(static_cast<OSLRenderServices *>(ss->renderer())),
+ ss(ss)
{
current_type = SHADER_TYPE_SURFACE;
current_shader = NULL;
@@ -614,6 +641,8 @@ string OSLCompiler::id(ShaderNode *node)
{
/* assign layer unique name based on pointer address + bump mode */
stringstream stream;
+ stream.imbue(std::locale("C")); /* Ensure that no grouping characters (e.g. commas with en_US
+ locale) are added to the pointer string */
stream << "node_" << node->type->name << "_" << node;
return stream.str();
@@ -1105,7 +1134,12 @@ OSL::ShaderGroupRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph
{
current_type = type;
- OSL::ShaderGroupRef group = ss->ShaderGroupBegin(shader->name.c_str());
+ /* Use name hash to identify shader group to avoid issues with non-alphanumeric characters */
+ stringstream name;
+ name.imbue(std::locale("C"));
+ name << "shader_" << shader->name.hash();
+
+ OSL::ShaderGroupRef group = ss->ShaderGroupBegin(name.str());
ShaderNode *output = graph->output();
ShaderNodeSet dependencies;
diff --git a/intern/cycles/scene/osl.h b/intern/cycles/scene/osl.h
index 76c6bd96ce1..c0e82a9dc8d 100644
--- a/intern/cycles/scene/osl.h
+++ b/intern/cycles/scene/osl.h
@@ -54,7 +54,7 @@ struct OSLShaderInfo {
class OSLShaderManager : public ShaderManager {
public:
- OSLShaderManager();
+ OSLShaderManager(Device *device);
~OSLShaderManager();
static void free_memory();
@@ -92,25 +92,22 @@ class OSLShaderManager : public ShaderManager {
const std::string &bytecode_hash = "",
const std::string &bytecode = "");
- protected:
+ private:
void texture_system_init();
void texture_system_free();
void shading_system_init();
void shading_system_free();
- OSL::ShadingSystem *ss;
- OSL::TextureSystem *ts;
- OSLRenderServices *services;
- OSL::ErrorHandler errhandler;
+ Device *device_;
map<string, OSLShaderInfo> loaded_shaders;
static OSL::TextureSystem *ts_shared;
static thread_mutex ts_shared_mutex;
static int ts_shared_users;
- static OSL::ShadingSystem *ss_shared;
- static OSLRenderServices *services_shared;
+ static OSL::ErrorHandler errhandler;
+ static map<int, OSL::ShadingSystem *> ss_shared;
static thread_mutex ss_shared_mutex;
static thread_mutex ss_mutex;
static int ss_shared_users;
@@ -123,10 +120,7 @@ class OSLShaderManager : public ShaderManager {
class OSLCompiler {
public:
#ifdef WITH_OSL
- OSLCompiler(OSLShaderManager *manager,
- OSLRenderServices *services,
- OSL::ShadingSystem *shadingsys,
- Scene *scene);
+ OSLCompiler(OSLShaderManager *manager, OSL::ShadingSystem *shadingsys, Scene *scene);
#endif
void compile(OSLGlobals *og, Shader *shader);
diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp
index 3a05bede7a3..d5be86e1db9 100644
--- a/intern/cycles/scene/scene.cpp
+++ b/intern/cycles/scene/scene.cpp
@@ -99,11 +99,8 @@ Scene::Scene(const SceneParams &params_, Device *device)
{
memset((void *)&dscene.data, 0, sizeof(dscene.data));
- /* OSL only works on the CPU */
- if (device->info.has_osl)
- shader_manager = ShaderManager::create(params.shadingsystem);
- else
- shader_manager = ShaderManager::create(SHADINGSYSTEM_SVM);
+ shader_manager = ShaderManager::create(
+ device->info.has_osl ? params.shadingsystem : SHADINGSYSTEM_SVM, device);
light_manager = new LightManager();
geometry_manager = new GeometryManager();
diff --git a/intern/cycles/scene/shader.cpp b/intern/cycles/scene/shader.cpp
index 56670c6e4e3..f176c19ec95 100644
--- a/intern/cycles/scene/shader.cpp
+++ b/intern/cycles/scene/shader.cpp
@@ -395,15 +395,16 @@ ShaderManager::~ShaderManager()
{
}
-ShaderManager *ShaderManager::create(int shadingsystem)
+ShaderManager *ShaderManager::create(int shadingsystem, Device *device)
{
ShaderManager *manager;
(void)shadingsystem; /* Ignored when built without OSL. */
+ (void)device;
#ifdef WITH_OSL
if (shadingsystem == SHADINGSYSTEM_OSL) {
- manager = new OSLShaderManager();
+ manager = new OSLShaderManager(device);
}
else
#endif
@@ -722,6 +723,10 @@ uint ShaderManager::get_kernel_features(Scene *scene)
}
}
+ if (use_osl()) {
+ kernel_features |= KERNEL_FEATURE_OSL;
+ }
+
return kernel_features;
}
diff --git a/intern/cycles/scene/shader.h b/intern/cycles/scene/shader.h
index 2670776aca4..69b22d2ad19 100644
--- a/intern/cycles/scene/shader.h
+++ b/intern/cycles/scene/shader.h
@@ -170,7 +170,7 @@ class ShaderManager {
UPDATE_NONE = 0u,
};
- static ShaderManager *create(int shadingsystem);
+ static ShaderManager *create(int shadingsystem, Device *device);
virtual ~ShaderManager();
virtual void reset(Scene *scene) = 0;
diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp
index a9cd453947b..2c1cd3ee737 100644
--- a/intern/cycles/scene/shader_nodes.cpp
+++ b/intern/cycles/scene/shader_nodes.cpp
@@ -3677,9 +3677,6 @@ NODE_DEFINE(GeometryNode)
{
NodeType *type = NodeType::add("geometry", create, NodeType::SHADER);
- SOCKET_IN_NORMAL(
- normal_osl, "NormalIn", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
-
SOCKET_OUT_POINT(position, "Position");
SOCKET_OUT_NORMAL(normal, "Normal");
SOCKET_OUT_NORMAL(tangent, "Tangent");
@@ -3812,9 +3809,6 @@ NODE_DEFINE(TextureCoordinateNode)
SOCKET_BOOLEAN(use_transform, "Use Transform", false);
SOCKET_TRANSFORM(ob_tfm, "Object Transform", transform_identity());
- SOCKET_IN_NORMAL(
- normal_osl, "NormalIn", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
-
SOCKET_OUT_POINT(generated, "Generated");
SOCKET_OUT_NORMAL(normal, "Normal");
SOCKET_OUT_POINT(UV, "UV");
@@ -7305,8 +7299,6 @@ NODE_DEFINE(NormalMapNode)
SOCKET_STRING(attribute, "Attribute", ustring());
- SOCKET_IN_NORMAL(
- normal_osl, "NormalIn", zero_float3(), 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));
@@ -7400,8 +7392,6 @@ NODE_DEFINE(TangentNode)
SOCKET_STRING(attribute, "Attribute", ustring());
- SOCKET_IN_NORMAL(
- normal_osl, "NormalIn", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
SOCKET_OUT_NORMAL(tangent, "Tangent");
return type;
diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h
index cc3a71a0697..9b4d27b5b31 100644
--- a/intern/cycles/scene/shader_nodes.h
+++ b/intern/cycles/scene/shader_nodes.h
@@ -907,8 +907,6 @@ class GeometryNode : public ShaderNode {
return true;
}
int get_group();
-
- NODE_SOCKET_API(float3, normal_osl)
};
class TextureCoordinateNode : public ShaderNode {
@@ -924,7 +922,6 @@ class TextureCoordinateNode : public ShaderNode {
return true;
}
- NODE_SOCKET_API(float3, normal_osl)
NODE_SOCKET_API(bool, from_dupli)
NODE_SOCKET_API(bool, use_transform)
NODE_SOCKET_API(Transform, ob_tfm)
@@ -1542,6 +1539,10 @@ class OSLNode final : public ShaderNode {
{
return true;
}
+ virtual int get_feature()
+ {
+ return ShaderNode::get_feature() | KERNEL_FEATURE_NODE_RAYTRACE;
+ }
virtual bool equals(const ShaderNode & /*other*/)
{
@@ -1569,7 +1570,6 @@ class NormalMapNode : public ShaderNode {
NODE_SOCKET_API(ustring, attribute)
NODE_SOCKET_API(float, strength)
NODE_SOCKET_API(float3, color)
- NODE_SOCKET_API(float3, normal_osl)
};
class TangentNode : public ShaderNode {
@@ -1588,7 +1588,6 @@ class TangentNode : public ShaderNode {
NODE_SOCKET_API(NodeTangentDirectionType, direction_type)
NODE_SOCKET_API(NodeTangentAxis, axis)
NODE_SOCKET_API(ustring, attribute)
- NODE_SOCKET_API(float3, normal_osl)
};
class BevelNode : public ShaderNode {