mirror of
https://github.com/vonhyou/ray-tracer-comp371.git
synced 2025-06-08 07:22:01 +00:00
calculate nearest hit
This commit is contained in:
parent
a8a00d386e
commit
184812c533
6 changed files with 92 additions and 17 deletions
|
@ -1,6 +1,7 @@
|
|||
#include "Geometry.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <cmath>
|
||||
|
||||
Vector3f Geometry::diffuse() const { return cd; }
|
||||
Vector3f Geometry::specular() const { return cs; }
|
||||
|
@ -10,13 +11,24 @@ void Geometry::setTransform(const Matrix4f &transform) {
|
|||
this->transform = transform;
|
||||
}
|
||||
|
||||
bool Sphere::intersect(const Ray &r) const {
|
||||
Optional<float> 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;
|
||||
|
||||
return b * b - 4 * a * c >= 0;
|
||||
float delta = b * b - 4 * a * c;
|
||||
if (delta >= 0) {
|
||||
float t1 = (-b + sqrt(delta)) / 2.0f / a;
|
||||
float t2 = (-b - sqrt(delta)) / 2.0f / a;
|
||||
float mint = std::min(t1, t2);
|
||||
float maxt = std::max(t1, t2);
|
||||
return maxt <= 0
|
||||
? Optional<float>::nullopt
|
||||
: (mint < 0 ? Optional<float>(maxt) : Optional<float>(mint));
|
||||
}
|
||||
|
||||
return Optional<float>::nullopt;
|
||||
}
|
||||
|
||||
bool isInRectangle(const Vector3f &p, const Vector3f &a, const Vector3f &b,
|
||||
|
@ -30,18 +42,19 @@ bool isInRectangle(const Vector3f &p, const Vector3f &a, const Vector3f &b,
|
|||
(s1 <= 0 && s2 <= 0 && s3 <= 0 && s4 <= 0);
|
||||
}
|
||||
|
||||
bool 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());
|
||||
if (abs(denom) < 1e-6f)
|
||||
return false;
|
||||
return Optional<float>::nullopt;
|
||||
|
||||
float t = -normal.dot(r.getOrigin() - p1) / denom;
|
||||
if (t <= 0)
|
||||
return false;
|
||||
return Optional<float>::nullopt;
|
||||
|
||||
Vector3f p = r.getOrigin() + t * r.getDirection();
|
||||
|
||||
return isInRectangle(p, p1, p2, p3, p4, normal);
|
||||
return isInRectangle(p, p1, p2, p3, p4, normal) ? Optional<float>(t)
|
||||
: Optional<float>::nullopt;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef GEOMETRY_H_
|
||||
#define GEOMETRY_H_
|
||||
|
||||
#include "Optional.h"
|
||||
#include "Ray.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
|
@ -8,6 +9,7 @@
|
|||
using Eigen::Matrix;
|
||||
using Eigen::Matrix4f;
|
||||
using Eigen::Vector3f;
|
||||
using utils::Optional;
|
||||
|
||||
// Abstract class for Geometries
|
||||
class Geometry {
|
||||
|
@ -15,7 +17,7 @@ public:
|
|||
enum class Type { SPHERE, RECTANGLE };
|
||||
|
||||
virtual ~Geometry() = default;
|
||||
virtual bool intersect(const Ray &) const = 0;
|
||||
virtual Optional<float> intersect(const Ray &) const = 0;
|
||||
|
||||
protected:
|
||||
Geometry(Type type, float ka, float kd, float ks, const Vector3f &ca,
|
||||
|
@ -42,7 +44,7 @@ public:
|
|||
: Geometry(Type::SPHERE, ka, kd, ks, ca, cd, cs, pc), radius(radius),
|
||||
center(center) {}
|
||||
|
||||
bool intersect(const Ray &) const override;
|
||||
Optional<float> intersect(const Ray &) const override;
|
||||
|
||||
private:
|
||||
float radius;
|
||||
|
@ -57,7 +59,7 @@ public:
|
|||
: Geometry(Type::RECTANGLE, ka, kd, ks, ca, cd, cs, pc), p1(p1), p2(p2),
|
||||
p3(p3), p4(p4) {}
|
||||
|
||||
bool intersect(const Ray &) const override;
|
||||
Optional<float> intersect(const Ray &) const override;
|
||||
|
||||
private:
|
||||
Vector3f p1, p2, p3, p4;
|
||||
|
|
7
src/HitRecord.cc
Normal file
7
src/HitRecord.cc
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include "HitRecord.h"
|
||||
|
||||
bool HitRecord::operator<(const HitRecord &other) const {
|
||||
return this->t > other.t; // to get the nearest t
|
||||
}
|
||||
|
||||
Geometry *HitRecord::geometry() const { return g; }
|
19
src/HitRecord.h
Normal file
19
src/HitRecord.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef HITRECORD_H_
|
||||
#define HITRECORD_H_
|
||||
|
||||
#include "Geometry.h"
|
||||
|
||||
class HitRecord {
|
||||
public:
|
||||
HitRecord(float t, Geometry *g) : t(t), g(g) {}
|
||||
bool operator<(const HitRecord &) const;
|
||||
|
||||
private:
|
||||
float t;
|
||||
Geometry *g;
|
||||
|
||||
public:
|
||||
Geometry *geometry() const;
|
||||
};
|
||||
|
||||
#endif // !HITRECORD_H_
|
25
src/Optional.h
Normal file
25
src/Optional.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef OPTIONAL_H_
|
||||
|
||||
namespace utils {
|
||||
|
||||
// I write this class because we are using C++14
|
||||
// so std::optional is not available
|
||||
template <typename T> class Optional {
|
||||
public:
|
||||
Optional() : hasValue_(false) {}
|
||||
Optional(T value) : value_(value), hasValue_(true) {}
|
||||
|
||||
bool hasValue() const { return hasValue_; }
|
||||
T value() const { return value_; }
|
||||
|
||||
static const Optional nullopt;
|
||||
|
||||
private:
|
||||
T value_;
|
||||
bool hasValue_;
|
||||
};
|
||||
|
||||
template <typename T> const Optional<T> Optional<T>::nullopt = Optional<T>();
|
||||
} // namespace utils
|
||||
|
||||
#endif // !OPTIONAL_H_
|
|
@ -1,11 +1,15 @@
|
|||
#include "RayTracer.h"
|
||||
#include "../external/simpleppm.h"
|
||||
#include "HitRecord.h"
|
||||
#include "Output.h"
|
||||
#include "Parser.h"
|
||||
#include "Ray.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <cmath>
|
||||
#include <queue>
|
||||
|
||||
using std::priority_queue;
|
||||
|
||||
void RayTracer::parse() {
|
||||
for (auto i = json["output"].begin(); i != json["output"].end(); ++i)
|
||||
|
@ -46,15 +50,20 @@ void RayTracer::render(Scene *scene) {
|
|||
for (int y = 0; y < height; ++y)
|
||||
for (int x = 0; x < width; ++x) {
|
||||
Ray ray = getRay(x, y, cameraPos, pxUpperLeft, du, dv);
|
||||
priority_queue<HitRecord> records;
|
||||
for (auto g : geometries) {
|
||||
Optional<float> t = g->intersect(ray);
|
||||
if (t.hasValue())
|
||||
records.push(HitRecord(t.value(), g));
|
||||
}
|
||||
|
||||
for (auto g : geometries)
|
||||
if (g->intersect(ray)) {
|
||||
Vector3f diffuse = g->diffuse();
|
||||
buffer->r(y * width + x, diffuse.x());
|
||||
buffer->g(y * width + x, diffuse.y());
|
||||
buffer->b(y * width + x, diffuse.z());
|
||||
break;
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
outputs.push_back(buffer);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue