Merge pull request #8 from vonhyou/ray

Ray class and ray casting
This commit is contained in:
Shuo Feng 2024-02-21 01:35:05 -05:00 committed by GitHub
commit bcc65cb98e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 162 additions and 43 deletions

View file

@ -1,9 +1,43 @@
#include "Geometry.h"
#include <Eigen/Dense>
void Geometry::setTransform(const Matrix4f &transform) {
this->transform = transform;
}
bool Sphere::intersect() const { return false; }
bool Sphere::intersect(const Ray &r) const {
Vector3f originCenter = r.getOrigin() - center;
float a = r.getDirection().dot(r.getDirection());
float b = 2.0f * originCenter.dot(r.getDirection());
float c = originCenter.dot(originCenter) - radius * radius;
bool Rectangle::intersect() const { return false; }
return b * b - 4 * a * c >= 0;
}
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);
float s2 = (c - b).cross(p - b).dot(n);
float s3 = (d - c).cross(p - c).dot(n);
float s4 = (a - d).cross(p - d).dot(n);
return (s1 >= 0 && s2 >= 0 && s3 >= 0 && s4 >= 0) ||
(s1 <= 0 && s2 <= 0 && s3 <= 0 && s4 <= 0);
}
bool 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 false;
float t = -normal.dot(r.getOrigin() - p1) / denom;
if (t <= 0)
return false;
Vector3f p = r.getOrigin() + t * r.getDirection();
return isInRectangle(p, p1, p2, p3, p4, normal);
}

View file

@ -1,6 +1,8 @@
#ifndef GEOMETRY_H_
#define GEOMETRY_H_
#include "Ray.h"
#include <Eigen/Core>
using Eigen::Matrix;
@ -13,7 +15,7 @@ public:
enum class Type { SPHERE, RECTANGLE };
virtual ~Geometry() = default;
virtual bool intersect() const = 0;
virtual bool intersect(const Ray &) const = 0;
protected:
Geometry(Type type, float ka, float kd, float ks, const Vector3f &ca,
@ -37,7 +39,7 @@ public:
: Geometry(Type::SPHERE, ka, kd, ks, ca, cd, cs, pc), radius(radius),
center(center) {}
bool intersect() const override;
bool intersect(const Ray &) const override;
private:
float radius;
@ -47,14 +49,15 @@ private:
class Rectangle : public Geometry {
public:
Rectangle(float ka, float kd, float ks, const Vector3f &ca, const Vector3f cd,
const Vector3f &cs, float pc, const Matrix<float, 3, 4> &corners)
: Geometry(Type::RECTANGLE, ka, kd, ks, ca, cd, cs, pc),
corners(corners) {}
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) {}
bool intersect() const override;
bool intersect(const Ray &) const override;
private:
Matrix<float, 3, 4> corners;
Vector3f p1, p2, p3, p4;
};
#endif // !GEOMETRY_H_

View file

