work on direct illumination

This commit is contained in:
Shuo Feng 2024-02-29 00:15:00 -05:00
parent 184812c533
commit bb8819013c
Signed by: sfeng
GPG key ID: 1E83AE6CD1C037B1
8 changed files with 80 additions and 18 deletions

View file

@ -6,6 +6,9 @@
Vector3f Geometry::diffuse() const { return cd; } Vector3f Geometry::diffuse() const { return cd; }
Vector3f Geometry::specular() const { return cs; } Vector3f Geometry::specular() const { return cs; }
Vector3f Geometry::ambient() const { return ca; } Vector3f Geometry::ambient() const { return ca; }
float Geometry::coefDiffuse() const { return kd; }
float Geometry::coefSpecular() const { return ks; }
float Geometry::coefAmbient() const { return ka; }
void Geometry::setTransform(const Matrix4f &transform) { void Geometry::setTransform(const Matrix4f &transform) {
this->transform = transform; this->transform = transform;
@ -31,6 +34,10 @@ Optional<float> Sphere::intersect(const Ray &r) const {
return Optional<float>::nullopt; return Optional<float>::nullopt;
} }
Vector3f Sphere::getNormal(const Vector3f &p) const {
return (p - center).normalized();
}
bool isInRectangle(const Vector3f &p, const Vector3f &a, const Vector3f &b, bool isInRectangle(const Vector3f &p, const Vector3f &a, const Vector3f &b,
const Vector3f &c, const Vector3f &d, const Vector3f &n) { const Vector3f &c, const Vector3f &d, const Vector3f &n) {
float s1 = (b - a).cross(p - a).dot(n); float s1 = (b - a).cross(p - a).dot(n);
@ -43,8 +50,6 @@ bool isInRectangle(const Vector3f &p, const Vector3f &a, const Vector3f &b,
} }
Optional<float> Rectangle::intersect(const Ray &r) const { Optional<float> Rectangle::intersect(const Ray &r) const {
Vector3f normal = (p2 - p1).cross(p3 - p1).normalized();
float denom = normal.dot(r.getDirection()); float denom = normal.dot(r.getDirection());
if (abs(denom) < 1e-6f) if (abs(denom) < 1e-6f)
return Optional<float>::nullopt; return Optional<float>::nullopt;
@ -58,3 +63,5 @@ Optional<float> Rectangle::intersect(const Ray &r) const {
return isInRectangle(p, p1, p2, p3, p4, normal) ? Optional<float>(t) return isInRectangle(p, p1, p2, p3, p4, normal) ? Optional<float>(t)
: Optional<float>::nullopt; : Optional<float>::nullopt;
} }
Vector3f Rectangle::getNormal(const Vector3f &p) const { return normal; }

View file

@ -5,6 +5,7 @@
#include "Ray.h" #include "Ray.h"
#include <Eigen/Core> #include <Eigen/Core>
#include <Eigen/Dense>
using Eigen::Matrix; using Eigen::Matrix;
using Eigen::Matrix4f; using Eigen::Matrix4f;
@ -18,6 +19,7 @@ public:
virtual ~Geometry() = default; virtual ~Geometry() = default;
virtual Optional<float> intersect(const Ray &) const = 0; virtual Optional<float> intersect(const Ray &) const = 0;
virtual Vector3f getNormal(const Vector3f &) const = 0;
protected: protected:
Geometry(Type type, float ka, float kd, float ks, const Vector3f &ca, Geometry(Type type, float ka, float kd, float ks, const Vector3f &ca,
@ -34,6 +36,9 @@ public:
Vector3f diffuse() const; Vector3f diffuse() const;
Vector3f specular() const; Vector3f specular() const;
Vector3f ambient() const; Vector3f ambient() const;
float coefDiffuse() const;
float coefSpecular() const;
float coefAmbient() const;
void setTransform(const Matrix4f &); void setTransform(const Matrix4f &);
}; };
@ -45,6 +50,7 @@ public:
center(center) {} center(center) {}
Optional<float> intersect(const Ray &) const override; Optional<float> intersect(const Ray &) const override;
Vector3f getNormal(const Vector3f &) const override;
private: private:
float radius; float radius;
@ -57,12 +63,14 @@ public:
const Vector3f &cs, float pc, const Vector3f &p1, const Vector3f &cs, float pc, const Vector3f &p1,
const Vector3f &p2, const Vector3f &p3, const Vector3f &p4) const Vector3f &p2, const Vector3f &p3, const Vector3f &p4)
: Geometry(Type::RECTANGLE, ka, kd, ks, ca, cd, cs, pc), p1(p1), p2(p2), : Geometry(Type::RECTANGLE, ka, kd, ks, ca, cd, cs, pc), p1(p1), p2(p2),
p3(p3), p4(p4) {} p3(p3), p4(p4), normal((p2 - p1).cross(p3 - p1).normalized()) {}
Optional<float> intersect(const Ray &) const override; Optional<float> intersect(const Ray &) const override;
Vector3f getNormal(const Vector3f &) const override;
private: private:
Vector3f p1, p2, p3, p4; Vector3f p1, p2, p3, p4;
Vector3f normal;
}; };
#endif // !GEOMETRY_H_ #endif // !GEOMETRY_H_

