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::specular() const { return cs; }
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) {
this->transform = transform;
@ -31,6 +34,10 @@ Optional<float> Sphere::intersect(const Ray &r) const {
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,
const Vector3f &c, const Vector3f &d, const Vector3f &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 {
Vector3f normal = (p2 - p1).cross(p3 - p1).normalized();
float denom = normal.dot(r.getDirection());
if (abs(denom) < 1e-6f)
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)
: Optional<float>::nullopt;
}
Vector3f Rectangle::getNormal(const Vector3f &p) const { return normal; }

View file

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

View file

@ -5,3 +5,11 @@ bool HitRecord::operator<(const HitRecord &other) const {
}
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_
#include "Geometry.h"
#include "Ray.h"
#include <Eigen/Core>
using Eigen::Vector3f;
class HitRecord {
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;
private:
float t;
Ray r;
Vector3f n;
Geometry *g;
public:
Geometry *geometry() const;
Vector3f getPoint() const;
Vector3f normal() const;
void calcNormal();
};
#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 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_
#define LIGHT_H_
#include "HitRecord.h"
#include <Eigen/Core>
#include <vector>
using Eigen::Matrix;
using Eigen::Matrix4f;
using Eigen::Vector3f;
using std::vector;
// Abstract base class for Lights
class Light {
@ -13,7 +16,8 @@ public:
enum class Type { Point, Area };
virtual ~Light() = default;
virtual void illumination() const = 0;
virtual Vector3f illumination(const HitRecord &,
const vector<Geometry *> &) const = 0;
protected:
Light(Type type, const Vector3f &id, const Vector3f &is)
@ -38,7 +42,8 @@ public:
PointLight(const Vector3f &id, const Vector3f &is, Vector3f &center)
: Light(Type::Point, id, is), center(center) {}
virtual void illumination() const override;
virtual Vector3f illumination(const HitRecord &,
const vector<Geometry *> &) const override;
private:
Vector3f center;
@ -50,7 +55,8 @@ public:
const Vector3f &p2, const Vector3f &p3, const Vector3f &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:
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);
}
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) {
int width = scene->getWidth();
int height = scene->getHeight();
float fov = scene->getFov();
Vector3f cameraPos = scene->getCenter();
Vector3f lookAt = scene->getLookAt();
Vector3f up = scene->getUpVector();
float vpHeight = 2 * tan(fov / 180 * M_PI / 2) * lookAt.norm();
float vpHeight = 2 * tan(scene->getFov() / 180 * M_PI / 2) * lookAt.norm();
float vpWidth = vpHeight * width / height;
Vector3f vpU = Vector3f(vpWidth, 0, 0);
Vector3f vpV = Vector3f(0, -vpHeight, 0);
@ -54,15 +65,13 @@ void RayTracer::render(Scene *scene) {
for (auto g : geometries) {
Optional<float> t = g->intersect(ray);
if (t.hasValue())
records.push(HitRecord(t.value(), g));
records.push(HitRecord(t.value(), ray, g));
}
if (!records.empty()) {
HitRecord hit = records.top();
Vector3f diffuse = hit.geometry()->diffuse();
buffer->r(y * width + x, diffuse.x());
buffer->g(y * width + x, diffuse.y());
buffer->b(y * width + x, diffuse.z());
hit.calcNormal();
calculateColor(hit, buffer, y * width + x);
}
}

View file

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