Cycles: Use faster ray-quad-intersection test
authorLukas Stockner <lukas.stockner@freenet.de>
Mon, 6 Jun 2016 21:38:28 +0000 (23:38 +0200)
committerLukas Stockner <lukas.stockner@freenet.de>
Mon, 6 Jun 2016 21:38:50 +0000 (23:38 +0200)
The original quad intersection test works by just testing against the two triangles that define the quad.
However, in this case it's actually faster to use the same test that's also used for portals: Determining
the distance to the plane in which the quad lies, calculating the hitpoint and checking whether it's in the
quad by projecting onto the sides.

Reviewers: brecht, sergey, dingto

Reviewed By: dingto

Differential Revision: https://developer.blender.org/D2045

intern/cycles/kernel/kernel_light.h
intern/cycles/util/util_math.h

index 675eacfc5eeb3e068ef1a0d31200a3577e1be0ef..736a884f8192a6c0833e3cb6e2e45f90e9d7d9ca 100644 (file)
@@ -291,24 +291,13 @@ ccl_device float background_portal_pdf(KernelGlobals *kg,
                }
                num_possible++;
 
-               float t = -(dot(P, dir) - dot(lightpos, dir)) / dot(direction, dir);
-               if(t <= 1e-4f) {
-                       /* Either behind the portal or too close. */
-                       continue;
-               }
-
                float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
                float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
 
                float3 axisu = make_float3(data1.y, data1.z, data1.w);
                float3 axisv = make_float3(data2.y, data2.z, data2.w);
 
-               float3 hit = P + t*direction;
-               float3 inplane = hit - lightpos;
-               /* Skip if the the ray doesn't pass through portal. */
-               if(fabsf(dot(inplane, axisu) / dot(axisu, axisu)) > 0.5f)
-                       continue;
-               if(fabsf(dot(inplane, axisv) / dot(axisv, axisv)) > 0.5f)
+               if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL))
                        continue;
 
                portal_pdf += area_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false);
@@ -729,8 +718,8 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
 
                float3 light_P = make_float3(data0.y, data0.z, data0.w);
 
-               if(!ray_quad_intersect(P, D, t,
-                                      light_P, axisu, axisv, &ls->P, &ls->t))
+               if(!ray_quad_intersect(P, D, 0.0f, t,
+                                      light_P, axisu, axisv, Ng, &ls->P, &ls->t))
                {
                        return false;
                }
index 32924f9a8c2682d139993555206c0e20cf240ffa..53944ec1cc4cc0455a38e95b0af7cf0f4fcb3bf4 100644 (file)
@@ -1479,21 +1479,25 @@ ccl_device bool ray_triangle_intersect_uv(
        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,
+ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_mint, float ray_maxt,
+                                   float3 quad_P, float3 quad_u, float3 quad_v, float3 quad_n,
                                    float3 *isect_P, float *isect_t)
 {
-       float3 v0 = quad_P - quad_u*0.5f - quad_v*0.5f;
-       float3 v1 = quad_P + quad_u*0.5f - quad_v*0.5f;
-       float3 v2 = quad_P + quad_u*0.5f + quad_v*0.5f;
-       float3 v3 = quad_P - quad_u*0.5f + quad_v*0.5f;
+       float t = -(dot(ray_P, quad_n) - dot(quad_P, quad_n)) / dot(ray_D, quad_n);
+       if(t < ray_mint || t > ray_maxt)
+               return false;
 
-       if(ray_triangle_intersect(ray_P, ray_D, ray_t, v0, v1, v2, isect_P, isect_t))
-               return true;
-       else if(ray_triangle_intersect(ray_P, ray_D, ray_t, v0, v2, v3, isect_P, isect_t))
-               return true;
-       
-       return false;
+       float3 hit = ray_P + t*ray_D;
+       float3 inplane = hit - quad_P;
+       if(fabsf(dot(inplane, quad_u) / dot(quad_u, quad_u)) > 0.5f)
+               return false;
+       if(fabsf(dot(inplane, quad_v) / dot(quad_v, quad_v)) > 0.5f)
+               return false;
+
+       if(isect_P) *isect_P = hit;
+       if(isect_t) *isect_t = t;
+
+       return true;
 }
 
 /* projections */