Path Renderer::createPath(const Ray& primaryRay, const Intersectable &scene, const Sample pathSamples[], cv::Vec3f alpha, int pathLength, float russianRoulettePdf, int russianRouletteStartIndex) { Path result; HitRecord hit = scene.intersect(primaryRay); for(int i = 0; i < pathLength; i++) { if(!hit.intersects()) return result; float pdf; cv::Vec3f brdf; QVector3D outDirection = hit.getMaterial().outDirection(hit, pathSamples[i], pdf, brdf); if(hit.getMaterial().emitsLight()) { result.alphaValues.push_back(alpha); result.hitRecords.push_back(hit); return result; } else if(hit.getMaterial().isSpecular()) { //Try not to terminate on refractive vertices if(i == pathLength - 1 && pathLength < MAX_DEPTH) pathLength++; } else { result.alphaValues.push_back(alpha); result.hitRecords.push_back(hit); if(pdf == 0 || alpha == cv::Vec3f()) return result; float cos = fabs(QVector3D::dotProduct(outDirection.normalized(), hit.getSurfaceNormal().normalized())); assert(cos >= 0 && !isnan(pdf)); assert(pdf > 0 && !isnan(pdf)); alpha = alpha.mul(brdf) * (cos / pdf); if(i > russianRouletteStartIndex) alpha *= (1 / russianRoulettePdf); } hit = scene.intersect(Ray(hit.getIntersectingPoint(), outDirection)); } return result; }
cv::Vec3f AreaLight::getIntensity(const HitRecord & hit, QVector3D &direction, const Intersectable &scene, const Sample &sample) const { QVector3D at = hit.getIntersectingPoint().toVector3DAffine(); QPointF p = sample.getSample(); QVector3D lightLocation = getLocation(p); direction = at - lightLocation; HitRecord shadowHit = scene.intersect(Ray(at, -direction.normalized(), EPSILON, direction.length() - EPSILON)); if(shadowHit.intersects() && &shadowHit.getMaterial() != this) { return cv::Vec3f(); } else { return getIntensity(direction); } }
cv::Vec3f AreaLight::emission(const HitRecord & hit) const { assert(&hit.getMaterial() == this); return getIntensity(-hit.getRay().getDirection()); }