-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathShape.hpp
More file actions
176 lines (139 loc) · 5.17 KB
/
Shape.hpp
File metadata and controls
176 lines (139 loc) · 5.17 KB
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#pragma once
#include <memory>
#include <mutex>
#include <numbers>
#include "Ray.hpp"
#include "AABB.hpp"
#include "Material.hpp"
class Mesh;
class Shape{
public:
virtual AABB BoundingBox() const = 0;
virtual bool IntersectPred(const Ray& ray, float max) const = 0;
virtual bool Intersect(const Ray& ray, SurfaceInteraction& interaction, float max) const = 0;
virtual float Area() const = 0;
virtual SurfaceInteraction Sample(const glm::vec2& u) const = 0;
virtual float PDF(const GeometricInteraction& interaction) const = 0;
virtual float PDF(const GeometricInteraction& interaction, const Ray& ray) const = 0; //should just give normal info (shape sample context, maybe get that from sample?)
};
class SphereShape : public Shape{
public:
SphereShape(const glm::vec3& sphereCenter, float sphereRadius) : center(sphereCenter), bbox {}, radius(sphereRadius){
glm::vec3 rvec = glm::vec3(radius);
bbox.Expand(center - rvec);
bbox.Expand(center + rvec);
}
bool Intersect(const Ray& ray, SurfaceInteraction& interaction, float max) const override;
bool IntersectPred(const Ray& ray, float max) const override;
AABB BoundingBox() const override{
return bbox;
}
static glm::vec2 GetSphereUV(glm::vec3 p){
p = glm::normalize(p);
float theta = std::acos(glm::clamp(p.y, -1.0f, 1.0f));
float phi = std::atan2(p.z, p.x);
if(phi < 0) phi += 2.0f * std::numbers::pi_v<float>;
float u = std::numbers::inv_pi_v<float> *phi * 0.5f;
float v = std::numbers::inv_pi_v<float> *theta;
return { u,v };
}
SurfaceInteraction Sample(const glm::vec2& u) const override;
float Area() const override;
float PDF(const GeometricInteraction& interaction) const override;
float PDF(const GeometricInteraction& interaction, const Ray& ray) const override;
private:
glm::vec3 center;
AABB bbox;
float radius;
};
class TriangleShape : public Shape{
public:
TriangleShape(uint32_t meshIndex, uint32_t triangleIndex) : MeshIndex(meshIndex), TriIndex(triangleIndex){}
bool Intersect(const Ray& ray, SurfaceInteraction& interaction, float max) const override;
bool IntersectPred(const Ray& ray, float max) const override;
AABB BoundingBox() const override;
SurfaceInteraction Sample(const glm::vec2& u) const override;
float Area() const override;
float PDF(const GeometricInteraction& interaction) const override;
float PDF(const GeometricInteraction& interaction, const Ray& ray) const override;
//maybe move this to resource manager?
static uint32_t addMesh(Mesh* mesh){
const std::lock_guard<std::mutex> ml(meshListLock);
for(uint32_t i = 0;i < meshList.size();i++){
if(meshList[i] == nullptr || meshList[i] == mesh){
meshList[i] = mesh;
return i;
}
}
meshList.push_back(mesh);
return static_cast<uint32_t>(meshList.size() - 1);
}
static void removeMesh(Mesh* mesh){
const std::lock_guard<std::mutex> ml(meshListLock);
for(uint32_t i = 0;i < meshList.size();i++){
if(meshList[i] == mesh){
meshList[i] = nullptr;
}
}
}
static Mesh* getMeshAt(uint32_t idx){
return meshList[idx];
}
uint32_t getMeshIndex() const {
return MeshIndex;
}
uint32_t getTriIndex() const {
return TriIndex;
}
private:
uint32_t MeshIndex;
uint32_t TriIndex;
static inline std::vector<Mesh*> meshList;
static inline std::mutex meshListLock;
};
class QuadShape : public Shape{
public:
QuadShape(const glm::vec3& origin, const glm::vec3& u, const glm::vec3& v) : Q(origin), u(u), v(v), bbox {}{
glm::vec3 n = glm::cross(u, v);
normal = glm::normalize(n);
D = glm::dot(normal, Q);
bbox.Expand(Q);
bbox.Expand(Q + u + v);
bbox.Expand(Q + u);
bbox.Expand(Q + v);
w = n / glm::dot(n, n);
}
bool Intersect(const Ray& ray, SurfaceInteraction& interaction, float max) const override;
bool IntersectPred(const Ray& ray, float max) const override;
AABB BoundingBox() const override{
return bbox;
}
SurfaceInteraction Sample(const glm::vec2& uv) const override{
return GeometricInteraction { Q + uv.x * u + uv.y * v, normal };
}
float Area() const override{
return glm::length(glm::cross(u, v));
}
float PDF([[maybe_unused]] const GeometricInteraction& interaction) const override{
return 1.0f / Area();
}
float PDF(const GeometricInteraction& interaction, const Ray& ray) const override{
glm::vec3 to_shape = interaction.p - ray.origin;
float dist_squared = glm::dot(to_shape, to_shape);
float light_cosine = std::abs(glm::dot(-ray.dir, interaction.n));
float area = Area();
if(area == 0)return 0;
return dist_squared / (light_cosine * area);
}
private:
static bool is_interior(float a, float b){
return a >= 0 && a <= 1 && b >= 0 && b <= 1;
}
glm::vec3 Q;
glm::vec3 u;
glm::vec3 v;
glm::vec3 normal;
float D;
glm::vec3 w;
AABB bbox;
};