diff options
Diffstat (limited to 'intern/cycles/kernel')
25 files changed, 997 insertions, 234 deletions
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index fde881c0a06..6d5b9a063a0 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -20,12 +20,12 @@ set(SRC set(SRC_HEADERS kernel.h kernel_accumulate.h - kernel_attribute.h kernel_bvh.h kernel_camera.h kernel_compat_cpu.h kernel_compat_cuda.h kernel_compat_opencl.h + kernel_curve.h kernel_differential.h kernel_displace.h kernel_emission.h @@ -37,6 +37,7 @@ set(SRC_HEADERS kernel_object.h kernel_passes.h kernel_path.h + kernel_primitive.h kernel_projection.h kernel_random.h kernel_shader.h diff --git a/intern/cycles/kernel/kernel_attribute.h b/intern/cycles/kernel/kernel_attribute.h deleted file mode 100644 index b7ad731c883..00000000000 --- a/intern/cycles/kernel/kernel_attribute.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - */ - -#ifndef __KERNEL_ATTRIBUTE_CL__ -#define __KERNEL_ATTRIBUTE_CL__ - -CCL_NAMESPACE_BEGIN - -/* note: declared in kernel.h, have to add it here because kernel.h is not available */ -bool kernel_osl_use(KernelGlobals *kg); - -__device_inline int find_attribute(KernelGlobals *kg, ShaderData *sd, uint id) -{ -#ifdef __OSL__ - if (kg->osl) { - return OSLShader::find_attribute(kg, sd, id); - } - else -#endif - { - /* for SVM, find attribute by unique id */ - uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride; - uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); - - while(attr_map.x != id) - attr_map = kernel_tex_fetch(__attributes_map, ++attr_offset); - - /* return result */ - return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z; - } -} - -CCL_NAMESPACE_END - -#endif /* __KERNEL_ATTRIBUTE_CL__ */ diff --git a/intern/cycles/kernel/kernel_bvh.h b/intern/cycles/kernel/kernel_bvh.h index d70485fd6cf..2cb29207b05 100644 --- a/intern/cycles/kernel/kernel_bvh.h +++ b/intern/cycles/kernel/kernel_bvh.h @@ -205,6 +205,145 @@ __device_inline void bvh_triangle_intersect(KernelGlobals *kg, Intersection *ise } } +#ifdef __HAIR__ +__device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect, + float3 P, float3 idir, uint visibility, int object, int curveAddr, int segment) +{ + /* curve Intersection check */ + + int flags = kernel_data.curve_kernel_data.curveflags; + + int prim = kernel_tex_fetch(__prim_index, curveAddr); + float4 v00 = kernel_tex_fetch(__curves, prim); + + int k0 = __float_as_int(v00.x) + segment; + int k1 = k0 + 1; + + float4 P1 = kernel_tex_fetch(__curve_keys, k0); + float4 P2 = kernel_tex_fetch(__curve_keys, k1); + + float l = len(P2 - P1); + float r1 = P1.w; + float r2 = P2.w; + float mr = max(r1,r2); + float3 p1 = float4_to_float3(P1); + float3 p2 = float4_to_float3(P2); + float3 dif = P - p1; + float3 dir = 1.0f/idir; + + float sp_r = mr + 0.5f * l; + float3 sphere_dif = P - ((p1 + p2) * 0.5f); + float sphere_b = dot(dir,sphere_dif); + sphere_dif = sphere_dif - sphere_b * dir; + sphere_b = dot(dir,sphere_dif); + float sdisc = sphere_b * sphere_b - len_squared(sphere_dif) + sp_r * sp_r; + if(sdisc < 0.0f) + return; + + /* obtain parameters and test midpoint distance for suitable modes*/ + float3 tg = (p2 - p1) / l; + float gd = (r2 - r1) / l; + float dirz = dot(dir,tg); + float difz = dot(dif,tg); + + float a = 1.0f - (dirz*dirz*(1 + gd*gd)); + float halfb = (dot(dir,dif) - dirz*(difz + gd*(difz*gd + r1))); + + float tcentre = -halfb/a; + float zcentre = difz + (dirz * tcentre); + + if((tcentre > isect->t) && !(flags & CURVE_KN_ACCURATE)) + return; + if((zcentre < 0 || zcentre > l) && !(flags & CURVE_KN_ACCURATE) && !(flags & CURVE_KN_INTERSECTCORRECTION)) + return; + + /* test minimum separation*/ + float3 cprod = cross(tg, dir); + float3 cprod2 = cross(tg, dif); + float cprodsq = len_squared(cprod); + float cprod2sq = len_squared(cprod2); + float distscaled = dot(cprod,dif); + + if(cprodsq == 0) + distscaled = cprod2sq; + else + distscaled = (distscaled*distscaled)/cprodsq; + + if(distscaled > mr*mr) + return; + + /* calculate true intersection*/ + float3 tdif = P - p1 + tcentre * dir; + float tdifz = dot(tdif,tg); + float tb = 2*(dot(dir,tdif) - dirz*(tdifz + gd*(tdifz*gd + r1))); + float tc = dot(tdif,tdif) - tdifz * tdifz * (1 + gd*gd) - r1*r1 - 2*r1*tdifz*gd; + float td = tb*tb - 4*a*tc; + + if (td < 0.0f) + return; + + float rootd = 0.0f; + float correction = 0.0f; + if(flags & CURVE_KN_ACCURATE) { + rootd = sqrtf(td); + correction = ((-tb - rootd)/(2*a)); + } + + float t = tcentre + correction; + + if(t < isect->t) { + + if(flags & CURVE_KN_INTERSECTCORRECTION) { + rootd = sqrtf(td); + correction = ((-tb - rootd)/(2*a)); + t = tcentre + correction; + } + + float z = zcentre + (dirz * correction); + bool backface = false; + + if(flags & CURVE_KN_BACKFACING && (t < 0.0f || z < 0 || z > l)) { + backface = true; + correction = ((-tb + rootd)/(2*a)); + t = tcentre + correction; + z = zcentre + (dirz * correction); + } + + if(t > 0.0f && t < isect->t && z >= 0 && z <= l) { + + if (flags & CURVE_KN_ENCLOSEFILTER) { + + float enc_ratio = kernel_data.curve_kernel_data.encasing_ratio; + if((dot(P - p1, tg) > -r1 * enc_ratio) && (dot(P - p2, tg) < r2 * enc_ratio)) { + float a2 = 1.0f - (dirz*dirz*(1 + gd*gd*enc_ratio*enc_ratio)); + float c2 = dot(dif,dif) - difz * difz * (1 + gd*gd*enc_ratio*enc_ratio) - r1*r1*enc_ratio*enc_ratio - 2*r1*difz*gd*enc_ratio; + if(a2*c2 < 0.0f) + return; + } + } + +#ifdef __VISIBILITY_FLAG__ + /* visibility flag test. we do it here under the assumption + * that most triangles are culled by node flags */ + if(kernel_tex_fetch(__prim_visibility, curveAddr) & visibility) +#endif + { + /* record intersection */ + isect->prim = curveAddr; + isect->segment = segment; + isect->object = object; + isect->u = z/l; + isect->v = td/(4*a*a); + isect->t = t; + + if(backface) + isect->u = -isect->u; + } + } + } +} +#endif + __device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect) { /* traversal stack in CUDA thread-local memory */ @@ -281,10 +420,16 @@ __device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint nodeAddr = traversalStack[stackPtr]; --stackPtr; - /* triangle intersection */ + /* primitive intersection */ while(primAddr < primAddr2) { - /* intersect ray against triangle */ - bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); + /* intersect ray against primitive */ +#ifdef __HAIR__ + uint segment = kernel_tex_fetch(__prim_segment, primAddr); + if(segment != ~0) + bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment); + else +#endif + bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); /* shadow ray early termination */ if(visibility == PATH_RAY_SHADOW_OPAQUE && isect->prim != ~0) @@ -401,10 +546,16 @@ __device_inline bool bvh_intersect_motion(KernelGlobals *kg, const Ray *ray, con nodeAddr = traversalStack[stackPtr]; --stackPtr; - /* triangle intersection */ + /* primitive intersection */ while(primAddr < primAddr2) { - /* intersect ray against triangle */ - bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); + /* intersect ray against primitive */ +#ifdef __HAIR__ + uint segment = kernel_tex_fetch(__prim_segment, primAddr); + if(segment != ~0) + bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment); + else +#endif + bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); /* shadow ray early termination */ if(visibility == PATH_RAY_SHADOW_OPAQUE && isect->prim != ~0) @@ -457,12 +608,15 @@ __device_inline float3 ray_offset(float3 P, float3 Ng) { #ifdef __INTERSECTION_REFINE__ const float epsilon_f = 1e-5f; + /* ideally this should match epsilon_f, but instancing/mblur + * precision makes it problematic */ + const float epsilon_test = 1e-1f; const int epsilon_i = 32; float3 res; /* x component */ - if(fabsf(P.x) < epsilon_f) { + if(fabsf(P.x) < epsilon_test) { res.x = P.x + Ng.x*epsilon_f; } else { @@ -472,7 +626,7 @@ __device_inline float3 ray_offset(float3 P, float3 Ng) } /* y component */ - if(fabsf(P.y) < epsilon_f) { + if(fabsf(P.y) < epsilon_test) { res.y = P.y + Ng.y*epsilon_f; } else { @@ -482,7 +636,7 @@ __device_inline float3 ray_offset(float3 P, float3 Ng) } /* z component */ - if(fabsf(P.z) < epsilon_f) { + if(fabsf(P.z) < epsilon_test) { res.z = P.z + Ng.z*epsilon_f; } else { @@ -542,5 +696,105 @@ __device_inline float3 bvh_triangle_refine(KernelGlobals *kg, ShaderData *sd, co #endif } +#ifdef __HAIR__ +__device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, float t) +{ + int flag = kernel_data.curve_kernel_data.curveflags; + float3 P = ray->P; + float3 D = ray->D; + + if(isect->object != ~0) { +#ifdef __OBJECT_MOTION__ + Transform tfm = sd->ob_itfm; +#else + Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM); +#endif + + P = transform_point(&tfm, P); + D = transform_direction(&tfm, D*t); + D = normalize_len(D, &t); + } + + int prim = kernel_tex_fetch(__prim_index, isect->prim); + float4 v00 = kernel_tex_fetch(__curves, prim); + + int k0 = __float_as_int(v00.x) + isect->segment; + int k1 = k0 + 1; + + float4 P1 = kernel_tex_fetch(__curve_keys, k0); + float4 P2 = kernel_tex_fetch(__curve_keys, k1); + float l = len(P2 - P1); + float r1 = P1.w; + float r2 = P2.w; + float3 tg = float4_to_float3(P2 - P1) / l; + float3 dif = P - float4_to_float3(P1) + t * D; + float gd = ((r2 - r1)/l); + + P = P + D*t; + + dif = P - float4_to_float3(P1); + + #ifdef __UV__ + sd->u = dot(dif,tg)/l; + sd->v = 0.0f; + #endif + + if (flag & CURVE_KN_TRUETANGENTGNORMAL) { + sd->Ng = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix)); + sd->Ng = normalize(sd->Ng); + if (flag & CURVE_KN_NORMALCORRECTION) + { + //sd->Ng = normalize(sd->Ng); + sd->Ng = sd->Ng - gd * tg; + sd->Ng = normalize(sd->Ng); + } + } + else { + sd->Ng = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd); + if (gd != 0.0f) { + sd->Ng = sd->Ng - gd * tg ; + sd->Ng = normalize(sd->Ng); + } + } + + sd->N = sd->Ng; + + if (flag & CURVE_KN_TANGENTGNORMAL && !(flag & CURVE_KN_TRUETANGENTGNORMAL)) { + sd->N = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix)); + sd->N = normalize(sd->N); + if (flag & CURVE_KN_NORMALCORRECTION) { + //sd->N = normalize(sd->N); + sd->N = sd->N - gd * tg; + sd->N = normalize(sd->N); + } + } + if (!(flag & CURVE_KN_TANGENTGNORMAL) && flag & CURVE_KN_TRUETANGENTGNORMAL) { + sd->N = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd); + if (gd != 0.0f) { + sd->N = sd->N - gd * tg ; + sd->N = normalize(sd->N); + } + } + + #ifdef __DPDU__ + /* dPdu/dPdv */ + sd->dPdu = tg; + sd->dPdv = cross(tg,sd->Ng); + #endif + + if(isect->object != ~0) { +#ifdef __OBJECT_MOTION__ + Transform tfm = sd->ob_tfm; +#else + Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM); +#endif + + P = transform_point(&tfm, P); + } + + return P; +} +#endif + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_curve.h b/intern/cycles/kernel/kernel_curve.h new file mode 100644 index 00000000000..e065717888c --- /dev/null +++ b/intern/cycles/kernel/kernel_curve.h @@ -0,0 +1,141 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +#ifdef __HAIR__ + +/* curve attributes */ + +__device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy) +{ + if(elem == ATTR_ELEMENT_CURVE) { +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = 0.0f; + if(dy) *dy = 0.0f; +#endif + + return kernel_tex_fetch(__attributes_float, offset + sd->prim); + } + else if(elem == ATTR_ELEMENT_CURVE_KEY) { + float4 curvedata = kernel_tex_fetch(__curves, sd->prim); + int k0 = __float_as_int(curvedata.x) + sd->segment; + int k1 = k0 + 1; + + float f0 = kernel_tex_fetch(__attributes_float, offset + k0); + float f1 = kernel_tex_fetch(__attributes_float, offset + k1); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = sd->du.dx*(f1 - f0); + if(dy) *dy = 0.0f; +#endif + + return (1.0f - sd->u)*f0 + sd->u*f1; + } + else { +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = 0.0f; + if(dy) *dy = 0.0f; +#endif + + return 0.0f; + } +} + +__device float3 curve_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy) +{ + if(elem == ATTR_ELEMENT_CURVE) { + /* idea: we can't derive any useful differentials here, but for tiled + * mipmap image caching it would be useful to avoid reading the highest + * detail level always. maybe a derivative based on the hair density + * could be computed somehow? */ +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); +#endif + + return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + sd->prim)); + } + else if(elem == ATTR_ELEMENT_CURVE_KEY) { + float4 curvedata = kernel_tex_fetch(__curves, sd->prim); + int k0 = __float_as_int(curvedata.x) + sd->segment; + int k1 = k0 + 1; + + float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k0)); + float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k1)); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = sd->du.dx*(f1 - f0); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); +#endif + + return (1.0f - sd->u)*f0 + sd->u*f1; + } + else { +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); +#endif + + return make_float3(0.0f, 0.0f, 0.0f); + } +} + +/* hair info node functions */ + +__device float curve_thickness(KernelGlobals *kg, ShaderData *sd) +{ + float r = 0.0f; + + if(sd->segment != ~0) { + float4 curvedata = kernel_tex_fetch(__curves, sd->prim); + int k0 = __float_as_int(curvedata.x) + sd->segment; + int k1 = k0 + 1; + + float4 P1 = kernel_tex_fetch(__curve_keys, k0); + float4 P2 = kernel_tex_fetch(__curve_keys, k1); + r = (P2.w - P1.w) * sd->u + P1.w; + } + + return r*2.0f; +} + +__device float3 curve_tangent_normal(KernelGlobals *kg, ShaderData *sd) +{ + float3 tgN = make_float3(0.0f,0.0f,0.0f); + + if(sd->segment != ~0) { + float normalmix = kernel_data.curve_kernel_data.normalmix; + + tgN = -(-sd->I - sd->dPdu * (dot(sd->dPdu,-sd->I) * normalmix / len_squared(sd->dPdu))); + tgN = normalize(tgN); + + /* need to find suitable scaled gd for corrected normal */ +#if 0 + if (kernel_data.curve_kernel_data.use_tangent_normal_correction) + tgN = normalize(tgN - gd * sd->dPdu); +#endif + } + + return tgN; +} + +#endif + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h index e56633c9358..d5506ad1dd0 100644 --- a/intern/cycles/kernel/kernel_emission.h +++ b/intern/cycles/kernel/kernel_emission.h @@ -47,7 +47,13 @@ __device float3 direct_emissive_eval(KernelGlobals *kg, float rando, else #endif { - shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time); +#ifdef __HAIR__ + if(ls->type == LIGHT_STRAND) + shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time, ls->prim); + else +#endif + shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time); + ls->Ng = sd.Ng; /* no path flag, we're evaluating this for all closures. that's weak but @@ -150,7 +156,11 @@ __device float3 indirect_emission(KernelGlobals *kg, ShaderData *sd, float t, in /* evaluate emissive closure */ float3 L = shader_emissive_eval(kg, sd); +#ifdef __HAIR__ + if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_SAMPLE_AS_LIGHT) && (sd->segment == ~0)) { +#else if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_SAMPLE_AS_LIGHT)) { +#endif /* multiple importance sampling, get triangle light pdf, * and compute weight with respect to BSDF pdf */ float pdf = triangle_light_pdf(kg, sd->Ng, sd->I, t); diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index 97ae2d3db87..ea0e4d014fe 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -326,6 +326,61 @@ __device float triangle_light_pdf(KernelGlobals *kg, return (t*t*kernel_data.integrator.pdf_triangles)/cos_pi; } +#ifdef __HAIR__ +/* Strand Light */ + +__device void curve_segment_light_sample(KernelGlobals *kg, int prim, int object, + int segment, float randu, float randv, float time, LightSample *ls) +{ + /* this strand code needs completion */ + float4 v00 = kernel_tex_fetch(__curves, prim); + + int k0 = __float_as_int(v00.x) + segment; + int k1 = k0 + 1; + + float4 P1 = kernel_tex_fetch(__curve_keys, k0); + float4 P2 = kernel_tex_fetch(__curve_keys, k1); + + float l = len(P2 - P1); + + float r1 = P1.w; + float r2 = P2.w; + float3 tg = float4_to_float3(P2 - P1) / l; + float3 xc = make_float3(tg.x * tg.z, tg.y * tg.z, -(tg.x * tg.x + tg.y * tg.y)); + if (dot(xc, xc) == 0.0f) + xc = make_float3(tg.x * tg.y, -(tg.x * tg.x + tg.z * tg.z), tg.z * tg.y); + xc = normalize(xc); + float3 yc = cross(tg, xc); + float gd = ((r2 - r1)/l); + + /* normal currently ignores gradient */ + ls->Ng = sinf(2 * M_PI_F * randv) * xc + cosf(2 * M_PI_F * randv) * yc; + ls->P = randu * l * tg + (gd * l + r1) * ls->Ng; + ls->object = object; + ls->prim = prim; + ls->t = 0.0f; + ls->type = LIGHT_STRAND; + ls->eval_fac = 1.0f; + ls->shader = __float_as_int(v00.z); + +#ifdef __INSTANCING__ + /* instance transform */ + if(ls->object >= 0) { +#ifdef __OBJECT_MOTION__ + Transform itfm; + Transform tfm = object_fetch_transform_motion_test(kg, object, time, &itfm); +#else + Transform tfm = object_fetch_transform(kg, ls->object, OBJECT_TRANSFORM); + Transform itfm = object_fetch_transform(kg, ls->object, OBJECT_INVERSE_TRANSFORM); +#endif + + ls->P = transform_point(&tfm, ls->P); + ls->Ng = normalize(transform_direction(&tfm, ls->Ng)); + } +#endif +} +#endif + /* Light Distribution */ __device int light_distribution_sample(KernelGlobals *kg, float randt) @@ -365,10 +420,19 @@ __device void light_sample(KernelGlobals *kg, float randt, float randu, float ra /* fetch light data */ float4 l = kernel_tex_fetch(__light_distribution, index); int prim = __float_as_int(l.y); +#ifdef __HAIR__ + int segment = __float_as_int(l.z); +#endif if(prim >= 0) { int object = __float_as_int(l.w); - triangle_light_sample(kg, prim, object, randu, randv, time, ls); + +#ifdef __HAIR__ + if (segment != ~0) + curve_segment_light_sample(kg, prim, object, segment, randu, randv, time, ls); + else +#endif + triangle_light_sample(kg, prim, object, randu, randv, time, ls); } else { int point = -prim-1; diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h index 7f8b611ba14..727639386ed 100644 --- a/intern/cycles/kernel/kernel_passes.h +++ b/intern/cycles/kernel/kernel_passes.h @@ -70,11 +70,11 @@ __device_inline void kernel_write_data_passes(KernelGlobals *kg, __global float kernel_write_pass_float3(buffer + kernel_data.film.pass_normal, sample, normal); } if(flag & PASS_UV) { - float3 uv = triangle_uv(kg, sd); + float3 uv = primitive_uv(kg, sd); kernel_write_pass_float3(buffer + kernel_data.film.pass_uv, sample, uv); } if(flag & PASS_MOTION) { - float4 speed = triangle_motion_vector(kg, sd); + float4 speed = primitive_motion_vector(kg, sd); kernel_write_pass_float4(buffer + kernel_data.film.pass_motion, sample, speed); kernel_write_pass_float(buffer + kernel_data.film.pass_motion_weight, sample, 1.0f); } diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 8da21751cbe..20feaf50a2e 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -24,9 +24,10 @@ #include "kernel_montecarlo.h" #include "kernel_projection.h" #include "kernel_object.h" -#include "kernel_attribute.h" -#include "kernel_projection.h" #include "kernel_triangle.h" +#include "kernel_curve.h" +#include "kernel_primitive.h" +#include "kernel_projection.h" #ifdef __QBVH__ #include "kernel_qbvh.h" #else diff --git a/intern/cycles/kernel/kernel_primitive.h b/intern/cycles/kernel/kernel_primitive.h new file mode 100644 index 00000000000..0851af21e87 --- /dev/null +++ b/intern/cycles/kernel/kernel_primitive.h @@ -0,0 +1,185 @@ +/* + * 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. + */ + +#ifndef __KERNEL_ATTRIBUTE_CL__ +#define __KERNEL_ATTRIBUTE_CL__ + +CCL_NAMESPACE_BEGIN + +/* attribute lookup */ + +__device_inline int find_attribute(KernelGlobals *kg, ShaderData *sd, uint id, AttributeElement *elem) +{ + if(sd->object == ~0) + return (int)ATTR_STD_NOT_FOUND; + +#ifdef __OSL__ + if (kg->osl) { + return OSLShader::find_attribute(kg, sd, id, elem); + } + else +#endif + { + /* for SVM, find attribute by unique id */ + uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride; +#ifdef __HAIR__ + attr_offset = (sd->segment == ~0)? attr_offset: attr_offset + ATTR_PRIM_CURVE; +#endif + uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); + + while(attr_map.x != id) { + attr_offset += ATTR_PRIM_TYPES; + attr_map = kernel_tex_fetch(__attributes_map, attr_offset); + } + + *elem = (AttributeElement)attr_map.y; + + /* return result */ + return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z; + } +} + +__device float primitive_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy) +{ +#ifdef __HAIR__ + if(sd->segment == ~0) +#endif + return triangle_attribute_float(kg, sd, elem, offset, dx, dy); +#ifdef __HAIR__ + else + return curve_attribute_float(kg, sd, elem, offset, dx, dy); +#endif +} + +__device float3 primitive_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy) +{ +#ifdef __HAIR__ + if(sd->segment == ~0) +#endif + return triangle_attribute_float3(kg, sd, elem, offset, dx, dy); +#ifdef __HAIR__ + else + return curve_attribute_float3(kg, sd, elem, offset, dx, dy); +#endif +} + +__device float3 primitive_uv(KernelGlobals *kg, ShaderData *sd) +{ + AttributeElement elem_uv; + int offset_uv = find_attribute(kg, sd, ATTR_STD_UV, &elem_uv); + + if(offset_uv == ATTR_STD_NOT_FOUND) + return make_float3(0.0f, 0.0f, 0.0f); + + float3 uv = primitive_attribute_float3(kg, sd, elem_uv, offset_uv, NULL, NULL); + uv.z = 1.0f; + return uv; +} + +__device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd) +{ +#ifdef __HAIR__ + if(sd->segment != ~0) + return normalize(sd->dPdu); +#endif + + /* try to create spherical tangent from generated coordinates */ + AttributeElement attr_elem; + int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED, &attr_elem); + + if(attr_offset != ATTR_STD_NOT_FOUND) { + float3 data = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL); + data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f); + object_normal_transform(kg, sd, &data); + return cross(sd->N, normalize(cross(data, sd->N)));; + } + else { + /* otherwise use surface derivatives */ + return normalize(sd->dPdu); + } +} + +/* motion */ + +__device float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd) +{ + float3 motion_pre = sd->P, motion_post = sd->P; + + /* deformation motion */ + AttributeElement elem_pre, elem_post; + int offset_pre = find_attribute(kg, sd, ATTR_STD_MOTION_PRE, &elem_pre); + int offset_post = find_attribute(kg, sd, ATTR_STD_MOTION_POST, &elem_post); + + if(offset_pre != ATTR_STD_NOT_FOUND) + motion_pre = primitive_attribute_float3(kg, sd, elem_pre, offset_pre, NULL, NULL); + if(offset_post != ATTR_STD_NOT_FOUND) + motion_post = primitive_attribute_float3(kg, sd, elem_post, offset_post, NULL, NULL); + + /* object motion. note that depending on the mesh having motion vectors, this + * transformation was set match the world/object space of motion_pre/post */ + Transform tfm; + + tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE); + motion_pre = transform_point(&tfm, motion_pre); + + tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST); + motion_post = transform_point(&tfm, motion_post); + + float3 P; + + /* camera motion, for perspective/orthographic motion.pre/post will be a + * world-to-raster matrix, for panorama it's world-to-camera */ + if (kernel_data.cam.type != CAMERA_PANORAMA) { + tfm = kernel_data.cam.worldtoraster; + P = transform_perspective(&tfm, sd->P); + + tfm = kernel_data.cam.motion.pre; + motion_pre = transform_perspective(&tfm, motion_pre); + + tfm = kernel_data.cam.motion.post; + motion_post = transform_perspective(&tfm, motion_post); + } + else { + tfm = kernel_data.cam.worldtocamera; + P = normalize(transform_point(&tfm, sd->P)); + P = float2_to_float3(direction_to_panorama(kg, P)); + P.x *= kernel_data.cam.width; + P.y *= kernel_data.cam.height; + + tfm = kernel_data.cam.motion.pre; + motion_pre = normalize(transform_point(&tfm, motion_pre)); + motion_pre = float2_to_float3(direction_to_panorama(kg, motion_pre)); + motion_pre.x *= kernel_data.cam.width; + motion_pre.y *= kernel_data.cam.height; + + tfm = kernel_data.cam.motion.post; + motion_post = normalize(transform_point(&tfm, motion_post)); + motion_post = float2_to_float3(direction_to_panorama(kg, motion_post)); + motion_post.x *= kernel_data.cam.width; + motion_post.y *= kernel_data.cam.height; + } + + motion_pre = motion_pre - P; + motion_post = P - motion_post; + + return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y); +} + +CCL_NAMESPACE_END + +#endif /* __KERNEL_ATTRIBUTE_CL__ */ diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 47b4d02e5bf..0a5a2ab54b0 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -56,24 +56,11 @@ __device_noinline void shader_setup_object_transforms(KernelGlobals *kg, ShaderD __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray) { - /* fetch triangle data */ - int prim = kernel_tex_fetch(__prim_index, isect->prim); - float4 Ns = kernel_tex_fetch(__tri_normal, prim); - float3 Ng = make_float3(Ns.x, Ns.y, Ns.z); - int shader = __float_as_int(Ns.w); - - /* triangle */ #ifdef __INSTANCING__ sd->object = (isect->object == ~0)? kernel_tex_fetch(__prim_object, isect->prim): isect->object; #endif - sd->prim = prim; -#ifdef __UV__ - sd->u = isect->u; - sd->v = isect->v; -#endif - sd->flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*2); - sd->flag |= kernel_tex_fetch(__object_flag, sd->object); + sd->flag = kernel_tex_fetch(__object_flag, sd->object); /* matrices and time */ #ifdef __OBJECT_MOTION__ @@ -81,23 +68,63 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd, sd->time = ray->time; #endif - /* vectors */ - sd->P = bvh_triangle_refine(kg, sd, isect, ray); - sd->Ng = Ng; - sd->N = Ng; - sd->I = -ray->D; - sd->shader = shader; + sd->prim = kernel_tex_fetch(__prim_index, isect->prim); sd->ray_length = isect->t; - /* smooth normal */ - if(sd->shader & SHADER_SMOOTH_NORMAL) - sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); +#ifdef __HAIR__ + if(kernel_tex_fetch(__prim_segment, isect->prim) != ~0) { + /* Strand Shader setting*/ + float4 curvedata = kernel_tex_fetch(__curves, sd->prim); + + sd->shader = __float_as_int(curvedata.z); + sd->segment = isect->segment; + + float tcorr = isect->t; + if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_POSTINTERSECTCORRECTION) { + tcorr = (isect->u < 0)? tcorr + sqrtf(isect->v) : tcorr - sqrtf(isect->v); + sd->ray_length = tcorr; + } + + sd->P = bvh_curve_refine(kg, sd, isect, ray, tcorr); + } + else { +#endif + /* fetch triangle data */ + float4 Ns = kernel_tex_fetch(__tri_normal, sd->prim); + float3 Ng = make_float3(Ns.x, Ns.y, Ns.z); + sd->shader = __float_as_int(Ns.w); + +#ifdef __HAIR__ + sd->segment = ~0; +#endif + +#ifdef __UV__ + sd->u = isect->u; + sd->v = isect->v; +#endif + + /* vectors */ + sd->P = bvh_triangle_refine(kg, sd, isect, ray); + sd->Ng = Ng; + sd->N = Ng; + + /* smooth normal */ + if(sd->shader & SHADER_SMOOTH_NORMAL) + sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); #ifdef __DPDU__ - /* dPdu/dPdv */ - triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim); + /* dPdu/dPdv */ + triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim); +#endif + +#ifdef __HAIR__ + } #endif + sd->I = -ray->D; + + sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2); + #ifdef __INSTANCING__ if(isect->object != ~0) { /* instance transform */ @@ -135,7 +162,7 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd, __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, const float3 P, const float3 Ng, const float3 I, - int shader, int object, int prim, float u, float v, float t, float time) + int shader, int object, int prim, float u, float v, float t, float time, int segment = ~0) { /* vectors */ sd->P = P; @@ -143,11 +170,15 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, sd->Ng = Ng; sd->I = I; sd->shader = shader; +#ifdef __HAIR__ + sd->segment = segment; +#endif /* primitive */ #ifdef __INSTANCING__ sd->object = object; #endif + /* currently no access to bvh prim index for strand sd->prim - this will cause errors with needs fixing*/ sd->prim = prim; #ifdef __UV__ sd->u = u; @@ -183,8 +214,13 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, #endif /* smooth normal */ +#ifdef __HAIR__ + if(sd->shader & SHADER_SMOOTH_NORMAL && sd->segment == ~0) { + sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); +#else if(sd->shader & SHADER_SMOOTH_NORMAL) { sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); +#endif #ifdef __INSTANCING__ if(instanced) @@ -194,10 +230,17 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, #ifdef __DPDU__ /* dPdu/dPdv */ +#ifdef __HAIR__ + if(sd->prim == ~0 || sd->segment != ~0) { + sd->dPdu = make_float3(0.0f, 0.0f, 0.0f); + sd->dPdv = make_float3(0.0f, 0.0f, 0.0f); + } +#else if(sd->prim == ~0) { sd->dPdu = make_float3(0.0f, 0.0f, 0.0f); sd->dPdv = make_float3(0.0f, 0.0f, 0.0f); } +#endif else { triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim); @@ -279,6 +322,9 @@ __device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData sd->object = ~0; #endif sd->prim = ~0; +#ifdef __HAIR__ + sd->segment = ~0; +#endif #ifdef __UV__ sd->u = 0.0f; sd->v = 0.0f; @@ -732,8 +778,20 @@ __device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd, Shader __device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect) { int prim = kernel_tex_fetch(__prim_index, isect->prim); - float4 Ns = kernel_tex_fetch(__tri_normal, prim); - int shader = __float_as_int(Ns.w); + int shader = 0; + +#ifdef __HAIR__ + if(kernel_tex_fetch(__prim_segment, isect->prim) == ~0) { +#endif + float4 Ns = kernel_tex_fetch(__tri_normal, prim); + shader = __float_as_int(Ns.w); +#ifdef __HAIR__ + } + else { + float4 str = kernel_tex_fetch(__curves, prim); + shader = __float_as_int(str.z); + } +#endif int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*2); return (flag & SD_HAS_SURFACE_TRANSPARENT) != 0; diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h index 29f6b3f072c..e27de95e7ab 100644 --- a/intern/cycles/kernel/kernel_textures.h +++ b/intern/cycles/kernel/kernel_textures.h @@ -27,6 +27,7 @@ /* bvh */ KERNEL_TEX(float4, texture_float4, __bvh_nodes) KERNEL_TEX(float4, texture_float4, __tri_woop) +KERNEL_TEX(uint, texture_uint, __prim_segment) KERNEL_TEX(uint, texture_uint, __prim_visibility) KERNEL_TEX(uint, texture_uint, __prim_index) KERNEL_TEX(uint, texture_uint, __prim_object) @@ -42,6 +43,10 @@ KERNEL_TEX(float4, texture_float4, __tri_vnormal) KERNEL_TEX(float4, texture_float4, __tri_vindex) KERNEL_TEX(float4, texture_float4, __tri_verts) +/* curves */ +KERNEL_TEX(float4, texture_float4, __curves) +KERNEL_TEX(float4, texture_float4, __curve_keys) + /* attributes */ KERNEL_TEX(uint4, texture_uint4, __attributes_map) KERNEL_TEX(float, texture_float, __attributes_float) diff --git a/intern/cycles/kernel/kernel_triangle.h b/intern/cycles/kernel/kernel_triangle.h index 570ae52d6c2..d346137760f 100644 --- a/intern/cycles/kernel/kernel_triangle.h +++ b/intern/cycles/kernel/kernel_triangle.h @@ -190,82 +190,5 @@ __device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *s } } -/* motion */ - -__device float4 triangle_motion_vector(KernelGlobals *kg, ShaderData *sd) -{ - float3 motion_pre = sd->P, motion_post = sd->P; - - /* deformation motion */ - int offset_pre = find_attribute(kg, sd, ATTR_STD_MOTION_PRE); - int offset_post = find_attribute(kg, sd, ATTR_STD_MOTION_POST); - - if(offset_pre != ATTR_STD_NOT_FOUND) - motion_pre = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_pre, NULL, NULL); - if(offset_post != ATTR_STD_NOT_FOUND) - motion_post = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_post, NULL, NULL); - - /* object motion. note that depending on the mesh having motion vectors, this - * transformation was set match the world/object space of motion_pre/post */ - Transform tfm; - - tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE); - motion_pre = transform_point(&tfm, motion_pre); - - tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST); - motion_post = transform_point(&tfm, motion_post); - - float3 P; - - /* camera motion, for perspective/orthographic motion.pre/post will be a - * world-to-raster matrix, for panorama it's world-to-camera */ - if (kernel_data.cam.type != CAMERA_PANORAMA) { - tfm = kernel_data.cam.worldtoraster; - P = transform_perspective(&tfm, sd->P); - - tfm = kernel_data.cam.motion.pre; - motion_pre = transform_perspective(&tfm, motion_pre); - - tfm = kernel_data.cam.motion.post; - motion_post = transform_perspective(&tfm, motion_post); - } - else { - tfm = kernel_data.cam.worldtocamera; - P = normalize(transform_point(&tfm, sd->P)); - P = float2_to_float3(direction_to_panorama(kg, P)); - P.x *= kernel_data.cam.width; - P.y *= kernel_data.cam.height; - - tfm = kernel_data.cam.motion.pre; - motion_pre = normalize(transform_point(&tfm, motion_pre)); - motion_pre = float2_to_float3(direction_to_panorama(kg, motion_pre)); - motion_pre.x *= kernel_data.cam.width; - motion_pre.y *= kernel_data.cam.height; - - tfm = kernel_data.cam.motion.post; - motion_post = normalize(transform_point(&tfm, motion_post)); - motion_post = float2_to_float3(direction_to_panorama(kg, motion_post)); - motion_post.x *= kernel_data.cam.width; - motion_post.y *= kernel_data.cam.height; - } - - motion_pre = motion_pre - P; - motion_post = P - motion_post; - - return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y); -} - -__device float3 triangle_uv(KernelGlobals *kg, ShaderData *sd) -{ - int offset_uv = find_attribute(kg, sd, ATTR_STD_UV); - - if(offset_uv == ATTR_STD_NOT_FOUND) - return make_float3(0.0f, 0.0f, 0.0f); - - float3 uv = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, offset_uv, NULL, NULL); - uv.z = 1.0f; - return uv; -} - CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index d11b96503d9..2bd6b5859f3 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -47,6 +47,7 @@ CCL_NAMESPACE_BEGIN #define __OSL__ #endif #define __NON_PROGRESSIVE__ +#define __HAIR__ #endif #ifdef __KERNEL_CUDA__ @@ -116,7 +117,6 @@ CCL_NAMESPACE_BEGIN #define __ANISOTROPIC__ #define __OBJECT_MOTION__ #endif - //#define __SOBOL_FULL_SCREEN__ /* Shader Evaluation */ @@ -292,7 +292,8 @@ typedef enum LightType { LIGHT_BACKGROUND, LIGHT_AREA, LIGHT_AO, - LIGHT_SPOT + LIGHT_SPOT, + LIGHT_STRAND } LightType; /* Camera Type */ @@ -343,18 +344,44 @@ typedef struct Intersection { float t, u, v; int prim; int object; + int segment; } Intersection; /* Attributes */ +#define ATTR_PRIM_TYPES 2 +#define ATTR_PRIM_CURVE 1 + typedef enum AttributeElement { + ATTR_ELEMENT_NONE, + ATTR_ELEMENT_VALUE, ATTR_ELEMENT_FACE, ATTR_ELEMENT_VERTEX, ATTR_ELEMENT_CORNER, - ATTR_ELEMENT_VALUE, - ATTR_ELEMENT_NONE + ATTR_ELEMENT_CURVE, + ATTR_ELEMENT_CURVE_KEY } AttributeElement; +typedef enum AttributeStandard { + ATTR_STD_NONE = 0, + ATTR_STD_VERTEX_NORMAL, + ATTR_STD_FACE_NORMAL, + ATTR_STD_UV, + ATTR_STD_UV_TANGENT, + ATTR_STD_UV_TANGENT_SIGN, + ATTR_STD_GENERATED, + ATTR_STD_POSITION_UNDEFORMED, + ATTR_STD_POSITION_UNDISPLACED, + ATTR_STD_MOTION_PRE, + ATTR_STD_MOTION_POST, + ATTR_STD_PARTICLE, + ATTR_STD_CURVE_TANGENT, + ATTR_STD_CURVE_INTERCEPT, + ATTR_STD_NUM, + + ATTR_STD_NOT_FOUND = ~0 +} AttributeStandard; + /* Closure data */ #define MAX_CLOSURE 8 @@ -436,6 +463,11 @@ typedef struct ShaderData { /* primitive id if there is one, ~0 otherwise */ int prim; + +#ifdef __HAIR__ + /* for curves, segment number in curve, ~0 for triangles */ + int segment; +#endif /* parametric coordinates * - barycentric weights for triangles */ float u, v; @@ -650,6 +682,29 @@ typedef struct KernelBVH { int pad2; } KernelBVH; +typedef enum CurveFlag { + /* runtime flags */ + CURVE_KN_BACKFACING = 1, /* backside of cylinder? */ + CURVE_KN_ENCLOSEFILTER = 2, /* don't consider strands surrounding start point? */ + CURVE_KN_CURVEDATA = 4, /* curve data available? */ + CURVE_KN_INTERPOLATE = 8, /* render as a curve? - not supported yet */ + CURVE_KN_ACCURATE = 16, /* use accurate intersections test? */ + CURVE_KN_INTERSECTCORRECTION = 32, /* correct for width after determing closest midpoint? */ + CURVE_KN_POSTINTERSECTCORRECTION = 64, /* correct for width after intersect? */ + CURVE_KN_NORMALCORRECTION = 128, /* correct tangent normal for slope? */ + CURVE_KN_TRUETANGENTGNORMAL = 256, /* use tangent normal for geometry? */ + CURVE_KN_TANGENTGNORMAL = 512, /* use tangent normal for shader? */ +} CurveFlag; + +typedef struct KernelCurves { + /* strand intersect and normal parameters - many can be changed to flags*/ + float normalmix; + float encasing_ratio; + int curveflags; + int pad; + +} KernelCurves; + typedef struct KernelData { KernelCamera cam; KernelFilm film; @@ -657,6 +712,7 @@ typedef struct KernelData { KernelSunSky sunsky; KernelIntegrator integrator; KernelBVH bvh; + KernelCurves curve_kernel_data; } KernelData; CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 498d10f385b..28742d56e3b 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -37,9 +37,10 @@ #include "kernel_differential.h" #include "kernel_object.h" #include "kernel_bvh.h" -#include "kernel_attribute.h" -#include "kernel_projection.h" #include "kernel_triangle.h" +#include "kernel_curve.h" +#include "kernel_primitive.h" +#include "kernel_projection.h" #include "kernel_accumulate.h" #include "kernel_shader.h" @@ -74,6 +75,11 @@ ustring OSLRenderServices::u_geom_numpolyvertices("geom:numpolyvertices"); ustring OSLRenderServices::u_geom_trianglevertices("geom:trianglevertices"); ustring OSLRenderServices::u_geom_polyvertices("geom:polyvertices"); ustring OSLRenderServices::u_geom_name("geom:name"); +#ifdef __HAIR__ +ustring OSLRenderServices::u_is_curve("geom:is_curve"); +ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness"); +ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal"); +#endif ustring OSLRenderServices::u_path_ray_length("path:ray_length"); ustring OSLRenderServices::u_trace("trace"); ustring OSLRenderServices::u_hit("hit"); @@ -495,14 +501,14 @@ static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OS attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) { float3 fval[3]; - fval[0] = triangle_attribute_float3(kg, sd, attr.elem, attr.offset, - (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL); + fval[0] = primitive_attribute_float3(kg, sd, attr.elem, attr.offset, + (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL); return set_attribute_float3(fval, type, derivatives, val); } else if (attr.type == TypeDesc::TypeFloat) { float fval[3]; - fval[0] = triangle_attribute_float(kg, sd, attr.elem, attr.offset, - (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL); + fval[0] = primitive_attribute_float(kg, sd, attr.elem, attr.offset, + (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL); return set_attribute_float(fval, type, derivatives, val); } else { @@ -593,10 +599,13 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD float3 f = particle_angular_velocity(kg, particle_id); return set_attribute_float3(f, type, derivatives, val); } + + /* Geometry Attributes */ else if (name == u_geom_numpolyvertices) { return set_attribute_int(3, type, derivatives, val); } - else if (name == u_geom_trianglevertices || name == u_geom_polyvertices) { + else if ((name == u_geom_trianglevertices || name == u_geom_polyvertices) + && sd->segment == ~0) { float3 P[3]; triangle_vertices(kg, sd->prim, P); @@ -612,6 +621,22 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD ustring object_name = kg->osl->object_names[sd->object]; return set_attribute_string(object_name, type, derivatives, val); } + +#ifdef __HAIR__ + /* Hair Attributes */ + else if (name == u_is_curve) { + float f = (sd->segment != ~0); + return set_attribute_float(f, type, derivatives, val); + } + else if (name == u_curve_thickness) { + float f = curve_thickness(kg, sd); + return set_attribute_float(f, type, derivatives, val); + } + else if (name == u_curve_tangent_normal) { + float3 f = curve_tangent_normal(kg, sd); + return set_attribute_float3(f, type, derivatives, val); + } +#endif else return false; } @@ -634,7 +659,7 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri { KernelGlobals *kg = kernel_globals; ShaderData *sd = (ShaderData *)renderstate; - int object, tri; + int object, prim, segment; /* lookup of attribute on another object */ if (object_name != u_empty || sd == NULL) { @@ -644,17 +669,20 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri return false; object = it->second; - tri = ~0; + prim = ~0; + segment = ~0; } else { object = sd->object; - tri = sd->prim; + prim = sd->prim; + segment = sd->segment; if (object == ~0) return get_background_attribute(kg, sd, name, type, derivatives, val); } /* find attribute on object */ + object = object*ATTR_PRIM_TYPES + (segment != ~0); OSLGlobals::AttributeMap& attribute_map = kg->osl->attribute_map[object]; OSLGlobals::AttributeMap::iterator it = attribute_map.find(name); @@ -663,7 +691,7 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri if (attr.elem != ATTR_ELEMENT_VALUE) { /* triangle and vertex attributes */ - if (tri != ~0) + if (prim != ~0) return get_mesh_attribute(kg, sd, attr, type, derivatives, val); } else { diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h index cd4a4163209..50c50b9952c 100644 --- a/intern/cycles/kernel/osl/osl_services.h +++ b/intern/cycles/kernel/osl/osl_services.h @@ -130,6 +130,9 @@ public: static ustring u_geom_trianglevertices; static ustring u_geom_polyvertices; static ustring u_geom_name; + static ustring u_is_curve; + static ustring u_curve_thickness; + static ustring u_curve_tangent_normal; static ustring u_path_ray_length; static ustring u_trace; static ustring u_hit; diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp index 3ff032374fc..59e307bb408 100644 --- a/intern/cycles/kernel/osl/osl_shader.cpp +++ b/intern/cycles/kernel/osl/osl_shader.cpp @@ -26,9 +26,10 @@ #include "osl_services.h" #include "osl_shader.h" -#include "util_attribute.h" #include "util_foreach.h" +#include "attribute.h" + #include <OSL/oslexec.h> CCL_NAMESPACE_BEGIN @@ -453,15 +454,17 @@ float3 OSLShader::volume_eval_phase(const ShaderClosure *sc, const float3 omega_ /* Attributes */ -int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id) +int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem) { /* for OSL, a hash map is used to lookup the attribute by name. */ - OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[sd->object]; - ustring stdname(std::string("std::") + std::string(attribute_standard_name((AttributeStandard)id))); + int object = sd->object*ATTR_PRIM_TYPES + (sd->segment != ~0); + OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[object]; + ustring stdname(std::string("geom:") + std::string(Attribute::standard_name((AttributeStandard)id))); OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname); if (it != attr_map.end()) { const OSLGlobals::Attribute &osl_attr = it->second; + *elem = osl_attr.elem; /* return result */ return (osl_attr.elem == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : osl_attr.offset; } diff --git a/intern/cycles/kernel/osl/osl_shader.h b/intern/cycles/kernel/osl/osl_shader.h index 2e46a2de42c..2062c651162 100644 --- a/intern/cycles/kernel/osl/osl_shader.h +++ b/intern/cycles/kernel/osl/osl_shader.h @@ -74,7 +74,7 @@ public: const float3 omega_in, const float3 omega_out); /* attributes */ - static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id); + static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem); }; CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt index 70fc8610c98..acae46f1615 100644 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/shaders/CMakeLists.txt @@ -27,6 +27,7 @@ set(SRC_OSL node_glass_bsdf.osl node_glossy_bsdf.osl node_gradient_texture.osl + node_hair_info.osl node_holdout.osl node_hsv.osl node_image_texture.osl diff --git a/intern/cycles/kernel/shaders/node_hair_info.osl b/intern/cycles/kernel/shaders/node_hair_info.osl new file mode 100644 index 00000000000..cbb3b98383f --- /dev/null +++ b/intern/cycles/kernel/shaders/node_hair_info.osl @@ -0,0 +1,32 @@ +/* + * Copyright 2012, 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_hair_info( + output float IsStrand = 0.0, + output float Intercept = 0.0, + output float Thickness = 0.0, + output normal TangentNormal = N) +{ + getattribute("geom:is_curve", IsStrand); + getattribute("geom:curve_intercept", Intercept); + getattribute("geom:curve_thickness", Thickness); + getattribute("geom:curve_tangent_normal", TangentNormal); +} + diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h index 69ca6b32c36..f340eaff95f 100644 --- a/intern/cycles/kernel/shaders/stdosl.h +++ b/intern/cycles/kernel/shaders/stdosl.h @@ -161,6 +161,15 @@ vector cross (vector a, vector b) BUILTIN; float dot (vector a, vector b) BUILTIN; float length (vector v) BUILTIN; float distance (point a, point b) BUILTIN; +float distance (point a, point b, point q) +{ + vector d = b - a; + float dd = dot(d, d); + if(dd == 0.0) + return distance(q, a); + float t = dot(q - a, d)/dd; + return distance(q, a + clamp(t, 0.0, 1.0)*d); +} normal normalize (normal v) BUILTIN; vector normalize (vector v) BUILTIN; vector faceforward (vector N, vector I, vector Nref) BUILTIN; @@ -304,7 +313,7 @@ color transformc (string to, color x) r = color (dot (vector(0.299, 0.587, 0.114), (vector)x), dot (vector(0.596, -0.275, -0.321), (vector)x), dot (vector(0.212, -0.523, 0.311), (vector)x)); - else if (to == "xyz") + else if (to == "XYZ") r = color (dot (vector(0.412453, 0.357580, 0.180423), (vector)x), dot (vector(0.212671, 0.715160, 0.072169), (vector)x), dot (vector(0.019334, 0.119193, 0.950227), (vector)x)); @@ -366,7 +375,7 @@ color transformc (string from, string to, color x) r = color (dot (vector(1, 0.9557, 0.6199), (vector)x), dot (vector(1, -0.2716, -0.6469), (vector)x), dot (vector(1, -1.1082, 1.7051), (vector)x)); - else if (from == "xyz") + else if (from == "XYZ") r = color (dot (vector( 3.240479, -1.537150, -0.498535), (vector)x), dot (vector(-0.969256, 1.875991, 0.041556), (vector)x), dot (vector( 0.055648, -0.204043, 1.057311), (vector)x)); @@ -409,6 +418,8 @@ int startswith (string s, string prefix) BUILTIN; int endswith (string s, string suffix) BUILTIN; string substr (string s, int start, int len) BUILTIN; string substr (string s, int start) { return substr (s, start, strlen(s)); } +float strtof (string str) BUILTIN; +int strtoi (string str) BUILTIN; // Define concat in terms of shorter concat string concat (string a, string b, string c) { diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index ec7978066c2..1f4857c0924 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -301,6 +301,12 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT case NODE_PARTICLE_INFO: svm_node_particle_info(kg, sd, stack, node.y, node.z); break; +#ifdef __HAIR__ + case NODE_HAIR_INFO: + svm_node_hair_info(kg, sd, stack, node.y, node.z); + break; +#endif + #endif case NODE_CONVERT: svm_node_convert(sd, stack, node.y, node.z, node.w); diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h index ed70a6dc423..2beec995151 100644 --- a/intern/cycles/kernel/svm/svm_attribute.h +++ b/intern/cycles/kernel/svm/svm_attribute.h @@ -28,10 +28,15 @@ __device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd, /* find attribute by unique id */ uint id = node.y; uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride; +#ifdef __HAIR__ + attr_offset = (sd->segment == ~0)? attr_offset: attr_offset + ATTR_PRIM_CURVE; +#endif uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); - - while(attr_map.x != id) - attr_map = kernel_tex_fetch(__attributes_map, ++attr_offset); + + while(attr_map.x != id) { + attr_offset += ATTR_PRIM_TYPES; + attr_map = kernel_tex_fetch(__attributes_map, attr_offset); + } /* return result */ *elem = (AttributeElement)attr_map.y; @@ -61,21 +66,21 @@ __device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, uin /* fetch and store attribute */ if(type == NODE_ATTR_FLOAT) { if(mesh_type == NODE_ATTR_FLOAT) { - float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL); + float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL); stack_store_float(stack, out_offset, f); } else { - float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL); stack_store_float(stack, out_offset, average(f)); } } else { if(mesh_type == NODE_ATTR_FLOAT3) { - float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL); stack_store_float3(stack, out_offset, f); } else { - float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL); + float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL); stack_store_float3(stack, out_offset, make_float3(f, f, f)); } } @@ -94,24 +99,24 @@ __device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *st if(type == NODE_ATTR_FLOAT) { if(mesh_type == NODE_ATTR_FLOAT) { float dx; - float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL); + float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL); stack_store_float(stack, out_offset, f+dx); } else { float3 dx; - float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL); stack_store_float(stack, out_offset, average(f+dx)); } } else { if(mesh_type == NODE_ATTR_FLOAT3) { float3 dx; - float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL); stack_store_float3(stack, out_offset, f+dx); } else { float dx; - float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL); + float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL); stack_store_float3(stack, out_offset, make_float3(f+dx, f+dx, f+dx)); } } @@ -130,24 +135,24 @@ __device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *st if(type == NODE_ATTR_FLOAT) { if(mesh_type == NODE_ATTR_FLOAT) { float dy; - float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy); + float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy); stack_store_float(stack, out_offset, f+dy); } else { float3 dy; - float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy); stack_store_float(stack, out_offset, average(f+dy)); } } else { if(mesh_type == NODE_ATTR_FLOAT3) { float3 dy; - float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy); stack_store_float3(stack, out_offset, f+dy); } else { float dy; - float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy); + float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy); stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy)); } } diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h index c4d03c1f948..a04f4ea0fa7 100644 --- a/intern/cycles/kernel/svm/svm_geometry.h +++ b/intern/cycles/kernel/svm/svm_geometry.h @@ -28,23 +28,7 @@ __device void svm_node_geometry(KernelGlobals *kg, ShaderData *sd, float *stack, case NODE_GEOM_P: data = sd->P; break; case NODE_GEOM_N: data = sd->N; break; #ifdef __DPDU__ - case NODE_GEOM_T: { - /* 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.5f), (data.x - 0.5f), 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); - } - - break; - } + case NODE_GEOM_T: data = primitive_tangent(kg, sd); break; #endif case NODE_GEOM_I: data = sd->I; break; case NODE_GEOM_Ng: data = sd->Ng; break; @@ -160,5 +144,36 @@ __device void svm_node_particle_info(KernelGlobals *kg, ShaderData *sd, float *s } } +#ifdef __HAIR__ + +/* Hair Info */ + +__device void svm_node_hair_info(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset) +{ + float data; + float3 data3; + + switch(type) { + case NODE_INFO_CURVE_IS_STRAND: { + data = (sd->segment != ~0); + stack_store_float(stack, out_offset, data); + break; + } + case NODE_INFO_CURVE_INTERCEPT: + break; /* handled as attribute */ + case NODE_INFO_CURVE_THICKNESS: { + data = curve_thickness(kg, sd); + stack_store_float(stack, out_offset, data); + break; + } + case NODE_INFO_CURVE_TANGENT_NORMAL: { + data3 = curve_tangent_normal(kg, sd); + stack_store_float3(stack, out_offset, data3); + break; + } + } +} +#endif + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h index 9f2d3367420..7a1af43b625 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -248,8 +248,9 @@ __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stac } /* 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); + AttributeElement attr_elem, attr_sign_elem; + int attr_offset = find_attribute(kg, sd, node.z, &attr_elem); + int attr_sign_offset = find_attribute(kg, sd, node.w, &attr_sign_elem); if(attr_offset == ATTR_STD_NOT_FOUND || attr_sign_offset == ATTR_STD_NOT_FOUND) { stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f)); @@ -257,8 +258,8 @@ __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stac } /* 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); + float3 tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL); + float sign = primitive_attribute_float(kg, sd, attr_sign_elem, attr_sign_offset, NULL, NULL); object_normal_transform(kg, sd, &tangent); tangent = cross(sd->N, normalize(cross(tangent, sd->N)));; @@ -295,22 +296,24 @@ __device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack, if(direction_type == NODE_TANGENT_UVMAP) { /* UV map */ - int attr_offset = find_attribute(kg, sd, node.z); + AttributeElement attr_elem; + int attr_offset = find_attribute(kg, sd, node.z, &attr_elem); 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); + tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL); } else { /* radial */ - int attr_offset = find_attribute(kg, sd, node.z); + AttributeElement attr_elem; + int attr_offset = find_attribute(kg, sd, node.z, &attr_elem); 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); + generated = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL); if(axis == NODE_TANGENT_AXIS_X) tangent = make_float3(0.0f, -(generated.z - 0.5f), (generated.y - 0.5f)); diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index e1a583625fc..57177eec48f 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -97,7 +97,8 @@ typedef enum NodeType { NODE_CLOSURE_SET_NORMAL, NODE_CLOSURE_AMBIENT_OCCLUSION, NODE_TANGENT, - NODE_NORMAL_MAP + NODE_NORMAL_MAP, + NODE_HAIR_INFO } NodeType; typedef enum NodeAttributeType { @@ -132,6 +133,13 @@ typedef enum NodeParticleInfo { NODE_INFO_PAR_ANGULAR_VELOCITY } NodeParticleInfo; +typedef enum NodeHairInfo { + NODE_INFO_CURVE_IS_STRAND, + NODE_INFO_CURVE_INTERCEPT, + NODE_INFO_CURVE_THICKNESS, + NODE_INFO_CURVE_TANGENT_NORMAL +} NodeHairInfo; + typedef enum NodeLightPath { NODE_LP_camera = 0, NODE_LP_shadow, |