mirror of
https://github.com/vonhyou/ray-tracer-comp371.git
synced 2025-06-08 07:22:01 +00:00
Merge pull request #10 from vonhyou/ray
Add ray class and impl ray casting
This commit is contained in:
commit
d808e05449
10 changed files with 162 additions and 43 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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
5
src/Ray.cc
Normal 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
21
src/Ray.h
Normal 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_
|
|
@ -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) {
|
||||
void RayTracer::render(Scene *scene) {
|
||||
int width = scene->getWidth();
|
||||
int height = scene->getHeight();
|
||||
vector<double> buffer(3 * width * height);
|
||||
save_ppm(scene->getName(), buffer, width, height);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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_
|
||||
|
|
10
src/Scene.cc
10
src/Scene.cc
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue