Skip to content
Snippets Groups Projects
CirclePlane.cpp 2.05 KiB
Newer Older
Yoel's avatar
Yoel committed
#define _USE_MATH_DEFINES

Postea's avatar
Postea committed
#include "CirclePlane.h"

Yoel's avatar
Yoel committed
#include "../tools/Random.h"
#include "math.h"

namespace shapes {
CirclePlane::CirclePlane(float radius, bool twofaced,
Yoel's avatar
Yoel committed
                         const std::shared_ptr<material::Material>& material)
    : radius(radius), twofaced(twofaced), material(material) {
Yoel's avatar
Yoel committed
std::optional<cam::Hit> CirclePlane::intersect(const cam::Ray& r) const {
Yoel's avatar
Yoel committed
	util::Vec3 n(0, 1, 0);
	util::Vec3 x0 = r.x0;
	util::Vec3 d = r.d;
Postea's avatar
Postea committed

Yoel's avatar
Yoel committed
	float a = util::dot(d, n);
	if (a == 0) {
Yoel's avatar
Yoel committed
		return std::nullopt;
	} else if (a > 0) {
		if (twofaced)
			n = -n;
		else
Yoel's avatar
Yoel committed
			return std::nullopt;
	}
	float t = -x0[1] / d[1];
	util::Vec3 t_hitpoint = r(t);

	if (r.in_range(t) && t_hitpoint.length() <= radius) {
		return std::optional<cam::Hit>({t_hitpoint, n, t, material});
Yoel's avatar
Yoel committed
	}
Postea's avatar
Postea committed
}
util::AxisAlignedBoundingBox CirclePlane::bounds() const {
	return util::AxisAlignedBoundingBox(util::Vec3(-radius, 0, -radius),
	                                    util::Vec3(radius, 0, radius));
}
Yoel's avatar
Yoel committed
util::SurfacePoint CirclePlane::sampleLight() const {
	// Radius of the sampled point.
	float r = std::sqrt(util::dis0to1(util::gen)) * radius;
	// Degreee of the sampled point.
	float theta = 2 * M_PI * util::dis0to1(util::gen);
	// Polar coordinates have to be converted to cartesian.
Yoel's avatar
Yoel committed
	return util::SurfacePoint(
	    util::Vec3(r * std::cos(theta), 0, r * std::sin(theta)),
	    util::Vec3(0, 1, 0), material);
	// The sampled point will be in local coordinates.
Yoel's avatar
Yoel committed
}
util::Vec3 CirclePlane::calculateLightEmission(const util::SurfacePoint& p,
                                               const util::Vec3& d) const {
	// Basically this is just the emission at a surface point. And the pdf dimms
	// the light in regard to the angle.
	// Uniform pdf of shape is 1/area, converting to pdf over solid angle is
	// pdf/(dot/length^2).
	auto emission = p.emission();
	auto dot = std::max<float>(util::dot(p.normal(), d.normalize()), 0);
	auto area = M_PI * std::pow(radius, 2);
	auto pdf = std::pow(d.length(), 2) / (dot * area);
	return emission / pdf;
Yoel's avatar
Yoel committed
}
Yoel's avatar
Yoel committed
}  // namespace shapes