Cycles: Use faster ray-quad-intersection test

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
This commit is contained in:
Lukas Stockner 2016-06-06 23:38:28 +02:00
parent ac7feaed3d
commit 7a5a02509b
2 changed files with 19 additions and 26 deletions

@ -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;
}

@ -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 */