Light_SampleRes PointLight_sample(const Light* super, const DifferentialGeometry& dg, const Vec2f& s) { const PointLight* self = (PointLight*)super; Light_SampleRes res; // extant light vector from the hit point const Vec3fa dir = self->position - dg.P; const float dist2 = dot(dir, dir); const float invdist = rsqrt(dist2); // normalized light vector res.dir = dir * invdist; res.dist = dist2 * invdist; res.pdf = inf; // per default we always take this res // convert from power to radiance by attenuating by distance^2 res.weight = self->power * sqr(invdist); const float sinTheta = self->radius * invdist; if ((self->radius > 0.f) & (sinTheta > 0.005f)) { // res surface of sphere as seen by hit point -> cone of directions // for very small cones treat as point light, because float precision is not good enough if (sinTheta < 1.f) { const float cosTheta = sqrt(1.f - sinTheta * sinTheta); const Vec3fa localDir = uniformSampleCone(cosTheta, s); res.dir = frame(res.dir) * localDir; res.pdf = uniformSampleConePDF(cosTheta); const float c = localDir.z; res.dist = c*res.dist - sqrt(sqr(self->radius) - (1.f - c*c) * dist2); // TODO scale radiance by actual distance } else { // inside sphere const Vec3fa localDir = cosineSampleHemisphere(s); res.dir = frame(dg.Ns) * localDir; res.pdf = cosineSampleHemispherePDF(localDir); // TODO: res.weight = self->power * rcp(sqr(self->radius)); res.dist = self->radius; } } return res; }
Light_SampleRes DirectionalLight_sample(const Light* super, const DifferentialGeometry& dg, const Vec2f& s) { const DirectionalLight* self = (DirectionalLight*)super; Light_SampleRes res; res.dir = self->frame.vz; res.dist = inf; res.pdf = self->pdf; if (self->cosAngle < COS_ANGLE_MAX) res.dir = self->frame * uniformSampleCone(self->cosAngle, s); res.weight = self->radiance; // *pdf/pdf cancel return res; }
/*! Uniform sampling of spherical cone. Cone direction is provided as argument. */ inline direction_sample uniformSampleCone(real u, real v, real angle, const real3& N) { direction_sample s = uniformSampleCone(u, v, angle); return direction_sample(frameZ(N) * s.value(), s.density()); }