object.h 4.16 KB
Newer Older
TheNumbat's avatar
TheNumbat committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

#pragma once

#include "../lib/mathlib.h"
#include "../scene/object.h"
#include <variant>

#include "bvh.h"
#include "list.h"
#include "shapes.h"
#include "trace.h"
#include "tri_mesh.h"

namespace PT {

class Object {
public:
    Object(Shape&& shape, Scene_ID id, unsigned int m = 0, const Mat4& T = Mat4::I)
        : trans(T), itrans(T.inverse()), _id(id), material(m), underlying(std::move(shape)) {
        has_trans = trans != Mat4::I;
    }
    Object(Tri_Mesh&& tri_mesh, Scene_ID id, unsigned int m = 0, const Mat4& T = Mat4::I)
        : trans(T), itrans(T.inverse()), _id(id), material(m), underlying(std::move(tri_mesh)) {
        has_trans = trans != Mat4::I;
    }
    Object(List<Object>&& list, Scene_ID id, unsigned int m = 0, const Mat4& T = Mat4::I)
        : trans(T), itrans(T.inverse()), _id(id), material(m), underlying(std::move(list)) {
        has_trans = trans != Mat4::I;
    }
    Object(BVH<Object>&& bvh, Scene_ID id, unsigned int m = 0, const Mat4& T = Mat4::I)
        : trans(T), itrans(T.inverse()), _id(id), material(m), underlying(std::move(bvh)) {
        has_trans = trans != Mat4::I;
    }

TheNumbat's avatar
TheNumbat committed
35
36
37
38
39
40
41
42
43
    Object() {
    }
    Object(List<Object>&& list, const Mat4& T = Mat4::I)
        : trans(T), itrans(T.inverse()), underlying(std::move(list)) {
    }
    Object(BVH<Object>&& bvh, const Mat4& T = Mat4::I)
        : trans(T), itrans(T.inverse()), underlying(std::move(bvh)) {
    }

TheNumbat's avatar
TheNumbat committed
44
45
46
47
48
49
    Object(const Object& src) = delete;
    Object& operator=(const Object& src) = delete;
    Object& operator=(Object&& src) = default;
    Object(Object&& src) = default;

    BBox bbox() const {
TheNumbat's avatar
TheNumbat committed
50
        BBox box = std::visit([](const auto& o) { return o.bbox(); }, underlying);
TheNumbat's avatar
TheNumbat committed
51
52
53
54
55
56
        if(has_trans) box.transform(trans);
        return box;
    }

    Trace hit(Ray ray) const {
        if(has_trans) ray.transform(itrans);
TheNumbat's avatar
TheNumbat committed
57
        Trace ret = std::visit([&ray](const auto& o) { return o.hit(ray); }, underlying);
TheNumbat's avatar
TheNumbat committed
58
        if(ret.hit) {
TheNumbat's avatar
TheNumbat committed
59
            if(material != -1) ret.material = material;
TheNumbat's avatar
TheNumbat committed
60
61
62
63
64
            if(has_trans) ret.transform(trans, itrans.T());
        }
        return ret;
    }

TheNumbat's avatar
TheNumbat committed
65
66
    size_t visualize(GL::Lines& lines, GL::Lines& active, size_t level, Mat4 vtrans) const {
        if(has_trans) vtrans = vtrans * trans;
TheNumbat's avatar
TheNumbat committed
67
68
        return std::visit(
            overloaded{
TheNumbat's avatar
TheNumbat committed
69
70
                [&](const BVH<Object>& bvh) { return bvh.visualize(lines, active, level, vtrans); },
                [&](const Tri_Mesh& mesh) { return mesh.visualize(lines, active, level, vtrans); },
TheNumbat's avatar
TheNumbat committed
71
72
73
74
                [](const auto&) { return size_t(0); }},
            underlying);
    }

TheNumbat's avatar
TheNumbat committed
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
    Vec3 sample(Vec3 from) const {
        if(has_trans) from = itrans * from;
        Vec3 dir =
            std::visit(overloaded{[from](const List<Object>& list) { return list.sample(from); },
                                  [from](const Tri_Mesh& mesh) { return mesh.sample(from); },
                                  [](const auto&) -> Vec3 {
                                      die("Sampling implicit objects/BVHs is not yet supported.");
                                  }},
                       underlying);
        if(has_trans) dir = trans.rotate(dir).unit();
        return dir;
    }

    float pdf(Ray ray, Mat4 T = Mat4::I, Mat4 iT = Mat4::I) const {
        if(has_trans) {
            T = T * trans;
            iT = itrans * iT;
        }
        return std::visit(
            overloaded{[ray, T, iT](const List<Object>& list) { return list.pdf(ray, T, iT); },
                       [ray, T, iT](const Tri_Mesh& mesh) { return mesh.pdf(ray, T, iT); },
                       [](const auto&) -> float {
                           die("Sampling implicit objects/BVHs is not yet supported.");
                       }},
            underlying);
    }

TheNumbat's avatar
TheNumbat committed
102
103
104
105
106
107
108
109
110
111
112
113
    Scene_ID id() const {
        return _id;
    }
    void set_trans(const Mat4& T) {
        trans = T;
        itrans = T.inverse();
        has_trans = trans != Mat4::I;
    }

private:
    bool has_trans;
    Mat4 trans, itrans;
TheNumbat's avatar
TheNumbat committed
114
    int material = -1;
TheNumbat's avatar
TheNumbat committed
115
116
117
118
    Scene_ID _id;
    std::variant<Tri_Mesh, Shape, BVH<Object>, List<Object>> underlying;
};

TheNumbat's avatar
TheNumbat committed
119
} // namespace PT