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:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2012-11-06 23:59:02 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2012-11-06 23:59:02 +0400
commit27d647dcf8c5d9ea46133761c899bce0860e0fa2 (patch)
tree8c3ef1e71c55f5e79be2a73a1650c2a61a50a8d2
parentccffb6811c9db614047e9dba0eb5e509609128dc (diff)
Cycles: 4 new nodes.
* Tangent: generate a tangent direction for anisotropic shading. Can be either radial around X/Y/Z axis, or from a UV map. The default tangent for the anisotropic BSDF and geometry node is now always radial Z, for UV tangent use this node now. http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes/More#Tangent * Normal Map: generate a perturbed normal from an RGB normal map image. This is usually chained with an Image Texture node in the color input, to specify the normal map image. For tangent space normal maps, the UV coordinates for the image must match, and the image texture should be set to Non-Color mode to give correct results. http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes/More#Normal_Map * Refraction BSDF: for best results this node should be considered as a building block and not be used on its own, but rather mixed with a glossy node using a fresnel type factor. Otherwise it will give quite dark results at the edges for glossy refraction. http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes/Shaders#Refraction * Ambient Occlusion: controls the amount of AO a surface receives, rather than having just a global factor in the world. Note that this outputs a shader and not a color, that's for another time. http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes/Shaders#Ambient_Occlusion
-rw-r--r--intern/cycles/blender/blender_mesh.cpp106
-rw-r--r--intern/cycles/blender/blender_shader.cpp38
-rw-r--r--intern/cycles/kernel/closure/bsdf_ward.h10
-rw-r--r--intern/cycles/kernel/kernel_path.h9
-rw-r--r--intern/cycles/kernel/kernel_shader.h21
-rw-r--r--intern/cycles/kernel/kernel_types.h13
-rw-r--r--intern/cycles/kernel/osl/background.cpp27
-rw-r--r--intern/cycles/kernel/osl/osl_closures.cpp2
-rw-r--r--intern/cycles/kernel/osl/osl_closures.h6
-rw-r--r--intern/cycles/kernel/osl/osl_shader.cpp14
-rw-r--r--intern/cycles/kernel/shaders/CMakeLists.txt12
-rw-r--r--intern/cycles/kernel/shaders/node_ambient_occlusion.osl27
-rw-r--r--intern/cycles/kernel/shaders/node_geometry.osl21
-rw-r--r--intern/cycles/kernel/shaders/node_normal_map.osl48
-rw-r--r--intern/cycles/kernel/shaders/node_refraction_bsdf.osl39
-rw-r--r--intern/cycles/kernel/shaders/node_tangent.osl50
-rw-r--r--intern/cycles/kernel/shaders/node_ward_bsdf.osl8
-rw-r--r--intern/cycles/kernel/shaders/stdosl.h1
-rw-r--r--intern/cycles/kernel/svm/svm.h9
-rw-r--r--intern/cycles/kernel/svm/svm_closure.h73
-rw-r--r--intern/cycles/kernel/svm/svm_geometry.h23
-rw-r--r--intern/cycles/kernel/svm/svm_tex_coord.h86
-rw-r--r--intern/cycles/kernel/svm/svm_types.h28
-rw-r--r--intern/cycles/render/attribute.cpp4
-rw-r--r--intern/cycles/render/nodes.cpp264
-rw-r--r--intern/cycles/render/nodes.h38
-rw-r--r--intern/cycles/util/util_attribute.cpp4
-rw-r--r--intern/cycles/util/util_types.h3
-rw-r--r--source/blender/blenkernel/BKE_node.h4
-rw-r--r--source/blender/blenkernel/intern/node.c4
-rw-r--r--source/blender/editors/space_node/drawnode.c31
-rw-r--r--source/blender/makesdna/DNA_node_types.h25
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c61
-rw-r--r--source/blender/makesrna/intern/rna_nodetree_types.h6
-rw-r--r--source/blender/nodes/CMakeLists.txt28
-rw-r--r--source/blender/nodes/NOD_shader.h4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c63
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c68
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c69
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tangent.c60
40 files changed, 1280 insertions, 127 deletions
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index 0e13479a761..69b330db483 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -116,7 +116,7 @@ static void mikk_set_tangent_space(const SMikkTSpaceContext *context, const floa
userdata->tangent[face*4 + vert] = make_float4(T[0], T[1], T[2], sign);
}
-static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_layer, Mesh *mesh, vector<int>& nverts)
+static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_layer, Mesh *mesh, vector<int>& nverts, bool need_sign, bool active_render)
{
/* setup userdata */
MikkUserData userdata(b_mesh, b_layer, nverts.size());
@@ -140,22 +140,57 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_la
/* compute tangents */
genTangSpaceDefault(&context);
- /* create attribute */
- /* todo: create float4 attribute for sign */
- Attribute *attr = mesh->attributes.add(ATTR_STD_TANGENT, ustring("tangent"));
+ /* create tangent attributes */
+ Attribute *attr;
+ ustring name = ustring((string(b_layer.name().c_str()) + ".tangent").c_str());
+
+ if(active_render)
+ attr = mesh->attributes.add(ATTR_STD_UV_TANGENT, name);
+ else
+ attr = mesh->attributes.add(name, TypeDesc::TypeVector, Attribute::CORNER);
+
float3 *tangent = attr->data_float3();
- for (int i = 0; i < nverts.size(); i++) {
+ /* create bitangent sign attribute */
+ float *tangent_sign = NULL;
+
+ if(need_sign) {
+ Attribute *attr_sign;
+ ustring name_sign = ustring((string(b_layer.name().c_str()) + ".tangent_sign").c_str());
+
+ if(active_render)
+ attr_sign = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign);
+ else
+ attr_sign = mesh->attributes.add(name_sign, TypeDesc::TypeFloat, Attribute::CORNER);
+
+ tangent_sign = attr_sign->data_float();
+ }
+
+ for(int i = 0; i < nverts.size(); i++) {
tangent[0] = float4_to_float3(userdata.tangent[i*4 + 0]);
tangent[1] = float4_to_float3(userdata.tangent[i*4 + 1]);
tangent[2] = float4_to_float3(userdata.tangent[i*4 + 2]);
tangent += 3;
+ if(tangent_sign) {
+ tangent_sign[0] = userdata.tangent[i*4 + 0].w;
+ tangent_sign[1] = userdata.tangent[i*4 + 1].w;
+ tangent_sign[2] = userdata.tangent[i*4 + 2].w;
+ tangent_sign += 3;
+ }
+
if(nverts[i] == 4) {
tangent[0] = float4_to_float3(userdata.tangent[i*4 + 0]);
tangent[1] = float4_to_float3(userdata.tangent[i*4 + 2]);
tangent[2] = float4_to_float3(userdata.tangent[i*4 + 3]);
tangent += 3;
+
+ if(tangent_sign) {
+ tangent_sign[0] = userdata.tangent[i*4 + 0].w;
+ tangent_sign[1] = userdata.tangent[i*4 + 2].w;
+ tangent_sign[2] = userdata.tangent[i*4 + 3].w;
+ tangent_sign += 3;
+ }
}
}
}
@@ -233,48 +268,49 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
BL::Mesh::tessface_uv_textures_iterator l;
for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
- AttributeStandard std = (l->active_render())? ATTR_STD_UV: ATTR_STD_NONE;
+ bool active_render = l->active_render();
+ AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
ustring name = ustring(l->name().c_str());
- if(!(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)))
- continue;
+ /* UV map */
+ if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
+ Attribute *attr;
- Attribute *attr;
-
- if(l->active_render())
- attr = mesh->attributes.add(std, name);
- else
- attr = mesh->attributes.add(name, TypeDesc::TypePoint, Attribute::CORNER);
-
- BL::MeshTextureFaceLayer::data_iterator t;
- float3 *fdata = attr->data_float3();
- size_t i = 0;
+ if(active_render)
+ attr = mesh->attributes.add(std, name);
+ else
+ attr = mesh->attributes.add(name, TypeDesc::TypePoint, Attribute::CORNER);
- for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
- fdata[0] = get_float3(t->uv1());
- fdata[1] = get_float3(t->uv2());
- fdata[2] = get_float3(t->uv3());
- fdata += 3;
+ BL::MeshTextureFaceLayer::data_iterator t;
+ float3 *fdata = attr->data_float3();
+ size_t i = 0;
- if(nverts[i] == 4) {
+ for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
fdata[0] = get_float3(t->uv1());
- fdata[1] = get_float3(t->uv3());
- fdata[2] = get_float3(t->uv4());
+ fdata[1] = get_float3(t->uv2());
+ fdata[2] = get_float3(t->uv3());
fdata += 3;
+
+ if(nverts[i] == 4) {
+ fdata[0] = get_float3(t->uv1());
+ fdata[1] = get_float3(t->uv3());
+ fdata[2] = get_float3(t->uv4());
+ fdata += 3;
+ }
}
}
- }
- }
- /* create texcoord-based tangent attributes */
- if(mesh->need_attribute(scene, ATTR_STD_TANGENT)) {
- BL::Mesh::tessface_uv_textures_iterator l;
+ /* UV tangent */
+ std = (active_render)? ATTR_STD_UV_TANGENT: ATTR_STD_NONE;
+ name = ustring((string(name.c_str()) + ".tangent").c_str());
- for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
- if(!l->active_render())
- continue;
+ if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
+ std = (active_render)? ATTR_STD_UV_TANGENT_SIGN: ATTR_STD_NONE;
+ name = ustring((string(name.c_str()) + ".tangent_sign").c_str());
+ bool need_sign = (mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std));
- mikk_compute_tangents(b_mesh, *l, mesh, nverts);
+ mikk_compute_tangents(b_mesh, *l, mesh, nverts, need_sign, active_render);
+ }
}
}
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 1f8d86a7f70..6dc0bbdb90e 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -173,6 +173,7 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
case BL::ShaderNode::type_OUTPUT: break;
case BL::ShaderNode::type_SQUEEZE: break;
case BL::ShaderNode::type_TEXTURE: break;
+ case BL::ShaderNode::type_FRAME: break;
/* handled outside this function */
case BL::ShaderNode::type_GROUP: break;
/* existing blender nodes */
@@ -366,6 +367,23 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
node = glass;
break;
}
+ case BL::ShaderNode::type_BSDF_REFRACTION: {
+ BL::ShaderNodeBsdfRefraction b_refraction_node(b_node);
+ RefractionBsdfNode *refraction = new RefractionBsdfNode();
+ switch(b_refraction_node.distribution()) {
+ case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
+ refraction->distribution = ustring("Sharp");
+ break;
+ case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
+ refraction->distribution = ustring("Beckmann");
+ break;
+ case BL::ShaderNodeBsdfRefraction::distribution_GGX:
+ refraction->distribution = ustring("GGX");
+ break;
+ }
+ node = refraction;
+ break;
+ }
case BL::ShaderNode::type_BSDF_TRANSLUCENT: {
node = new TranslucentBsdfNode();
break;
@@ -382,6 +400,10 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
node = new EmissionNode();
break;
}
+ case BL::ShaderNode::type_AMBIENT_OCCLUSION: {
+ node = new AmbientOcclusionNode();
+ break;
+ }
case BL::ShaderNode::type_VOLUME_ISOTROPIC: {
node = new IsotropicVolumeNode();
break;
@@ -573,7 +595,21 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
node = sky;
break;
}
- case BL::ShaderNode::type_FRAME: {
+ case BL::ShaderNode::type_NORMAL_MAP: {
+ BL::ShaderNodeNormalMap b_normal_map_node(b_node);
+ NormalMapNode *nmap = new NormalMapNode();
+ nmap->space = NormalMapNode::space_enum[(int)b_normal_map_node.space()];
+ nmap->attribute = b_normal_map_node.uv_map();
+ node = nmap;
+ break;
+ }
+ case BL::ShaderNode::type_TANGENT: {
+ BL::ShaderNodeTangent b_tangent_node(b_node);
+ TangentNode *tangent = new TangentNode();
+ tangent->direction_type = TangentNode::direction_type_enum[(int)b_tangent_node.direction_type()];
+ tangent->axis = TangentNode::axis_enum[(int)b_tangent_node.axis()];
+ tangent->attribute = b_tangent_node.uv_map();
+ node = tangent;
break;
}
}
diff --git a/intern/cycles/kernel/closure/bsdf_ward.h b/intern/cycles/kernel/closure/bsdf_ward.h
index 9c81548a2c3..dbddcf20dba 100644
--- a/intern/cycles/kernel/closure/bsdf_ward.h
+++ b/intern/cycles/kernel/closure/bsdf_ward.h
@@ -68,7 +68,10 @@ __device float3 bsdf_ward_eval_reflect(const ShaderClosure *sc, const float3 I,
float cosNO = dot(N, I);
float cosNI = dot(N, omega_in);
- if(cosNI > 0 && cosNO > 0) {
+ if(cosNI > 0.0f && cosNO > 0.0f) {
+ cosNO = max(cosNO, 1e-4f);
+ cosNI = max(cosNI, 1e-4f);
+
// get half vector and get x,y basis on the surface for anisotropy
float3 H = normalize(omega_in + I); // normalize needed for pdf
float3 X, Y;
@@ -103,7 +106,7 @@ __device int bsdf_ward_sample(const ShaderClosure *sc, float3 Ng, float3 I, floa
float3 T = sc->T;
float cosNO = dot(N, I);
- if(cosNO > 0) {
+ if(cosNO > 0.0f) {
// get x,y basis on the surface for anisotropy
float3 X, Y;
make_orthonormals_tangent(N, T, &X, &Y);
@@ -165,6 +168,9 @@ __device int bsdf_ward_sample(const ShaderClosure *sc, float3 Ng, float3 I, floa
if(dot(Ng, *omega_in) > 0) {
float cosNI = dot(N, *omega_in);
if(cosNI > 0) {
+ cosNO = max(cosNO, 1e-4f);
+ cosNI = max(cosNI, 1e-4f);
+
// eq. 9
float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn);
float denom = 4 * M_PI_F * m_ax * m_ay * oh * dotn * dotn * dotn;
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 817f254a5e5..585068ce8e2 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -326,7 +326,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
#ifdef __AO__
/* ambient occlusion */
- if(kernel_data.integrator.use_ambient_occlusion) {
+ if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
/* todo: solve correlation */
float bsdf_u = path_rng(kg, rng, sample, rng_offset + PRNG_BSDF_U);
float bsdf_v = path_rng(kg, rng, sample, rng_offset + PRNG_BSDF_V);
@@ -349,6 +349,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow)) {
float3 ao_bsdf = shader_bsdf_diffuse(kg, &sd)*kernel_data.background.ao_factor;
+ ao_bsdf += shader_bsdf_ao(kg, &sd);
path_radiance_accum_ao(&L, throughput, ao_bsdf, ao_shadow, state.bounce);
}
}
@@ -503,7 +504,7 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
#ifdef __AO__
/* ambient occlusion */
- if(kernel_data.integrator.use_ambient_occlusion) {
+ if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
/* todo: solve correlation */
float bsdf_u = path_rng(kg, rng, sample, rng_offset + PRNG_BSDF_U);
float bsdf_v = path_rng(kg, rng, sample, rng_offset + PRNG_BSDF_V);
@@ -526,6 +527,7 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow)) {
float3 ao_bsdf = shader_bsdf_diffuse(kg, &sd)*kernel_data.background.ao_factor;
+ ao_bsdf += shader_bsdf_ao(kg, &sd);
path_radiance_accum_ao(L, throughput, ao_bsdf, ao_shadow, state.bounce);
}
}
@@ -706,7 +708,7 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
#ifdef __AO__
/* ambient occlusion */
- if(kernel_data.integrator.use_ambient_occlusion) {
+ if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
int num_samples = kernel_data.integrator.ao_samples;
float num_samples_inv = 1.0f/num_samples;
float ao_factor = kernel_data.background.ao_factor;
@@ -734,6 +736,7 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow)) {
float3 ao_bsdf = shader_bsdf_diffuse(kg, &sd)*ao_factor;
+ ao_bsdf += shader_bsdf_ao(kg, &sd);
path_radiance_accum_ao(&L, throughput*num_samples_inv, ao_bsdf, ao_shadow, state.bounce);
}
}
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index 86886a6a231..1af5e048ad9 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -599,6 +599,27 @@ __device float3 shader_bsdf_transmission(KernelGlobals *kg, ShaderData *sd)
#endif
}
+__device float3 shader_bsdf_ao(KernelGlobals *kg, ShaderData *sd)
+{
+#ifdef __MULTI_CLOSURE__
+ float3 eval = make_float3(0.0f, 0.0f, 0.0f);
+
+ for(int i = 0; i< sd->num_closure; i++) {
+ ShaderClosure *sc = &sd->closure[i];
+
+ if(CLOSURE_IS_AMBIENT_OCCLUSION(sc->type))
+ eval += sc->weight;
+ }
+
+ return eval;
+#else
+ if(CLOSURE_IS_AMBIENT_OCCLUSION(sd->closure.type))
+ return sd->closure.weight;
+ else
+ return make_float3(0.0f, 0.0f, 0.0f);
+#endif
+}
+
/* Emission */
__device float3 shader_emissive_eval(KernelGlobals *kg, ShaderData *sd)
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 98d998351a7..d4d88466688 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -393,16 +393,17 @@ enum ShaderDataFlag {
SD_BSDF_GLOSSY = 16, /* have glossy bsdf */
SD_HOLDOUT = 32, /* have holdout closure? */
SD_VOLUME = 64, /* have volume closure? */
+ SD_AO = 128, /* have ao closure? */
/* shader flags */
- SD_SAMPLE_AS_LIGHT = 128, /* direct light sample */
- SD_HAS_SURFACE_TRANSPARENT = 256, /* has surface transparency */
- SD_HAS_VOLUME = 512, /* has volume shader */
- SD_HOMOGENEOUS_VOLUME = 1024, /* has homogeneous volume */
+ SD_SAMPLE_AS_LIGHT = 256, /* direct light sample */
+ SD_HAS_SURFACE_TRANSPARENT = 512, /* has surface transparency */
+ SD_HAS_VOLUME = 1024, /* has volume shader */
+ SD_HOMOGENEOUS_VOLUME = 2048, /* has homogeneous volume */
/* object flags */
- SD_HOLDOUT_MASK = 2048, /* holdout for camera rays */
- SD_OBJECT_MOTION = 4096 /* has object motion blur */
+ SD_HOLDOUT_MASK = 4096, /* holdout for camera rays */
+ SD_OBJECT_MOTION = 8192 /* has object motion blur */
};
typedef struct ShaderData {
diff --git a/intern/cycles/kernel/osl/background.cpp b/intern/cycles/kernel/osl/background.cpp
index b6e9473b7bf..eed4446cddc 100644
--- a/intern/cycles/kernel/osl/background.cpp
+++ b/intern/cycles/kernel/osl/background.cpp
@@ -73,6 +73,22 @@ public:
void print_on(std::ostream &out) const { out << name() << " ()"; }
};
+/// ambient occlusion closure
+///
+/// We only have a ambient occlusion closure for the shaders
+/// to return a color in ambient occlusion shaders. No methods,
+/// only the weight is taking into account
+///
+class AmbientOcclusionClosure : public ClosurePrimitive {
+public:
+ AmbientOcclusionClosure () : ClosurePrimitive((ClosurePrimitive::Category)AmbientOcclusion) {}
+
+ void setup() {};
+ size_t memsize() const { return sizeof(*this); }
+ const char *name() const { return "ambient_occlusion"; }
+ void print_on(std::ostream &out) const { out << name() << " ()"; }
+};
+
ClosureParam *closure_background_params()
{
static ClosureParam params[] = {
@@ -94,5 +110,16 @@ ClosureParam *closure_holdout_params()
CLOSURE_PREPARE(closure_holdout_prepare, HoldoutClosure)
+ClosureParam *closure_ambient_occlusion_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(AmbientOcclusionClosure)
+ };
+ return params;
+}
+
+CLOSURE_PREPARE(closure_ambient_occlusion_prepare, AmbientOcclusionClosure)
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp
index 73e96643df7..de572d0e585 100644
--- a/intern/cycles/kernel/osl/osl_closures.cpp
+++ b/intern/cycles/kernel/osl/osl_closures.cpp
@@ -190,6 +190,8 @@ void OSLShader::register_closures(OSL::ShadingSystem *ss)
closure_background_params(), closure_background_prepare);
register_closure(ss, "holdout", id++,
closure_holdout_params(), closure_holdout_prepare);
+ register_closure(ss, "ambient_occlusion", id++,
+ closure_ambient_occlusion_params(), closure_ambient_occlusion_prepare);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h
index 574cb685db5..9137bad58d3 100644
--- a/intern/cycles/kernel/osl/osl_closures.h
+++ b/intern/cycles/kernel/osl/osl_closures.h
@@ -46,10 +46,16 @@ CCL_NAMESPACE_BEGIN
OSL::ClosureParam *closure_emission_params();
OSL::ClosureParam *closure_background_params();
OSL::ClosureParam *closure_holdout_params();
+OSL::ClosureParam *closure_ambient_occlusion_params();
void closure_emission_prepare(OSL::RendererServices *, int id, void *data);
void closure_background_prepare(OSL::RendererServices *, int id, void *data);
void closure_holdout_prepare(OSL::RendererServices *, int id, void *data);
+void closure_ambient_occlusion_prepare(OSL::RendererServices *, int id, void *data);
+
+enum {
+ AmbientOcclusion = 100
+};
#define CLOSURE_PREPARE(name, classname) \
void name(RendererServices *, int id, void *data) \
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
index 8b71ac30ab6..5d26f543efc 100644
--- a/intern/cycles/kernel/osl/osl_shader.cpp
+++ b/intern/cycles/kernel/osl/osl_shader.cpp
@@ -159,6 +159,20 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
sd->closure[sd->num_closure++] = sc;
break;
}
+ case AmbientOcclusion: {
+ if (sd->num_closure == MAX_CLOSURE)
+ return;
+
+ /* sample weight */
+ float sample_weight = fabsf(average(weight));
+
+ sc.sample_weight = sample_weight;
+ sc.type = CLOSURE_AMBIENT_OCCLUSION_ID;
+
+ sd->closure[sd->num_closure++] = sc;
+ sd->flag |= SD_AO;
+ break;
+ }
case OSL::ClosurePrimitive::Holdout:
if (sd->num_closure == MAX_CLOSURE)
return;
diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt
index 00ab52a1d13..4f5a97c1bb6 100644
--- a/intern/cycles/kernel/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/shaders/CMakeLists.txt
@@ -3,9 +3,11 @@
set(SRC_OSL
node_add_closure.osl
+ node_ambient_occlusion.osl
node_attribute.osl
node_background.osl
node_brick_texture.osl
+ node_brightness.osl
node_bump.osl
node_camera.osl
node_checker_texture.osl
@@ -21,35 +23,37 @@ set(SRC_OSL
node_environment_texture.osl
node_fresnel.osl
node_gamma.osl
- node_gradient_texture.osl
- node_brightness.osl
node_geometry.osl
node_glass_bsdf.osl
node_glossy_bsdf.osl
+ node_gradient_texture.osl
node_holdout.osl
node_hsv.osl
node_image_texture.osl
node_invert.osl
node_layer_weight.osl
- node_light_path.osl
node_light_falloff.osl
+ node_light_path.osl
node_magic_texture.osl
node_mapping.osl
node_math.osl
node_mix.osl
node_mix_closure.osl
node_musgrave_texture.osl
- node_normal.osl
node_noise_texture.osl
+ node_normal.osl
+ node_normal_map.osl
node_object_info.osl
node_output_displacement.osl
node_output_surface.osl
node_output_volume.osl
node_particle_info.osl
+ node_refraction_bsdf.osl
node_rgb_ramp.osl
node_separate_rgb.osl
node_set_normal.osl
node_sky_texture.osl
+ node_tangent.osl
node_texture_coordinate.osl
node_translucent_bsdf.osl
node_transparent_bsdf.osl
diff --git a/intern/cycles/kernel/shaders/node_ambient_occlusion.osl b/intern/cycles/kernel/shaders/node_ambient_occlusion.osl
new file mode 100644
index 00000000000..57a06f35461
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_ambient_occlusion.osl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_ambient_occlusion(
+ color Color = color(0.8, 0.8, 0.8),
+ output closure color AO = ambient_occlusion())
+{
+ AO = Color * ambient_occlusion();
+}
+
diff --git a/intern/cycles/kernel/shaders/node_geometry.osl b/intern/cycles/kernel/shaders/node_geometry.osl
index 953c5d1fa2b..3940b98eec1 100644
--- a/intern/cycles/kernel/shaders/node_geometry.osl
+++ b/intern/cycles/kernel/shaders/node_geometry.osl
@@ -47,26 +47,17 @@ shader node_geometry(
}
/* first try to get tangent attribute */
- vector T;
+ point generated;
- if (getattribute("geom:tangent", T)) {
- /* ensure orthogonal and normalized (interpolation breaks it) */
+ /* try to create spherical tangent from generated coordinates */
+ if (getattribute("geom:generated", generated)) {
+ vector T = vector(-(generated[1] - 0.5), (generated[0] - 0.5), 0.0);
T = transform("object", "world", T);
Tangent = cross(Normal, normalize(cross(T, Normal)));
}
else {
- point generated;
-
- /* try to create spherical tangent from generated coordinates */
- if (getattribute("geom:generated", generated)) {
- T = vector(-(generated[1] - 0.5), (generated[0] - 0.5), 0.0);
- T = transform("object", "world", T);
- Tangent = cross(Normal, normalize(cross(T, Normal)));
- }
- else {
- /* otherwise use surface derivatives */
- Tangent = normalize(dPdu);
- }
+ /* otherwise use surface derivatives */
+ Tangent = normalize(dPdu);
}
}
diff --git a/intern/cycles/kernel/shaders/node_normal_map.osl b/intern/cycles/kernel/shaders/node_normal_map.osl
new file mode 100644
index 00000000000..e238313509e
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_normal_map.osl
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_normal_map(
+ normal NormalIn = N,
+ color Color = color(0.5, 0.5, 1.0),
+ string space = "Tangent",
+ string attr_name = "geom:tangent",
+ string attr_sign_name = "geom:tangent_sign",
+ output normal Normal = NormalIn)
+{
+ color mcolor = 2.0*color(Color[0] - 0.5, Color[1] - 0.5, Color[2] - 0.5);
+
+ if (space == "Tangent") {
+ vector tangent;
+ float tangent_sign;
+
+ getattribute(attr_name, tangent);
+ getattribute(attr_sign_name, tangent_sign);
+
+ tangent = transform("object", "world", tangent);
+
+ vector B = tangent_sign * cross(NormalIn, tangent);
+ Normal = normalize(mcolor[0] * tangent + mcolor[1] * B + mcolor[2] * NormalIn);
+ }
+ else if (space == "Object")
+ Normal = normalize(transform("object", "world", vector(mcolor)));
+ else if (space == "World")
+ Normal = normalize(vector(mcolor));
+}
+
diff --git a/intern/cycles/kernel/shaders/node_refraction_bsdf.osl b/intern/cycles/kernel/shaders/node_refraction_bsdf.osl
new file mode 100644
index 00000000000..0cf9d460c6e
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_refraction_bsdf.osl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_refraction_bsdf(
+ color Color = color(0.8, 0.8, 0.8),
+ string distribution = "Sharp",
+ float Roughness = 0.2,
+ float IOR = 1.45,
+ normal Normal = N,
+ output closure color BSDF = diffuse(Normal))
+{
+ float f = max(IOR, 1.0 + 1e-5);
+ float eta = backfacing() ? 1.0 / f: f;
+
+ if (distribution == "Sharp")
+ BSDF = Color * refraction(Normal, eta);
+ else if (distribution == "Beckmann")
+ BSDF = Color * microfacet_beckmann_refraction(Normal, Roughness, eta);
+ else if (distribution == "GGX")
+ BSDF = Color * microfacet_ggx_refraction(Normal, Roughness, eta);
+}
+
diff --git a/intern/cycles/kernel/shaders/node_tangent.osl b/intern/cycles/kernel/shaders/node_tangent.osl
new file mode 100644
index 00000000000..731af89231a
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_tangent.osl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_tangent(
+ normal NormalIn = N,
+ string attr_name = "geom:tangent",
+ string direction_type = "Radial",
+ string axis = "Z",
+ output normal Tangent = normalize(dPdu))
+{
+ vector T;
+
+ if (direction_type == "UV Map") {
+ getattribute(attr_name, T);
+ }
+ else if (direction_type == "Radial") {
+ point generated;
+
+ if (!getattribute("geom:generated", generated))
+ generated = P;
+
+ if (axis == "X")
+ T = vector(0.0, -(generated[2] - 0.5), (generated[1] - 0.5));
+ else if (axis == "Y")
+ T = vector(-(generated[2] - 0.5), 0.0, (generated[0] - 0.5));
+ else
+ T = vector(-(generated[1] - 0.5), (generated[0] - 0.5), 0.0);
+ }
+
+ T = transform("object", "world", T);
+ Tangent = cross(NormalIn, normalize(cross(T, NormalIn)));
+}
+
diff --git a/intern/cycles/kernel/shaders/node_ward_bsdf.osl b/intern/cycles/kernel/shaders/node_ward_bsdf.osl
index 03a0477038e..e5c6f0ad705 100644
--- a/intern/cycles/kernel/shaders/node_ward_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_ward_bsdf.osl
@@ -38,12 +38,12 @@ shader node_ward_bsdf(
float aniso = clamp(Anisotropy, -0.99, 0.99);
if(aniso < 0.0) {
- RoughnessU = Roughness*(1.0 + aniso);
- RoughnessV = Roughness/(1.0 + aniso);
+ RoughnessU = Roughness/(1.0 + aniso);
+ RoughnessV = Roughness*(1.0 + aniso);
}
else {
- RoughnessU = Roughness/(1.0 - aniso);
- RoughnessV = Roughness*(1.0 - aniso);
+ RoughnessU = Roughness*(1.0 - aniso);
+ RoughnessV = Roughness/(1.0 - aniso);
}
BSDF = Color * ward(Normal, T, RoughnessU, RoughnessV);
diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h
index 4237291c7a4..c55def2b47a 100644
--- a/intern/cycles/kernel/shaders/stdosl.h
+++ b/intern/cycles/kernel/shaders/stdosl.h
@@ -446,6 +446,7 @@ closure color ashikhmin_velvet(normal N, float sigma) BUILTIN;
closure color emission() BUILTIN;
closure color background() BUILTIN;
closure color holdout() BUILTIN;
+closure color ambient_occlusion() BUILTIN;
// Renderer state
int raytype (string typename) BUILTIN;
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index 698ef5016f0..886fce63fd4 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -215,6 +215,9 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT
case NODE_CLOSURE_HOLDOUT:
svm_node_closure_holdout(sd, stack, node);
break;
+ case NODE_CLOSURE_AMBIENT_OCCLUSION:
+ svm_node_closure_ambient_occlusion(sd, stack, node);
+ break;
case NODE_CLOSURE_VOLUME:
svm_node_closure_volume(kg, sd, stack, node, path_flag);
break;
@@ -398,6 +401,12 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT
case NODE_LIGHT_FALLOFF:
svm_node_light_falloff(sd, stack, node);
break;
+ case NODE_TANGENT:
+ svm_node_tangent(kg, sd, stack, node);
+ break;
+ case NODE_NORMAL_MAP:
+ svm_node_normal_map(kg, sd, stack, node);
+ break;
#endif
case NODE_END:
default:
diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h
index 11ce3b7c5d1..f378d24463d 100644
--- a/intern/cycles/kernel/svm/svm_closure.h
+++ b/intern/cycles/kernel/svm/svm_closure.h
@@ -20,9 +20,9 @@ CCL_NAMESPACE_BEGIN
/* Closure Nodes */
-__device void svm_node_glossy_setup(ShaderData *sd, ShaderClosure *sc, int type, float eta, float roughness, bool refract)
+__device void svm_node_glass_setup(ShaderData *sd, ShaderClosure *sc, int type, float eta, float roughness, bool refract)
{
- if(type == CLOSURE_BSDF_REFRACTION_ID) {
+ if(type == CLOSURE_BSDF_SHARP_GLASS_ID) {
if(refract) {
sc->data0 = eta;
sd->flag |= bsdf_refraction_setup(sc);
@@ -30,7 +30,7 @@ __device void svm_node_glossy_setup(ShaderData *sd, ShaderClosure *sc, int type,
else
sd->flag |= bsdf_reflection_setup(sc);
}
- else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID) {
+ else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID) {
sc->data0 = roughness;
sc->data1 = eta;
@@ -159,6 +159,31 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
if(kernel_data.integrator.no_caustics && (path_flag & PATH_RAY_DIFFUSE))
break;
#endif
+ ShaderClosure *sc = svm_node_closure_get(sd);
+ sc->N = N;
+ sc->data0 = param1;
+ svm_node_closure_set_mix_weight(sc, mix_weight);
+
+ float eta = fmaxf(param2, 1.0f + 1e-5f);
+ sc->data1 = (sd->flag & SD_BACKFACING)? 1.0f/eta: eta;
+
+ /* setup bsdf */
+ if(type == CLOSURE_BSDF_REFRACTION_ID)
+ sd->flag |= bsdf_refraction_setup(sc);
+ else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID)
+ sd->flag |= bsdf_microfacet_beckmann_refraction_setup(sc);
+ else
+ sd->flag |= bsdf_microfacet_ggx_refraction_setup(sc);
+
+ break;
+ }
+ case CLOSURE_BSDF_SHARP_GLASS_ID:
+ case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID:
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: {
+#ifdef __CAUSTICS_TRICKS__
+ if(kernel_data.integrator.no_caustics && (path_flag & PATH_RAY_DIFFUSE))
+ break;
+#endif
/* index of refraction */
float eta = fmaxf(param2, 1.0f + 1e-5f);
eta = (sd->flag & SD_BACKFACING)? 1.0f/eta: eta;
@@ -177,7 +202,7 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
float sample_weight = sc->sample_weight;
svm_node_closure_set_mix_weight(sc, mix_weight*fresnel);
- svm_node_glossy_setup(sd, sc, type, eta, roughness, false);
+ svm_node_glass_setup(sd, sc, type, eta, roughness, false);
/* refraction */
sc = svm_node_closure_get(sd);
@@ -187,7 +212,7 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
sc->sample_weight = sample_weight;
svm_node_closure_set_mix_weight(sc, mix_weight*(1.0f - fresnel));
- svm_node_glossy_setup(sd, sc, type, eta, roughness, true);
+ svm_node_glass_setup(sd, sc, type, eta, roughness, true);
#else
ShaderClosure *sc = svm_node_closure_get(sd);
sc->N = N;
@@ -195,7 +220,7 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
bool refract = (randb > fresnel);
svm_node_closure_set_mix_weight(sc, mix_weight);
- svm_node_glossy_setup(sd, sc, type, eta, roughness, refract);
+ svm_node_glass_setup(sd, sc, type, eta, roughness, refract);
#endif
break;
@@ -222,12 +247,12 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
float anisotropy = clamp(param2, -0.99f, 0.99f);
if(anisotropy < 0.0f) {
- sc->data0 = roughness*(1.0f + anisotropy);
- sc->data1 = roughness/(1.0f + anisotropy);
+ sc->data0 = roughness/(1.0f + anisotropy);
+ sc->data1 = roughness*(1.0f + anisotropy);
}
else {
- sc->data0 = roughness/(1.0f - anisotropy);
- sc->data1 = roughness*(1.0f - anisotropy);
+ sc->data0 = roughness*(1.0f - anisotropy);
+ sc->data1 = roughness/(1.0f - anisotropy);
}
sd->flag |= bsdf_ward_setup(sc);
@@ -372,6 +397,34 @@ __device void svm_node_closure_holdout(ShaderData *sd, float *stack, uint4 node)
sd->flag |= SD_HOLDOUT;
}
+__device void svm_node_closure_ambient_occlusion(ShaderData *sd, float *stack, uint4 node)
+{
+#ifdef __MULTI_CLOSURE__
+ uint mix_weight_offset = node.y;
+
+ if(stack_valid(mix_weight_offset)) {
+ float mix_weight = stack_load_float(stack, mix_weight_offset);
+
+ if(mix_weight == 0.0f)
+ return;
+
+ ShaderClosure *sc = svm_node_closure_get(sd);
+ sc->weight *= mix_weight;
+ sc->type = CLOSURE_AMBIENT_OCCLUSION_ID;
+ }
+ else {
+ ShaderClosure *sc = svm_node_closure_get(sd);
+ sc->type = CLOSURE_AMBIENT_OCCLUSION_ID;
+ }
+
+#else
+ ShaderClosure *sc = &sd->closure;
+ sc->type = CLOSURE_AMBIENT_OCCLUSION_ID;
+#endif
+
+ sd->flag |= SD_AO;
+}
+
/* Closure Nodes */
__device_inline void svm_node_closure_store_weight(ShaderData *sd, float3 weight)
diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h
index 8e772f849c7..68177493f4e 100644
--- a/intern/cycles/kernel/svm/svm_geometry.h
+++ b/intern/cycles/kernel/svm/svm_geometry.h
@@ -29,29 +29,18 @@ __device void svm_node_geometry(KernelGlobals *kg, ShaderData *sd, float *stack,
case NODE_GEOM_N: data = sd->N; break;
#ifdef __DPDU__
case NODE_GEOM_T: {
- /* first try to get tangent attribute */
- int attr_offset = (sd->object != ~0)? find_attribute(kg, sd, ATTR_STD_TANGENT): ATTR_STD_NOT_FOUND;
+ /* try to create spherical tangent from generated coordinates */
+ int attr_offset = (sd->object != ~0)? find_attribute(kg, sd, ATTR_STD_GENERATED): ATTR_STD_NOT_FOUND;
if(attr_offset != ATTR_STD_NOT_FOUND) {
- /* ensure orthogonal and normalized (interpolation breaks it) */
- data = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, attr_offset, NULL, NULL);
+ data = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, attr_offset, NULL, NULL);
+ data = make_float3(-(data.y - 0.5), (data.x - 0.5), 0.0f);
object_normal_transform(kg, sd, &data);
data = cross(sd->N, normalize(cross(data, sd->N)));;
}
else {
- /* try to create spherical tangent from generated coordinates */
- int attr_offset = (sd->object != ~0)? find_attribute(kg, sd, ATTR_STD_GENERATED): ATTR_STD_NOT_FOUND;
-
- if(attr_offset != ATTR_STD_NOT_FOUND) {
- data = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, attr_offset, NULL, NULL);
- data = make_float3(-(data.y - 0.5), (data.x - 0.5), 0.0f);
- object_normal_transform(kg, sd, &data);
- data = cross(sd->N, normalize(cross(data, sd->N)));;
- }
- else {
- /* otherwise use surface derivatives */
- data = normalize(sd->dPdu);
- }
+ /* otherwise use surface derivatives */
+ data = normalize(sd->dPdu);
}
break;
diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h
index 6bd8f2ac69c..2f73f7b9d40 100644
--- a/intern/cycles/kernel/svm/svm_tex_coord.h
+++ b/intern/cycles/kernel/svm/svm_tex_coord.h
@@ -225,5 +225,91 @@ __device void svm_node_tex_coord_bump_dy(KernelGlobals *kg, ShaderData *sd, floa
#endif
}
+__device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
+{
+ uint color_offset, normal_offset, space;
+ decode_node_uchar4(node.y, &color_offset, &normal_offset, &space, NULL);
+
+ float3 color = stack_load_float3(stack, color_offset);
+ color = 2.0f*make_float3(color.x - 0.5f, color.y - 0.5f, color.z - 0.5f);
+
+ if(space == NODE_NORMAL_MAP_TANGENT) {
+ /* tangent space */
+ if(sd->object == ~0) {
+ stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f));
+ return;
+ }
+
+ /* first try to get tangent attribute */
+ int attr_offset = find_attribute(kg, sd, node.z);
+ int attr_sign_offset = find_attribute(kg, sd, node.w);
+
+ if(attr_offset == ATTR_STD_NOT_FOUND || attr_offset == ATTR_STD_NOT_FOUND) {
+ stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f));
+ return;
+ }
+
+ /* ensure orthogonal and normalized (interpolation breaks it) */
+ float3 tangent = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, attr_offset, NULL, NULL);
+ float sign = triangle_attribute_float(kg, sd, ATTR_ELEMENT_CORNER, attr_sign_offset, NULL, NULL);
+
+ object_normal_transform(kg, sd, &tangent);
+ tangent = cross(sd->N, normalize(cross(tangent, sd->N)));;
+
+ float3 B = sign * cross(sd->N, tangent);
+ float3 N = color.x * tangent + color.y * B + color.z * sd->N;
+
+ stack_store_float3(stack, normal_offset, normalize(N));
+ }
+ else {
+ /* object, world space */
+ float3 N = color;
+
+ if(space == NODE_NORMAL_MAP_OBJECT)
+ object_normal_transform(kg, sd, &N);
+
+ stack_store_float3(stack, normal_offset, normalize(N));
+ }
+}
+
+__device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
+{
+ uint tangent_offset, direction_type, axis;
+ decode_node_uchar4(node.y, &tangent_offset, &direction_type, &axis, NULL);
+
+ float3 tangent;
+
+ if(direction_type == NODE_TANGENT_UVMAP) {
+ /* UV map */
+ int attr_offset = find_attribute(kg, sd, node.z);
+
+ if(attr_offset == ATTR_STD_NOT_FOUND)
+ tangent = make_float3(0.0f, 0.0f, 0.0f);
+ else
+ tangent = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, attr_offset, NULL, NULL);
+ }
+ else {
+ /* radial */
+ int attr_offset = find_attribute(kg, sd, node.z);
+ float3 generated;
+
+ if(attr_offset == ATTR_STD_NOT_FOUND)
+ generated = sd->P;
+ else
+ generated = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, attr_offset, NULL, NULL);
+
+ if(axis == NODE_TANGENT_AXIS_X)
+ tangent = make_float3(0.0f, -(generated.z - 0.5f), (generated.y - 0.5f));
+ else if(axis == NODE_TANGENT_AXIS_Y)
+ tangent = make_float3(-(generated.z - 0.5f), 0.0f, (generated.x - 0.5f));
+ else
+ tangent = make_float3(-(generated.y - 0.5f), (generated.x - 0.5f), 0.0f);
+ }
+
+ object_normal_transform(kg, sd, &tangent);
+ tangent = cross(sd->N, normalize(cross(tangent, sd->N)));
+ stack_store_float3(stack, tangent_offset, tangent);
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index 77df373a159..54767f3c87f 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -94,6 +94,9 @@ typedef enum NodeType {
NODE_PARTICLE_INFO,
NODE_TEX_BRICK,
NODE_CLOSURE_SET_NORMAL,
+ NODE_CLOSURE_AMBIENT_OCCLUSION,
+ NODE_TANGENT,
+ NODE_NORMAL_MAP
} NodeType;
typedef enum NodeAttributeType {
@@ -279,6 +282,23 @@ typedef enum NodeBlendWeightType {
NODE_LAYER_WEIGHT_FACING
} NodeBlendWeightType;
+typedef enum NodeTangentDirectionType {
+ NODE_TANGENT_RADIAL,
+ NODE_TANGENT_UVMAP
+} NodeTangentDirectionType;
+
+typedef enum NodeTangentAxis {
+ NODE_TANGENT_AXIS_X,
+ NODE_TANGENT_AXIS_Y,
+ NODE_TANGENT_AXIS_Z
+} NodeTangentAxis;
+
+typedef enum NodeNormalMapSpace {
+ NODE_NORMAL_MAP_TANGENT,
+ NODE_NORMAL_MAP_OBJECT,
+ NODE_NORMAL_MAP_WORLD
+} NodeNormalMapSpace;
+
typedef enum ShaderType {
SHADER_TYPE_SURFACE,
SHADER_TYPE_VOLUME,
@@ -307,7 +327,9 @@ typedef enum ClosureType {
CLOSURE_BSDF_WESTIN_BACKSCATTER_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID,
CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID,
- CLOSURE_BSDF_GLASS_ID,
+ CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID,
+ CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
+ CLOSURE_BSDF_SHARP_GLASS_ID,
CLOSURE_BSDF_TRANSPARENT_ID,
@@ -317,6 +339,7 @@ typedef enum ClosureType {
CLOSURE_BACKGROUND_ID,
CLOSURE_HOLDOUT_ID,
CLOSURE_SUBSURFACE_ID,
+ CLOSURE_AMBIENT_OCCLUSION_ID,
CLOSURE_VOLUME_ID,
CLOSURE_VOLUME_TRANSPARENT_ID,
@@ -329,11 +352,12 @@ typedef enum ClosureType {
#define CLOSURE_IS_BSDF(type) (type <= CLOSURE_BSDF_TRANSPARENT_ID)
#define CLOSURE_IS_BSDF_DIFFUSE(type) (type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_OREN_NAYAR_ID)
#define CLOSURE_IS_BSDF_GLOSSY(type) (type >= CLOSURE_BSDF_GLOSSY_ID && type <= CLOSURE_BSDF_WESTIN_SHEEN_ID)
-#define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_GLASS_ID)
+#define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_SHARP_GLASS_ID)
#define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_ISOTROPIC_ID)
#define CLOSURE_IS_EMISSION(type) (type == CLOSURE_EMISSION_ID)
#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID)
#define CLOSURE_IS_BACKGROUND(type) (type == CLOSURE_BACKGROUND_ID)
+#define CLOSURE_IS_AMBIENT_OCCLUSION(type) (type == CLOSURE_AMBIENT_OCCLUSION_ID)
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp
index c7a9ab3e51a..95941c14b6c 100644
--- a/intern/cycles/render/attribute.cpp
+++ b/intern/cycles/render/attribute.cpp
@@ -162,8 +162,10 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
attr = add(name, TypeDesc::TypeNormal, Attribute::FACE);
else if(std == ATTR_STD_UV)
attr = add(name, TypeDesc::TypePoint, Attribute::CORNER);
- else if(std == ATTR_STD_TANGENT)
+ else if(std == ATTR_STD_UV_TANGENT)
attr = add(name, TypeDesc::TypeVector, Attribute::CORNER);
+ else if(std == ATTR_STD_UV_TANGENT_SIGN)
+ attr = add(name, TypeDesc::TypeFloat, Attribute::CORNER);
else if(std == ATTR_STD_GENERATED)
attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
else if(std == ATTR_STD_POSITION_UNDEFORMED)
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index d7bf71337f6..4f50de11edf 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -1284,10 +1284,8 @@ void WardBsdfNode::attributes(AttributeRequestSet *attributes)
{
ShaderInput *tangent_in = input("Tangent");
- if(!tangent_in->link) {
- attributes->add(ATTR_STD_TANGENT);
+ if(!tangent_in->link)
attributes->add(ATTR_STD_GENERATED);
- }
ShaderNode::attributes(attributes);
}
@@ -1346,9 +1344,9 @@ static ShaderEnum glass_distribution_init()
{
ShaderEnum enm;
- enm.insert("Sharp", CLOSURE_BSDF_REFRACTION_ID);
- enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
- enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
+ enm.insert("Sharp", CLOSURE_BSDF_SHARP_GLASS_ID);
+ enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
+ enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
return enm;
}
@@ -1367,7 +1365,7 @@ void GlassBsdfNode::compile(SVMCompiler& compiler)
{
closure = (ClosureType)distribution_enum[distribution];
- if(closure == CLOSURE_BSDF_REFRACTION_ID)
+ if(closure == CLOSURE_BSDF_SHARP_GLASS_ID)
BsdfNode::compile(compiler, NULL, input("IOR"));
else
BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
@@ -1379,6 +1377,45 @@ void GlassBsdfNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_glass_bsdf");
}
+/* Refraction BSDF Closure */
+
+static ShaderEnum refraction_distribution_init()
+{
+ ShaderEnum enm;
+
+ enm.insert("Sharp", CLOSURE_BSDF_REFRACTION_ID);
+ enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
+ enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
+
+ return enm;
+}
+
+ShaderEnum RefractionBsdfNode::distribution_enum = refraction_distribution_init();
+
+RefractionBsdfNode::RefractionBsdfNode()
+{
+ distribution = ustring("Sharp");
+
+ add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
+ add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f);
+}
+
+void RefractionBsdfNode::compile(SVMCompiler& compiler)
+{
+ closure = (ClosureType)distribution_enum[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("distribution", distribution);
+ compiler.add(this, "node_refraction_bsdf");
+}
+
/* Velvet BSDF Closure */
VelvetBsdfNode::VelvetBsdfNode()
@@ -1536,6 +1573,34 @@ void HoldoutNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_holdout");
}
+/* Ambient Occlusion */
+
+AmbientOcclusionNode::AmbientOcclusionNode()
+: ShaderNode("ambient_occlusion")
+{
+ add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
+ add_output("AO", SHADER_SOCKET_CLOSURE);
+}
+
+void AmbientOcclusionNode::compile(SVMCompiler& compiler)
+{
+ ShaderInput *color_in = input("Color");
+
+ if(color_in->link) {
+ compiler.stack_assign(color_in);
+ compiler.add_node(NODE_CLOSURE_WEIGHT, color_in->stack_offset);
+ }
+ else
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value);
+
+ 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()
@@ -1635,10 +1700,8 @@ GeometryNode::GeometryNode()
void GeometryNode::attributes(AttributeRequestSet *attributes)
{
- if(!output("Tangent")->links.empty()) {
- attributes->add(ATTR_STD_TANGENT);
+ if(!output("Tangent")->links.empty())
attributes->add(ATTR_STD_GENERATED);
- }
ShaderNode::attributes(attributes);
}
@@ -2075,13 +2138,14 @@ void ParticleInfoNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LOCATION, out->stack_offset);
}
- #if 0 /* XXX Quaternion data is not yet supported by Cycles */
+ /* quaternion data is not yet supported by Cycles */
+#if 0
out = output("Rotation");
if(!out->links.empty()) {
compiler.stack_assign(out);
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_ROTATION, out->stack_offset);
}
- #endif
+#endif
out = output("Size");
if(!out->links.empty()) {
@@ -2946,5 +3010,181 @@ void OSLScriptNode::compile(OSLCompiler& compiler)
compiler.add(this, bytecode_hash.c_str(), false);
}
+/* Normal Map */
+
+static ShaderEnum normal_map_space_init()
+{
+ ShaderEnum enm;
+
+ enm.insert("Tangent", NODE_NORMAL_MAP_TANGENT);
+ enm.insert("Object", NODE_NORMAL_MAP_OBJECT);
+ enm.insert("World", NODE_NORMAL_MAP_WORLD);
+
+ return enm;
+}
+
+ShaderEnum NormalMapNode::space_enum = normal_map_space_init();
+
+NormalMapNode::NormalMapNode()
+: ShaderNode("normal_map")
+{
+ space = ustring("Tangent");
+ attribute = ustring("");
+
+ add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true);
+ add_input("Color", SHADER_SOCKET_COLOR);
+ add_output("Normal", SHADER_SOCKET_NORMAL);
+}
+
+void NormalMapNode::attributes(AttributeRequestSet *attributes)
+{
+ if(space == ustring("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()));
+ }
+ }
+
+ ShaderNode::attributes(attributes);
+}
+
+void NormalMapNode::compile(SVMCompiler& compiler)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderOutput *normal_out = output("Normal");
+ int attr = 0, attr_sign = 0;
+
+ if(space == ustring("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.stack_assign(color_in);
+ compiler.stack_assign(normal_out);
+
+ compiler.add_node(NODE_NORMAL_MAP,
+ compiler.encode_uchar4(
+ color_in->stack_offset,
+ normal_out->stack_offset,
+ space_enum[space]),
+ attr, attr_sign);
+}
+
+void NormalMapNode::compile(OSLCompiler& compiler)
+{
+ if(space == ustring("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("space", space);
+
+ compiler.add(this, "node_normal_map");
+}
+
+/* Tangent */
+
+static ShaderEnum tangent_direction_type_init()
+{
+ ShaderEnum enm;
+
+ enm.insert("Radial", NODE_TANGENT_RADIAL);
+ enm.insert("UV Map", NODE_TANGENT_UVMAP);
+
+ return enm;
+}
+
+static ShaderEnum tangent_axis_init()
+{
+ ShaderEnum enm;
+
+ enm.insert("X", NODE_TANGENT_AXIS_X);
+ enm.insert("Y", NODE_TANGENT_AXIS_Y);
+ enm.insert("Z", NODE_TANGENT_AXIS_Z);
+
+ return enm;
+}
+
+ShaderEnum TangentNode::direction_type_enum = tangent_direction_type_init();
+ShaderEnum TangentNode::axis_enum = tangent_axis_init();
+
+TangentNode::TangentNode()
+: ShaderNode("normal_map")
+{
+ direction_type = ustring("Radial");
+ axis = ustring("X");
+ attribute = ustring("");
+
+ add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true);
+ add_output("Tangent", SHADER_SOCKET_NORMAL);
+}
+
+void TangentNode::attributes(AttributeRequestSet *attributes)
+{
+ if(direction_type == ustring("UV Map")) {
+ 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(attributes);
+}
+
+void TangentNode::compile(SVMCompiler& compiler)
+{
+ ShaderOutput *tangent_out = output("Tangent");
+ int attr;
+
+ if(direction_type == ustring("UV Map")) {
+ 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.stack_assign(tangent_out);
+
+ compiler.add_node(NODE_TANGENT,
+ compiler.encode_uchar4(
+ tangent_out->stack_offset,
+ direction_type_enum[direction_type],
+ axis_enum[axis]), attr);
+}
+
+void TangentNode::compile(OSLCompiler& compiler)
+{
+ if(direction_type == ustring("UV Map")) {
+ 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("direction_type", direction_type);
+ compiler.parameter("axis", axis);
+ compiler.add(this, "node_tangent");
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index d90cae5f668..27b07769e28 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -240,6 +240,14 @@ public:
static ShaderEnum distribution_enum;
};
+class RefractionBsdfNode : public BsdfNode {
+public:
+ SHADER_NODE_CLASS(RefractionBsdfNode)
+
+ ustring distribution;
+ static ShaderEnum distribution_enum;
+};
+
class EmissionNode : public ShaderNode {
public:
SHADER_NODE_CLASS(EmissionNode)
@@ -257,6 +265,11 @@ public:
SHADER_NODE_CLASS(HoldoutNode)
};
+class AmbientOcclusionNode : public ShaderNode {
+public:
+ SHADER_NODE_CLASS(AmbientOcclusionNode)
+};
+
class VolumeNode : public ShaderNode {
public:
SHADER_NODE_CLASS(VolumeNode)
@@ -457,6 +470,31 @@ public:
vector<ustring> output_names;
};
+class NormalMapNode : public ShaderNode {
+public:
+ SHADER_NODE_CLASS(NormalMapNode)
+ void attributes(AttributeRequestSet *attributes);
+
+ ustring space;
+ static ShaderEnum space_enum;
+
+ ustring attribute;
+};
+
+class TangentNode : public ShaderNode {
+public:
+ SHADER_NODE_CLASS(TangentNode)
+ void attributes(AttributeRequestSet *attributes);
+
+ ustring direction_type;
+ static ShaderEnum direction_type_enum;
+
+ ustring axis;
+ static ShaderEnum axis_enum;
+
+ ustring attribute;
+};
+
CCL_NAMESPACE_END
#endif /* __NODES_H__ */
diff --git a/intern/cycles/util/util_attribute.cpp b/intern/cycles/util/util_attribute.cpp
index 163a92902f3..057fb6213e9 100644
--- a/intern/cycles/util/util_attribute.cpp
+++ b/intern/cycles/util/util_attribute.cpp
@@ -30,8 +30,10 @@ const char *attribute_standard_name(AttributeStandard std)
return "uv";
else if(std == ATTR_STD_GENERATED)
return "generated";
- else if(std == ATTR_STD_TANGENT)
+ else if(std == ATTR_STD_UV_TANGENT)
return "tangent";
+ else if(std == ATTR_STD_UV_TANGENT_SIGN)
+ return "tangent_sign";
else if(std == ATTR_STD_POSITION_UNDEFORMED)
return "undeformed";
else if(std == ATTR_STD_POSITION_UNDISPLACED)
diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h
index f2c02cadcbf..fe530d727ad 100644
--- a/intern/cycles/util/util_types.h
+++ b/intern/cycles/util/util_types.h
@@ -449,7 +449,8 @@ typedef enum AttributeStandard {
ATTR_STD_VERTEX_NORMAL,
ATTR_STD_FACE_NORMAL,
ATTR_STD_UV,
- ATTR_STD_TANGENT,
+ ATTR_STD_UV_TANGENT,
+ ATTR_STD_UV_TANGENT_SIGN,
ATTR_STD_GENERATED,
ATTR_STD_POSITION_UNDEFORMED,
ATTR_STD_POSITION_UNDISPLACED,
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 29e03f66bcc..b365d93b246 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -553,6 +553,10 @@ struct ShadeResult;
#define SH_NODE_TEX_BRICK 169
#define SH_NODE_BUMP 170
#define SH_NODE_SCRIPT 171
+#define SH_NODE_AMBIENT_OCCLUSION 172
+#define SH_NODE_BSDF_REFRACTION 173
+#define SH_NODE_TANGENT 174
+#define SH_NODE_NORMAL_MAP 175
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 153eb5271c5..2d76484b60a 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -2293,17 +2293,21 @@ static void registerShaderNodes(bNodeTreeType *ttype)
register_node_type_sh_particle_info(ttype);
register_node_type_sh_bump(ttype);
register_node_type_sh_script(ttype);
+ register_node_type_sh_tangent(ttype);
+ register_node_type_sh_normal_map(ttype);
register_node_type_sh_background(ttype);
register_node_type_sh_bsdf_anisotropic(ttype);
register_node_type_sh_bsdf_diffuse(ttype);
register_node_type_sh_bsdf_glossy(ttype);
register_node_type_sh_bsdf_glass(ttype);
+ register_node_type_sh_bsdf_refraction(ttype);
register_node_type_sh_bsdf_translucent(ttype);
register_node_type_sh_bsdf_transparent(ttype);
register_node_type_sh_bsdf_velvet(ttype);
register_node_type_sh_emission(ttype);
register_node_type_sh_holdout(ttype);
+ register_node_type_sh_ambient_occlusion(ttype);
//register_node_type_sh_volume_transparent(ttype);
//register_node_type_sh_volume_isotropic(ttype);
register_node_type_sh_mix_shader(ttype);
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 0938562857b..b99842502ec 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -1379,6 +1379,30 @@ static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), Po
uiItemR(layout, ptr, "from_dupli", 0, NULL, 0);
}
+static void node_shader_buts_normal_map(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "space", 0, "", 0);
+
+ if(RNA_enum_get(ptr, "space") == SHD_NORMAL_MAP_TANGENT)
+ uiItemR(layout, ptr, "uv_map", 0, NULL, 0);
+}
+
+static void node_shader_buts_tangent(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *split, *row;
+
+ split = uiLayoutSplit(layout, 0.0f, FALSE);
+
+ uiItemR(split, ptr, "direction_type", 0, "", 0);
+
+ row = uiLayoutRow(split, FALSE);
+
+ if(RNA_enum_get(ptr, "direction_type") == SHD_TANGENT_UVMAP)
+ uiItemR(row, ptr, "uv_map", 0, "", 0);
+ else
+ uiItemR(row, ptr, "axis", UI_ITEM_R_EXPAND, NULL, 0);
+}
+
static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
@@ -1491,8 +1515,15 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_TEX_COORD:
ntype->uifunc = node_shader_buts_tex_coord;
break;
+ case SH_NODE_NORMAL_MAP:
+ ntype->uifunc = node_shader_buts_normal_map;
+ break;
+ case SH_NODE_TANGENT:
+ ntype->uifunc = node_shader_buts_tangent;
+ break;
case SH_NODE_BSDF_GLOSSY:
case SH_NODE_BSDF_GLASS:
+ case SH_NODE_BSDF_REFRACTION:
ntype->uifunc = node_shader_buts_glossy;
break;
case SH_NODE_SCRIPT:
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index c73ba87754f..3437e6dfcf1 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -716,6 +716,17 @@ typedef struct NodeShaderScript {
IDProperty *prop;
} NodeShaderScript;
+typedef struct NodeShaderTangent {
+ int direction_type;
+ int axis;
+ char uv_map[64];
+} NodeShaderTangent;
+
+typedef struct NodeShaderNormalMap {
+ int space;
+ char uv_map[64];
+} NodeShaderNormalMap;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -800,6 +811,20 @@ typedef struct NodeShaderScript {
#define SHD_PROJ_FLAT 0
#define SHD_PROJ_BOX 1
+/* tangent */
+#define SHD_TANGENT_RADIAL 0
+#define SHD_TANGENT_UVMAP 1
+
+/* tangent */
+#define SHD_TANGENT_AXIS_X 0
+#define SHD_TANGENT_AXIS_Y 1
+#define SHD_TANGENT_AXIS_Z 2
+
+/* normal map space */
+#define SHD_NORMAL_MAP_TANGENT 0
+#define SHD_NORMAL_MAP_OBJECT 1
+#define SHD_NORMAL_MAP_WORLD 2
+
/* blur node */
#define CMP_NODE_BLUR_ASPECT_NONE 0
#define CMP_NODE_BLUR_ASPECT_Y 1
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 312469340a7..93f37682aa3 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -1850,6 +1850,67 @@ static void def_glossy(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_sh_normal_map(StructRNA *srna)
+{
+ static EnumPropertyItem prop_space_items[] = {
+ {SHD_NORMAL_MAP_TANGENT, "TANGENT", 0, "Tangent Space", "Tangent space normal mapping"},
+ {SHD_NORMAL_MAP_OBJECT, "OBJECT", 0, "Object Space", "Object space normal mapping"},
+ {SHD_NORMAL_MAP_WORLD, "WORLD", 0, "World Space", "World space normal mapping"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeShaderNormalMap", "storage");
+
+ prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_space_items);
+ RNA_def_property_ui_text(prop, "Space", "Space of the input normal");
+ RNA_def_property_update(prop, 0, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "uv_map", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "UV Map", "Name of the UV Map for for tangent space maps");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ RNA_def_struct_sdna_from(srna, "bNode", NULL);
+}
+
+static void def_sh_tangent(StructRNA *srna)
+{
+ static EnumPropertyItem prop_direction_type_items[] = {
+ {SHD_TANGENT_RADIAL, "RADIAL", 0, "Radial", "Radial tangent around the X, Y or Z axis"},
+ {SHD_TANGENT_UVMAP, "UV_MAP", 0, "UV Map", "Tangent from UV map"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem prop_axis_items[] = {
+ {SHD_TANGENT_AXIS_X, "X", 0, "X", "X axis"},
+ {SHD_TANGENT_AXIS_Y, "Y", 0, "Y", "Y axis"},
+ {SHD_TANGENT_AXIS_Z, "Z", 0, "Z", "Z axis"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeShaderTangent", "storage");
+
+ prop = RNA_def_property(srna, "direction_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_direction_type_items);
+ RNA_def_property_ui_text(prop, "Direction", "Method to use for the tangent");
+ RNA_def_property_update(prop, 0, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_axis_items);
+ RNA_def_property_ui_text(prop, "Axis", "Axis for radial tangents");
+ RNA_def_property_update(prop, 0, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "uv_map", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "UV Map", "Name of the UV Map for for tangent generated from UV");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ RNA_def_struct_sdna_from(srna, "bNode", NULL);
+}
+
static void def_sh_script(StructRNA *srna)
{
FunctionRNA *func;
diff --git a/source/blender/makesrna/intern/rna_nodetree_types.h b/source/blender/makesrna/intern/rna_nodetree_types.h
index c45c9b71442..fbbcbae6c12 100644
--- a/source/blender/makesrna/intern/rna_nodetree_types.h
+++ b/source/blender/makesrna/intern/rna_nodetree_types.h
@@ -65,12 +65,14 @@ DefNode( ShaderNode, SH_NODE_LAYER_WEIGHT, 0, "LA
DefNode( ShaderNode, SH_NODE_MIX_SHADER, 0, "MIX_SHADER", MixShader, "Mix Shader", "" )
DefNode( ShaderNode, SH_NODE_ADD_SHADER, 0, "ADD_SHADER", AddShader, "Add Shader", "" )
DefNode( ShaderNode, SH_NODE_ATTRIBUTE, def_sh_attribute, "ATTRIBUTE", Attribute, "Attribute", "" )
+DefNode( ShaderNode, SH_NODE_AMBIENT_OCCLUSION, 0, "AMBIENT_OCCLUSION", AmbientOcclusion, "Ambient Occlusion", "" )
DefNode( ShaderNode, SH_NODE_BACKGROUND, 0, "BACKGROUND", Background, "Background", "" )
DefNode( ShaderNode, SH_NODE_HOLDOUT, 0, "HOLDOUT", Holdout, "Holdout", "" )
DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, 0, "BSDF_ANISOTROPIC", BsdfAnisotropic, "Anisotropic Bsdf", "" )
DefNode( ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse Bsdf", "" )
DefNode( ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy Bsdf", "" )
DefNode( ShaderNode, SH_NODE_BSDF_GLASS, def_glossy, "BSDF_GLASS", BsdfGlass, "Glass Bsdf", "" )
+DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_glossy, "BSDF_REFRACTION", BsdfRefraction, "Refraction Bsdf", "" )
DefNode( ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BSDF_TRANSLUCENT", BsdfTranslucent, "Translucent Bsdf", "" )
DefNode( ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent Bsdf", "" )
DefNode( ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet Bsdf", "" )
@@ -82,7 +84,9 @@ DefNode( ShaderNode, SH_NODE_LIGHT_PATH, 0, "LI
DefNode( ShaderNode, SH_NODE_LIGHT_FALLOFF, 0, "LIGHT_FALLOFF", LightFalloff, "Light Falloff", "" )
DefNode( ShaderNode, SH_NODE_OBJECT_INFO, 0, "OBJECT_INFO", ObjectInfo, "Object Info", "" )
DefNode( ShaderNode, SH_NODE_PARTICLE_INFO, 0, "PARTICLE_INFO", ParticleInfo, "Particle Info", "" )
-DefNode( ShaderNode, SH_NODE_BUMP, 0, "BUMP", BumpNode, "Bump", "" )
+DefNode( ShaderNode, SH_NODE_BUMP, 0, "BUMP", Bump, "Bump", "" )
+DefNode( ShaderNode, SH_NODE_NORMAL_MAP, def_sh_normal_map, "NORMAL_MAP", NormalMap, "Normal Map", "" )
+DefNode( ShaderNode, SH_NODE_TANGENT, def_sh_tangent, "TANGENT", Tangent, "Tangent", "" )
DefNode( ShaderNode, SH_NODE_SCRIPT, def_sh_script, "SCRIPT", Script, "Script", "" )
DefNode( ShaderNode, SH_NODE_TEX_IMAGE, def_sh_tex_image, "TEX_IMAGE", TexImage, "Image Texture", "" )
DefNode( ShaderNode, SH_NODE_TEX_ENVIRONMENT, def_sh_tex_environment, "TEX_ENVIRONMENT", TexEnvironment, "Environment Texture","" )
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 323a534c989..7dca4d07b24 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -145,36 +145,40 @@ set(SRC
shader/nodes/node_shader_valToRgb.c
shader/nodes/node_shader_value.c
shader/nodes/node_shader_vectMath.c
+ shader/nodes/node_shader_add_shader.c
+ shader/nodes/node_shader_ambient_occlusion.c
shader/nodes/node_shader_attribute.c
shader/nodes/node_shader_background.c
shader/nodes/node_shader_bsdf_anisotropic.c
shader/nodes/node_shader_bsdf_diffuse.c
- shader/nodes/node_shader_bsdf_glossy.c
shader/nodes/node_shader_bsdf_glass.c
+ shader/nodes/node_shader_bsdf_glossy.c
+ shader/nodes/node_shader_bsdf_refraction.c
shader/nodes/node_shader_bsdf_translucent.c
shader/nodes/node_shader_bsdf_transparent.c
shader/nodes/node_shader_bsdf_velvet.c
shader/nodes/node_shader_bump.c
shader/nodes/node_shader_emission.c
shader/nodes/node_shader_fresnel.c
- shader/nodes/node_shader_layer_weight.c
shader/nodes/node_shader_geometry.c
shader/nodes/node_shader_holdout.c
- shader/nodes/node_shader_volume_transparent.c
- shader/nodes/node_shader_volume_isotropic.c
- shader/nodes/node_shader_light_path.c
+ shader/nodes/node_shader_layer_weight.c
shader/nodes/node_shader_light_falloff.c
- shader/nodes/node_shader_object_info.c
- shader/nodes/node_shader_script.c
- shader/nodes/node_shader_particle_info.c
+ shader/nodes/node_shader_light_path.c
shader/nodes/node_shader_mix_shader.c
- shader/nodes/node_shader_add_shader.c
+ shader/nodes/node_shader_normal_map.c
+ shader/nodes/node_shader_object_info.c
shader/nodes/node_shader_output_lamp.c
shader/nodes/node_shader_output_material.c
shader/nodes/node_shader_output_world.c
- shader/nodes/node_shader_tex_gradient.c
+ shader/nodes/node_shader_particle_info.c
+ shader/nodes/node_shader_script.c
+ shader/nodes/node_shader_tangent.c
+ shader/nodes/node_shader_tex_brick.c
+ shader/nodes/node_shader_tex_checker.c
shader/nodes/node_shader_tex_coord.c
shader/nodes/node_shader_tex_environment.c
+ shader/nodes/node_shader_tex_gradient.c
shader/nodes/node_shader_tex_image.c
shader/nodes/node_shader_tex_magic.c
shader/nodes/node_shader_tex_musgrave.c
@@ -182,8 +186,8 @@ set(SRC
shader/nodes/node_shader_tex_sky.c
shader/nodes/node_shader_tex_voronoi.c
shader/nodes/node_shader_tex_wave.c
- shader/nodes/node_shader_tex_checker.c
- shader/nodes/node_shader_tex_brick.c
+ shader/nodes/node_shader_volume_isotropic.c
+ shader/nodes/node_shader_volume_transparent.c
shader/node_shader_tree.c
shader/node_shader_util.c
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 66ab15ce29f..e402924c04f 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -81,11 +81,15 @@ void register_node_type_sh_layer_weight(struct bNodeTreeType *ttype);
void register_node_type_sh_tex_coord(struct bNodeTreeType *ttype);
void register_node_type_sh_particle_info(struct bNodeTreeType *ttype);
void register_node_type_sh_script(struct bNodeTreeType *ttype);
+void register_node_type_sh_normal_map(struct bNodeTreeType *ttype);
+void register_node_type_sh_tangent(struct bNodeTreeType *ttype);
+void register_node_type_sh_ambient_occlusion(struct bNodeTreeType *ttype);
void register_node_type_sh_background(struct bNodeTreeType *ttype);
void register_node_type_sh_bsdf_diffuse(struct bNodeTreeType *ttype);
void register_node_type_sh_bsdf_glossy(struct bNodeTreeType *ttype);
void register_node_type_sh_bsdf_glass(struct bNodeTreeType *ttype);
+void register_node_type_sh_bsdf_refraction(struct bNodeTreeType *ttype);
void register_node_type_sh_bsdf_translucent(struct bNodeTreeType *ttype);
void register_node_type_sh_bsdf_transparent(struct bNodeTreeType *ttype);
void register_node_type_sh_bsdf_velvet(struct bNodeTreeType *ttype);
diff --git a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
new file mode 100644
index 00000000000..7dfefc9ece0
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
@@ -0,0 +1,63 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_ambient_occlusion_in[] = {
+ { SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate sh_node_ambient_occlusion_out[] = {
+ { SOCK_SHADER, 0, N_("AO")},
+ { -1, 0, "" }
+};
+
+static int node_shader_gpu_ambient_occlusion(GPUMaterial *mat, bNode *UNUSED(node), GPUNodeStack *in, GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, "node_ambient_occlusion", in, out, GPU_builtin(GPU_VIEW_NORMAL));
+}
+
+/* node type definition */
+void register_node_type_sh_ambient_occlusion(bNodeTreeType *ttype)
+{
+ static bNodeType ntype;
+
+ node_type_base(ttype, &ntype, SH_NODE_AMBIENT_OCCLUSION, "Ambient Occlusion", NODE_CLASS_SHADER, 0);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_socket_templates(&ntype, sh_node_ambient_occlusion_in, sh_node_ambient_occlusion_out);
+ node_type_size(&ntype, 150, 60, 200);
+ node_type_init(&ntype, NULL);
+ node_type_storage(&ntype, "", NULL, NULL);
+ node_type_exec(&ntype, NULL);
+ node_type_gpu(&ntype, node_shader_gpu_ambient_occlusion);
+
+ nodeRegisterType(ttype, &ntype);
+}
+
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
new file mode 100644
index 00000000000..99e66e39002
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
@@ -0,0 +1,68 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_bsdf_refraction_in[] = {
+ { SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 1.0f, 1000.0f},
+ { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate sh_node_bsdf_refraction_out[] = {
+ { SOCK_SHADER, 0, N_("BSDF")},
+ { -1, 0, "" }
+};
+
+static int node_shader_gpu_bsdf_refraction(GPUMaterial *mat, bNode *UNUSED(node), GPUNodeStack *in, GPUNodeStack *out)
+{
+ if (!in[3].link)
+ in[3].link = GPU_builtin(GPU_VIEW_NORMAL);
+
+ return GPU_stack_link(mat, "node_bsdf_refraction", in, out);
+}
+
+/* node type definition */
+void register_node_type_sh_bsdf_refraction(bNodeTreeType *ttype)
+{
+ static bNodeType ntype;
+
+ node_type_base(ttype, &ntype, SH_NODE_BSDF_REFRACTION, "Refraction BSDF", NODE_CLASS_SHADER, NODE_OPTIONS);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_socket_templates(&ntype, sh_node_bsdf_refraction_in, sh_node_bsdf_refraction_out);
+ node_type_size(&ntype, 150, 60, 200);
+ node_type_init(&ntype, NULL);
+ node_type_storage(&ntype, "", NULL, NULL);
+ node_type_exec(&ntype, NULL);
+ node_type_gpu(&ntype, node_shader_gpu_bsdf_refraction);
+
+ nodeRegisterType(ttype, &ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
new file mode 100644
index 00000000000..39fd8a5decc
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -0,0 +1,69 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_normal_map_in[] = {
+ { SOCK_RGBA, 0, N_("Color"), 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate sh_node_normal_map_out[] = {
+ { SOCK_VECTOR, 0, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_init_normal_map(bNodeTree *UNUSED(ntree), bNode *node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeShaderNormalMap *attr = MEM_callocN(sizeof(NodeShaderNormalMap), "NodeShaderNormalMap");
+ node->storage = attr;
+}
+
+static int gpu_shader_normal_map(GPUMaterial *mat, bNode *UNUSED(node), GPUNodeStack *in, GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, "node_normal_map", in, out, GPU_builtin(GPU_VIEW_NORMAL));
+}
+
+/* node type definition */
+void register_node_type_sh_normal_map(bNodeTreeType *ttype)
+{
+ static bNodeType ntype;
+
+ node_type_base(ttype, &ntype, SH_NODE_NORMAL_MAP, "Normal Map", NODE_CLASS_OP_VECTOR, NODE_OPTIONS);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_socket_templates(&ntype, sh_node_normal_map_in, sh_node_normal_map_out);
+ node_type_size(&ntype, 250, 60, 250);
+ node_type_init(&ntype, node_shader_init_normal_map);
+ node_type_storage(&ntype, "NodeShaderNormalMap", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, NULL);
+ node_type_gpu(&ntype, gpu_shader_normal_map);
+
+ nodeRegisterType(ttype, &ntype);
+}
+
diff --git a/source/blender/nodes/shader/nodes/node_shader_tangent.c b/source/blender/nodes/shader/nodes/node_shader_tangent.c
new file mode 100644
index 00000000000..6c0d6d7cd9f
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_tangent.c
@@ -0,0 +1,60 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_tangent_out[] = {
+ { SOCK_VECTOR, 0, N_("Tangent"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_init_tangent(bNodeTree *UNUSED(ntree), bNode *node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeShaderTangent *attr = MEM_callocN(sizeof(NodeShaderTangent), "NodeShaderTangent");
+ attr->axis = SHD_TANGENT_AXIS_Z;
+ node->storage = attr;
+}
+
+/* node type definition */
+void register_node_type_sh_tangent(bNodeTreeType *ttype)
+{
+ static bNodeType ntype;
+
+ node_type_base(ttype, &ntype, SH_NODE_TANGENT, "Tangent", NODE_CLASS_INPUT, NODE_OPTIONS);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_socket_templates(&ntype, NULL, sh_node_tangent_out);
+ node_type_size(&ntype, 150, 60, 200);
+ node_type_init(&ntype, node_shader_init_tangent);
+ node_type_storage(&ntype, "NodeShaderTangent", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, NULL);
+ node_type_gpu(&ntype, NULL);
+
+ nodeRegisterType(ttype, &ntype);
+}
+