View file

@ -5,3 +5,11 @@ bool HitRecord::operator<(const HitRecord &other) const {
} }
Geometry *HitRecord::geometry() const { return g; } Geometry *HitRecord::geometry() const { return g; }
Vector3f HitRecord::getPoint() const {
return r.getOrigin() + t * r.getDirection();
}
Vector3f HitRecord::normal() const { return n; }
void HitRecord::calcNormal() { n = g->getNormal(getPoint()); }

View file

@ -2,18 +2,27 @@
#define HITRECORD_H_ #define HITRECORD_H_
#include "Geometry.h" #include "Geometry.h"
#include "Ray.h"
#include <Eigen/Core>
using Eigen::Vector3f;
class HitRecord { class HitRecord {
public: public:
HitRecord(float t, Geometry *g) : t(t), g(g) {} HitRecord(float t, const Ray &r, Geometry *g) : t(t), r(r), g(g) {}
bool operator<(const HitRecord &) const; bool operator<(const HitRecord &) const;
private: private:
float t; float t;
Ray r;
Vector3f n;
Geometry *g; Geometry *g;
public: public:
Geometry *geometry() const; Geometry *geometry() const;
Vector3f getPoint() const;
Vector3f normal() const;
void calcNormal();
}; };
#endif // !HITRECORD_H_ #endif // !HITRECORD_H_

View file

@ -8,6 +8,21 @@ void Light::setGridSize(unsigned int gridSize) { this->gridSize = gridSize; }
void Light::setUseCenter(bool useCenter) { this->useCenter = useCenter; } void Light::setUseCenter(bool useCenter) { this->useCenter = useCenter; }
void PointLight::illumination() const {} Vector3f PointLight::illumination(const HitRecord &hit,
const vector<Geometry *> &geometries) const {
Vector3f shadingPoint = hit.getPoint();
Vector3f rayDirection = (center - shadingPoint).normalized();
Geometry *geometry = hit.geometry();
Ray shadowRay(shadingPoint, rayDirection);
void AreaLight::illumination() const {} for (auto g : geometries)
if (g != geometry && g->intersect(shadowRay).hasValue())
return Vector3f::Zero();
return Vector3f::Zero();
}
Vector3f AreaLight::illumination(const HitRecord &hit,
const vector<Geometry *> &geometries) const {
return Vector3f::Zero();
}

View file

