it's me again! :D
I have finally implemented area lights, but without modifying the emission value of the material, this is what it looks like with indirect light only, this is what it looks like with direct only and this is both direct+indirect!
Clearly there is something wrong going on with the direct light sampling.
This is the function for one light:
float pdf, dist;
glm::vec3 wi;
Ray visibilityRay;
auto li = light->li(sampler, hr, visibilityRay, wi, pdf, dist);
if (scene->visibilityCheck(visibilityRay, EPS, dist - EPS, light))
{
return glm::dot(hr.normal, wi) * material->brdf(hr, wi) * li / pdf;
}
return BLACK;
In case of the area light, li is the following:
glm::vec3 samplePoint, sampleNormal;
shape->sample(sampler, samplePoint, sampleNormal, pdf);
wi = (samplePoint - hr.point);
dist = glm::length(wi);
wi = glm::normalize(wi);
vRay.origin = hr.point + EPS * wi;
vRay.direction = wi;
float cosT = glm::dot(sampleNormal, -wi);
auto solidAngle = (cosT * this->area()) / (dist * dist);
if(cosT > 0.0f) {
return this->color * solidAngle;
} else {
return BLACK;
}
And I think the code to sample the spheres is correct
glm::vec3 sampleUniformSphere(std::shared_ptr<Sampler> &sampler)
{
float z = 1 - 2 * sampler->getSample();
float r = sqrt(std::max(0.0f, 1.0f - z * z));
float phi = 2 * PI * sampler->getSample();
return glm::vec3(
r * cos(phi),
r * sin(phi),
z);
}
void Sphere::sample(std::shared_ptr<Sampler> &sampler, glm::vec3 &point, glm::vec3 &normal, float &pdf) const
{
glm::vec3 local = sampleUniformSphere(sampler);
normal = glm::normalize(local);
point = m_obj2World.transformPoint(radius * local);
pdf = 1.0f / area();
}
It looks like either the solid angle or the distance attenuation aren't working correctly. This is a Mitsuba3 render with roughly the same values.
Thanks!