diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2012-10-10 19:56:43 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2012-10-10 19:56:43 +0400 |
commit | fe09b24e86e340e733f91c8ed9fcc7b8519157f4 (patch) | |
tree | dfe21334e003d8e73ea993d5fcac54c19facd987 /intern | |
parent | e9a61cd29db61513dedeb4d656e7dadff7439b1a (diff) |
Cycles: per-BSDF normal input and new Bump node.
Each BSDF node now has a Normal input, which can be used to set a custom normal
for the BSDF, for example if you want to have only bump on one of the layers in
a multilayer material.
The Bump node can be used to generate a normal from a scalar value, the same as
what happens when you connect a scalar value to the displacement output.
Documentation has been updated with the latest changes:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes
Patch by Agustin Benavidez, some implementation tweaks by me.
Diffstat (limited to 'intern')
-rw-r--r-- | intern/cycles/blender/blender_shader.cpp | 4 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_types.h | 1 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h | 4 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/bsdf_diffuse.h | 8 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/bsdf_microfacet.h | 12 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/bsdf_oren_nayar.h | 12 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/bsdf_reflection.h | 2 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/bsdf_refraction.h | 2 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/bsdf_ward.h | 4 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/bsdf_westin.h | 8 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/svm.h | 9 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/svm_closure.h | 34 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/svm_displace.h | 26 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/svm_types.h | 1 | ||||
-rw-r--r-- | intern/cycles/render/graph.cpp | 78 | ||||
-rw-r--r-- | intern/cycles/render/graph.h | 1 | ||||
-rw-r--r-- | intern/cycles/render/nodes.cpp | 58 | ||||
-rw-r--r-- | intern/cycles/render/nodes.h | 5 |
18 files changed, 224 insertions, 45 deletions
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 56548613647..98ac8692f36 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -402,6 +402,10 @@ static ShaderNode *add_node(BL::BlendData b_data, BL::Scene b_scene, ShaderGraph node = new ParticleInfoNode(); break; } + case BL::ShaderNode::type_BUMP: { + node = new BumpNode(); + break; + } case BL::ShaderNode::type_TEX_IMAGE: { BL::ShaderNodeTexImage b_image_node(b_node); BL::Image b_image(b_image_node.image()); diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index ae9b0ac6d99..be49aa54e47 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -370,6 +370,7 @@ typedef struct ShaderClosure { #endif float data0; float data1; + float3 N; } ShaderClosure; diff --git a/intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h b/intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h index 40249dbe9c6..785fc038e9e 100644 --- a/intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h +++ b/intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h @@ -58,7 +58,7 @@ __device void bsdf_ashikhmin_velvet_blur(ShaderClosure *sc, float roughness) __device float3 bsdf_ashikhmin_velvet_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { float m_invsigma2 = sc->data0; - float3 m_N = sd->N; + float3 m_N = sc->N; float cosNO = dot(m_N, I); float cosNI = dot(m_N, omega_in); @@ -106,7 +106,7 @@ __device float bsdf_ashikhmin_velvet_albedo(const ShaderData *sd, const ShaderCl __device int bsdf_ashikhmin_velvet_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { float m_invsigma2 = sc->data0; - float3 m_N = sd->N; + float3 m_N = sc->N; // we are viewing the surface from above - send a ray out with uniform // distribution over the hemisphere diff --git a/intern/cycles/kernel/svm/bsdf_diffuse.h b/intern/cycles/kernel/svm/bsdf_diffuse.h index edf8dd93341..6a67c184854 100644 --- a/intern/cycles/kernel/svm/bsdf_diffuse.h +++ b/intern/cycles/kernel/svm/bsdf_diffuse.h @@ -53,7 +53,7 @@ __device void bsdf_diffuse_blur(ShaderClosure *sc, float roughness) __device float3 bsdf_diffuse_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float3 m_N = sd->N; + float3 m_N = sc->N; float cos_pi = fmaxf(dot(m_N, omega_in), 0.0f) * M_1_PI_F; *pdf = cos_pi; @@ -72,7 +72,7 @@ __device float bsdf_diffuse_albedo(const ShaderData *sd, const ShaderClosure *sc __device int bsdf_diffuse_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float3 m_N = sd->N; + float3 m_N = sc->N; // distribution over the hemisphere sample_cos_hemisphere(m_N, randu, randv, omega_in, pdf); @@ -116,7 +116,7 @@ __device float3 bsdf_translucent_eval_reflect(const ShaderData *sd, const Shader __device float3 bsdf_translucent_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float3 m_N = sd->N; + float3 m_N = sc->N; float cos_pi = fmaxf(-dot(m_N, omega_in), 0.0f) * M_1_PI_F; *pdf = cos_pi; @@ -130,7 +130,7 @@ __device float bsdf_translucent_albedo(const ShaderData *sd, const ShaderClosure __device int bsdf_translucent_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float3 m_N = sd->N; + float3 m_N = sc->N; // we are viewing the surface from the right side - send a ray out with cosine // distribution over the hemisphere diff --git a/intern/cycles/kernel/svm/bsdf_microfacet.h b/intern/cycles/kernel/svm/bsdf_microfacet.h index d8f0310bd02..60f8e23818c 100644 --- a/intern/cycles/kernel/svm/bsdf_microfacet.h +++ b/intern/cycles/kernel/svm/bsdf_microfacet.h @@ -76,7 +76,7 @@ __device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderData *sd, const Sha float m_ag = sc->data0; //float m_eta = sc->data1; int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; - float3 m_N = sd->N; + float3 m_N = sc->N; if(m_refractive) return make_float3 (0, 0, 0); float cosNO = dot(m_N, I); @@ -113,7 +113,7 @@ __device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderData *sd, const Sh float m_ag = sc->data0; float m_eta = sc->data1; int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; - float3 m_N = sd->N; + float3 m_N = sc->N; if(!m_refractive) return make_float3 (0, 0, 0); float cosNO = dot(m_N, I); @@ -154,7 +154,7 @@ __device int bsdf_microfacet_ggx_sample(const ShaderData *sd, const ShaderClosur float m_ag = sc->data0; float m_eta = sc->data1; int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; - float3 m_N = sd->N; + float3 m_N = sc->N; float cosNO = dot(m_N, sd->I); if(cosNO > 0) { @@ -302,7 +302,7 @@ __device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderData *sd, cons float m_ab = sc->data0; //float m_eta = sc->data1; int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; - float3 m_N = sd->N; + float3 m_N = sc->N; if(m_refractive) return make_float3 (0, 0, 0); float cosNO = dot(m_N, I); @@ -341,7 +341,7 @@ __device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderData *sd, con float m_ab = sc->data0; float m_eta = sc->data1; int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; - float3 m_N = sd->N; + float3 m_N = sc->N; if(!m_refractive) return make_float3 (0, 0, 0); float cosNO = dot(m_N, I); @@ -384,7 +384,7 @@ __device int bsdf_microfacet_beckmann_sample(const ShaderData *sd, const ShaderC float m_ab = sc->data0; float m_eta = sc->data1; int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; - float3 m_N = sd->N; + float3 m_N = sc->N; float cosNO = dot(m_N, sd->I); if(cosNO > 0) { diff --git a/intern/cycles/kernel/svm/bsdf_oren_nayar.h b/intern/cycles/kernel/svm/bsdf_oren_nayar.h index a7edccdc423..04fbb091fb4 100644 --- a/intern/cycles/kernel/svm/bsdf_oren_nayar.h +++ b/intern/cycles/kernel/svm/bsdf_oren_nayar.h @@ -57,9 +57,9 @@ __device void bsdf_oren_nayar_blur(ShaderClosure *sc, float roughness) __device float3 bsdf_oren_nayar_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - if (dot(sd->N, omega_in) > 0.0f) { + if (dot(sc->N, omega_in) > 0.0f) { *pdf = 0.5f * M_1_PI_F; - return bsdf_oren_nayar_get_intensity(sc, sd->N, I, omega_in); + return bsdf_oren_nayar_get_intensity(sc, sc->N, I, omega_in); } else { *pdf = 0.0f; @@ -79,15 +79,15 @@ __device float bsdf_oren_nayar_albedo(const ShaderData *sd, const ShaderClosure __device int bsdf_oren_nayar_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - sample_uniform_hemisphere(sd->N, randu, randv, omega_in, pdf); + sample_uniform_hemisphere(sc->N, randu, randv, omega_in, pdf); if (dot(sd->Ng, *omega_in) > 0.0f) { - *eval = bsdf_oren_nayar_get_intensity(sc, sd->N, sd->I, *omega_in); + *eval = bsdf_oren_nayar_get_intensity(sc, sc->N, sd->I, *omega_in); #ifdef __RAY_DIFFERENTIALS__ // TODO: find a better approximation for the bounce - *domega_in_dx = (2.0f * dot(sd->N, sd->dI.dx)) * sd->N - sd->dI.dx; - *domega_in_dy = (2.0f * dot(sd->N, sd->dI.dy)) * sd->N - sd->dI.dy; + *domega_in_dx = (2.0f * dot(sc->N, sd->dI.dx)) * sc->N - sd->dI.dx; + *domega_in_dy = (2.0f * dot(sc->N, sd->dI.dy)) * sc->N - sd->dI.dy; *domega_in_dx *= 125.0f; *domega_in_dy *= 125.0f; #endif diff --git a/intern/cycles/kernel/svm/bsdf_reflection.h b/intern/cycles/kernel/svm/bsdf_reflection.h index 09b4e0e48f0..7ce38050a9a 100644 --- a/intern/cycles/kernel/svm/bsdf_reflection.h +++ b/intern/cycles/kernel/svm/bsdf_reflection.h @@ -69,7 +69,7 @@ __device float bsdf_reflection_albedo(const ShaderData *sd, const ShaderClosure __device int bsdf_reflection_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { //const BsdfReflectionClosure *self = (const BsdfReflectionClosure*)sc->data; - float3 m_N = sd->N; + float3 m_N = sc->N; // only one direction is possible float cosNO = dot(m_N, sd->I); diff --git a/intern/cycles/kernel/svm/bsdf_refraction.h b/intern/cycles/kernel/svm/bsdf_refraction.h index c9c268999c0..7579a4c6276 100644 --- a/intern/cycles/kernel/svm/bsdf_refraction.h +++ b/intern/cycles/kernel/svm/bsdf_refraction.h @@ -71,7 +71,7 @@ __device float bsdf_refraction_albedo(const ShaderData *sd, const ShaderClosure __device int bsdf_refraction_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { float m_eta = sc->data0; - float3 m_N = sd->N; + float3 m_N = sc->N; float3 R, T; #ifdef __RAY_DIFFERENTIALS__ diff --git a/intern/cycles/kernel/svm/bsdf_ward.h b/intern/cycles/kernel/svm/bsdf_ward.h index 56b8ad72c89..3c08a3d54d3 100644 --- a/intern/cycles/kernel/svm/bsdf_ward.h +++ b/intern/cycles/kernel/svm/bsdf_ward.h @@ -66,7 +66,7 @@ __device float3 bsdf_ward_eval_reflect(const ShaderData *sd, const ShaderClosure { float m_ax = sc->data0; float m_ay = sc->data1; - float3 m_N = sd->N; + float3 m_N = sc->N; float3 m_T = sd->T; float cosNO = dot(m_N, I); @@ -108,7 +108,7 @@ __device int bsdf_ward_sample(const ShaderData *sd, const ShaderClosure *sc, flo { float m_ax = sc->data0; float m_ay = sc->data1; - float3 m_N = sd->N; + float3 m_N = sc->N; float3 m_T = sd->T; float cosNO = dot(m_N, sd->I); diff --git a/intern/cycles/kernel/svm/bsdf_westin.h b/intern/cycles/kernel/svm/bsdf_westin.h index 3e7c27f44a4..75f935e3267 100644 --- a/intern/cycles/kernel/svm/bsdf_westin.h +++ b/intern/cycles/kernel/svm/bsdf_westin.h @@ -62,7 +62,7 @@ __device void bsdf_westin_backscatter_blur(ShaderClosure *sc, float roughness) __device float3 bsdf_westin_backscatter_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { float m_invroughness = sc->data0; - float3 m_N = sd->N; + float3 m_N = sc->N; // pdf is implicitly 0 (no indirect sampling) float cosNO = dot(m_N, I); @@ -89,7 +89,7 @@ __device float bsdf_westin_backscatter_albedo(const ShaderData *sd, const Shader __device int bsdf_westin_backscatter_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { float m_invroughness = sc->data0; - float3 m_N = sd->N; + float3 m_N = sc->N; float cosNO = dot(m_N, sd->I); if(cosNO > 0) { @@ -151,7 +151,7 @@ __device void bsdf_westin_sheen_blur(ShaderClosure *sc, float roughness) __device float3 bsdf_westin_sheen_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { float m_edginess = sc->data0; - float3 m_N = sd->N; + float3 m_N = sc->N; // pdf is implicitly 0 (no indirect sampling) float cosNO = dot(m_N, I); @@ -178,7 +178,7 @@ __device float bsdf_westin_sheen_albedo(const ShaderData *sd, const ShaderClosur __device int bsdf_westin_sheen_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { float m_edginess = sc->data0; - float3 m_N = sd->N; + float3 m_N = sc->N; // we are viewing the surface from the right side - send a ray out with cosine // distribution over the hemisphere diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index e5167a4f670..5e22edc4696 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -185,7 +185,7 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT break; } case NODE_CLOSURE_BSDF: - svm_node_closure_bsdf(kg, sd, stack, node, randb, path_flag); + svm_node_closure_bsdf(kg, sd, stack, node, randb, path_flag, &offset); break; case NODE_CLOSURE_EMISSION: svm_node_closure_emission(sd, stack, node); @@ -342,7 +342,7 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT svm_node_set_displacement(sd, stack, node.y); break; case NODE_SET_BUMP: - svm_node_set_bump(sd, stack, node.y, node.z, node.w); + svm_node_set_bump(kg, sd, stack, node); break; case NODE_MATH: svm_node_math(kg, sd, stack, node.y, node.z, node.w, &offset); @@ -370,6 +370,9 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT case NODE_TEX_COORD_BUMP_DY: svm_node_tex_coord_bump_dy(kg, sd, stack, node.y, node.z); break; + case NODE_CLOSURE_SET_NORMAL: + svm_node_set_normal(kg, sd, stack, node.y, node.z ); + break; #endif case NODE_EMISSION_SET_WEIGHT_TOTAL: svm_node_emission_set_weight_total(kg, sd, node.y, node.z, node.w); @@ -384,7 +387,7 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT case NODE_LIGHT_FALLOFF: svm_node_light_falloff(sd, stack, node); break; -#endif +#endif case NODE_END: default: #ifndef __MULTI_CLOSURE__ diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h index c942d50908c..6a0e6915e99 100644 --- a/intern/cycles/kernel/svm/svm_closure.h +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -57,7 +57,7 @@ __device_inline void svm_node_closure_set_mix_weight(ShaderClosure *sc, float mi #endif } -__device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, float randb, int path_flag) +__device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, float randb, int path_flag, int *offset) { uint type, param1_offset, param2_offset; @@ -66,11 +66,19 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st decode_node_uchar4(node.y, &type, ¶m1_offset, ¶m2_offset, &mix_weight_offset); float mix_weight = (stack_valid(mix_weight_offset)? stack_load_float(stack, mix_weight_offset): 1.0f); + /* note we read this extra node before weight check, so offset is added */ + uint4 data_node = read_node(kg, offset); + if(mix_weight == 0.0f) return; + + float3 N = stack_valid(data_node.y)? stack_load_float3(stack, data_node.y): sd->N; #else decode_node_uchar4(node.y, &type, ¶m1_offset, ¶m2_offset, NULL); float mix_weight = 1.0f; + + uint4 data_node = read_node(kg, offset); + float3 N = stack_valid(data_node.y)? stack_load_float3(stack, data_node.y): sd->N; #endif float param1 = (stack_valid(param1_offset))? stack_load_float(stack, param1_offset): __int_as_float(node.z); @@ -79,6 +87,7 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st switch(type) { case CLOSURE_BSDF_DIFFUSE_ID: { ShaderClosure *sc = svm_node_closure_get(sd); + sc->N = N; svm_node_closure_set_mix_weight(sc, mix_weight); float roughness = param1; @@ -90,12 +99,14 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st } case CLOSURE_BSDF_TRANSLUCENT_ID: { ShaderClosure *sc = svm_node_closure_get(sd); + sc->N = N; svm_node_closure_set_mix_weight(sc, mix_weight); bsdf_translucent_setup(sd, sc); break; } case CLOSURE_BSDF_TRANSPARENT_ID: { ShaderClosure *sc = svm_node_closure_get(sd); + sc->N = N; svm_node_closure_set_mix_weight(sc, mix_weight); bsdf_transparent_setup(sd, sc); break; @@ -108,6 +119,7 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st break; #endif ShaderClosure *sc = svm_node_closure_get(sd); + sc->N = N; svm_node_closure_set_mix_weight(sc, mix_weight); float roughness = param1; @@ -134,13 +146,14 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st eta = (sd->flag & SD_BACKFACING)? 1.0f/eta: eta; /* fresnel */ - float cosNO = dot(sd->N, sd->I); + float cosNO = dot(N, sd->I); float fresnel = fresnel_dielectric_cos(cosNO, eta); float roughness = param1; #ifdef __MULTI_CLOSURE__ /* reflection */ ShaderClosure *sc = svm_node_closure_get(sd); + sc->N = N; float3 weight = sc->weight; float sample_weight = sc->sample_weight; @@ -150,6 +163,7 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st /* refraction */ sc = svm_node_closure_get(sd); + sc->N = N; sc->weight = weight; sc->sample_weight = sample_weight; @@ -158,6 +172,7 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st svm_node_glossy_setup(sd, sc, type, eta, roughness, true); #else ShaderClosure *sc = svm_node_closure_get(sd); + sc->N = N; bool refract = (randb > fresnel); @@ -174,17 +189,19 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st break; #endif ShaderClosure *sc = svm_node_closure_get(sd); + sc->N = N; svm_node_closure_set_mix_weight(sc, mix_weight); float roughness_u = param1; float roughness_v = param2; - bsdf_ward_setup(sd, sc, normalize(sd->T), roughness_u, roughness_v); + bsdf_ward_setup(sd, sc, sd->T, roughness_u, roughness_v); break; } #endif case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: { ShaderClosure *sc = svm_node_closure_get(sd); + sc->N = N; svm_node_closure_set_mix_weight(sc, mix_weight); /* sigma */ @@ -425,6 +442,8 @@ __device void svm_node_add_closure(ShaderData *sd, float *stack, uint unused, #endif } +/* Tangent */ + #ifdef __DPDU__ __device_inline void svm_node_closure_store_tangent(ShaderData *sd, float3 tangent) { @@ -444,5 +463,14 @@ __device void svm_node_closure_tangent(ShaderData *sd, float *stack, uint tangen } #endif +/* (Bump) normal */ + +__device void svm_node_set_normal(KernelGlobals *kg, ShaderData *sd, float *stack, uint in_direction, uint out_normal) +{ + float3 normal = stack_load_float3(stack, in_direction); + sd->N = normal; + stack_store_float3(stack, out_normal, normal); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/svm_displace.h b/intern/cycles/kernel/svm/svm_displace.h index b1677f67eca..92f23990ad1 100644 --- a/intern/cycles/kernel/svm/svm_displace.h +++ b/intern/cycles/kernel/svm/svm_displace.h @@ -20,23 +20,35 @@ CCL_NAMESPACE_BEGIN /* Bump Node */ -__device void svm_node_set_bump(ShaderData *sd, float *stack, uint c_offset, uint x_offset, uint y_offset) +__device void svm_node_set_bump(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) { #ifdef __RAY_DIFFERENTIALS__ + /* get normal input */ + float3 normal_in = stack_valid(node.y)? stack_load_float3(stack, node.y): sd->N; + + /* get surface tangents from normal */ + float3 Rx = cross(sd->dP.dy, normal_in); + float3 Ry = cross(normal_in, sd->dP.dx); + + /* get bump values */ + uint c_offset, x_offset, y_offset, intensity_offset; + decode_node_uchar4(node.z, &c_offset, &x_offset, &y_offset, &intensity_offset); + float h_c = stack_load_float(stack, c_offset); float h_x = stack_load_float(stack, x_offset); float h_y = stack_load_float(stack, y_offset); - float3 Rx = cross(sd->dP.dy, sd->N); - float3 Ry = cross(sd->N, sd->dP.dx); - + /* compute surface gradient and determinant */ float det = dot(sd->dP.dx, Rx); float3 surfgrad = (h_x - h_c)*Rx + (h_y - h_c)*Ry; + float intensity = stack_load_float(stack, intensity_offset); - surfgrad *= 0.1f; /* todo: remove this factor */ - + surfgrad *= intensity; float absdet = fabsf(det); - sd->N = normalize(absdet*sd->N - signf(det)*surfgrad); + + /* compute and output perturbed normal */ + float3 outN = normalize(absdet*normal_in - signf(det)*surfgrad); + stack_store_float3(stack, node.w, outN); #endif } diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index 22afa304432..327d9cfa014 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -95,6 +95,7 @@ typedef enum NodeType { NODE_TEX_BRICK, NODE_CLOSURE_SET_TANGENT, NODE_CLOSURE_TANGENT, + NODE_CLOSURE_SET_NORMAL, } NodeType; typedef enum NodeAttributeType { diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index c13102e9567..c1c976dc193 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -229,6 +229,8 @@ void ShaderGraph::finalize(bool do_bump, bool do_osl) if(!finalized) { clean(); default_inputs(do_osl); + refine_bump_nodes(); + if(do_bump) bump_from_displacement(); @@ -484,6 +486,61 @@ void ShaderGraph::default_inputs(bool do_osl) add(texco); } +void ShaderGraph::refine_bump_nodes() +{ + /* we transverse the node graph looking for bump nodes, when we find them, + * like in bump_from_displacement(), we copy the sub-graph defined from "bump" + * input to the inputs "center","dx" and "dy" What is in "bump" input is moved + * to "center" input. */ + + foreach(ShaderNode *node, nodes) { + if(node->name == ustring("bump") && node->input("Height")->link) { + ShaderInput *bump_input = node->input("Height"); + set<ShaderNode*> nodes_bump; + + /* make 2 extra copies of the subgraph defined in Bump input */ + map<ShaderNode*, ShaderNode*> nodes_dx; + map<ShaderNode*, ShaderNode*> nodes_dy; + + /* find dependencies for the given input */ + find_dependencies(nodes_bump, bump_input ); + + copy_nodes(nodes_bump, nodes_dx); + copy_nodes(nodes_bump, nodes_dy); + + /* mark nodes to indicate they are use for bump computation, so + that any texture coordinates are shifted by dx/dy when sampling */ + foreach(ShaderNode *node, nodes_bump) + node->bump = SHADER_BUMP_CENTER; + foreach(NodePair& pair, nodes_dx) + pair.second->bump = SHADER_BUMP_DX; + foreach(NodePair& pair, nodes_dy) + pair.second->bump = SHADER_BUMP_DY; + + ShaderOutput *out = bump_input->link; + ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name); + ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name); + + connect(out_dx, node->input("SampleX")); + connect(out_dy, node->input("SampleY")); + + /* add generated nodes */ + foreach(NodePair& pair, nodes_dx) + add(pair.second); + foreach(NodePair& pair, nodes_dy) + add(pair.second); + + /* connect what is conected is bump to samplecenter input*/ + connect(out , node->input("SampleCenter")); + + /* bump input is just for connectivity purpose for the graph input, + * we reconected this input to samplecenter, so lets disconnect it + * from bump input */ + disconnect(bump_input); + } + } +} + void ShaderGraph::bump_from_displacement() { /* generate bump mapping automatically from displacement. bump mapping is @@ -497,7 +554,7 @@ void ShaderGraph::bump_from_displacement() * different shifted coordinates. * * these 3 displacement values are then fed into the bump node, which will - * modify the normal. */ + * output the the perturbed normal. */ ShaderInput *displacement_in = output()->input("Displacement"); @@ -526,6 +583,12 @@ void ShaderGraph::bump_from_displacement() foreach(NodePair& pair, nodes_dy) pair.second->bump = SHADER_BUMP_DY; + /* add set normal node and connect the bump normal ouput to the set normal + * output, so it can finally set the shader normal, note we are only doing + * this for bump from displacement, this will be the only bump allowed to + * overwrite the shader normal */ + ShaderNode *set_normal = add(new SetNormalNode()); + /* add bump node and connect copied graphs to it */ ShaderNode *bump = add(new BumpNode()); @@ -537,6 +600,9 @@ void ShaderGraph::bump_from_displacement() connect(out_center, bump->input("SampleCenter")); connect(out_dx, bump->input("SampleX")); connect(out_dy, bump->input("SampleY")); + + /* connect the bump out to the set normal in: */ + connect(bump->output("Normal"), set_normal->input("Direction")); /* connect bump output to normal input nodes that aren't set yet. actually * this will only set the normal input to the geometry node that we created @@ -544,8 +610,14 @@ void ShaderGraph::bump_from_displacement() foreach(ShaderNode *node, nodes) foreach(ShaderInput *input, node->inputs) if(!input->link && input->default_value == ShaderInput::NORMAL) - connect(bump->output("Normal"), input); - + connect(set_normal->output("Normal"), input); + + /* for displacement bump, clear the normal input in case the above loop + * connected the setnormal out to the bump normalin */ + ShaderInput *bump_normal_in = bump->input("NormalIn"); + if(bump_normal_in) + bump_normal_in->link = NULL; + /* finally, add the copied nodes to the graph. we can't do this earlier * because we would create dependency cycles in the above loop */ foreach(NodePair& pair, nodes_center) diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index d485ed02150..acafe1d5278 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -235,6 +235,7 @@ protected: void break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack); void clean(); void bump_from_displacement(); + void refine_bump_nodes(); void default_inputs(bool do_osl); }; diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index da31a528310..b4ef93a4ff8 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1175,7 +1175,7 @@ BsdfNode::BsdfNode() closure = ccl::CLOSURE_BSDF_DIFFUSE_ID; add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); + add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL); add_output("BSDF", SHADER_SOCKET_CLOSURE); } @@ -1183,6 +1183,7 @@ BsdfNode::BsdfNode() void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2) { ShaderInput *color_in = input("Color"); + ShaderInput *normal_in = input("Normal"); if(color_in->link) { compiler.stack_assign(color_in); @@ -1203,6 +1204,10 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput * compiler.closure_mix_weight_offset()), __float_as_int((param1)? param1->value.x: 0.0f), __float_as_int((param2)? param2->value.x: 0.0f)); + + if(normal_in->link) + compiler.stack_assign(normal_in); + compiler.add_node(NODE_CLOSURE_BSDF, normal_in->stack_offset); } void BsdfNode::compile(SVMCompiler& compiler) @@ -2215,7 +2220,7 @@ static ShaderEnum mix_type_init() enm.insert("Burn", NODE_MIX_BURN); enm.insert("Hue", NODE_MIX_HUE); enm.insert("Saturation", NODE_MIX_SAT); - enm.insert("Value", NODE_MIX_VAL ); + enm.insert("Value", NODE_MIX_VAL); enm.insert("Color", NODE_MIX_COLOR); enm.insert("Soft Light", NODE_MIX_SOFT); enm.insert("Linear Light", NODE_MIX_LINEAR); @@ -2586,6 +2591,7 @@ OutputNode::OutputNode() add_input("Surface", SHADER_SOCKET_CLOSURE); add_input("Volume", SHADER_SOCKET_CLOSURE); add_input("Displacement", SHADER_SOCKET_FLOAT); + add_input("Normal", SHADER_SOCKET_NORMAL); } void OutputNode::compile(SVMCompiler& compiler) @@ -2733,9 +2739,15 @@ void VectorMathNode::compile(OSLCompiler& compiler) BumpNode::BumpNode() : ShaderNode("bump") { + /* this input is used by the user, but after graph transform it is no longer + * used and moved to sampler center/x/y instead */ + add_input("Height", SHADER_SOCKET_NORMAL); + add_input("SampleCenter", SHADER_SOCKET_FLOAT); add_input("SampleX", SHADER_SOCKET_FLOAT); add_input("SampleY", SHADER_SOCKET_FLOAT); + add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL); + add_input("Strength", SHADER_SOCKET_FLOAT, 0.1f); add_output("Normal", SHADER_SOCKET_NORMAL); } @@ -2745,12 +2757,25 @@ void BumpNode::compile(SVMCompiler& compiler) ShaderInput *center_in = input("SampleCenter"); ShaderInput *dx_in = input("SampleX"); ShaderInput *dy_in = input("SampleY"); + ShaderInput *normal_in = input("NormalIn"); + ShaderInput *intensity_in = input("Strength"); + ShaderOutput *normal_out = output("Normal"); compiler.stack_assign(center_in); compiler.stack_assign(dx_in); compiler.stack_assign(dy_in); + compiler.stack_assign(intensity_in); + compiler.stack_assign(normal_out); - compiler.add_node(NODE_SET_BUMP, center_in->stack_offset, dx_in->stack_offset, dy_in->stack_offset); + if(normal_in->link) + compiler.stack_assign(normal_in); + + /* pack all parameters in the node */ + compiler.add_node(NODE_SET_BUMP, + normal_in->stack_offset, + compiler.encode_uchar4(center_in->stack_offset, dx_in->stack_offset, + dy_in->stack_offset, intensity_in->stack_offset), + normal_out->stack_offset); } void BumpNode::compile(OSLCompiler& compiler) @@ -2819,17 +2844,44 @@ void RGBRampNode::compile(OSLCompiler& compiler) /* NB: cycles float3 type is actually 4 floats! need to use an explicit array */ float ramp_color[RAMP_TABLE_SIZE][3]; float ramp_alpha[RAMP_TABLE_SIZE]; + for (int i = 0; i < RAMP_TABLE_SIZE; ++i) { ramp_color[i][0] = ramp[i].x; ramp_color[i][1] = ramp[i].y; ramp_color[i][2] = ramp[i].z; ramp_alpha[i] = ramp[i].w; } + compiler.parameter_color_array("ramp_color", ramp_color, RAMP_TABLE_SIZE); compiler.parameter_array("ramp_alpha", ramp_alpha, RAMP_TABLE_SIZE); compiler.add(this, "node_rgb_ramp"); } +/* Set Normal Node */ + +SetNormalNode::SetNormalNode() +: ShaderNode("set_normal") +{ + add_input("Direction", SHADER_SOCKET_VECTOR); + add_output("Normal", SHADER_SOCKET_NORMAL); +} + +void SetNormalNode::compile(SVMCompiler& compiler) +{ + ShaderInput *direction_in = input("Direction"); + ShaderOutput *normal_out = output("Normal"); + + compiler.stack_assign(direction_in); + compiler.stack_assign(normal_out); + + compiler.add_node(NODE_CLOSURE_SET_NORMAL, direction_in->stack_offset, normal_out->stack_offset); +} + +void SetNormalNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "set_normal"); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 6e5d7be0091..fbc61e12fd4 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -440,6 +440,11 @@ public: float4 ramp[RAMP_TABLE_SIZE]; }; +class SetNormalNode : public ShaderNode { +public: + SHADER_NODE_CLASS(SetNormalNode) +}; + CCL_NAMESPACE_END #endif /* __NODES_H__ */ |