-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlightSource.h
225 lines (170 loc) · 6.19 KB
/
lightSource.h
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#ifndef _LIGHTSOURCE_H
#define _LIGHTSOURCE_H
#include <vector>
#include "mathHelper.h"
class LightSource {
protected:
Point position;
Color color;
public:
LightSource () {};
LightSource ( Point position, Color color ) : position(position), color(color) {}
virtual std::vector<Point> getPos () = 0;
virtual Color getColor () = 0;
virtual bool reaches(Point p) = 0;
virtual double getAttenuation(Point p) = 0;
virtual int getNumSamplesOnSurface() = 0;
virtual double getMinDistance(Point origin) = 0;
// Ray Marching
virtual std::vector<Point> intersect ( Ray ray ) = 0;
};
class PointLight : public LightSource {
public:
PointLight( Point position, Color color ) : LightSource(position, color) {}
std::vector<Point> getPos () {
return std::vector<Point>(1,position);
}
Color getColor () {
return color;
}
// Point light can always be reached
bool reaches (Point p) {
return true;
}
// Point light attenuation = 1, none
double getAttenuation (Point p) {
return 1.0f;
}
int getNumSamplesOnSurface() {
return 1; // point light
}
std::vector<Point> intersect ( Ray ray ) {
// does nothing so far
std::vector<Point> intersections;
return intersections;
}
double getMinDistance(Point origin) {
return distance(origin,position);
}
};
class SpotLight : public LightSource {
Vector dir;
double angle;
double aExp; // attenuation exponent;
public:
SpotLight( Point position, Color color, Vector dir, double angle, double aExp = 0 ) : LightSource(position, color), dir(dir), angle(angle), aExp(aExp) {}
std::vector<Point> getPos () {
return std::vector<Point>(1,position);
}
Color getColor () {
return color;
}
// SpotLight might not be reached depending on the angle and direction
bool reaches (Point p) {
Vector vObj(position, p, true);
double cosa = dot(vObj, dir);
return (cosa >= std::cos(angle * PI / 180.0f));
}
double getAttenuation (Point p) {
Vector vObj(position, p, true);
return std::pow ( dot(vObj, dir), aExp );
}
int getNumSamplesOnSurface() {
return 1; // point light
}
// This intersection will be used for the ray marching,
// based on http://www.geometrictools.com/Documentation/IntersectionLineCone.pdf
std::vector<Point> intersect ( Ray ray ) {
std::vector<Point> intersections;
Point origin = ray.getOrigin();
Vector direction = ray.getDirection();
normalize(direction);
// here we will turn some vectors in matrixes for calculations
double deltaVals[] = {origin.x-position.x,origin.y-position.y,origin.z-position.z};
Matrix delta(3,1,deltaVals);
Matrix d(dir);
Matrix u(direction);
Matrix m = d * d.transpose() - std::pow(std::cos(angle * PI / 180.0f),2) * indentityMatrix();
Matrix mc2 = u.transpose() * m * u; // matrix with one row and one col
Matrix mc1 = u.transpose() * m * delta; // matrix with one row and one col
Matrix mc0 = delta.transpose() * m * delta; // matrix with one row and one col
double w1, w2;
double c0 = mc0[0];
double c1 = mc1[0];
double c2 = mc2[0];
double c1c1minusc0c2 = c1 * c1 - c0 * c2;
if ( c1c1minusc0c2 == 0 ) {
w1 = - c1 / c2;
// there was a intersection
if (w1 > 0.0) {
Point inter(origin.x + direction.x * w1, origin.y + direction.y * w1, origin.z + direction.z * w1);
// if we are hitting the actual cone
if (dot( dir , Vector(position, inter, true) ) >= 0)
intersections.push_back( inter );
}
} else if (c1c1minusc0c2 > 0) {
w1 = - (c1 - sqrt(c1c1minusc0c2)) / c2;
w2 = - (c1 + sqrt(c1c1minusc0c2)) / c2;
if (w1 > 0.0) {
Point inter1(origin.x + direction.x * w1, origin.y + direction.y * w1, origin.z + direction.z * w1);
if ( dot( dir , Vector(position, inter1, true) ) >= 0 )
intersections.push_back( inter1 );
}
if (w2 > 0.0) {
Point inter2(origin.x + direction.x * w2, origin.y + direction.y * w2, origin.z + direction.z * w2);
if ( dot( dir , Vector(position, inter2, true) ) >= 0 )
intersections.push_back( inter2 );
}
}
return intersections;
}
double getMinDistance(Point origin) {
return distance(origin,position);
}
};
class AreaLight : public LightSource {
// This will be the object our light source will be based on
Object *object;
int numSamples;
public:
AreaLight( Object *object, int numSamples ) : object(object), numSamples(numSamples) {
}
std::vector<Point> getPos () {
return object->samplePoints(numSamples);
}
Color getColor () {
return object->getEmissiveColor();
}
// can always be reached / function to remove in factor of class?
bool reaches (Point p) {
return true;
}
// Point light attenuation = 1, none
double getAttenuation (Point p) {
return 1.0f;
}
int getNumSamplesOnSurface() {
return numSamples;
}
double getMinDistance(Point origin) {
std::vector<Point> points = getPos();
double minDistance = distance(origin,points[0]);
for(std::vector<Point>::iterator it = points.begin() ; it < points.end() ; ++it) {
double newDistance = distance(origin, *it);
if (minDistance > newDistance) {
minDistance = newDistance;
}
}
return minDistance;
}
// does the Ray ray intersect with this light (for ray marching only, here not usable?)
std::vector<Point> intersect ( Ray ray ) {
// TODO: this function might need to change, should it only return one value?
// the the calls to it for a spot light will change
//object->intersect(ray);
// does nothing so far
std::vector<Point> intersections;
return intersections;
}
};
#endif