Skip to content

Commit

Permalink
Some optimisations and corrections
Browse files Browse the repository at this point in the history
  • Loading branch information
Philip Abernethy committed Apr 20, 2016
1 parent 4b53fcc commit 7e7bec6
Show file tree
Hide file tree
Showing 22 changed files with 172 additions and 154 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# RayTracer
A whitted ray tracer written in C++
A Whitted ray tracer written in C++

This project mainly serves the purposes of making me more familiar with C++ as well as getting me into computer
graphics. I hope though, that it is helpful and/or educational for others too and I try to keep the code understandable,
Expand Down
2 changes: 1 addition & 1 deletion classes.dot
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ digraph Classes {
samples : unsigned long &)\l
+ camera()\l
+ get_rays(x : int, y : int) : ray &\l
+ set_data(x : unsigned long, y : unsigned long, data : std::vector\<color\>) : void\l
+ set_pixel(x : unsigned long, y : unsigned long, data : std::vector\<color\>) : void\l
+ get_pixel(x : int, y : int) : color\l
}"
]
Expand Down
15 changes: 8 additions & 7 deletions examples/example7.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<scene output_file="example7.png" renderer="pathtracer">
<background_color r="0.0" g="0.0" b="0.0"/>
<camera type="realistic">
<camera type="perspective">
<position x="0.0" y="0.0" z="5.0"/>
<lookat x="0.0" y="0.0" z="4.0"/>
<up x="0.0" y="1.0" z="0.0"/>
Expand All @@ -13,23 +13,24 @@
<shadow_rays n="1"/>
<sampling type="random" n="32"/>
<focus d="13"/>
<defocus d="4"/>
<defocus d="0.002"/>
<aperture d="0.2"/>
</camera>
<lights>
<sphere_light>
<mesh_light>
<color r="0.8" g="0.8" b="0.8"/>
<position x="0.0" y="0.0" z="0.0"/>
<sphere radius="1">
<mesh name="box.obj">
<material type="solid">
<emit r="0.8" g="0.8" b="0.8"/>
<color r="0.8" g="0.8" b="0.8"/>
</material>
<transform>
<translate x="0.0" y="5.0" z="-5.0"/>
<scale x="1.0" y="0.2" z="1.0"/>
<translate x="0.0" y="4.8" z="-5.0"/>
</transform>
</sphere>
</sphere_light>
</mesh>
</mesh_light>
</lights>
<surfaces>
<mesh name="plane_small.obj">
Expand Down
16 changes: 6 additions & 10 deletions lib/camera/camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,17 @@ camera::camera(const position &pos, const position &look_at, const direction &up
std::shared_ptr<mat4> m(new mat4(d));
transforms = transform(m);
data.resize(resolution[0]);
for (auto &i : data) {
for (std::vector<color> &i : data) {
i.resize(resolution[1]);
for (auto &j : i)
j.resize(samples);
for (color &j : i)
j = color();
}
}

void camera::set_data(const unsigned long &x, const unsigned long &y, const std::vector<color> data) {
void camera::set_pixel(const unsigned long &x, const unsigned long &y, const color &data) {
this->data[x][y] = data;
}

std::shared_ptr<color> camera::get_pixel(const unsigned long &x, const unsigned long &y) const {
std::shared_ptr<color> out(new color());
for (auto &i : data[x][y])
*out += i;
*out = *out * (1.0f / data[x][y].size());
return out;
const color &camera::get_pixel(const unsigned long &x, const unsigned long &y) const {
return data[x][y];
}
6 changes: 3 additions & 3 deletions lib/camera/camera.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
class camera {
protected:
transform transforms;
std::vector<std::vector<std::vector<color>>> data;
std::vector<std::vector<color>> data;

camera() { };

Expand Down Expand Up @@ -66,7 +66,7 @@ class camera {
*
* @param &data the std::vector of colors contributing the the pixel
*/
void set_data(const unsigned long &x, const unsigned long &y, const std::vector<color> data);
void set_pixel(const unsigned long &x, const unsigned long &y, const color &data);

/**
* @brief Returns the color of a pixel
Expand All @@ -79,7 +79,7 @@ class camera {
*
* @return the final color of the pixel with the given coordinates
*/
std::shared_ptr<color> get_pixel(const unsigned long &x, const unsigned long &y) const;
const color & get_pixel(const unsigned long &x, const unsigned long &y) const;
};

#endif //RAY_TRACER_CAMERA_H
2 changes: 1 addition & 1 deletion lib/camera/realistic_camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ std::shared_ptr<std::vector<ray>> realistic_camera::get_rays(const unsigned long
out->push_back(transforms(ray(o, position((focus + focus_offsets->at(i)) * d) - o)));
}
return out;
}
}
24 changes: 12 additions & 12 deletions lib/geometry/shapes/mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ mesh::mesh(const direction &offset, const std::shared_ptr<material> &matrl,
std::shared_ptr<std::vector<std::shared_ptr<triangle>>> faces) : shape(offset, matrl), faces(faces) {
assert(faces->size() > 0);
aabb[0] = position(std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::infinity());
std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::infinity());
aabb[1] = position(-std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity());
-std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity());
for (std::shared_ptr<triangle> t : *faces) {
std::array<position, 2> box = t->get_aabb();
aabb[0][0] = std::min(aabb[0][0], box[0][0]);
Expand All @@ -27,20 +27,20 @@ mesh::mesh(const direction &offset, const std::shared_ptr<material> &matrl,
bool mesh::intersect_quick(const position &o, const direction &inv_d) const {
float tmin = -std::numeric_limits<float>::infinity(), tmax = std::numeric_limits<float>::infinity();
if (inv_d[0] != 0) {
float tx1 = (aabb[0][0] - o[0])*inv_d[0];
float tx2 = (aabb[1][0] - o[0])*inv_d[0];
float tx1 = (aabb[0][0] - o[0]) * inv_d[0];
float tx2 = (aabb[1][0] - o[0]) * inv_d[0];
tmin = std::max(tmin, std::min(tx1, tx2));
tmax = std::min(tmax, std::max(tx1, tx2));
}
if (inv_d[1] != 0) {
float tx1 = (aabb[0][1] - o[1])*inv_d[1];
float tx2 = (aabb[1][1] - o[1])*inv_d[1];
float tx1 = (aabb[0][1] - o[1]) * inv_d[1];
float tx2 = (aabb[1][1] - o[1]) * inv_d[1];
tmin = std::max(tmin, std::min(tx1, tx2));
tmax = std::min(tmax, std::max(tx1, tx2));
}
if (inv_d[2] != 0) {
float tx1 = (aabb[0][2] - o[2])*inv_d[2];
float tx2 = (aabb[1][2] - o[2])*inv_d[2];
float tx1 = (aabb[0][2] - o[2]) * inv_d[2];
float tx2 = (aabb[1][2] - o[2]) * inv_d[2];
tmin = std::max(tmin, std::min(tx1, tx2));
tmax = std::min(tmax, std::max(tx1, tx2));
}
Expand All @@ -51,7 +51,7 @@ intersection mesh::intersect_full(const ray &r) const {
intersection out = intersection();
ray tr = world_to_object(r);
tr.o = tr.o - offset;
const direction inv_d = direction(1/tr.d[0], 1/tr.d[1], 1/tr.d[2]);
const direction inv_d = direction(1 / tr.d[0], 1 / tr.d[1], 1 / tr.d[2]);
if (!intersect_quick(tr.o, inv_d))
return out;
float dist = std::numeric_limits<float>::max();
Expand Down Expand Up @@ -82,7 +82,7 @@ bool mesh::intersect_shadow(const position &o, const direction &d) const {
position to = world_to_object(o);
direction td = world_to_object(d);
to -= offset;
const direction inv_d = direction(1/td[0], 1/td[1], 1/td[2]);
const direction inv_d = direction(1 / td[0], 1 / td[1], 1 / td[2]);
if (!intersect_quick(to, inv_d))
return false;
for (std::shared_ptr<triangle> t : *faces)
Expand Down
2 changes: 1 addition & 1 deletion lib/geometry/shapes/shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,4 @@ class shape : public std::enable_shared_from_this<shape> {
const float get_transmittance() const;
};

#endif //RAY_TRACER_SHAPE_H
#endif //RAY_TRACER_SHAPE_H
32 changes: 16 additions & 16 deletions lib/geometry/transform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,24 @@ transform::transform(const transform &in) : trans(in.trans), inv_trans(in.inv_tr


transform transform::operator()(const transform &t) const {
return transform(std::shared_ptr<mat4>(new mat4(*this->trans*(*t.trans))),
std::shared_ptr<mat4>(new mat4(*t.inv_trans*(*this->inv_trans))));
return transform(std::shared_ptr<mat4>(new mat4(*trans*(*t.trans))),
std::shared_ptr<mat4>(new mat4(*t.inv_trans*(*inv_trans))));
}

position transform::operator()(const position &p) const {
return position(*this->trans*p);
return position(*trans*p);
}

direction transform::operator()(const direction &v) const {
return direction(*this->trans*v);
return direction(*trans*v);
}

normal transform::operator()(const normal &n) const {
return normal(transpose(*this->inv_trans)*n);
return normal(transpose(*inv_trans)*n);
}

ray transform::operator()(const ray &r) const {
return ray(*this->trans*r.o, *this->trans*r.d);
return ray(*trans*r.o, *trans*r.d);
}

std::ostream &operator<<(std::ostream &out, const transform &a) {
Expand All @@ -53,8 +53,8 @@ void transform::translate(const direction t) {
{0, 0, 1, -t[2]},
{0, 0, 0, 1}
}};
*this->trans = mat4(tmp)*(*this->trans);
*this->inv_trans = *this->inv_trans*mat4(itmp);
*trans = mat4(tmp)*(*trans);
*inv_trans = *inv_trans*mat4(itmp);
}

void transform::scale(const std::array<float, 3> sf) {
Expand All @@ -70,8 +70,8 @@ void transform::scale(const std::array<float, 3> sf) {
{0, 0, 1/sf[2], 0},
{0, 0, 0, 1}
}};
*this->trans = mat4(tmp)*(*this->trans);
*this->inv_trans = *this->inv_trans*mat4(itmp);
*trans = mat4(tmp)*(*trans);
*inv_trans = *inv_trans*mat4(itmp);
}

void transform::rotateX(const float &angle) {
Expand Down Expand Up @@ -102,8 +102,8 @@ void transform::rotateX(const float &angle) {
{0, -s, c, 0},
{0, 0, 0, 1}
}};
*this->trans = mat4(tmp)*(*this->trans);
*this->inv_trans = *this->inv_trans*mat4(itmp);
*trans = mat4(tmp)*(*trans);
*inv_trans = *inv_trans*mat4(itmp);
}

void transform::rotateY(const float &angle) {
Expand Down Expand Up @@ -134,8 +134,8 @@ void transform::rotateY(const float &angle) {
{s, 0, c, 0},
{0, 0, 0, 1}
}};
*this->trans = mat4(tmp)*(*this->trans);
*this->inv_trans = *this->inv_trans*mat4(itmp);
*trans = mat4(tmp)*(*trans);
*inv_trans = *inv_trans*mat4(itmp);
}

void transform::rotateZ(const float &angle) {
Expand Down Expand Up @@ -166,6 +166,6 @@ void transform::rotateZ(const float &angle) {
{0, 0, 1, 0},
{0, 0, 0, 1}
}};
*this->trans = mat4(tmp)*(*this->trans);
*this->inv_trans = *this->inv_trans*mat4(itmp);
*trans = mat4(tmp)*(*trans);
*inv_trans = *inv_trans*mat4(itmp);
}
83 changes: 37 additions & 46 deletions lib/light/mesh_light.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,23 @@ mesh_light::mesh_light(const direction &offset, const std::shared_ptr<material>

mesh_light::mesh_light(const std::shared_ptr<mesh> &m) : light(direction()), mesh(*m) { }

intersection mesh_light::find_farthest(const ray &r) const {
intersection mesh_light::intersect_self(const ray &r) const {
intersection out = intersection();
ray tr = world_to_object(r);
tr.o = tr.o - offset;
const direction inv_d = direction(1 / tr.d[0], 1 / tr.d[1], 1 / tr.d[2]);
if (!intersect_quick(tr.o, inv_d))
return out;
float dist = 0;
float dist = std::numeric_limits<float>::max();
for (std::shared_ptr<triangle> t : *faces) {
if (!t->intersect_quick(tr.o, inv_d))
continue;
std::shared_ptr<normal> n = t->get_avg_normal();
if (dot(*n, tr.d) > 0)
continue;
intersection cur = t->intersect_full(tr);
if (!cur.pos)
continue;
float new_dist = length(tr.o - *cur.pos);
if (new_dist > dist) {
if (new_dist < dist) {
dist = new_dist;
out = cur;
*out.pos = object_to_world(*out.pos + offset);
Expand All @@ -40,51 +38,44 @@ intersection mesh_light::find_farthest(const ray &r) const {

const std::shared_ptr<std::vector<direction>> mesh_light::get_directions(const position &pos,
const unsigned long &samples) const {
std::vector<unsigned long> valid_faces = std::vector<unsigned long>(faces->size(), 0);
for (unsigned long i = 0; i < faces->size(); i++)
valid_faces[i] = i;
position tpos = world_to_object(pos);
std::shared_ptr<std::vector<direction>> out(new std::vector<direction>());
std::vector<float> area = std::vector<float>(faces->size(), 0);
for (unsigned long i = 0; i < faces->size(); i++) {
const std::array<position, 3> v = *faces->at(i)->get_vertices();
float e1 = length(object_to_world(v[0] - v[1]));
float e2 = length(object_to_world(v[0] - v[2]));
float e3 = length(object_to_world(v[1] - v[2]));
float s = (e1 + e2 + e3) / 2;
area[i] = std::sqrt(s * (s - e1) * (s - e2) * (s - e3));
}
float m = area[std::distance(area.begin(), std::min_element(area.begin(), area.end()))];
for (unsigned long i = 0; i < area.size(); i++)
area[i] = std::ceil(area[i] / m);
std::vector<float> wheighted = std::vector<float>(
static_cast<unsigned long>(std::accumulate(area.begin(), area.end(), 0)), 0);
std::vector<float>::iterator it = wheighted.begin();
for (unsigned long i = 0; i < area.size(); i++)
for (unsigned long j = 0; j < area[i]; j++)
*it++ = i;
random_sampler s;
std::vector<unsigned long> f = *s.get_1d_samples(static_cast<unsigned long>(0), faces->size() - 1, samples);
std::vector<unsigned long> f = *s.get_1d_samples(0, wheighted.size() - 1, samples);
std::vector<vec2> c = *s.get_2d_samples(0, 1, 0, 1, samples);
std::shared_ptr<std::vector<direction>> out(new std::vector<direction>());
for (unsigned long i = 0; i < samples; i++) {
while (true) {
if (valid_faces.size() == 0)
return out;
std::vector<unsigned long>::iterator result = std::find(valid_faces.begin(), valid_faces.end(), f[i]);
if (result == valid_faces.end()) {
f[i] = s.get_1d_samples(static_cast<unsigned long>(0), faces->size() - 1, 1)->at(0);
continue;
}
const std::shared_ptr<std::array<normal, 3>> n = faces->at(f[i])->get_normals();
const std::shared_ptr<std::array<position, 3>> d = faces->at(f[i])->get_vertices();
bool valid = dot(*faces->at(f[i])->get_avg_normal(),
tpos - *faces->at(f[i])->get_barycentric_position(1.0f / 3, 1.0f / 3, 1.0f / 3)) > 1e-3;
if (!valid) {
valid_faces.erase(result);
continue;
}
vec2 lcoord = vec2(c[i][0] + c[i][1] > 1 ? 1 - c[i][1] : c[i][0],
c[i][0] + c[i][1] > 1 ? 1 - c[i][0] : c[i][1]);
position lpos = object_to_world(
*faces->at(f[i])->get_barycentric_position(1 - lcoord[0] - lcoord[1], lcoord[0], lcoord[1]));
intersection closest = find_farthest(ray(lpos, pos - lpos));
if (closest.object && dot(*closest.norm, normalise(pos - *closest.pos)) <= 0) {
std::vector<std::shared_ptr<triangle>>::iterator cf = std::find(faces->begin(), faces->end(),
closest.object);
result = std::find(valid_faces.begin(), valid_faces.end(), std::distance(faces->begin(), cf));
valid_faces.erase(result);
c[i] = s.get_2d_samples(0, 1, 0, 1, 1)->at(0);
continue;
} else if (dot(*faces->at(f[i])->get_barycentric_normal(1 - lcoord[0] - lcoord[1], lcoord[0], lcoord[1]),
normalise(pos - lpos)) <= 0) {
c[i] = s.get_2d_samples(0, 1, 0, 1, 1)->at(0);
continue;
}
out->push_back((pos - lpos) * 0.999);
break;
std::shared_ptr<triangle> face = faces->at(static_cast<unsigned long>(wheighted[f[i]]));
std::shared_ptr<vec2> lcoord(new vec2(c[i][0] + c[i][1] > 1 ? 1 - c[i][1] : c[i][0],
c[i][0] + c[i][1] > 1 ? 1 - c[i][0] : c[i][1]));
std::shared_ptr<position> lpos = std::make_shared<position>(object_to_world(
*face->get_barycentric_position(1 - (*lcoord)[0] - (*lcoord)[1], (*lcoord)[0], (*lcoord)[1])));
intersection closest = intersect_self(ray(*lpos, pos - *lpos));
if (!closest.object) {
closest.pos = lpos;
closest.object = face;
closest.local_pos = lcoord;
closest.norm = face->get_barycentric_normal(1 - (*lcoord)[0] - (*lcoord)[1], (*lcoord)[0], (*lcoord)[1]);
}
direction dir = (pos - *closest.pos) * 0.9999;
if (dot(*closest.norm, normalise(dir)) >= 0)
out->push_back(dir);
}
return out;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/light/mesh_light.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

class mesh_light : public light, public mesh {
protected:
virtual intersection find_farthest(const ray &r) const;
virtual intersection intersect_self(const ray &r) const;

public:
mesh_light(const direction &offset, const std::shared_ptr<material> &matrl,
Expand Down
Loading

0 comments on commit 7e7bec6

Please sign in to comment.