diff options
26 files changed, 537 insertions, 59 deletions
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index cd6c9f319db..a90e0d3ddc4 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -866,6 +866,12 @@ static ShaderNode *add_node(Scene *scene, transform_inverse(get_transform(b_ob.matrix_world())); } } + else if(b_node.is_a(&RNA_ShaderNodeBevel)) { + BL::ShaderNodeBevel b_bevel_node(b_node); + BevelNode *bevel = new BevelNode(); + bevel->samples = b_bevel_node.samples(); + node = bevel; + } if(node) { node->name = b_node.name(); diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 9d52cef1f2c..de056ce97f0 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -160,6 +160,7 @@ set(SRC_CLOSURE_HEADERS set(SRC_SVM_HEADERS svm/svm.h svm/svm_attribute.h + svm/svm_bevel.h svm/svm_blackbody.h svm/svm_bump.h svm/svm_camera.h diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index 86a00d2124d..0a3f9ff23fe 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -29,9 +29,7 @@ #include "kernel/closure/bsdf_hair.h" #include "kernel/closure/bsdf_principled_diffuse.h" #include "kernel/closure/bsdf_principled_sheen.h" -#ifdef __SUBSURFACE__ -# include "kernel/closure/bssrdf.h" -#endif +#include "kernel/closure/bssrdf.h" #ifdef __VOLUME__ # include "kernel/closure/volume.h" #endif diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h index 267aeea6e86..6791c0b83cc 100644 --- a/intern/cycles/kernel/closure/bssrdf.h +++ b/intern/cycles/kernel/closure/bssrdf.h @@ -39,12 +39,11 @@ typedef ccl_addr_space struct Bssrdf { /* paper suggests 1/12.46 which is much too small, suspect it's *12.46 */ #define GAUSS_TRUNCATE 12.46f -ccl_device float bssrdf_gaussian_eval(const ShaderClosure *sc, float r) +ccl_device float bssrdf_gaussian_eval(const float radius, float r) { /* integrate (2*pi*r * exp(-r*r/(2*v)))/(2*pi*v)) from 0 to Rm * = 1 - exp(-Rm*Rm/(2*v)) */ - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float v = bssrdf->radius*bssrdf->radius*(0.25f*0.25f); + const float v = radius*radius*(0.25f*0.25f); const float Rm = sqrtf(v*GAUSS_TRUNCATE); if(r >= Rm) @@ -53,20 +52,19 @@ ccl_device float bssrdf_gaussian_eval(const ShaderClosure *sc, float r) return expf(-r*r/(2.0f*v))/(2.0f*M_PI_F*v); } -ccl_device float bssrdf_gaussian_pdf(const ShaderClosure *sc, float r) +ccl_device float bssrdf_gaussian_pdf(const float radius, float r) { /* 1.0 - expf(-Rm*Rm/(2*v)) simplified */ const float area_truncated = 1.0f - expf(-0.5f*GAUSS_TRUNCATE); - return bssrdf_gaussian_eval(sc, r) * (1.0f/(area_truncated)); + return bssrdf_gaussian_eval(radius, r) * (1.0f/(area_truncated)); } -ccl_device void bssrdf_gaussian_sample(const ShaderClosure *sc, float xi, float *r, float *h) +ccl_device void bssrdf_gaussian_sample(const float radius, float xi, float *r, float *h) { /* xi = integrate (2*pi*r * exp(-r*r/(2*v)))/(2*pi*v)) = -exp(-r^2/(2*v)) * r = sqrt(-2*v*logf(xi)) */ - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float v = bssrdf->radius*bssrdf->radius*(0.25f*0.25f); + const float v = radius*radius*(0.25f*0.25f); const float Rm = sqrtf(v*GAUSS_TRUNCATE); /* 1.0 - expf(-Rm*Rm/(2*v)) simplified */ @@ -87,13 +85,10 @@ ccl_device void bssrdf_gaussian_sample(const ShaderClosure *sc, float xi, float * far as I can tell has no closed form solution. So we get an iterative solution * instead with newton-raphson. */ -ccl_device float bssrdf_cubic_eval(const ShaderClosure *sc, float r) +ccl_device float bssrdf_cubic_eval(const float radius, const float sharpness, float r) { - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float sharpness = bssrdf->sharpness; - if(sharpness == 0.0f) { - const float Rm = bssrdf->radius; + const float Rm = radius; if(r >= Rm) return 0.0f; @@ -107,7 +102,7 @@ ccl_device float bssrdf_cubic_eval(const ShaderClosure *sc, float r) } else { - float Rm = bssrdf->radius*(1.0f + sharpness); + float Rm = radius*(1.0f + sharpness); if(r >= Rm) return 0.0f; @@ -135,9 +130,9 @@ ccl_device float bssrdf_cubic_eval(const ShaderClosure *sc, float r) } } -ccl_device float bssrdf_cubic_pdf(const ShaderClosure *sc, float r) +ccl_device float bssrdf_cubic_pdf(const float radius, const float sharpness, float r) { - return bssrdf_cubic_eval(sc, r); + return bssrdf_cubic_eval(radius, sharpness, r); } /* solve 10x^2 - 20x^3 + 15x^4 - 4x^5 - xi == 0 */ @@ -168,11 +163,9 @@ ccl_device_forceinline float bssrdf_cubic_quintic_root_find(float xi) return x; } -ccl_device void bssrdf_cubic_sample(const ShaderClosure *sc, float xi, float *r, float *h) +ccl_device void bssrdf_cubic_sample(const float radius, const float sharpness, float xi, float *r, float *h) { - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float sharpness = bssrdf->sharpness; - float Rm = bssrdf->radius; + float Rm = radius; float r_ = bssrdf_cubic_quintic_root_find(xi); if(sharpness != 0.0f) { @@ -224,10 +217,8 @@ ccl_device void bssrdf_burley_setup(Bssrdf *bssrdf) bssrdf->d = d; } -ccl_device float bssrdf_burley_eval(const ShaderClosure *sc, float r) +ccl_device float bssrdf_burley_eval(const float d, float r) { - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float d = bssrdf->d; const float Rm = BURLEY_TRUNCATE * d; if(r >= Rm) @@ -246,9 +237,9 @@ ccl_device float bssrdf_burley_eval(const ShaderClosure *sc, float r) return (exp_r_d + exp_r_3_d) / (4.0f*d); } -ccl_device float bssrdf_burley_pdf(const ShaderClosure *sc, float r) +ccl_device float bssrdf_burley_pdf(const float d, float r) { - return bssrdf_burley_eval(sc, r) * (1.0f/BURLEY_TRUNCATE_CDF); + return bssrdf_burley_eval(d, r) * (1.0f/BURLEY_TRUNCATE_CDF); } /* Find the radius for desired CDF value. @@ -291,13 +282,11 @@ ccl_device_forceinline float bssrdf_burley_root_find(float xi) return r; } -ccl_device void bssrdf_burley_sample(const ShaderClosure *sc, +ccl_device void bssrdf_burley_sample(const float d, float xi, float *r, float *h) { - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float d = bssrdf->d; const float Rm = BURLEY_TRUNCATE * d; const float r_ = bssrdf_burley_root_find(xi * BURLEY_TRUNCATE_CDF) * d; @@ -311,29 +300,26 @@ ccl_device void bssrdf_burley_sample(const ShaderClosure *sc, * * Samples distributed over disk with no falloff, for reference. */ -ccl_device float bssrdf_none_eval(const ShaderClosure *sc, float r) +ccl_device float bssrdf_none_eval(const float radius, float r) { - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float Rm = bssrdf->radius; + const float Rm = radius; return (r < Rm)? 1.0f: 0.0f; } -ccl_device float bssrdf_none_pdf(const ShaderClosure *sc, float r) +ccl_device float bssrdf_none_pdf(const float radius, float r) { /* integrate (2*pi*r)/(pi*Rm*Rm) from 0 to Rm = 1 */ - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float Rm = bssrdf->radius; + const float Rm = radius; const float area = (M_PI_F*Rm*Rm); - return bssrdf_none_eval(sc, r) / area; + return bssrdf_none_eval(radius, r) / area; } -ccl_device void bssrdf_none_sample(const ShaderClosure *sc, float xi, float *r, float *h) +ccl_device void bssrdf_none_sample(const float radius, float xi, float *r, float *h) { /* xi = integrate (2*pi*r)/(pi*Rm*Rm) = r^2/Rm^2 * r = sqrt(xi)*Rm */ - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float Rm = bssrdf->radius; + const float Rm = radius; const float r_ = sqrtf(xi)*Rm; *r = r_; @@ -406,22 +392,26 @@ ccl_device int bssrdf_setup(Bssrdf *bssrdf, ClosureType type) ccl_device void bssrdf_sample(const ShaderClosure *sc, float xi, float *r, float *h) { + const Bssrdf *bssrdf = (const Bssrdf*)sc; + if(sc->type == CLOSURE_BSSRDF_CUBIC_ID) - bssrdf_cubic_sample(sc, xi, r, h); + bssrdf_cubic_sample(bssrdf->radius, bssrdf->sharpness, xi, r, h); else if(sc->type == CLOSURE_BSSRDF_GAUSSIAN_ID) - bssrdf_gaussian_sample(sc, xi, r, h); + bssrdf_gaussian_sample(bssrdf->radius, xi, r, h); else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID || sc->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/ - bssrdf_burley_sample(sc, xi, r, h); + bssrdf_burley_sample(bssrdf->d, xi, r, h); } ccl_device_forceinline float bssrdf_pdf(const ShaderClosure *sc, float r) { + const Bssrdf *bssrdf = (const Bssrdf*)sc; + if(sc->type == CLOSURE_BSSRDF_CUBIC_ID) - return bssrdf_cubic_pdf(sc, r); + return bssrdf_cubic_pdf(bssrdf->radius, bssrdf->sharpness, r); else if(sc->type == CLOSURE_BSSRDF_GAUSSIAN_ID) - return bssrdf_gaussian_pdf(sc, r); + return bssrdf_gaussian_pdf(bssrdf->radius, r); else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID || sc->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/ - return bssrdf_burley_pdf(sc, r); + return bssrdf_burley_pdf(bssrdf->d, r); } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h index cd28b75c22c..7ac6807e749 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle.h @@ -117,4 +117,39 @@ ccl_device_inline void motion_triangle_vertices(KernelGlobals *kg, int object, i verts[2] = (1.0f - t)*verts[2] + t*next_verts[2]; } +ccl_device_inline float3 motion_triangle_smooth_normal(KernelGlobals *kg, float3 Ng, int object, int prim, float u, float v, float time) +{ + /* get motion info */ + int numsteps, numverts; + object_motion_info(kg, object, &numsteps, &numverts, NULL); + + /* figure out which steps we need to fetch and their interpolation factor */ + int maxstep = numsteps*2; + int step = min((int)(time*maxstep), maxstep-1); + float t = time*maxstep - step; + + /* find attribute */ + AttributeElement elem; + int offset = find_attribute_motion(kg, object, ATTR_STD_MOTION_VERTEX_NORMAL, &elem); + kernel_assert(offset != ATTR_STD_NOT_FOUND); + + /* fetch normals */ + float3 normals[3], next_normals[3]; + uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); + + motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step, normals); + motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_normals); + + /* interpolate between steps */ + normals[0] = (1.0f - t)*normals[0] + t*next_normals[0]; + normals[1] = (1.0f - t)*normals[1] + t*next_normals[1]; + normals[2] = (1.0f - t)*normals[2] + t*next_normals[2]; + + /* interpolate between vertices */ + float w = 1.0f - u - v; + float3 N = safe_normalize(u*normals[0] + v*normals[1] + w*normals[2]); + + return is_zero(N)? Ng: N; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h index 5cb32545c6e..73cddeb27f7 100644 --- a/intern/cycles/kernel/kernel_bake.h +++ b/intern/cycles/kernel/kernel_bake.h @@ -316,6 +316,13 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, sd.dv.dx = dvdx; sd.dv.dy = dvdy; + /* set RNG state for shaders that use sampling */ + state.rng_hash = rng_hash; + state.rng_offset = 0; + state.sample = sample; + state.num_samples = num_samples; + state.min_ray_pdf = FLT_MAX; + /* light passes if we need more than color */ if(pass_filter & ~BAKE_FILTER_COLOR) compute_light_pass(kg, &sd, &L, rng_hash, pass_filter, sample); diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 73cf63d42be..fc3e7b3da98 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -306,6 +306,9 @@ enum PathTraceDimension { PRNG_PHASE_CHANNEL = 6, PRNG_SCATTER_DISTANCE = 7, PRNG_BOUNCE_NUM = 8, + + PRNG_BEVEL_U = 6, /* reuse volume dimension, correlation won't harm */ + PRNG_BEVEL_V = 7, }; enum SamplingPattern { diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 8ae004031e1..3789073f344 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -117,6 +117,7 @@ ustring OSLRenderServices::u_I("I"); ustring OSLRenderServices::u_u("u"); ustring OSLRenderServices::u_v("v"); ustring OSLRenderServices::u_empty; +ustring OSLRenderServices::u_at_bevel("@bevel"); OSLRenderServices::OSLRenderServices() { @@ -958,20 +959,36 @@ bool OSLRenderServices::texture(ustring filename, return true; } #endif - bool status; + bool status = false; if(filename.length() && filename[0] == '@') { - int slot = atoi(filename.c_str() + 1); - float4 rgba = kernel_tex_image_interp(kg, slot, s, 1.0f - t); - - result[0] = rgba[0]; - if(nchannels > 1) - result[1] = rgba[1]; - if(nchannels > 2) - result[2] = rgba[2]; - if(nchannels > 3) - result[3] = rgba[3]; - status = true; + if(filename == u_at_bevel) { + /* Bevel shader hack. */ + if(nchannels >= 3) { + PathState *state = sd->osl_path_state; + int num_samples = (int)s; + float radius = t; + float3 N = svm_bevel(kg, sd, state, radius, num_samples); + result[0] = N.x; + result[1] = N.y; + result[2] = N.z; + status = true; + } + } + else { + /* Packed texture. */ + int slot = atoi(filename.c_str() + 1); + float4 rgba = kernel_tex_image_interp(kg, slot, s, 1.0f - t); + + result[0] = rgba[0]; + if(nchannels > 1) + result[1] = rgba[1]; + if(nchannels > 2) + result[2] = rgba[2]; + if(nchannels > 3) + result[3] = rgba[3]; + status = true; + } } else { if(texture_handle != NULL) { diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h index ec34ca77115..642529655bf 100644 --- a/intern/cycles/kernel/osl/osl_services.h +++ b/intern/cycles/kernel/osl/osl_services.h @@ -179,6 +179,7 @@ public: static ustring u_u; static ustring u_v; static ustring u_empty; + static ustring u_at_bevel; private: KernelGlobals *kernel_globals; diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt index 1a8ed4c884a..83cfdbcf8ba 100644 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/shaders/CMakeLists.txt @@ -7,6 +7,7 @@ set(SRC_OSL node_anisotropic_bsdf.osl node_attribute.osl node_background.osl + node_bevel.osl node_brick_texture.osl node_brightness.osl node_bump.osl diff --git a/intern/cycles/kernel/shaders/node_bevel.osl b/intern/cycles/kernel/shaders/node_bevel.osl new file mode 100644 index 00000000000..a5b185b6b4c --- /dev/null +++ b/intern/cycles/kernel/shaders/node_bevel.osl @@ -0,0 +1,31 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stdosl.h" + +shader node_bevel( + int samples = 4, + float Radius = 0.05, + normal NormalIn = N, + output normal NormalOut = N) +{ + /* Abuse texture call with special @bevel token. */ + NormalOut = (normal)(color)texture("@bevel", samples, Radius); + + /* Preserve input normal. */ + NormalOut = normalize(N + (NormalOut - NormalIn)); +} + diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index f0b3adcdad5..9ff02c1586b 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -183,6 +183,10 @@ CCL_NAMESPACE_END #include "kernel/svm/svm_voxel.h" #include "kernel/svm/svm_bump.h" +#ifdef __SHADER_RAYTRACE__ +# include "kernel/svm/svm_bevel.h" +#endif + CCL_NAMESPACE_BEGIN #define NODES_GROUP(group) ((group) <= __NODES_MAX_GROUP__) @@ -464,6 +468,11 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ccl_a svm_node_tex_voxel(kg, sd, stack, node, &offset); break; # endif /* NODES_FEATURE(NODE_FEATURE_VOLUME) */ +# ifdef __SHADER_RAYTRACE__ + case NODE_BEVEL: + svm_node_bevel(kg, sd, state, stack, node); + break; +# endif /* __SHADER_RAYTRACE__ */ #endif /* NODES_GROUP(NODE_GROUP_LEVEL_3) */ case NODE_END: return; diff --git a/intern/cycles/kernel/svm/svm_bevel.h b/intern/cycles/kernel/svm/svm_bevel.h new file mode 100644 index 00000000000..65afe1f74ec --- /dev/null +++ b/intern/cycles/kernel/svm/svm_bevel.h @@ -0,0 +1,227 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +CCL_NAMESPACE_BEGIN + +/* Bevel shader averaging normals from nearby surfaces. + * + * Sampling strategy from: BSSRDF Importance Sampling, SIGGRAPH 2013 + * http://library.imageworks.com/pdfs/imageworks-library-BSSRDF-sampling.pdf + */ + +ccl_device_noinline float3 svm_bevel( + KernelGlobals *kg, + ShaderData *sd, + ccl_addr_space PathState *state, + float radius, + int num_samples) +{ + /* Early out if no sampling needed. */ + if(radius <= 0.0f || num_samples < 1 || sd->object == OBJECT_NONE) { + return sd->N; + } + + /* Don't bevel for blurry indirect rays. */ + if(state->min_ray_pdf < 8.0f) { + return sd->N; + } + + /* Setup for multi intersection. */ + LocalIntersection isect; + uint lcg_state = lcg_state_init_addrspace(state, 0x64c6a40e); + + /* Sample normals from surrounding points on surface. */ + float3 sum_N = make_float3(0.0f, 0.0f, 0.0f); + + for(int sample = 0; sample < num_samples; sample++) { + float disk_u, disk_v; + path_branched_rng_2D(kg, state->rng_hash, state, sample, num_samples, + PRNG_BEVEL_U, &disk_u, &disk_v); + + /* Pick random axis in local frame and point on disk. */ + float3 disk_N, disk_T, disk_B; + float pick_pdf_N, pick_pdf_T, pick_pdf_B; + + disk_N = sd->Ng; + make_orthonormals(disk_N, &disk_T, &disk_B); + + float axisu = disk_u; + + if(axisu < 0.5f) { + pick_pdf_N = 0.5f; + pick_pdf_T = 0.25f; + pick_pdf_B = 0.25f; + disk_u *= 2.0f; + } + else if(axisu < 0.75f) { + float3 tmp = disk_N; + disk_N = disk_T; + disk_T = tmp; + pick_pdf_N = 0.25f; + pick_pdf_T = 0.5f; + pick_pdf_B = 0.25f; + disk_u = (disk_u - 0.5f)*4.0f; + } + else { + float3 tmp = disk_N; + disk_N = disk_B; + disk_B = tmp; + pick_pdf_N = 0.25f; + pick_pdf_T = 0.25f; + pick_pdf_B = 0.5f; + disk_u = (disk_u - 0.75f)*4.0f; + } + + /* Sample point on disk. */ + float phi = M_2PI_F * disk_u; + float disk_r = disk_v; + float disk_height; + + /* Perhaps find something better than Cubic BSSRDF, but happens to work well. */ + bssrdf_cubic_sample(radius, 0.0f, disk_r, &disk_r, &disk_height); + + float3 disk_P = (disk_r*cosf(phi)) * disk_T + (disk_r*sinf(phi)) * disk_B; + + /* Create ray. */ + Ray *ray = &isect.ray; + ray->P = sd->P + disk_N*disk_height + disk_P; + ray->D = -disk_N; + ray->t = 2.0f*disk_height; + ray->dP = sd->dP; + ray->dD = differential3_zero(); + ray->time = sd->time; + + /* Intersect with the same object. if multiple intersections are found it + * will use at most LOCAL_MAX_HITS hits, a random subset of all hits. */ + scene_intersect_local(kg, + *ray, + &isect, + sd->object, + &lcg_state, + LOCAL_MAX_HITS); + + int num_eval_hits = min(isect.num_hits, LOCAL_MAX_HITS); + + for(int hit = 0; hit < num_eval_hits; hit++) { + /* Quickly retrieve P and Ng without setting up ShaderData. */ + float3 hit_P; + if(sd->type & PRIMITIVE_TRIANGLE) { + hit_P = triangle_refine_local(kg, + sd, + &isect.hits[hit], + ray); + } +#ifdef __OBJECT_MOTION__ + else if(sd->type & PRIMITIVE_MOTION_TRIANGLE) { + float3 verts[3]; + motion_triangle_vertices( + kg, + sd->object, + kernel_tex_fetch(__prim_index, isect.hits[hit].prim), + sd->time, + verts); + hit_P = motion_triangle_refine_local(kg, + sd, + &isect.hits[hit], + ray, + verts); + } +#endif /* __OBJECT_MOTION__ */ + + float3 hit_Ng = isect.Ng[hit]; + + /* Compute smooth normal. */ + float3 N = hit_Ng; + int prim = kernel_tex_fetch(__prim_index, isect.hits[hit].prim); + int shader = kernel_tex_fetch(__tri_shader, prim); + + if (shader & SHADER_SMOOTH_NORMAL) { + float u = isect.hits[hit].u; + float v = isect.hits[hit].v; + + if (sd->type & PRIMITIVE_TRIANGLE) { + N = triangle_smooth_normal(kg, N, prim, u, v); + } +#ifdef __OBJECT_MOTION__ + else if(sd->type & PRIMITIVE_MOTION_TRIANGLE) { + N = motion_triangle_smooth_normal(kg, N, sd->object, prim, u, v, sd->time); + } +#endif /* __OBJECT_MOTION__ */ + } + + /* Transform normals to world space. */ + if(isect.hits[hit].object != OBJECT_NONE) { + object_normal_transform(kg, sd, &N); + object_normal_transform(kg, sd, &hit_Ng); + } + + /* Probability densities for local frame axes. */ + float pdf_N = pick_pdf_N * fabsf(dot(disk_N, hit_Ng)); + float pdf_T = pick_pdf_T * fabsf(dot(disk_T, hit_Ng)); + float pdf_B = pick_pdf_B * fabsf(dot(disk_B, hit_Ng)); + + /* Multiple importance sample between 3 axes, power heuristic + * found to be slightly better than balance heuristic. */ + float mis_weight = power_heuristic_3(pdf_N, pdf_T, pdf_B); + + /* Real distance to sampled point. */ + float r = len(hit_P - sd->P); + + /* Compute weight. */ + float w = mis_weight / pdf_N; + if(isect.num_hits > LOCAL_MAX_HITS) { + w *= isect.num_hits/(float)LOCAL_MAX_HITS; + } + + float pdf = bssrdf_cubic_pdf(radius, 0.0f, r); + float disk_pdf = bssrdf_cubic_pdf(radius, 0.0f, disk_r); + + w *= pdf / disk_pdf; + + /* Sum normal and weight. */ + sum_N += w * N; + } + } + + /* Normalize. */ + float3 N = safe_normalize(sum_N); + return is_zero(N) ? sd->N : N; +} + +ccl_device void svm_node_bevel( + KernelGlobals *kg, + ShaderData *sd, + ccl_addr_space PathState *state, + float *stack, + uint4 node) +{ + uint num_samples, radius_offset, normal_offset, out_offset; + decode_node_uchar4(node.y, &num_samples, &radius_offset, &normal_offset, &out_offset); + + float radius = stack_load_float(stack, radius_offset); + float3 bevel_N = svm_bevel(kg, sd, state, radius, num_samples); + + if(stack_valid(normal_offset)) { + /* Preserve input normal. */ + float3 ref_N = stack_load_float3(stack, normal_offset); + bevel_N = normalize(sd->N + (bevel_N - ref_N)); + } + + stack_store_float3(stack, out_offset, bevel_N); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index e81c9a211b0..f08ec76c055 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -132,6 +132,7 @@ typedef enum ShaderNodeType { NODE_TEX_VOXEL, NODE_ENTER_BUMP_EVAL, NODE_LEAVE_BUMP_EVAL, + NODE_BEVEL, } ShaderNodeType; typedef enum NodeAttributeType { diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 2b682756c6a..4452fadaf02 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -5604,4 +5604,44 @@ void TangentNode::compile(OSLCompiler& compiler) compiler.add(this, "node_tangent"); } +/* Bevel */ + +NODE_DEFINE(BevelNode) +{ + NodeType* type = NodeType::add("bevel", create, NodeType::SHADER); + + SOCKET_INT(samples, "Samples", 4); + + SOCKET_IN_FLOAT(radius, "Radius", 0.05f); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + + SOCKET_OUT_NORMAL(bevel, "Normal"); + + return type; +} + +BevelNode::BevelNode() +: ShaderNode(node_type) +{ +} + +void BevelNode::compile(SVMCompiler& compiler) +{ + ShaderInput *radius_in = input("Radius"); + ShaderInput *normal_in = input("Normal"); + ShaderOutput *normal_out = output("Normal"); + + compiler.add_node(NODE_BEVEL, + compiler.encode_uchar4(samples, + compiler.stack_assign(radius_in), + compiler.stack_assign_if_linked(normal_in), + compiler.stack_assign(normal_out))); +} + +void BevelNode::compile(OSLCompiler& compiler) +{ + compiler.parameter(this, "samples"); + compiler.add(this, "node_bevel"); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 3b8a8bcd4b5..64d7522a23a 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -1015,6 +1015,18 @@ public: float3 normal_osl; }; +class BevelNode : public ShaderNode { +public: + SHADER_NODE_CLASS(BevelNode) + bool has_spatial_varying() { return true; } + virtual int get_group() { return NODE_GROUP_LEVEL_3; } + virtual bool has_raytrace() { return true; } + + float radius; + float3 normal; + int samples; +}; + CCL_NAMESPACE_END #endif /* __NODES_H__ */ diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index bee6ae80590..8a8032e5bfb 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -207,6 +207,7 @@ shader_node_categories = [ NodeItem("ShaderNodeTangent"), NodeItem("ShaderNodeNewGeometry"), NodeItem("ShaderNodeWireframe"), + NodeItem("ShaderNodeBevel"), NodeItem("ShaderNodeObjectInfo"), NodeItem("ShaderNodeHairInfo"), NodeItem("ShaderNodeParticleInfo"), diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 81de70ca8a4..c364d0ebb1b 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -788,6 +788,7 @@ struct ShadeResult; #define SH_NODE_UVALONGSTROKE 191 #define SH_NODE_TEX_POINTDENSITY 192 #define SH_NODE_BSDF_PRINCIPLED 193 +#define SH_NODE_BEVEL 197 /* 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 f7c2ac8ecbf..2ca414c5e6e 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3564,6 +3564,7 @@ static void registerShaderNodes(void) register_node_type_sh_hue_sat(); register_node_type_sh_attribute(); + register_node_type_sh_bevel(); register_node_type_sh_geometry(); register_node_type_sh_light_path(); register_node_type_sh_light_falloff(); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 944c691ee64..8b103200862 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1131,6 +1131,11 @@ static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), Po uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE); } +static void node_shader_buts_bevel(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "samples", 0, NULL, ICON_NONE); +} + /* only once called */ static void node_shader_set_butfunc(bNodeType *ntype) { @@ -1262,6 +1267,9 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_OUTPUT_LINESTYLE: ntype->draw_buttons = node_buts_output_linestyle; break; + case SH_NODE_BEVEL: + ntype->draw_buttons = node_shader_buts_bevel; + break; } } diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index ce696706628..4ac69119a6c 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -3808,6 +3808,11 @@ void node_bump(float strength, float dist, float height, vec3 N, vec3 surf_pos, result = normalize(strength * result + (1.0 - strength) * N); } +void node_bevel(float radius, vec3 N, out vec3 result) +{ + result = N; +} + /* output */ void node_output_material(vec4 surface, vec4 volume, float displacement, out vec4 result) diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 45793635877..4c096beaca7 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4388,6 +4388,16 @@ static void def_sh_tangent(StructRNA *srna) RNA_def_struct_sdna_from(srna, "bNode", NULL); } +static void def_sh_bevel(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "samples", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "custom1"); + RNA_def_property_range(prop, 2, 16); + RNA_def_property_ui_text(prop, "Samples", "Number of rays to trace per shader evaluation"); + RNA_def_property_update(prop, 0, "rna_Node_update"); +} static void def_sh_subsurface(StructRNA *srna) { diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index c5a3c70100b..21f9afec903 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -192,6 +192,7 @@ set(SRC shader/nodes/node_shader_script.c shader/nodes/node_shader_subsurface_scattering.c shader/nodes/node_shader_tangent.c + shader/nodes/node_shader_bevel.c shader/nodes/node_shader_tex_brick.c shader/nodes/node_shader_tex_checker.c shader/nodes/node_shader_tex_coord.c diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index 804c1897a27..f7d36e3dbef 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -78,6 +78,7 @@ void register_node_type_sh_tex_brick(void); void register_node_type_sh_tex_pointdensity(void); void register_node_type_sh_attribute(void); +void register_node_type_sh_bevel(void); void register_node_type_sh_geometry(void); void register_node_type_sh_light_path(void); void register_node_type_sh_light_falloff(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 02422a8622a..13844298c5a 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -126,6 +126,7 @@ DefNode( ShaderNode, SH_NODE_UVMAP, def_sh_uvmap, "UV DefNode( ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UVALONGSTROKE", UVAlongStroke, "UV Along Stroke", "" ) DefNode( ShaderNode, SH_NODE_SEPXYZ, 0, "SEPXYZ", SeparateXYZ, "Separate XYZ", "" ) DefNode( ShaderNode, SH_NODE_COMBXYZ, 0, "COMBXYZ", CombineXYZ, "Combine XYZ", "" ) +DefNode( ShaderNode, SH_NODE_BEVEL, def_sh_bevel, "BEVEL", Bevel, "Bevel", "" ) DefNode( CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" ) DefNode( CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" ) diff --git a/source/blender/nodes/shader/nodes/node_shader_bevel.c b/source/blender/nodes/shader/nodes/node_shader_bevel.c new file mode 100644 index 00000000000..fc7d109f123 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_bevel.c @@ -0,0 +1,70 @@ +/* + * ***** 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_bevel_in[] = { + { SOCK_FLOAT, 0, N_("Radius"), 0.05f, 0.0f, 0.0f, 0.0f, 0.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_bevel_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_bevel(bNodeTree *UNUSED(ntree), bNode *node) +{ + node->custom1 = 4; /* samples */ +} + +static int gpu_shader_bevel(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + if (!in[1].link) { + in[1].link = GPU_builtin(GPU_VIEW_NORMAL); + } + + return GPU_stack_link(mat, "node_bevel", in, out); +} + +/* node type definition */ +void register_node_type_sh_bevel(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_BEVEL, "Bevel", NODE_CLASS_INPUT, 0); + node_type_compatibility(&ntype, NODE_NEW_SHADING); + node_type_socket_templates(&ntype, sh_node_bevel_in, sh_node_bevel_out); + node_type_init(&ntype, node_shader_init_bevel); + node_type_storage(&ntype, "", NULL, NULL); + node_type_gpu(&ntype, gpu_shader_bevel); + + nodeRegisterType(&ntype); +} |