I have been working on a path tracer running with OptiX for several years now in various contexts. Until yesterday I still worked with OptiX 4, but really wanted to try out that sweet denoiser, so I upgraded to 5.1.1. It now happened that the area light sampling somehow broke. Environment maps are still sampled alright, but spherical area lights don’t work anymore. In fact, the associated closestHitProgram is not even called anymore.
This is how I set the programs for the light source material:
__sm_lightMaterial->setClosestHitProgram ( ENUM_RAYTYPE_LIGHT, __sm_lightShader );
__sm_lightMaterial->setAnyHitProgram ( ENUM_RAYTYPE_OCCLUSION, __sm_lightShaderOcc );
The first program is what this is about. A ray of type ENUM_RAYTYPE_LIGHT is traced towards the light source when explicitly sampling for light contribution. This should in turn result in a call of the below closestHit program.
RT_PROGRAM void light_shader() {
float3 normalizedNormal = optix::normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal));
if (optix::dot(normalizedNormal, ray.direction) > 0) {
normalizedNormal = -normalizedNormal;
}
prd.hitDist = t_hit;
if (identifier == prd.queryIdentifier) {
prd.emittance = fmaxf(optix::dot(-ray.direction, normalizedNormal), 0.0f);
prd.occluded = false;
} else {
prd.emittance = 0.0f;
prd.occluded = true;
}
}
However, this works up to OptiX 5.0.1 and stops with 5.1.1, where the call is completely missing, all without changing anything apart from the OptiX version. The second program mentioned above, which is simply used when I need to know whether there is any occluder and is used in environment map sampling, works without any issues.
This is the code where the actual ray is traced:
prd.throughput = make_float3 ( 1.0f );
prd.emittance = 0.0f;
prd.queryIdentifier = sphereLights[p_lsIndex].getIdentifier();
prd.hitDist = FLT_MAX;
prd.occluded = false;
prd.seed = prd_pt.seed;
optix::Ray shadowRay = optix::make_Ray ( getAdjustedRayStart ( p_hitpoint, p_normal_geometric, scene_epsilon ), lightDir, shadow_ray_type, scene_epsilon, maxLightDist );
rtTrace ( top_object, shadowRay, prd );
++prd_pt.numCastRays;
if ( !prd.occluded ) {
float weight = prob2 > 0.f ? balanceHeuristic ( 1, lightPdf, 1, brdfPdf ) : 1.f;
float geometryTerm = fminf ( ( prd.emittance * fmaxf ( 0.f, optix::dot ( lightDir, p_normal ) ) / ( prd.hitDist * prd.hitDist ) ), 1.f );
optix::float3 E = ( lightEmission * geometryTerm * brdfValue * weight ) / lightPdf;
return ( E * prd.throughput );
}
Here, geometryTerm becomes 0 because prd.emittance is zero.
I’d be very grateful for any hints on this; if you need more information, just let me know. As of now I still need to test this with a minimal scene like a plane with a light source.