diff options
Diffstat (limited to 'intern/cycles/kernel/kernel_bvh.h')
-rw-r--r-- | intern/cycles/kernel/kernel_bvh.h | 267 |
1 files changed, 261 insertions, 6 deletions
diff --git a/intern/cycles/kernel/kernel_bvh.h b/intern/cycles/kernel/kernel_bvh.h index 73e7fb0e5d6..15af35a05f8 100644 --- a/intern/cycles/kernel/kernel_bvh.h +++ b/intern/cycles/kernel/kernel_bvh.h @@ -205,6 +205,151 @@ __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 triAddr) +{ + /* curve Intersection check */ + + int flags = kernel_data.curve_kernel_data.curveflags; + + int prim = kernel_tex_fetch(__prim_index, triAddr); + float4 v00 = kernel_tex_fetch(__cur_segs, prim); + + int v1 = __float_as_int(v00.x); + int v2 = __float_as_int(v00.y); + + float4 P1 = kernel_tex_fetch(__cur_keys, v1); + float4 P2 = kernel_tex_fetch(__cur_keys, v2); + + float l = v00.w; + 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; + + /* test bounding sphere intersection (introduce circular artifacts)*/ + /*float3 bvector = 0.5f * (p1 + p2) - P; + float bvectorl_sq = len_squared(bvector); + float dot_bv_dir = dot(bvector,dir); + float maxdist = l * 0.5f + mr; + if(bvectorl_sq - dot_bv_dir * dot_bv_dir > maxdist * maxdist) + 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) + 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; + } + } + + /*remove overlap - not functional yet*/ + /*if (flags & CURVE_KN_CURVEDATA) { + float3 tg1 = float4_to_float3(kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0)); + float3 tg2 = float4_to_float3(kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1)); + if((dot(P + t * dir - p1, tg1) < 0.0f) || (dot(P + t * dir - p2, tg2) > 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, triAddr) & visibility) + #endif + { + /* record intersection */ + isect->prim = triAddr; + 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 +426,15 @@ __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__ + if(kernel_tex_fetch(__prim_type, primAddr)) + bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr); + 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 +551,15 @@ __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__ + if(kernel_tex_fetch(__prim_type, primAddr)) + bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr); + 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) @@ -545,5 +700,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(__cur_segs, prim); + + int v1 = __float_as_int(v00.x); + int v2 = __float_as_int(v00.y); + + float4 P1 = kernel_tex_fetch(__cur_keys, v1); + float4 P2 = kernel_tex_fetch(__cur_keys, v2); + float l = v00.w; + 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 |