Skip to content
Snippets Groups Projects
Commit b4411a7d authored by Yoel's avatar Yoel
Browse files

Refactor of shapes with light_pdf, light_emission

parent bf501248
No related branches found
No related tags found
No related merge requests found
......@@ -36,8 +36,11 @@ std::optional<cam::Hit> CirclePlane::intersect(const cam::Ray& r) const {
}
std::pair<float, float> CirclePlane::texture_coordinates(
const util::Vec3& pos) const {
return std::pair<float, float>(
{pos.x() / radius + 0.5f, pos.z() / radius + 0.5f});
float x = pos.x() / radius;
float z = pos.z() / radius;
float r = std::sqrt(x * x + z * z);
float theta = std::atan2(z, x);
return std::pair<float, float>(r * r, (float)(theta / (2.0f * M_PI)));
}
util::AxisAlignedBoundingBox CirclePlane::bounds() const {
......@@ -55,18 +58,27 @@ util::SurfacePoint CirclePlane::sampleLight(const cam::Hit& h) const {
texture_coordinates(pos), material);
// The sampled point will be in local coordinates.
}
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).
// This is wrong. We just need the normal pdf, per area, as we do not sample
// with regard to a direction.
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 = 1 / area;
return emission / pdf;
/*std::pair<util::Vec3, float> 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).
// This is wrong. We just need the normal pdf, per area, as we do not sample
// with regard to a direction.
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 = 1 / area;
return {emission, pdf};
}*/
// TODO
util::Vec3 CirclePlane::lightEmission(const util::SurfacePoint& p) const {
return util::Vec3(0);
}
// TODO
float CirclePlane::lightPdf(const util::SurfacePoint& p,
const util::Vec3& dl_out) const {
return 0;
}
} // namespace shapes
......@@ -14,8 +14,9 @@ class CirclePlane : public Light, public Shape {
util::AxisAlignedBoundingBox bounds() const override;
util::SurfacePoint sampleLight(const cam::Hit& h) const override;
util::Vec3 calculateLightEmission(const util::SurfacePoint& p,
const util::Vec3& d) const override;
util::Vec3 lightEmission(const util::SurfacePoint& p) const override;
float lightPdf(const util::SurfacePoint& p,
const util::Vec3& dl_out) const override;
private:
std::shared_ptr<material::Material> material;
......
......@@ -42,32 +42,51 @@ std::pair<float, float> RectanglePlane::texture_coordinates(
return std::pair<float, float>(
{pos.x() / width + 0.5f, pos.z() / depth + 0.5f});
}
util::Vec3 RectanglePlane::texture_coordinates(
std::pair<float, float> texel) const {
return {(texel.first - 0.5f) * width, 0, (texel.second - 0.5f) * depth};
}
util::AxisAlignedBoundingBox RectanglePlane::bounds() const {
return util::AxisAlignedBoundingBox(util::Vec3(-width / 2, 0, -depth / 2),
util::Vec3(width / 2, 0, depth / 2));
}
util::SurfacePoint RectanglePlane::sampleLight(const cam::Hit& h) const {
// X coord of the sampled point.
float x = util::disMinus1To1(util::gen) * width / 2;
// Z coord of the sampled point.
float z = util::disMinus1To1(util::gen) * depth / 2;
util::Vec3 pos(x, 0, z);
return util::SurfacePoint(pos, util::Vec3(0, 1, 0),
texture_coordinates(pos), material);
// The sampled point will be in local coordinates.
auto uv = material->sampleEmissionProfile();
util::Vec3 point = texture_coordinates(uv);
return util::SurfacePoint(point, util::Vec3(0, 1, 0), uv, material);
}
/*std::pair<util::Vec3, float> RectanglePlane::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).
// Update: This is wrong. We just need the normal pdf, per area, as we do
// not sample with regard to a direction.
// Update 2: This is not wrong actually!
auto emission = p.emission();
auto dot = std::max<float>(util::dot(p.normal(), d.normalize()), 0);
auto area = width * depth;
auto uv = p.texel();
float pdf = material->emission_pdf(uv.first, uv.second).value_or(1) / area;
pdf = pdf / (dot / d.length());
return {emission, pdf};
}*/
util::Vec3 RectanglePlane::lightEmission(const util::SurfacePoint& p) const {
return p.emission();
}
util::Vec3 RectanglePlane::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).
// This is wrong. We just need the normal pdf, per area, as we do not sample
// with regard to a direction.
auto emission = p.emission();
auto dot = std::max<float>(util::dot(p.normal(), d.normalize()), 0);
float RectanglePlane::lightPdf(const util::SurfacePoint& p,
const util::Vec3& dl_out) const {
auto dot = util::dot(p.normal(), dl_out.normalize());
if (twofaced)
dot = std::abs(dot);
else
dot = std::max<float>(dot, 0);
auto area = width * depth;
auto pdf = 1 / area;
return emission / pdf;
auto uv = p.texel();
float pdf = material->emission_pdf(uv.first, uv.second).value_or(1) / area;
pdf = pdf / (dot / dl_out.length());
return pdf;
}
} // namespace shapes
......@@ -11,11 +11,13 @@ class RectanglePlane : public Light, public Shape {
std::optional<cam::Hit> intersect(const cam::Ray& r) const override;
std::pair<float, float> texture_coordinates(
const util::Vec3& pos) const override;
util::Vec3 texture_coordinates(std::pair<float, float> texel) const;
util::AxisAlignedBoundingBox bounds() const override;
util::SurfacePoint sampleLight(const cam::Hit& h) const override;
util::Vec3 calculateLightEmission(const util::SurfacePoint& p,
const util::Vec3& d) const override;
util::Vec3 lightEmission(const util::SurfacePoint& p) const override;
float lightPdf(const util::SurfacePoint& p,
const util::Vec3& dl_out) const override;
private:
std::shared_ptr<material::Material> material;
......
......@@ -2,6 +2,8 @@
#include "Sphere.h"
#include <cassert>
#include "../tools/Random.h"
#include "math.h"
......@@ -43,39 +45,55 @@ std::optional<cam::Hit> Sphere::intersect(const cam::Ray& r) const {
}
std::pair<float, float> Sphere::texture_coordinates(
const util::Vec3& pos) const {
float theta = std::acos(pos.y() / radius);
float phi = M_PI + std::atan2(pos.x(), pos.z());
return std::pair<float, float>(
{(float)(phi / (2 * M_PI)), (float)(theta / M_PI)});
float theta = std::atan2(pos.x(), pos.z());
float phi = std::acos(pos.y() / radius);
return std::make_pair<float, float>((float)(theta / (2 * M_PI)),
(float)(phi / (M_PI)));
}
util::Vec3 Sphere::texture_coordinates(std::pair<float, float> texel) const {
float theta = texel.first * M_PI * 2;
float phi = texel.second * M_PI;
float z = radius * std::cos(theta) * std::sin(phi);
float x = radius * std::sin(theta) * std::sin(phi);
float y = radius * std::cos(phi);
return {x, y, z};
}
util::AxisAlignedBoundingBox Sphere::bounds() const {
return util::AxisAlignedBoundingBox(util::Vec3(-radius),
util::Vec3(radius));
}
util::SurfacePoint Sphere::sampleLight(const cam::Hit& h) const {
// Theta of sampled point.
float theta = 2 * M_PI * util::dis0to1(util::gen);
// Phi of the sampled point.
float phi = std::acos((2 * util::dis0to1(util::gen) - 1));
// Convert from polar coordinates to cartesian.
util::Vec3 point(radius * std::cos(theta) * std::sin(phi),
radius * std::sin(theta) * std::sin(phi),
radius * std::cos(phi));
return util::SurfacePoint(point, point.normalize(),
texture_coordinates(point), material);
auto uv = material->sampleEmissionProfile();
util::Vec3 point = texture_coordinates(uv);
return util::SurfacePoint(point, point.normalize(), uv, material);
}
util::Vec3 Sphere::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).
// This is wrong. We just need the normal pdf, per area, as we do not sample
// with regard to a direction.
auto emission = p.emission();
auto dot = std::max<float>(util::dot(p.normal(), d.normalize()), 0);
auto area = 4 * M_PI * std::pow(radius, 2);
auto pdf = 1 / area;
return emission / pdf;
/*std::pair<util::Vec3, float> Sphere::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).
// This is wrong. We just need the normal pdf, per area, as we do not sample
// with regard to a direction.
auto emission = p.emission();
// auto dot = std::max<float>(util::dot(p.normal(), d.normalize()), 0);
auto area = 4 * M_PI * std::pow(radius, 2);
auto uv = p.texel();
float pdf = material->emission_pdf(uv.first, uv.second).value_or(1) / area;
return {emission, pdf};
}*/
util::Vec3 Sphere::lightEmission(const util::SurfacePoint& p) const {
return p.emission();
}
float Sphere::lightPdf(const util::SurfacePoint& p,
const util::Vec3& dl_out) const {
auto dot = std::max<float>(util::dot(p.normal(), dl_out.normalize()), 0);
auto uv = p.texel();
auto phi = uv.second * M_PI;
float pdf = material->emission_pdf(uv.first, uv.second).value_or(1);
pdf = pdf / (dot / dl_out.length());
return pdf;
}
} // namespace shapes
......@@ -10,12 +10,14 @@ class Sphere : public Light, public Shape {
std::optional<cam::Hit> intersect(const cam::Ray& r) const override;
std::pair<float, float> texture_coordinates(
const util::Vec3& pos) const override;
util::Vec3 texture_coordinates(std::pair<float, float> texel) const;
util::AxisAlignedBoundingBox bounds() const override;
util::SurfacePoint sampleLight(const cam::Hit& h) const override;
util::Vec3 calculateLightEmission(const util::SurfacePoint& p,
const util::Vec3& d) const override;
util::Vec3 lightEmission(const util::SurfacePoint& p) const override;
virtual float lightPdf(const util::SurfacePoint& p,
const util::Vec3& dl_out) const override;
private:
protected:
std::shared_ptr<material::Material> material;
const float radius;
};
......
......@@ -69,17 +69,26 @@ util::SurfacePoint Triangle::sampleLight(const cam::Hit& h) const {
// The sampled point will be in local coordinates.
}
// TODO
util::Vec3 Triangle::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 = 1;
auto pdf = std::pow(d.length(), 2) / (dot * area);
return emission / pdf;
/*std::pair<util::Vec3, float> Triangle::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 = 1;
auto pdf = std::pow(d.length(), 2) / (dot * area);
return {emission, pdf};
}*/
// TODO
util::Vec3 Triangle::lightEmission(const util::SurfacePoint& p) const {
return util::Vec3(0);
}
// TODO
float Triangle::lightPdf(const util::SurfacePoint& p,
const util::Vec3& dl_out) const {
return 0;
}
void Triangle::recalculateBB() {
......
......@@ -20,8 +20,9 @@ class Triangle : public Light, public Shape {
void recalculateBB();
util::SurfacePoint sampleLight(const cam::Hit& h) const;
util::Vec3 calculateLightEmission(const util::SurfacePoint& p,
const util::Vec3& d) const;
util::Vec3 lightEmission(const util::SurfacePoint& p) const override;
float lightPdf(const util::SurfacePoint& p,
const util::Vec3& dl_out) const override;
const std::shared_ptr<material::Material>& material;
......
......@@ -91,9 +91,18 @@ util::SurfacePoint TriangleMesh::sampleLight(const cam::Hit& h) const {
return util::SurfacePoint(util::Vec3({}), 0, {}, material);
}
// TODO
util::Vec3 TriangleMesh::calculateLightEmission(const util::SurfacePoint& p,
const util::Vec3& d) const {
return util::Vec3();
/*std::pair<util::Vec3, float> TriangleMesh::calculateLightEmission(
const util::SurfacePoint& p, const util::Vec3& d) const {
return {util::Vec3(), 0.0f};
}*/
// TODO
util::Vec3 TriangleMesh::lightEmission(const util::SurfacePoint& p) const {
return util::Vec3(0);
}
// TODO
float TriangleMesh::lightPdf(const util::SurfacePoint& p,
const util::Vec3& dl_out) const {
return 0;
}
util::AxisAlignedBoundingBox TriangleMesh::initBB() {
util::AxisAlignedBoundingBox init = triangles[0].bounds();
......
......@@ -28,8 +28,9 @@ class TriangleMesh : public Light, public Shape {
util::AxisAlignedBoundingBox bounds() const override;
util::SurfacePoint sampleLight(const cam::Hit& h) const override;
util::Vec3 calculateLightEmission(const util::SurfacePoint& p,
const util::Vec3& d) const override;
util::Vec3 lightEmission(const util::SurfacePoint& p) const override;
float lightPdf(const util::SurfacePoint& p,
const util::Vec3& dl_out) const override;
public:
std::shared_ptr<material::Material> material;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment