diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2014-03-29 16:03:47 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2014-03-29 16:03:47 +0400 |
commit | e2184c653e1f2cc7e05cf9a42a87d23ea3050eac (patch) | |
tree | dc39ada14e14259a4cd18c2d5974390a585eb7b8 /intern/cycles/kernel/geom | |
parent | 6020d0099039ed18c6a6cd330b68361123c85c1a (diff) |
Cycles: add support for curve deformation motion blur.
Diffstat (limited to 'intern/cycles/kernel/geom')
-rw-r--r-- | intern/cycles/kernel/geom/geom_bvh.h | 3 | ||||
-rw-r--r-- | intern/cycles/kernel/geom/geom_bvh_traversal.h | 3 | ||||
-rw-r--r-- | intern/cycles/kernel/geom/geom_curve.h | 95 | ||||
-rw-r--r-- | intern/cycles/kernel/geom/geom_motion_curve.h | 139 |
4 files changed, 213 insertions, 27 deletions
diff --git a/intern/cycles/kernel/geom/geom_bvh.h b/intern/cycles/kernel/geom/geom_bvh.h index 20c3c7c19ca..73bf0194d9a 100644 --- a/intern/cycles/kernel/geom/geom_bvh.h +++ b/intern/cycles/kernel/geom/geom_bvh.h @@ -41,9 +41,10 @@ #endif #include "geom_object.h" -#include "geom_curve.h" #include "geom_triangle.h" #include "geom_motion_triangle.h" +#include "geom_motion_curve.h" +#include "geom_curve.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/geom/geom_bvh_traversal.h b/intern/cycles/kernel/geom/geom_bvh_traversal.h index 1fd0772c9ae..e838fba6d46 100644 --- a/intern/cycles/kernel/geom/geom_bvh_traversal.h +++ b/intern/cycles/kernel/geom/geom_bvh_traversal.h @@ -261,7 +261,8 @@ ccl_device bool BVH_FUNCTION_NAME break; } #if FEATURE(BVH_HAIR) - case PRIMITIVE_CURVE: { + case PRIMITIVE_CURVE: + case PRIMITIVE_MOTION_CURVE: { #if FEATURE(BVH_HAIR_MINIMUM_WIDTH) if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) hit = bvh_cardinal_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax); diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h index 484f3ae6eb9..f13f92ed9d7 100644 --- a/intern/cycles/kernel/geom/geom_curve.h +++ b/intern/cycles/kernel/geom/geom_curve.h @@ -103,9 +103,17 @@ ccl_device float curve_thickness(KernelGlobals *kg, ShaderData *sd) int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(sd->type); 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; + float4 P_curve[2]; + + if(sd->type & PRIMITIVE_CURVE) { + P_curve[0]= kernel_tex_fetch(__curve_keys, k0); + P_curve[1]= kernel_tex_fetch(__curve_keys, k1); + } + else { + motion_curve_keys(kg, sd->object, sd->prim, sd->time, k0, k1, P_curve); + } + + r = (P_curve[1].w - P_curve[0].w) * sd->u + P_curve[0].w; } return r*2.0f; @@ -226,10 +234,16 @@ ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersect __m128 P_curve[4]; - P_curve[0] = _mm_load_ps(&kg->__curve_keys.data[ka].x); - P_curve[1] = _mm_load_ps(&kg->__curve_keys.data[k0].x); - P_curve[2] = _mm_load_ps(&kg->__curve_keys.data[k1].x); - P_curve[3] = _mm_load_ps(&kg->__curve_keys.data[kb].x); + if(type & PRIMITIVE_CURVE) { + P_curve[0] = _mm_load_ps(&kg->__curve_keys.data[ka].x); + P_curve[1] = _mm_load_ps(&kg->__curve_keys.data[k0].x); + P_curve[2] = _mm_load_ps(&kg->__curve_keys.data[k1].x); + P_curve[3] = _mm_load_ps(&kg->__curve_keys.data[kb].x); + } + else { + int fobject = (object == ~0)? kernel_tex_fetch(__prim_object, curveAddr): object; + motion_cardinal_curve_keys(kg, fobject, prim, time, ka, k0, k1, kb, (float4*)&P_curve); + } __m128 rd_sgn = set_sign_bit<0, 1, 1, 1>(broadcast<0>(rd_ss)); __m128 mul_zxxy = _mm_mul_ps(shuffle<2, 0, 0, 1>(vdir), rd_sgn); @@ -287,10 +301,16 @@ ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersect float4 P_curve[4]; - P_curve[0] = kernel_tex_fetch(__curve_keys, ka); - P_curve[1] = kernel_tex_fetch(__curve_keys, k0); - P_curve[2] = kernel_tex_fetch(__curve_keys, k1); - P_curve[3] = kernel_tex_fetch(__curve_keys, kb); + if(type & PRIMITIVE_CURVE) { + P_curve[0] = kernel_tex_fetch(__curve_keys, ka); + P_curve[1] = kernel_tex_fetch(__curve_keys, k0); + P_curve[2] = kernel_tex_fetch(__curve_keys, k1); + P_curve[3] = kernel_tex_fetch(__curve_keys, kb); + } + else { + int fobject = (object == ~0)? kernel_tex_fetch(__prim_object, curveAddr): object; + motion_cardinal_curve_keys(kg, fobject, prim, time, ka, k0, k1, kb, P_curve); + } float3 p0 = transform_point(&htfm, float4_to_float3(P_curve[0]) - P); float3 p1 = transform_point(&htfm, float4_to_float3(P_curve[1]) - P); @@ -593,8 +613,14 @@ ccl_device_inline bool bvh_curve_intersect(KernelGlobals *kg, Intersection *isec #ifndef __KERNEL_SSE2__ float4 P_curve[2]; - P_curve[0]= kernel_tex_fetch(__curve_keys, k0); - P_curve[1]= kernel_tex_fetch(__curve_keys, k1); + if(type & PRIMITIVE_CURVE) { + P_curve[0]= kernel_tex_fetch(__curve_keys, k0); + P_curve[1]= kernel_tex_fetch(__curve_keys, k1); + } + else { + int fobject = (object == ~0)? kernel_tex_fetch(__prim_object, curveAddr): object; + motion_curve_keys(kg, fobject, prim, time, k0, k1, P_curve); + } float or1 = P_curve[0].w; float or2 = P_curve[1].w; @@ -620,14 +646,23 @@ ccl_device_inline bool bvh_curve_intersect(KernelGlobals *kg, Intersection *isec float sphere_b_tmp = dot3(dir, sphere_dif1); float3 sphere_dif2 = sphere_dif1 - sphere_b_tmp * dir; #else - const __m128 p1 = _mm_load_ps(&kg->__curve_keys.data[k0].x); - const __m128 p2 = _mm_load_ps(&kg->__curve_keys.data[k1].x); - const __m128 or12 = shuffle<3, 3, 3, 3>(p1, p2); + __m128 P_curve[2]; + + if(type & PRIMITIVE_CURVE) { + P_curve[0] = _mm_load_ps(&kg->__curve_keys.data[k0].x); + P_curve[1] = _mm_load_ps(&kg->__curve_keys.data[k1].x); + } + else { + int fobject = (object == ~0)? kernel_tex_fetch(__prim_object, curveAddr): object; + motion_curve_keys(kg, fobject, prim, time, k0, k1, (float4*)&P_curve); + } + + const __m128 or12 = shuffle<3, 3, 3, 3>(P_curve[0], P_curve[1]); __m128 r12 = or12; const __m128 vP = load_m128(P); - const __m128 dif = _mm_sub_ps(vP, p1); - const __m128 dif_second = _mm_sub_ps(vP, p2); + const __m128 dif = _mm_sub_ps(vP, P_curve[0]); + const __m128 dif_second = _mm_sub_ps(vP, P_curve[1]); if(difl != 0.0f) { const __m128 len1_sq = len3_squared_splat(dif); const __m128 len2_sq = len3_squared_splat(dif_second); @@ -639,7 +674,7 @@ ccl_device_inline bool bvh_curve_intersect(KernelGlobals *kg, Intersection *isec float r1 = _mm_cvtss_f32(r12), r2 = _mm_cvtss_f32(broadcast<2>(r12)); const __m128 dir = _mm_div_ps(_mm_set1_ps(1.0f), load_m128(idir)); - const __m128 p21_diff = _mm_sub_ps(p2, p1); + const __m128 p21_diff = _mm_sub_ps(P_curve[1], P_curve[0]); const __m128 sphere_dif1 = _mm_mul_ps(_mm_add_ps(dif, dif_second), _mm_set1_ps(0.5f)); const __m128 sphere_b_tmp = dot3_splat(dir, sphere_dif1); const __m128 sphere_dif2 = fnma(sphere_b_tmp, dir, sphere_dif1); @@ -854,10 +889,15 @@ ccl_device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, con float4 P_curve[4]; - P_curve[0] = kernel_tex_fetch(__curve_keys, ka); - P_curve[1] = kernel_tex_fetch(__curve_keys, k0); - P_curve[2] = kernel_tex_fetch(__curve_keys, k1); - P_curve[3] = kernel_tex_fetch(__curve_keys, kb); + if(sd->type & PRIMITIVE_CURVE) { + P_curve[0] = kernel_tex_fetch(__curve_keys, ka); + P_curve[1] = kernel_tex_fetch(__curve_keys, k0); + P_curve[2] = kernel_tex_fetch(__curve_keys, k1); + P_curve[3] = kernel_tex_fetch(__curve_keys, kb); + } + else { + motion_cardinal_curve_keys(kg, sd->object, sd->prim, sd->time, ka, k0, k1, kb, P_curve); + } float l = 1.0f; tg = normalize_len(float4_to_float3(P_curve[2] - P_curve[1]), &l); @@ -893,8 +933,13 @@ ccl_device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, con else { float4 P_curve[2]; - P_curve[0]= kernel_tex_fetch(__curve_keys, k0); - P_curve[1]= kernel_tex_fetch(__curve_keys, k1); + if(sd->type & PRIMITIVE_CURVE) { + P_curve[0]= kernel_tex_fetch(__curve_keys, k0); + P_curve[1]= kernel_tex_fetch(__curve_keys, k1); + } + else { + motion_curve_keys(kg, sd->object, sd->prim, sd->time, k0, k1, P_curve); + } float l = 1.0f; tg = normalize_len(float4_to_float3(P_curve[1] - P_curve[0]), &l); diff --git a/intern/cycles/kernel/geom/geom_motion_curve.h b/intern/cycles/kernel/geom/geom_motion_curve.h new file mode 100644 index 00000000000..128e111be2f --- /dev/null +++ b/intern/cycles/kernel/geom/geom_motion_curve.h @@ -0,0 +1,139 @@ +/* + * 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 + +#ifdef __HAIR__ + +/* todo: find a better (faster) solution for this, maybe store offset per object */ +ccl_device_inline int find_attribute_curve_motion(KernelGlobals *kg, int object, uint id, AttributeElement *elem) +{ + uint attr_offset = object*kernel_data.bvh.attributes_map_stride + ATTR_PRIM_CURVE; + 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; +} + +ccl_device_inline void motion_curve_keys_for_step(KernelGlobals *kg, int offset, int numkeys, int numsteps, int step, int k0, int k1, float4 keys[2]) +{ + if(step == numsteps) { + /* center step: regular vertex location */ + keys[0] = kernel_tex_fetch(__curve_keys, k0); + keys[1] = kernel_tex_fetch(__curve_keys, k1); + } + else { + /* center step not store in this array */ + if(step > numsteps) + step--; + + offset += step*numkeys; + + keys[0] = kernel_tex_fetch(__attributes_float3, offset + k0); + keys[1] = kernel_tex_fetch(__attributes_float3, offset + k1); + } +} + +/* return 2 curve key locations */ +ccl_device_inline void motion_curve_keys(KernelGlobals *kg, int object, int prim, float time, int k0, int k1, float4 keys[2]) +{ + /* get motion info */ + int numsteps, numkeys; + object_motion_info(kg, object, &numsteps, NULL, &numkeys); + + /* 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_curve_motion(kg, object, ATTR_STD_MOTION_VERTEX_POSITION, &elem); + kernel_assert(offset != ATTR_STD_NOT_FOUND); + + /* fetch key coordinates */ + float4 next_keys[2]; + + motion_curve_keys_for_step(kg, offset, numkeys, numsteps, step, k0, k1, keys); + motion_curve_keys_for_step(kg, offset, numkeys, numsteps, step+1, k0, k1, next_keys); + + /* interpolate between steps */ + keys[0] = (1.0f - t)*keys[0] + t*next_keys[0]; + keys[1] = (1.0f - t)*keys[1] + t*next_keys[1]; +} + +ccl_device_inline void motion_cardinal_curve_keys_for_step(KernelGlobals *kg, int offset, int numkeys, int numsteps, int step, int k0, int k1, int k2, int k3, float4 keys[4]) +{ + if(step == numsteps) { + /* center step: regular vertex location */ + keys[0] = kernel_tex_fetch(__curve_keys, k0); + keys[1] = kernel_tex_fetch(__curve_keys, k1); + keys[2] = kernel_tex_fetch(__curve_keys, k2); + keys[3] = kernel_tex_fetch(__curve_keys, k3); + } + else { + /* center step not store in this array */ + if(step > numsteps) + step--; + + offset += step*numkeys; + + keys[0] = kernel_tex_fetch(__attributes_float3, offset + k0); + keys[1] = kernel_tex_fetch(__attributes_float3, offset + k1); + keys[2] = kernel_tex_fetch(__attributes_float3, offset + k2); + keys[3] = kernel_tex_fetch(__attributes_float3, offset + k3); + } +} + +/* return 2 curve key locations */ +ccl_device_inline void motion_cardinal_curve_keys(KernelGlobals *kg, int object, int prim, float time, int k0, int k1, int k2, int k3, float4 keys[4]) +{ + /* get motion info */ + int numsteps, numkeys; + object_motion_info(kg, object, &numsteps, NULL, &numkeys); + + /* 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_curve_motion(kg, object, ATTR_STD_MOTION_VERTEX_POSITION, &elem); + kernel_assert(offset != ATTR_STD_NOT_FOUND); + + /* fetch key coordinates */ + float4 next_keys[4]; + + motion_cardinal_curve_keys_for_step(kg, offset, numkeys, numsteps, step, k0, k1, k2, k3, keys); + motion_cardinal_curve_keys_for_step(kg, offset, numkeys, numsteps, step+1, k0, k1, k2, k3, next_keys); + + /* interpolate between steps */ + keys[0] = (1.0f - t)*keys[0] + t*next_keys[0]; + keys[1] = (1.0f - t)*keys[1] + t*next_keys[1]; + keys[2] = (1.0f - t)*keys[2] + t*next_keys[2]; + keys[3] = (1.0f - t)*keys[3] + t*next_keys[3]; +} + +#endif + +CCL_NAMESPACE_END + |