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 | 6020d0099039ed18c6a6cd330b68361123c85c1a (patch) | |
tree | 511c682800b981019f2eb5dfaf341238ea4882f8 | |
parent | 8f33538fabe9b2485478b7ce0167c15396bdb355 (diff) |
Cycles: add support for mesh deformation motion blur.
-rw-r--r-- | intern/cycles/blender/blender_mesh.cpp | 3 | ||||
-rw-r--r-- | intern/cycles/blender/blender_object.cpp | 4 | ||||
-rw-r--r-- | intern/cycles/bvh/bvh.cpp | 18 | ||||
-rw-r--r-- | intern/cycles/bvh/bvh_build.cpp | 17 | ||||
-rw-r--r-- | intern/cycles/kernel/CMakeLists.txt | 1 | ||||
-rw-r--r-- | intern/cycles/kernel/geom/geom_bvh.h | 1 | ||||
-rw-r--r-- | intern/cycles/kernel/geom/geom_bvh_subsurface.h | 4 | ||||
-rw-r--r-- | intern/cycles/kernel/geom/geom_bvh_traversal.h | 4 | ||||
-rw-r--r-- | intern/cycles/kernel/geom/geom_motion_triangle.h | 370 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_shader.h | 14 | ||||
-rw-r--r-- | intern/cycles/kernel/osl/osl_services.cpp | 6 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/svm_wireframe.h | 5 | ||||
-rw-r--r-- | intern/cycles/render/light.cpp | 8 | ||||
-rw-r--r-- | intern/cycles/render/mesh.cpp | 14 | ||||
-rw-r--r-- | intern/cycles/render/mesh.h | 3 | ||||
-rw-r--r-- | intern/cycles/render/object.cpp | 42 | ||||
-rw-r--r-- | intern/cycles/util/util_math.h | 44 |
17 files changed, 534 insertions, 24 deletions
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index ed19fb2672b..8c9734283ea 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -559,6 +559,9 @@ void BlenderSync::sync_mesh_motion(BL::Object b_ob, Object *object, float motion int time_index = 0; if(scene->need_motion() == Scene::MOTION_BLUR) { + if(!mesh->use_motion_blur) + return; + /* see if this mesh needs motion data at this time */ vector<float> object_times = object->motion_times(); bool found = false; diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index f5945a68fc1..bd4becb2dd4 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -324,8 +324,10 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P Mesh *mesh = object->mesh; if(true) { - if(true) + if(true) { mesh->motion_steps = 3; + mesh->use_motion_blur = true; + } vector<float> times = object->motion_times(); foreach(float time, times) diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index c0d70e0bc61..92ad3cd24a5 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -241,6 +241,10 @@ void BVH::pack_triangle(int idx, float4 woop[3]) /* create Woop triangle */ int tob = pack.prim_object[idx]; const Mesh *mesh = objects[tob]->mesh; + + if(mesh->has_motion_blur()) + return; + int tidx = pack.prim_index[idx]; const int *vidx = mesh->triangles[tidx].v; const float3* vpos = &mesh->verts[0]; @@ -646,6 +650,20 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility const float3 *vpos = &mesh->verts[0]; triangle.bounds_grow(vpos, bbox); + + /* motion triangles */ + if(mesh->use_motion_blur) { + Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if(attr) { + size_t mesh_size = mesh->verts.size(); + size_t steps = mesh->motion_steps - 1; + float3 *vert_steps = attr->data_float3(); + + for (size_t i = 0; i < steps; i++) + triangle.bounds_grow(vert_steps + i*mesh_size, bbox); + } + } } } diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index ef48c1edc63..f52626d02d2 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -70,6 +70,11 @@ BVHBuild::~BVHBuild() void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i) { + Attribute *attr_mP = NULL; + + if(mesh->has_motion_blur()) + attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + for(uint j = 0; j < mesh->triangles.size(); j++) { Mesh::Triangle t = mesh->triangles[j]; BoundBox bounds = BoundBox::empty; @@ -77,6 +82,18 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, t.bounds_grow(&mesh->verts[0], bounds); + /* motion triangles */ + if(attr_mP) { + size_t mesh_size = mesh->verts.size(); + size_t steps = mesh->motion_steps - 1; + float3 *vert_steps = attr_mP->data_float3(); + + for(size_t i = 0; i < steps; i++) + t.bounds_grow(vert_steps + i*mesh_size, bounds); + + type = PRIMITIVE_MOTION_TRIANGLE; + } + if(bounds.valid()) { references.push_back(BVHReference(bounds, j, i, type)); root.grow(bounds); diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index ccefb314894..7e9b0c53d94 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -113,6 +113,7 @@ set(SRC_GEOM_HEADERS geom/geom_bvh_subsurface.h geom/geom_bvh_traversal.h geom/geom_curve.h + geom/geom_motion_triangle.h geom/geom_object.h geom/geom_triangle.h ) diff --git a/intern/cycles/kernel/geom/geom_bvh.h b/intern/cycles/kernel/geom/geom_bvh.h index 055b18e63d7..20c3c7c19ca 100644 --- a/intern/cycles/kernel/geom/geom_bvh.h +++ b/intern/cycles/kernel/geom/geom_bvh.h @@ -43,6 +43,7 @@ #include "geom_object.h" #include "geom_curve.h" #include "geom_triangle.h" +#include "geom_motion_triangle.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/geom/geom_bvh_subsurface.h b/intern/cycles/kernel/geom/geom_bvh_subsurface.h index d61929405ef..994c98e5f5f 100644 --- a/intern/cycles/kernel/geom/geom_bvh_subsurface.h +++ b/intern/cycles/kernel/geom/geom_bvh_subsurface.h @@ -218,6 +218,10 @@ ccl_device uint BVH_FUNCTION_NAME(KernelGlobals *kg, const Ray *ray, Intersectio triangle_intersect_subsurface(kg, isect_array, P, idir, object, primAddr, isect_t, &num_hits, lcg_state, max_hits); break; } + case PRIMITIVE_MOTION_TRIANGLE: { + motion_triangle_intersect_subsurface(kg, isect_array, P, idir, ray->time, object, primAddr, isect_t, &num_hits, lcg_state, max_hits); + break; + } default: { break; } diff --git a/intern/cycles/kernel/geom/geom_bvh_traversal.h b/intern/cycles/kernel/geom/geom_bvh_traversal.h index 1abefb51976..1fd0772c9ae 100644 --- a/intern/cycles/kernel/geom/geom_bvh_traversal.h +++ b/intern/cycles/kernel/geom/geom_bvh_traversal.h @@ -256,6 +256,10 @@ ccl_device bool BVH_FUNCTION_NAME hit = triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); break; } + case PRIMITIVE_MOTION_TRIANGLE: { + hit = motion_triangle_intersect(kg, isect, P, idir, ray->time, visibility, object, primAddr); + break; + } #if FEATURE(BVH_HAIR) case PRIMITIVE_CURVE: { #if FEATURE(BVH_HAIR_MINIMUM_WIDTH) diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h new file mode 100644 index 00000000000..05642d8ab14 --- /dev/null +++ b/intern/cycles/kernel/geom/geom_motion_triangle.h @@ -0,0 +1,370 @@ +/* + * Adapted from code Copyright 2009-2010 NVIDIA Corporation + * Modifications Copyright 2011, 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 + +/* todo: find a better (faster) solution for this, maybe store offset per object */ +ccl_device_inline int find_attribute_motion(KernelGlobals *kg, int object, uint id, AttributeElement *elem) +{ + uint attr_offset = object*kernel_data.bvh.attributes_map_stride; + 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_triangle_verts_for_step(KernelGlobals *kg, float3 tri_vindex, int offset, int numverts, int numsteps, int step, float3 verts[3]) +{ + if(step == numsteps) { + /* center step: regular vertex location */ + verts[0] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x))); + verts[1] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y))); + verts[2] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z))); + } + else { + /* center step not store in this array */ + if(step > numsteps) + step--; + + offset += step*numverts; + + verts[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x))); + verts[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y))); + verts[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z))); + } +} + +ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals *kg, float3 tri_vindex, int offset, int numverts, int numsteps, int step, float3 normals[3]) +{ + if(step == numsteps) { + /* center step: regular vertex location */ + normals[0] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.x))); + normals[1] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.y))); + normals[2] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.z))); + } + else { + /* center step not store in this array */ + if(step > numsteps) + step--; + + offset += step*numverts; + + normals[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x))); + normals[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y))); + normals[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z))); + } +} + +/* return 3 triangle vertex locations */ +ccl_device_inline void motion_triangle_vertices(KernelGlobals *kg, int object, int prim, float time, float3 verts[3]) +{ + /* 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_POSITION, &elem); + kernel_assert(offset != ATTR_STD_NOT_FOUND); + + /* fetch vertex coordinates */ + float3 next_verts[3]; + float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, prim)); + + motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts); + motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_verts); + + /* interpolate between steps */ + verts[0] = (1.0f - t)*verts[0] + t*next_verts[0]; + verts[1] = (1.0f - t)*verts[1] + t*next_verts[1]; + verts[2] = (1.0f - t)*verts[2] + t*next_verts[2]; +} + +/* Refine triangle intersection to more precise hit point. For rays that travel + * far the precision is often not so good, this reintersects the primitive from + * a closer distance. */ + +ccl_device_inline float3 motion_triangle_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, float3 verts[3]) +{ + float3 P = ray->P; + float3 D = ray->D; + float t = isect->t; + +#ifdef __INTERSECTION_REFINE__ + 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); + } + + P = P + D*t; + + /* compute refined intersection distance */ + const float3 e1 = verts[0] - verts[2]; + const float3 e2 = verts[1] - verts[2]; + const float3 s1 = cross(D, e2); + + const float invdivisor = 1.0f/dot(s1, e1); + const float3 d = P - verts[2]; + const float3 s2 = cross(d, e1); + float rt = dot(e2, s2)*invdivisor; + + /* compute refined position */ + P = P + D*rt; + + 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; +#else + return P + D*t; +#endif +} + +/* same as above, except that isect->t is assumed to be in object space for instancing */ +ccl_device_inline float3 motion_triangle_refine_subsurface(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, float3 verts[3]) +{ + float3 P = ray->P; + float3 D = ray->D; + float t = isect->t; + +#ifdef __INTERSECTION_REFINE__ + 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); + D = normalize(D); + } + + P = P + D*t; + + /* compute refined intersection distance */ + const float3 e1 = verts[0] - verts[2]; + const float3 e2 = verts[1] - verts[2]; + const float3 s1 = cross(D, e2); + + const float invdivisor = 1.0f/dot(s1, e1); + const float3 d = P - verts[2]; + const float3 s2 = cross(d, e1); + float rt = dot(e2, s2)*invdivisor; + + P = P + D*rt; + + 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; +#else + return P + D*t; +#endif +} + +/* return 3 triangle vertex normals */ +ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, bool subsurface) +{ + /* get shader */ + float4 Ns = kernel_tex_fetch(__tri_normal, sd->prim); + sd->shader = __float_as_int(Ns.w); + + /* get motion info */ + int numsteps, numverts; + object_motion_info(kg, sd->object, &numsteps, &numverts, NULL); + + /* figure out which steps we need to fetch and their interpolation factor */ + int maxstep = numsteps*2; + int step = min((int)(sd->time*maxstep), maxstep-1); + float t = sd->time*maxstep - step; + + /* find attribute */ + AttributeElement elem; + int offset = find_attribute_motion(kg, sd->object, ATTR_STD_MOTION_VERTEX_POSITION, &elem); + kernel_assert(offset != ATTR_STD_NOT_FOUND); + + /* fetch vertex coordinates */ + float3 verts[3], next_verts[3]; + float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, sd->prim)); + + motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts); + motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_verts); + + /* interpolate between steps */ + verts[0] = (1.0f - t)*verts[0] + t*next_verts[0]; + verts[1] = (1.0f - t)*verts[1] + t*next_verts[1]; + verts[2] = (1.0f - t)*verts[2] + t*next_verts[2]; + + /* compute refined position */ + if(!subsurface) + sd->P = motion_triangle_refine(kg, sd, isect, ray, verts); + else + sd->P = motion_triangle_refine_subsurface(kg, sd, isect, ray, verts); + + /* compute face normal */ + float3 Ng = normalize(cross(verts[1] - verts[0], verts[2] - verts[0])); + + sd->Ng = Ng; + sd->N = Ng; + + /* compute derivatives of P w.r.t. uv */ +#ifdef __DPDU__ + sd->dPdu = (verts[0] - verts[2]); + sd->dPdv = (verts[1] - verts[2]); +#endif + + /* compute smooth normal */ + if(sd->shader & SHADER_SMOOTH_NORMAL) { + /* find attribute */ + AttributeElement elem; + int offset = find_attribute_motion(kg, sd->object, ATTR_STD_MOTION_VERTEX_NORMAL, &elem); + kernel_assert(offset != ATTR_STD_NOT_FOUND); + + /* fetch vertex coordinates */ + float3 normals[3], next_normals[3]; + 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 u = sd->u; + float v = sd->v; + float w = 1.0f - u - v; + sd->N = (u*normals[0] + v*normals[1] + w*normals[2]); + } +} + + + +ccl_device_inline bool motion_triangle_intersect(KernelGlobals *kg, Intersection *isect, + float3 P, float3 idir, float time, uint visibility, int object, int triAddr) +{ + /* primitive index for vertex location lookup */ + int prim = kernel_tex_fetch(__prim_index, triAddr); + int fobject = (object == ~0)? kernel_tex_fetch(__prim_object, triAddr): object; + + /* get vertex locations for intersection */ + float3 verts[3]; + motion_triangle_vertices(kg, fobject, prim, time, verts); + + /* ray-triangle intersection, unoptimized */ + float3 D = 1.0f/idir; + float t, u, v; + + if(ray_triangle_intersect_uv(P, D, isect->t, verts[2], verts[0], verts[1], &u, &v, &t)) { + isect->prim = triAddr; + isect->object = object; + isect->type = PRIMITIVE_MOTION_TRIANGLE; + isect->u = u; + isect->v = v; + isect->t = t; + + return true; + } + + return false; +} + +#ifdef __SUBSURFACE__ +/* Special ray intersection routines for subsurface scattering. In that case we + * only want to intersect with primitives in the same object, and if case of + * multiple hits we pick a single random primitive as the intersection point. */ + +ccl_device_inline void motion_triangle_intersect_subsurface(KernelGlobals *kg, Intersection *isect_array, + float3 P, float3 idir, float time, int object, int triAddr, float tmax, uint *num_hits, uint *lcg_state, int max_hits) +{ + /* primitive index for vertex location lookup */ + int prim = kernel_tex_fetch(__prim_index, triAddr); + int fobject = (object == ~0)? kernel_tex_fetch(__prim_object, triAddr): object; + + /* get vertex locations for intersection */ + float3 verts[3]; + motion_triangle_vertices(kg, fobject, prim, time, verts); + + /* ray-triangle intersection, unoptimized */ + float3 D = 1.0f/idir; + float t, u, v; + + if(ray_triangle_intersect_uv(P, D, tmax, verts[2], verts[0], verts[1], &u, &v, &t)) { + (*num_hits)++; + + int hit; + + if(*num_hits <= max_hits) { + hit = *num_hits - 1; + } + else { + /* reservoir sampling: if we are at the maximum number of + * hits, randomly replace element or skip it */ + hit = lcg_step_uint(lcg_state) % *num_hits; + + if(hit >= max_hits) + return; + } + + /* record intersection */ + Intersection *isect = &isect_array[hit]; + isect->prim = triAddr; + isect->object = object; + isect->type = PRIMITIVE_MOTION_TRIANGLE; + isect->u = u; + isect->v = v; + isect->t = t; + } +} +#endif + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 95cdfd1a80a..2ba87e29786 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -83,8 +83,8 @@ ccl_device void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd, } else #endif - { - /* fetch triangle data */ + if(sd->type & PRIMITIVE_TRIANGLE) { + /* static triangle */ 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); @@ -103,6 +103,10 @@ ccl_device void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd, triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv); #endif } + else { + /* motion triangle */ + motion_triangle_shader_setup(kg, sd, isect, ray, false); + } sd->I = -ray->D; @@ -160,7 +164,7 @@ ccl_device_inline void shader_setup_from_subsurface(KernelGlobals *kg, ShaderDat #endif /* fetch triangle data */ - { + if(sd->type == PRIMITIVE_TRIANGLE) { 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); @@ -178,6 +182,10 @@ ccl_device_inline void shader_setup_from_subsurface(KernelGlobals *kg, ShaderDat triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv); #endif } + else { + /* motion triangle */ + motion_triangle_shader_setup(kg, sd, isect, ray, true); + } sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2); diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 6768114e5fd..10216c22818 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -648,7 +648,11 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD ) { #endif float3 P[3]; - triangle_vertices(kg, sd->prim, P); + + if(sd->type & PRIMITIVE_TRIANGLE) + triangle_vertices(kg, sd->prim, P); + else + motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, P); if(!(sd->flag & SD_TRANSFORM_APPLIED)) { object_position_transform(kg, sd, &P[0]); diff --git a/intern/cycles/kernel/svm/svm_wireframe.h b/intern/cycles/kernel/svm/svm_wireframe.h index a20dcfa3fae..98630803efe 100644 --- a/intern/cycles/kernel/svm/svm_wireframe.h +++ b/intern/cycles/kernel/svm/svm_wireframe.h @@ -55,7 +55,10 @@ ccl_device void svm_node_wireframe(KernelGlobals *kg, ShaderData *sd, float *sta /* Triangles */ float np = 3; - triangle_vertices(kg, sd->prim, Co); + if(sd->type & PRIMITIVE_TRIANGLE) + triangle_vertices(kg, sd->prim, Co); + else + motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, Co); if(!(sd->flag & SD_TRANSFORM_APPLIED)) { object_position_transform(kg, sd, &Co[0]); diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index 29160e64082..cfc4f55ed5e 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -159,6 +159,10 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) continue; + /* skip motion blurred deforming meshes, not supported yet */ + if(mesh->has_motion_blur()) + continue; + /* skip if we have no emission shaders */ foreach(uint sindex, mesh->used_shaders) { Shader *shader = scene->shaders[sindex]; @@ -201,6 +205,10 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen continue; } + /* skip motion blurred deforming meshes, not supported yet */ + if(mesh->has_motion_blur()) + continue; + /* skip if we have no emission shaders */ foreach(uint sindex, mesh->used_shaders) { Shader *shader = scene->shaders[sindex]; diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 8e2cc97eba0..e216630b48c 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -81,6 +81,7 @@ Mesh::Mesh() bounds = BoundBox::empty; motion_steps = 3; + use_motion_blur = false; bvh = NULL; @@ -187,9 +188,9 @@ void Mesh::compute_bounds() for(size_t i = 0; i < curve_keys_size; i++) bnds.grow(float4_to_float3(curve_keys[i]), curve_keys[i].w); - + Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - if (attr) { + if (use_motion_blur && attr) { size_t steps_size = verts.size() * (motion_steps - 1); float3 *vert_steps = attr->data_float3(); @@ -216,7 +217,7 @@ void Mesh::compute_bounds() for(size_t i = 0; i < curve_keys_size; i++) bnds.grow_safe(float4_to_float3(curve_keys[i]), curve_keys[i].w); - if (attr) { + if (use_motion_blur && attr) { size_t steps_size = verts.size() * (motion_steps - 1); float3 *vert_steps = attr->data_float3(); @@ -329,7 +330,7 @@ void Mesh::add_vertex_normals() Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); Attribute *attr_mN = attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); - if(false && !attr_mN) { + if(has_motion_blur() && !attr_mN) { /* create attribute */ attr_mN = attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL); @@ -533,6 +534,11 @@ void Mesh::tag_update(Scene *scene, bool rebuild) scene->object_manager->need_update = true; } +bool Mesh::has_motion_blur() const +{ + return (use_motion_blur && attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)); +} + /* Mesh Manager */ MeshManager::MeshManager() diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index 5ae8f1f6033..eec20acd3a9 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -90,6 +90,7 @@ public: DisplacementMethod displacement_method; uint motion_steps; + bool use_motion_blur; /* Update Flags */ bool need_update; @@ -127,6 +128,8 @@ public: bool need_attribute(Scene *scene, ustring name); void tag_update(Scene *scene, bool rebuild); + + bool has_motion_blur() const; }; /* Mesh Manager */ diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index e99ca323929..df03fa4a04c 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -89,17 +89,36 @@ void Object::apply_transform() float3 c2 = transform_get_column(&tfm, 2); float scalar = pow(fabsf(dot(cross(c0, c1), c2)), 1.0f/3.0f); - /* apply to mesh vertices */ - for(size_t i = 0; i < mesh->verts.size(); i++) - mesh->verts[i] = transform_point(&tfm, mesh->verts[i]); + /* triangles */ + if(mesh->verts.size()) { + /* store matrix to transform later. when accessing these as attributes we + * do not want the transform to be applied for consistency between static + * and dynamic BVH, so we do it on packing. */ + mesh->transform_normal = transform_transpose(transform_inverse(tfm)); + + /* apply to mesh vertices */ + for(size_t i = 0; i < mesh->verts.size(); i++) + mesh->verts[i] = transform_point(&tfm, mesh->verts[i]); + + Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (attr) { + size_t steps_size = mesh->verts.size() * (mesh->motion_steps - 1); + float3 *vert_steps = attr->data_float3(); + + for (size_t i = 0; i < steps_size; i++) + vert_steps[i] = transform_point(&tfm, vert_steps[i]); + } - Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - if (attr) { - size_t steps_size = mesh->verts.size() * (mesh->motion_steps - 1); - float3 *vert_steps = attr->data_float3(); + Attribute *attr_N = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); - for (size_t i = 0; i < steps_size; i++) - vert_steps[i] = transform_point(&tfm, vert_steps[i]); + if(attr_N) { + Transform ntfm = mesh->transform_normal; + size_t steps_size = mesh->verts.size() * (mesh->motion_steps - 1); + float3 *normal_steps = attr_N->data_float3(); + + for (size_t i = 0; i < steps_size; i++) + normal_steps[i] = normalize(transform_direction(&ntfm, normal_steps[i])); + } } /* apply to curve keys */ @@ -121,11 +140,6 @@ void Object::apply_transform() vert_steps[i] = transform_point(&tfm, vert_steps[i]); } - /* store matrix to transform later. when accessing these as attributes we - * do not want the transform to be applied for consistency between static - * and dynamic BVH, so we do it on packing. */ - mesh->transform_normal = transform_transpose(transform_inverse(tfm)); - /* we keep normals pointing in same direction on negative scale, notify * mesh about this in it (re)calculates normals */ if(transform_negative_scale(tfm)) diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index dc58b93bd5d..bb73aa1bbfe 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -1360,6 +1360,50 @@ ccl_device bool ray_triangle_intersect( return true; } +ccl_device bool ray_triangle_intersect_uv( + float3 ray_P, float3 ray_D, float ray_t, + float3 v0, float3 v1, float3 v2, + float *isect_u, float *isect_v, float *isect_t) +{ + /* Calculate intersection */ + float3 e1 = v1 - v0; + float3 e2 = v2 - v0; + float3 s1 = cross(ray_D, e2); + + const float divisor = dot(s1, e1); + if(divisor == 0.0f) + return false; + + const float invdivisor = 1.0f/divisor; + + /* compute first barycentric coordinate */ + const float3 d = ray_P - v0; + const float u = dot(d, s1)*invdivisor; + if(u < 0.0f) + return false; + + /* Compute second barycentric coordinate */ + const float3 s2 = cross(d, e1); + const float v = dot(ray_D, s2)*invdivisor; + if(v < 0.0f) + return false; + + const float b0 = 1.0f - u - v; + if(b0 < 0.0f) + return false; + + /* compute t to intersection point */ + const float t = dot(e2, s2)*invdivisor; + if(t < 0.0f || t > ray_t) + return false; + + *isect_u = u; + *isect_v = v; + *isect_t = t; + + return true; +} + ccl_device bool ray_quad_intersect( float3 ray_P, float3 ray_D, float ray_t, float3 quad_P, float3 quad_u, float3 quad_v, |