From a9bb4607660a2f68a78732fd7f5d5280d8075dcb Mon Sep 17 00:00:00 2001 From: William Leeson Date: Thu, 13 Jan 2022 17:12:03 +0100 Subject: Cycles: compute triangle location from barycentric instead of re-intersecting This is a bit more efficient than what we did before. Ref D12954 --- .../cycles/kernel/geom/motion_triangle_intersect.h | 112 ++------------------ intern/cycles/kernel/geom/motion_triangle_shader.h | 10 +- intern/cycles/kernel/geom/shader_data.h | 2 +- intern/cycles/kernel/geom/triangle_intersect.h | 114 ++------------------- intern/cycles/kernel/svm/bevel.h | 17 ++- 5 files changed, 36 insertions(+), 219 deletions(-) (limited to 'intern') diff --git a/intern/cycles/kernel/geom/motion_triangle_intersect.h b/intern/cycles/kernel/geom/motion_triangle_intersect.h index cb6d210d90f..a11cb88385b 100644 --- a/intern/cycles/kernel/geom/motion_triangle_intersect.h +++ b/intern/cycles/kernel/geom/motion_triangle_intersect.h @@ -29,46 +29,19 @@ CCL_NAMESPACE_BEGIN -/* 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. +/** + * Use the barycentric coordinates to get the intersection location */ - -ccl_device_inline float3 motion_triangle_refine(KernelGlobals kg, - ccl_private ShaderData *sd, - float3 P, - float3 D, - float t, - const int isect_object, - const int isect_prim, - float3 verts[3]) +ccl_device_inline float3 motion_triangle_point_from_uv(KernelGlobals kg, + ccl_private ShaderData *sd, + const int isect_object, + const int isect_prim, + const float u, + const float v, + float3 verts[3]) { -#ifdef __INTERSECTION_REFINE__ - if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { - if (UNLIKELY(t == 0.0f)) { - return P; - } - const Transform tfm = object_get_inverse_transform(kg, sd); - - 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; + float w = 1.0f - u - v; + float3 P = u * verts[0] + v * verts[1] + w * verts[2]; if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { const Transform tfm = object_get_transform(kg, sd); @@ -76,71 +49,8 @@ ccl_device_inline float3 motion_triangle_refine(KernelGlobals kg, } return P; -#else - return P + D * t; -#endif } -/* Same as above, except that t is assumed to be in object space - * for instancing. - */ - -#ifdef __BVH_LOCAL__ -# if defined(__KERNEL_CUDA__) && (defined(i386) || defined(_M_IX86)) -ccl_device_noinline -# else -ccl_device_inline -# endif - float3 - motion_triangle_refine_local(KernelGlobals kg, - ccl_private ShaderData *sd, - float3 P, - float3 D, - float t, - const int isect_object, - const int isect_prim, - float3 verts[3]) -{ -# if defined(__KERNEL_GPU_RAYTRACING__) - /* t is always in world space with OptiX and MetalRT. */ - return motion_triangle_refine(kg, sd, P, D, t, isect_object, isect_prim, verts); -# else -# ifdef __INTERSECTION_REFINE__ - if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { - const Transform tfm = object_get_inverse_transform(kg, sd); - - 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 (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { - const Transform tfm = object_get_transform(kg, sd); - P = transform_point(&tfm, P); - } - - return P; -# else /* __INTERSECTION_REFINE__ */ - return P + D * t; -# endif /* __INTERSECTION_REFINE__ */ -# endif -} -#endif /* __BVH_LOCAL__ */ - /* Ray intersection. We simply compute the vertex positions at the given ray * time and do a ray intersection with the resulting triangle. */ diff --git a/intern/cycles/kernel/geom/motion_triangle_shader.h b/intern/cycles/kernel/geom/motion_triangle_shader.h index fc7c181882e..15730c83969 100644 --- a/intern/cycles/kernel/geom/motion_triangle_shader.h +++ b/intern/cycles/kernel/geom/motion_triangle_shader.h @@ -68,15 +68,7 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals kg, 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. */ -#ifdef __BVH_LOCAL__ - if (is_local) { - sd->P = motion_triangle_refine_local(kg, sd, P, D, ray_t, isect_object, isect_prim, verts); - } - else -#endif /* __BVH_LOCAL__*/ - { - sd->P = motion_triangle_refine(kg, sd, P, D, ray_t, isect_object, isect_prim, verts); - } + sd->P = motion_triangle_point_from_uv(kg, sd, isect_object, isect_prim, sd->u, sd->v, verts); /* Compute face normal. */ float3 Ng; if (sd->object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) { diff --git a/intern/cycles/kernel/geom/shader_data.h b/intern/cycles/kernel/geom/shader_data.h index f5055d8b285..2027190fdd2 100644 --- a/intern/cycles/kernel/geom/shader_data.h +++ b/intern/cycles/kernel/geom/shader_data.h @@ -89,7 +89,7 @@ ccl_device_inline void shader_setup_from_ray(KernelGlobals kg, sd->shader = kernel_tex_fetch(__tri_shader, sd->prim); /* vectors */ - sd->P = triangle_refine(kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim); + sd->P = triangle_point_from_uv(kg, sd, isect->object, isect->prim, isect->u, isect->v); sd->Ng = Ng; sd->N = Ng; diff --git a/intern/cycles/kernel/geom/triangle_intersect.h b/intern/cycles/kernel/geom/triangle_intersect.h index 0169b40bc34..8458cf020a0 100644 --- a/intern/cycles/kernel/geom/triangle_intersect.h +++ b/intern/cycles/kernel/geom/triangle_intersect.h @@ -142,116 +142,23 @@ ccl_device_inline bool triangle_intersect_local(KernelGlobals kg, } #endif /* __BVH_LOCAL__ */ -/* 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. */ - -/* Reintersections uses the paper: - * - * Tomas Moeller - * Fast, minimum storage ray/triangle intersection - * http://www.cs.virginia.edu/~gfx/Courses/2003/ImageSynthesis/papers/Acceleration/Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf +/** + * Use the barycentric coordinates to get the intersection location */ - -ccl_device_inline float3 triangle_refine(KernelGlobals kg, - ccl_private ShaderData *sd, - float3 P, - float3 D, - float t, - const int isect_object, - const int isect_prim) +ccl_device_inline float3 triangle_point_from_uv(KernelGlobals kg, + ccl_private ShaderData *sd, + const int isect_object, + const int isect_prim, + const float u, + const float v) { -#ifdef __INTERSECTION_REFINE__ - if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { - if (UNLIKELY(t == 0.0f)) { - return P; - } - const Transform tfm = object_get_inverse_transform(kg, sd); - - P = transform_point(&tfm, P); - D = transform_direction(&tfm, D * t); - D = normalize_len(D, &t); - } - - P = P + D * t; - const uint tri_vindex = kernel_tex_fetch(__tri_vindex, isect_prim).w; const packed_float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0), tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1), tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2); - float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z); - float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z); - float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z); - float3 qvec = cross(tvec, edge1); - float3 pvec = cross(D, edge2); - float det = dot(edge1, pvec); - if (det != 0.0f) { - /* If determinant is zero it means ray lies in the plane of - * the triangle. It is possible in theory due to watertight - * nature of triangle intersection. For such cases we simply - * don't refine intersection hoping it'll go all fine. - */ - float rt = dot(edge2, qvec) / det; - P = P + D * rt; - } - - if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { - const Transform tfm = object_get_transform(kg, sd); - P = transform_point(&tfm, P); - } - - return P; -#else - return P + D * t; -#endif -} - -/* Same as above, except that t is assumed to be in object space for - * instancing. - */ -ccl_device_inline float3 triangle_refine_local(KernelGlobals kg, - ccl_private ShaderData *sd, - float3 P, - float3 D, - float t, - const int isect_object, - const int isect_prim) -{ -#if defined(__KERNEL_GPU_RAYTRACING__) - /* t is always in world space with OptiX and MetalRT. */ - return triangle_refine(kg, sd, P, D, t, isect_object, isect_prim); -#else - if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { - const Transform tfm = object_get_inverse_transform(kg, sd); - - P = transform_point(&tfm, P); - D = transform_direction(&tfm, D); - D = normalize(D); - } + float w = 1.0f - u - v; - P = P + D * t; - -# ifdef __INTERSECTION_REFINE__ - const uint tri_vindex = kernel_tex_fetch(__tri_vindex, isect_prim).w; - const packed_float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0), - tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1), - tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2); - float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z); - float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z); - float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z); - float3 qvec = cross(tvec, edge1); - float3 pvec = cross(D, edge2); - float det = dot(edge1, pvec); - if (det != 0.0f) { - /* If determinant is zero it means ray lies in the plane of - * the triangle. It is possible in theory due to watertight - * nature of triangle intersection. For such cases we simply - * don't refine intersection hoping it'll go all fine. - */ - float rt = dot(edge2, qvec) / det; - P = P + D * rt; - } -# endif /* __INTERSECTION_REFINE__ */ + float3 P = u * tri_a + v * tri_b + w * tri_c; if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { const Transform tfm = object_get_transform(kg, sd); @@ -259,7 +166,6 @@ ccl_device_inline float3 triangle_refine_local(KernelGlobals kg, } return P; -#endif } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/bevel.h b/intern/cycles/kernel/svm/bevel.h index 46dfb6631da..57c0288a96f 100644 --- a/intern/cycles/kernel/svm/bevel.h +++ b/intern/cycles/kernel/svm/bevel.h @@ -207,15 +207,24 @@ ccl_device float3 svm_bevel( /* Quickly retrieve P and Ng without setting up ShaderData. */ float3 hit_P; if (sd->type == PRIMITIVE_TRIANGLE) { - hit_P = triangle_refine_local( - kg, sd, ray.P, ray.D, ray.t, isect.hits[hit].object, isect.hits[hit].prim); + hit_P = triangle_point_from_uv(kg, + sd, + isect.hits[hit].object, + isect.hits[hit].prim, + isect.hits[hit].u, + isect.hits[hit].v); } # ifdef __OBJECT_MOTION__ else if (sd->type == PRIMITIVE_MOTION_TRIANGLE) { float3 verts[3]; motion_triangle_vertices(kg, sd->object, isect.hits[hit].prim, sd->time, verts); - hit_P = motion_triangle_refine_local( - kg, sd, ray.P, ray.D, ray.t, isect.hits[hit].object, isect.hits[hit].prim, verts); + hit_P = motion_triangle_point_from_uv(kg, + sd, + isect.hits[hit].object, + isect.hits[hit].prim, + isect.hits[hit].u, + isect.hits[hit].v, + verts); } # endif /* __OBJECT_MOTION__ */ -- cgit v1.2.3