@ -46,14 +46,14 @@ private:
class AreaLight : public Light {
public:
AreaLight(const Vector3f &id, const Vector3f &is,
const Matrix<float, 3, 4> &corners)
: Light(Type::Area, id, is), corners(corners) {}
AreaLight(const Vector3f &id, const Vector3f &is, const Vector3f &p1,
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;
private:
Matrix<float, 3, 4> corners; // stores `p1`, `p2`, `p3` and `p4`
Vector3f p1, p2, p3, p4;
};
#endif // !LIGHT_H_

View file

@ -72,15 +72,6 @@ Geometry *Parser::getGeometry(const nlohmann::json &j) {
return g;
}
// helper function to get four corners of a rectangle
const Matrix<float, 3, 4> getCorners(const nlohmann::json &j) {
Matrix<float, 3, 4> corners;
for (int i = 0; i < 4; ++i) {
corners.col(i) = getVector3f(j["p" + std::to_string(i + 1)]);
}
return corners;
}
Sphere *Parser::getSphere(const nlohmann::json &j, float ka, float kd, float ks,
const Vector3f &ca, const Vector3f &cd,
const Vector3f &cs, float pc) {
@ -94,9 +85,12 @@ Rectangle *Parser::getRectangle(const nlohmann::json &j, float ka, float kd,
float ks, const Vector3f &ca,
const Vector3f &cd, const Vector3f &cs,
float pc) {
Matrix<float, 3, 4> corners = getCorners(j);
Vector3f p1 = getVector3f(j["p1"]);
Vector3f p2 = getVector3f(j["p2"]);
Vector3f p3 = getVector3f(j["p3"]);
Vector3f p4 = getVector3f(j["p4"]);
return new Rectangle(ka, kd, ks, ca, cd, cs, pc, corners);
return new Rectangle(ka, kd, ks, ca, cd, cs, pc, p1, p2, p3, p4);
}
Light *Parser::getLight(const nlohmann::json &j) {
@ -121,9 +115,12 @@ Light *Parser::getLight(const nlohmann::json &j) {
AreaLight *Parser::getAreaLight(const nlohmann::json &j, const Vector3f &id,
const Vector3f &is) {
Matrix<float, 3, 4> corners = getCorners(j);
return new AreaLight(id, is, corners);
Vector3f p1 = getVector3f(j["p1"]);
Vector3f p2 = getVector3f(j["p2"]);
Vector3f p3 = getVector3f(j["p3"]);
Vector3f p4 = getVector3f(j["p4"]);
return new AreaLight(id, is, p1, p2, p3, p4);
}
PointLight *Parser::getPointLight(const nlohmann::json &j, const Vector3f &id,

5
src/Ray.cc Normal file
View file

@ -0,0 +1,5 @@
#include "Ray.h"
Vector3f Ray::getOrigin() const { return origin; }
Vector3f Ray::getDirection() const { return direction; }

21
src/Ray.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef RAY_H_
#define RAY_H_
#include <Eigen/Core>
using Eigen::Vector3f;
class Ray {
public:
Ray(const Vector3f &o, const Vector3f &d) : origin(o), direction(d) {}
private:
Vector3f origin;
Vector3f direction;
public:
Vector3f getOrigin() const;
Vector3f getDirection() const;
};
#endif // !RAY_H_

View file

@ -1,10 +1,10 @@
#include "RayTracer.h"
#include "../external/simpleppm.h"
#include "Parser.h"
#include "Ray.h"
#include <vector>
using std::vector;
#include <Eigen/Core>
#include <cmath>
void RayTracer::parse() {
for (auto i = json["output"].begin(); i != json["output"].end(); ++i)
@ -17,19 +17,60 @@ void RayTracer::parse() {
lights.push_back(Parser::getLight(*i));
}
void RayTracer::render() {}
Ray getRay(int x, int y, const Vector3f &camPos, const Vector3f &pxUpperLeft,
const Vector3f &du, const Vector3f &dv) {
return Ray(camPos, pxUpperLeft + x * du + y * dv - camPos);
}
void RayTracer::output() {
for (auto scene : scenes) {
int width = scene->getWidth();
int height = scene->getHeight();
vector<double> buffer(3 * width * height);
save_ppm(scene->getName(), buffer, width, height);
}
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 vpWidth = vpHeight * width / height;
Vector3f vpU = Vector3f(vpWidth, 0, 0);
Vector3f vpV = Vector3f(0, -vpHeight, 0);
Vector3f du = vpU / width;
Vector3f dv = vpV / height;
Vector3f vpUpperLeft = cameraPos + lookAt - vpU / 2.0 - vpV / 2.0;
Vector3f pxUpperLeft = vpUpperLeft + (du + dv) / 2.0;
Buffer buffer(width * height * 3);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x) {
Ray ray = getRay(x, y, cameraPos, pxUpperLeft, du, dv);
for (auto geometry : geometries)
if (geometry->intersect(ray)) {
buffer[3 * y * width + 3 * x + 0] = 1;
buffer[3 * y * width + 3 * x + 1] = 1;
buffer[3 * y * width + 3 * x + 2] = 1;
break;
}
}
Task *task = new Task(scene, buffer);
tasks.push_back(task);
}
void RayTracer::output(Task *task) {
string path = task->first->getName();
int width = task->first->getWidth();
int height = task->first->getHeight();
save_ppm(path, task->second, width, height);
}
void RayTracer::run() {
parse();
render();
output();
for (auto scene : scenes)
render(scene);
for (auto task : tasks)
output(task);
}

View file

@ -6,8 +6,12 @@
#include "Light.h"
#include "Scene.h"
#include <utility>
#include <vector>
using Buffer = std::vector<double>;
using Task = std::pair<Scene *, Buffer>;
class RayTracer {
public:
RayTracer(const nlohmann::json &j) : json(j) {}
@ -19,9 +23,11 @@ private:
std::vector<Light *> lights;
std::vector<Geometry *> geometries;
std::vector<Task *> tasks;
void parse();
void render();
void output();
void render(Scene *);
void output(Task *);
};
#endif // !RAY_TRACER_H_

View file

@ -1,11 +1,19 @@
#include "Scene.h"
string Scene::getName() { return name; }
string Scene::getName() const { return name; }
int Scene::getWidth() { return width; }
int Scene::getHeight() { return height; }
float Scene::getFov() { return fov; }
Vector3f Scene::getCenter() const { return center; }
Vector3f Scene::getUpVector() const { return up; }
Vector3f Scene::getLookAt() const { return lookAt; }
void Scene::setRaysPerPixel(const Eigen::VectorXi &raysPerPixel) {
this->raysPerPixel = raysPerPixel;
}

View file

@ -32,9 +32,13 @@ private:
bool globalIllum = false;
public:
string getName();
string getName() const;
int getWidth();
int getHeight();
float getFov();
Vector3f getCenter() const;
Vector3f getUpVector() const;
Vector3f getLookAt() const;
void setRaysPerPixel(const Eigen::VectorXi &);
void setAntialiasing(bool);
void setTwoSideRender(bool);