@ -1,11 +1,14 @@
#ifndef LIGHT_H_ #ifndef LIGHT_H_
#define LIGHT_H_ #define LIGHT_H_
#include "HitRecord.h"
#include <Eigen/Core> #include <Eigen/Core>
#include <vector>
using Eigen::Matrix; using Eigen::Matrix;
using Eigen::Matrix4f; using Eigen::Matrix4f;
using Eigen::Vector3f; using Eigen::Vector3f;
using std::vector;
// Abstract base class for Lights // Abstract base class for Lights
class Light { class Light {
@ -13,7 +16,8 @@ public:
enum class Type { Point, Area }; enum class Type { Point, Area };
virtual ~Light() = default; virtual ~Light() = default;
virtual void illumination() const = 0; virtual Vector3f illumination(const HitRecord &,
const vector<Geometry *> &) const = 0;
protected: protected:
Light(Type type, const Vector3f &id, const Vector3f &is) Light(Type type, const Vector3f &id, const Vector3f &is)
@ -38,7 +42,8 @@ public:
PointLight(const Vector3f &id, const Vector3f &is, Vector3f &center) PointLight(const Vector3f &id, const Vector3f &is, Vector3f &center)
: Light(Type::Point, id, is), center(center) {} : Light(Type::Point, id, is), center(center) {}
virtual void illumination() const override; virtual Vector3f illumination(const HitRecord &,
const vector<Geometry *> &) const override;
private: private:
Vector3f center; Vector3f center;
@ -50,7 +55,8 @@ public:
const Vector3f &p2, const Vector3f &p3, const Vector3f &p4) const Vector3f &p2, const Vector3f &p3, const Vector3f &p4)
: Light(Type::Area, id, is), p1(p1), p2(p2), p3(p3), p4(p4) {} : Light(Type::Area, id, is), p1(p1), p2(p2), p3(p3), p4(p4) {}
virtual void illumination() const override; virtual Vector3f illumination(const HitRecord &,
const vector<Geometry *> &) const override;
private: private:
Vector3f p1, p2, p3, p4; Vector3f p1, p2, p3, p4;

View file

@ -27,14 +27,25 @@ Ray getRay(int x, int y, const Vector3f &camPos, const Vector3f &pxUpperLeft,
return Ray(camPos, pxUpperLeft + x * du + y * dv - camPos); return Ray(camPos, pxUpperLeft + x * du + y * dv - camPos);
} }
void RayTracer::calculateColor(const HitRecord &hit, Output *buffer, int i) {
buffer->r(i, 0);
buffer->g(i, 0);
buffer->b(i, 0);
for (auto light : lights) {
Vector3f contribution = light->illumination(hit, geometries);
buffer->r(i, buffer->r(i) + contribution.x());
buffer->g(i, buffer->g(i) + contribution.y());
buffer->b(i, buffer->b(i) + contribution.z());
}
}
void RayTracer::render(Scene *scene) { void RayTracer::render(Scene *scene) {
int width = scene->getWidth(); int width = scene->getWidth();
int height = scene->getHeight(); int height = scene->getHeight();
float fov = scene->getFov();
Vector3f cameraPos = scene->getCenter(); Vector3f cameraPos = scene->getCenter();
Vector3f lookAt = scene->getLookAt(); Vector3f lookAt = scene->getLookAt();
Vector3f up = scene->getUpVector(); float vpHeight = 2 * tan(scene->getFov() / 180 * M_PI / 2) * lookAt.norm();
float vpHeight = 2 * tan(fov / 180 * M_PI / 2) * lookAt.norm();
float vpWidth = vpHeight * width / height; float vpWidth = vpHeight * width / height;
Vector3f vpU = Vector3f(vpWidth, 0, 0); Vector3f vpU = Vector3f(vpWidth, 0, 0);
Vector3f vpV = Vector3f(0, -vpHeight, 0); Vector3f vpV = Vector3f(0, -vpHeight, 0);
@ -54,15 +65,13 @@ void RayTracer::render(Scene *scene) {
for (auto g : geometries) { for (auto g : geometries) {
Optional<float> t = g->intersect(ray); Optional<float> t = g->intersect(ray);
if (t.hasValue()) if (t.hasValue())
records.push(HitRecord(t.value(), g)); records.push(HitRecord(t.value(), ray, g));
} }
if (!records.empty()) { if (!records.empty()) {
HitRecord hit = records.top(); HitRecord hit = records.top();
Vector3f diffuse = hit.geometry()->diffuse(); hit.calcNormal();
buffer->r(y * width + x, diffuse.x()); calculateColor(hit, buffer, y * width + x);
buffer->g(y * width + x, diffuse.y());
buffer->b(y * width + x, diffuse.z());
} }
} }

View file

@ -20,10 +20,10 @@ private:
std::vector<Scene *> scenes; std::vector<Scene *> scenes;
std::vector<Light *> lights; std::vector<Light *> lights;
std::vector<Geometry *> geometries; std::vector<Geometry *> geometries;
std::vector<Output *> outputs; std::vector<Output *> outputs;
void parse(); void parse();
void calculateColor(const HitRecord &, Output *, int);
void render(Scene *); void render(Scene *);
void output(); void output();
}; };