· 6 years ago · Dec 12, 2019, 04:40 PM
1#ifndef AABB_H
2#define AABB_H
3
4#include <math/RTMath.h>
5#include <array>
6#include <vector>
7#include <iostream>
8#include <limits>
9#include <Vertex.h>
10#include <math/MathHelpers.h>
11#include <ContributionResult.h>
12#include <Ray.h>
13
14namespace RT
15{
16 class Mesh;
17 class Model;
18
19 template<unsigned Dim, typename T>
20 class AABB
21 {
22 public:
23 using Vector = Vector<Dim, T>;
24 using Matrix = Matrix<Dim + 1, Dim + 1, T>;
25 using Type = T;
26 static auto constexpr getDim() { return Dim; }
27 static const auto NUM_VERTS = 1 << Dim;
28 AABB() = default;
29 AABB(AABB const & other) = default;
30 AABB& operator=(AABB const & other) = default;
31 ~AABB() = default;
32 AABB(Vector const & min, Vector const & max) :
33 _min(min),
34 _max(max)
35 {}
36 explicit AABB(Model const & model)
37 {
38 for (auto const & m : model.meshes()) {
39 unify(m->aabb());
40 }
41 }
42 explicit AABB(Mesh const & mesh) :
43 AABB(mesh.vertices().begin(), mesh.vertices().end())
44 {
45 }
46 AABB(Vertex const * begin, Vertex const * const end)
47 {
48 while (begin != end) {
49 update((begin++)->position());
50 }
51 }
52 AABB(AABB const & other, const Matrix & transform)
53 {
54 ComputeFromTransform<NUM_VERTS - 1>::call(transform, other, *this);
55 }
56 AABB(Vector const * begin, Vector const * const end)
57 {
58 while (begin != end) {
59 update(*begin++);
60 }
61 }
62 auto const & min() const
63 {
64 return _min;
65 }
66 auto const & max() const
67 {
68 return _max;
69 }
70 auto & min()
71 {
72 return _min;
73 }
74 auto & max()
75 {
76 return _max;
77 }
78 auto update(Vector const & vec)
79 {
80 _min.minimize(vec);
81 _max.maximize(vec);
82 }
83 auto contains(AABB const & other) const
84 {
85 return _min <= other._min && _max >= other._max;
86 }
87 auto fullyContains(AABB const & other) const
88 {
89 return _min < other._min && _max > other._max;
90 }
91 auto contains(Vector const & p) const
92 {
93 return _min <= p && _max >= p;
94 }
95 auto fullyContains(Vector const & p) const
96 {
97 return _min < p && _max > p;
98 }
99 auto intersects(AABB const & other) const
100 {
101 return _max >= other._min && _min <= other._max;
102 }
103 auto intersects(AABB const & moving, Vector const & v, Vector const & v_inv, T& t_min) const
104 {
105 t_min = static_cast<T>(0);
106 auto t_max = static_cast<T>(1);
107 return intersects(moving) || updateSlab(moving, v, v_inv, t_min, t_max);
108 }
109 template<unsigned i>
110 auto intersectSlab(AABB const & b, Vector const & v, Vector const & v_inv, T& t_min, T& t_max) const
111 {
112 if (v.at<i>() == static_cast<T>(0) && (b._min.at<i>() > _max.at<i>() || b._max.at<i>() < _min.at<i>())) {
113 return false;
114 }
115 else if (v.at<i>() < static_cast<T>(0)) {
116 if (b._max.at<i>() < _min.at<i>()) return false;
117 if (_max.at<i>() < b._min.at<i>()) maximize((_max.at<i>() - b._min.at<i>()) * v_inv.at<i>(), t_min);
118 if (b._max.at<i>() > _min.at<i>()) minimize((_min.at<i>() - b._max.at<i>()) * v_inv.at<i>(), t_max);
119 }
120 else {
121 if (b._min.at<i>() > _max.at<i>()) return false;
122 if (b._max.at<i>() < _min.at<i>()) maximize((_min.at<i>() - b._max.at<i>()) * v_inv.at<i>(), t_min);
123 if (_max.at<i>() > b._min.at<i>()) minimize((_max.at<i>() - b._min.at<i>()) * v_inv.at<i>(), t_max);
124 }
125 return t_min <= t_max;
126 }
127 template<unsigned i = Dim - 1u>
128 auto updateSlab(AABB const & b, Vector const & v, Vector const & v_inv, T& t_min, T& t_max) const
129 {
130 return intersectSlab<i>(b, v, v_inv, t_min, t_max) && updateSlab<i - 1>(b, v, v_inv, t_min, t_max);
131 }
132 template<>
133 auto updateSlab<0>(AABB const & b, Vector const & v, Vector const & v_inv, T& t_min, T& t_max) const
134 {
135 return intersectSlab<0>(b, v, v_inv, t_min, t_max);
136 }
137 auto union_(AABB const & other) const
138 {
139 return AABB(minimum(_min, other._min), maximum(_max, other._max));
140 }
141 auto intersection(AABB const & other) const
142 {
143 return AABB(maximum(_min, other._min), minimum(_max, other._max));
144 }
145 auto& unify(AABB const & other)
146 {
147 _min.minimize(other._min);
148 _max.maximize(other._max);
149 return *this;
150 }
151 auto& intersect(AABB const & other)
152 {
153 _min.maximize(other._min);
154 _max.minimize(other._max);
155 return *this;
156 }
157 auto valid() const
158 {
159 return _max >= _min;
160 }
161 auto minVec(Vector const & p) const
162 {
163 return _min - p;
164 }
165 auto maxVec(Vector const & p) const
166 {
167 return p - _max;
168 }
169 auto distToBorderForPointInside(Vector const & p) const
170 {
171 return std::min(minReduce(abs(minVec(p))), minReduce(abs(maxVec(p))));
172 }
173 auto distToBorder(Vector const & p) const
174 {
175 return contains(p) ? distToBorderForPointInside(p) : std::sqrt(minSquaredDist(p));
176 }
177 auto cost(AABB const & other) const
178 {
179 return union_(other).squaredSize() - squaredSize();
180 }
181 auto intersect(Ray<Dim, T> const & ray, T& t_min) const
182 {
183 T t_max;
184 return computeIntersect(ray, t_min, t_max);
185 }
186 template<unsigned i>
187 auto intersectSlab(Vector const & v, Ray<Dim, T> const & ray) const
188 {
189 return (v.at<i>() - ray.origin().at<i>()) * ray.invDir().at<i>();
190 }
191 template<unsigned i>
192 auto intersectSlab(Ray<Dim, T> const & ray, T& t_near, T& t_far) const
193 {
194 t_near = intersectSlab<i>(_max, ray);
195 t_far = intersectSlab<i>(_min, ray);
196 if (t_far < t_near) Algorithm::swap(t_far, t_near);
197 }
198 template<unsigned i>
199 auto updateSlabs(Ray<Dim, T> const & ray, T& t_min, T& t_max) const
200 {
201 T t_near, t_far;
202 intersectSlab<i>(ray, t_near, t_far);
203 return minimize(t_far, t_max) >= static_cast<T>(0) && maximize(t_near, t_min) <= t_max;
204 }
205 template<>
206 auto updateSlabs<Dim - 1>(Ray<Dim, T> const & ray, T& t_min, T& t_max) const
207 {
208 intersectSlab<Dim - 1>(ray, t_min, t_max);
209 return t_max >= static_cast<T>(0);
210 }
211 template<unsigned i = Dim - 1>
212 auto computeIntersect(Ray<Dim, T> const & ray, T& t_min, T& t_max) const
213 {
214 return updateSlabs<i>(ray, t_min, t_max) && computeIntersect<i - 1>(ray, t_min, t_max);
215 }
216 template<>
217 auto computeIntersect<0>(Ray<Dim, T> const & ray, T& t_min, T& t_max) const
218 {
219 return updateSlabs<0>(ray, t_min, t_max);
220 }
221 auto vertices() const
222 {
223 std::array<Vector, NUM_VERTS> vertices;
224 FillArray<NUM_VERTS - 1>::call(*this, vertices);
225 return vertices;
226 }
227 template<unsigned count>
228 static auto fromTransform(Vector const * first, Matrix const & transform)
229 {
230 Vector verts[count];
231 FillVerts<count - 1u>::call(first, transform, verts);
232 return fromVertices<count>(verts);
233 }
234 template<unsigned i>
235 static auto fillVerts(Vector const * first, Matrix const & transform, Vector* res)
236 {
237 *(res + i) = (transform * *(first + i)).toCartesian();
238 }
239 template<unsigned i>
240 struct FillVerts
241 {
242 static auto call(Vector const * first, Matrix const & transform, Vector* res)
243 {
244 fillVerts<i>(first, transform, res);
245 FillVerts<i - 1u>::call(first, transform, res);
246 }
247 };
248 template<>
249 struct FillVerts<0>
250 {
251 static auto call(Vector const * first, Matrix const & transform, Vector* res)
252 {
253 fillVerts<0>(first, transform, res);
254 }
255 };
256 template<unsigned count>
257 static auto fromVertices(Vector const * first)
258 {
259 AABB ret;
260 ComputeFromVertices<count - 1>::call(first, ret);
261 return ret;
262 }
263 auto centerTimesTwo() const
264 {
265 return _min + _max;
266 }
267 auto center() const
268 {
269 return centerTimesTwo() * static_cast<T>(0.5);
270 }
271 auto center(unsigned const & axis) const
272 {
273 return (_min[axis] + _max[axis]) * static_cast<T>(0.5);
274 }
275 template<unsigned axis>
276 auto center() const
277 {
278 return (_min.at<axis>() + _max.at<axis>()) * static_cast<T>(0.5);
279 }
280 auto extent() const
281 {
282 return _max - _min;
283 }
284 auto halfExtent(Vector const & center) const
285 {
286 return _max - center;
287 }
288 auto halfExtent() const
289 {
290 return halfExtent(center());
291 }
292 struct CenterExtent
293 {
294 Vector _center;
295 Vector _halfExtent;
296 };
297 CenterExtent centerExtent() const
298 {
299 auto c = center();
300 return { c, halfExtent(c) };
301 }
302 auto size() const
303 {
304 return extent().length();
305 }
306 auto squaredSize() const
307 {
308 return extent().squaredLength();
309 }
310 auto largerThan(AABB const & other) const
311 {
312 return squaredSize() > other.squaredSize();
313 }
314 auto volume() const
315 {
316 return extent().volume();
317 }
318 auto closestPoint(Vector const & point) const
319 {
320 return clamp(point, _min, _max);
321 }
322 template<unsigned index>
323 auto squaredDistToVertex(Vector const & point) const
324 {
325 static_assert(index < NUM_VERTS, "Invalid index");
326 return squaredDistance(point, vertex<index>());
327 }
328 auto minSquaredDist(Vector const & point) const
329 {
330 auto dist = static_cast<T>(0);
331 computeMinSquaredDist(point, dist);
332 return dist;
333 }
334 auto maxSquaredDist(Vector const & point) const
335 {
336 return maxSquaredDist(minVec(point), maxVec(point));
337 }
338 static_assert(std::numeric_limits<float>::is_iec559, "Division by zero not supported on this platform.");
339 template<typename T>
340 auto contributes(Vector const & p_eye, T const & alpha, T const & max_squared_size) const
341 {
342 return max_squared_size / minSquaredDist(p_eye) > alpha;
343 }
344 template<typename T>
345 auto contributes(Vector const & p_eye, T const & alpha) const
346 {
347 return contributes(p_eye, alpha, squaredSize());
348 }
349 template<typename T>
350 auto fullyContributes(Vector const & p_eye, T const & alpha, T const & min_squared_size) const
351 {
352 return min_squared_size / maxSquaredDist(p_eye) > alpha;
353 }
354 template<typename T>
355 auto fullyContributes(Vector const & p_eye, T const & alpha) const
356 {
357 return fullyContributes(p_eye, alpha, squaredSize());
358 }
359 template<typename T>
360 ContribResult computeContribution(Vector const & p_eye, T const & alpha, T const & min_squared_size, T const & max_squared_size) const
361 {
362 auto min_vec = minVec(p_eye);
363 auto max_vec = maxVec(p_eye);
364 if (max_squared_size / minSquaredDist(p_eye, min_vec, max_vec) > alpha) {
365 return min_squared_size / maxSquaredDist(min_vec, max_vec) > alpha ? ContributionResult::INSIDE : ContributionResult::INTERSECTING;
366 }
367 return ContributionResult::OUTSIDE;
368 }
369 auto longestAxis() const
370 {
371 return extent().longestAxis();
372 }
373 friend auto& operator << (std::ostream& os, AABB const & aabb)
374 {
375 os << "AABB [ " << aabb.min() << " " << aabb.max() << " ]";
376 return os;
377 }
378 static auto minMemOffset() { return offsetof(AABB, _min); }
379 static auto maxMemOffset() { return offsetof(AABB, _max); }
380 private:
381 Vector _min = std::numeric_limits<T>::max();
382 Vector _max = std::numeric_limits<T>::lowest();
383
384 template<unsigned i>
385 auto fillFromTransform(Matrix const & transform, AABB const & other)
386 {
387 update((transform * other.vertex<i>()).reduce<>());
388 }
389 template<unsigned i>
390 struct ComputeFromTransform
391 {
392 static auto call(Matrix const & transform, AABB const & other, AABB& res)
393 {
394 res.fillFromTransform<i>(transform, other);
395 ComputeFromTransform<i - 1>::call(transform, other, res);
396 }
397 };
398 template<>
399 struct ComputeFromTransform<0>
400 {
401 static auto call(Matrix const & transform, AABB const & other, AABB& res)
402 {
403 res.fillFromTransform<0>(transform, other);
404 }
405 };
406 template<unsigned i>
407 auto fillArray(std::array<Vector, NUM_VERTS>& res) const
408 {
409 res[i] = vertex<i>();
410 }
411 template<unsigned i>
412 struct FillArray
413 {
414 static auto call(AABB const & aabb, std::array<Vector, NUM_VERTS>& res)
415 {
416 aabb.fillArray<i>(res);
417 FillArray<i - 1>::call(aabb, res);
418 }
419 };
420 template<>
421 struct FillArray<0>
422 {
423 static auto call(AABB const & aabb, std::array<Vector, NUM_VERTS>& res)
424 {
425 aabb.fillArray<0>(res);
426 }
427 };
428 template<unsigned i>
429 auto fillFromVertices(Vector const * first)
430 {
431 update(*(first + i));
432 }
433 template<unsigned i>
434 struct ComputeFromVertices
435 {
436 static auto call(Vector const * first, AABB& res)
437 {
438 res.fillFromVertices<i>(first);
439 ComputeFromVertices<i - 1>::call(first, res);
440 }
441 };
442 template<>
443 struct ComputeFromVertices<0>
444 {
445 static auto call(Vector const * first, AABB& res)
446 {
447 res.fillFromVertices<0>(first);
448 }
449 };
450 template<unsigned i>
451 auto fillMinSquaredDist(Vector const & point, T& dist) const
452 {
453 if (point.at<i>() < _min.at<i>()) {
454 dist += MathHelpers::pow<2>(_min.at<i>() - point.at<i>());
455 }
456 else if (point.at<i>() > _max.at<i>()) {
457 dist += MathHelpers::pow<2>(point.at<i>() - _max.at<i>());
458 }
459 }
460 template<unsigned i = Dim - 1>
461 auto computeMinSquaredDist(Vector const & point, T& dist) const
462 {
463 fillMinSquaredDist<i>(point, dist);
464 computeMinSquaredDist<i - 1>(point, dist);
465 }
466 template<>
467 auto computeMinSquaredDist<0>(Vector const & point, T& dist) const
468 {
469 fillMinSquaredDist<0>(point, dist);
470 }
471 template<unsigned i>
472 auto fillMinSquaredDist(Vector const & point, Vector const & min_vec, Vector const & max_vec, T& dist) const
473 {
474 if (min_vec.at<i>() > static_cast<T>(0)) {
475 dist += MathHelpers::pow<2>(min_vec.at<i>());
476 }
477 else if (max_vec.at<i>() > static_cast<T>(0)) {
478 dist += MathHelpers::pow<2>(max_vec.at<i>());
479 }
480 }
481 template<unsigned i = Dim - 1>
482 auto computeMinSquaredDist(Vector const & point, Vector const & min_vec, Vector const & max_vec, T& dist) const
483 {
484 fillMinSquaredDist<i>(point, min_vec, max_vec, dist);
485 computeMinSquaredDist<i - 1>(point, min_vec, max_vec, dist);
486 }
487 template<>
488 auto computeMinSquaredDist<0>(Vector const & point, Vector const & min_vec, Vector const & max_vec, T& dist) const
489 {
490 fillMinSquaredDist<0>(point, min_vec, max_vec, dist);
491 }
492 template<unsigned index>
493 auto vertex() const
494 {
495 Vector res;
496 GetVertex<index>::call(*this, res);
497 return res;
498 }
499 template<unsigned i, unsigned axis>
500 auto fillVertex(Vector& res) const
501 {
502 res.at<axis>() = (i & (1 << axis)) ? _max.at<axis>() : _min.at<axis>();
503 }
504 template<unsigned i, unsigned axis = Dim - 1u>
505 struct GetVertex
506 {
507 static auto call(AABB const & aabb, Vector& res)
508 {
509 aabb.fillVertex<i, axis>(res);
510 GetVertex<i, axis - 1u>::call(aabb, res);
511 }
512 };
513 template<unsigned i>
514 struct GetVertex<i, 0>
515 {
516 static auto call(AABB const & aabb, Vector& res)
517 {
518 aabb.fillVertex<i, 0>(res);
519 }
520 };
521 auto minSquaredDist(Vector const & point, Vector const & min_vec, Vector const & max_vec) const
522 {
523 auto dist = static_cast<T>(0);
524 computeMinSquaredDist(point, min_vec, max_vec, dist);
525 return dist;
526 }
527 auto maxSquaredDist(Vector const & min_vec, Vector const & max_vec) const
528 {
529 return maximum(abs(min_vec), abs(max_vec)).squaredLength();
530 }
531 };
532
533 using AABB2f = AABB<2, float>;
534 using AABB3f = AABB<3, float>;
535 using AABB4f = AABB<4, float>;
536
537 using AABB2i = AABB<2, int>;
538 using AABB3i = AABB<3, int>;
539 using AABB4i = AABB<4, int>;
540
541 using AABB2u = AABB<2, unsigned>;
542 using AABB3u = AABB<3, unsigned>;
543 using AABB4u = AABB<4, unsigned>;
544}
545
546#endif // !AABB_H
547#ifndef ADAPTIVEDOFSYSTEM_H
548#define ADAPTIVEDOFSYSTEM_H
549
550#include <renderer/Renderer.h>
551#include <FixedTimestepSystem.h>
552
553namespace RT
554{
555 class AdaptiveDofSystem : public FixedTimestepSystem
556 {
557 public:
558 AdaptiveDofSystem(Renderer& renderer, GraphicsSettings & gs):
559 _renderer(renderer),
560 _gs(gs)
561 {
562 _dt = 1.f / 20.f;
563 }
564 virtual void updateSystem() override
565 {
566 auto ray = _renderer.rayFromUV(0.5f);
567 if (auto res = _renderer.findNearestPrimitive(ray)) {
568 _gs.setDofCenter(lerp(dot(_renderer.viewMatrix().row<2>(), ray.pos(res.minTMin()).toHomogeneous()), _gs.dofCenter(), _lerpFactor));
569 }
570 }
571 virtual unsigned getID() override
572 {
573 return 1024;
574 }
575 virtual const char* getName() override
576 {
577 return "AdaptiveDofSystem";
578 }
579 private:
580 Renderer& _renderer;
581 GraphicsSettings & _gs;
582 float _lerpFactor = 0.9f;
583 };
584}
585
586#endif
587#ifndef ALGORITHM_H
588#define ALGORITHM_H
589
590#include <functional>
591#include <type_traits>
592
593namespace RT
594{
595 class Algorithm
596 {
597 public:
598 Algorithm() = delete;
599 template<typename T>
600 static auto ptrDiff(T const * const begin, T const * const end)
601 {
602 return end - begin;
603 }
604 template<typename T>
605 static auto midPtr(T* const begin, long long const & ptr_diff)
606 {
607 return begin + ptr_diff / 2u;
608 }
609 template<typename T>
610 static auto midPtr(T* const begin, T* const end)
611 {
612 return midPtr(begin, ptrDiff(begin, end));
613 }
614 static auto continueSplit(long long const & ptr_diff)
615 {
616 return ptr_diff > 1u;
617 }
618 template<typename T>
619 static auto continueSplit(T const * const begin, T const * const end)
620 {
621 return continueSplit(ptrDiff(begin, end));
622 }
623 template<typename T>
624 static auto swap(T& a, T& b)
625 {
626 auto temp = a;
627 a = b;
628 b = temp;
629 }
630 template<typename T, typename Pred>
631 static auto partition(T* begin, T const * const end, Pred&& pred)
632 {
633 auto* mid = begin;
634 while (begin != end) {
635 pred(*begin) ? swap(*begin++, *mid++) : ++begin;
636 }
637 return mid;
638 }
639 template<typename T>
640 static auto isPalindrom(T const * begin, T const * end)
641 {
642 return isPalindrom(begin, end, std::equal_to<T>());
643 }
644 template<typename T, typename Pred>
645 static auto isPalindrom(T const * begin, T const * end, Pred&& pred)
646 {
647 auto const * const mid = midPtr(begin, end);
648 while (begin != mid && end != mid) {
649 if (!pred(*begin++, *--end)) {
650 return false;
651 }
652 }
653 return true;
654 }
655 template<typename T>
656 static auto compare(T const * a, T const * b, size_t len)
657 {
658 return compare(a, b, len, std::equal_to<T>());
659 }
660 template<typename T, typename Comp>
661 static auto compare(T const * a, T const * b, size_t len, Comp&& comp)
662 {
663 auto const * const end = a + len;
664 while (a != end) {
665 if (!comp(*a++, *b++)) {
666 return false;
667 }
668 }
669 return true;
670 }
671 /**
672 * Same as partition, but returns the midpoint if the range cannot be split based on pred.
673 */
674 template<typename T, typename Pred>
675 static auto partitionForceSplit(T* const begin, T* const end, Pred&& pred)
676 {
677 auto* const mid = partition(begin, end, pred);
678 return mid == begin || mid == end ? midPtr(begin, end) : mid;
679 }
680 /**
681 * Update peak
682 */
683 template<typename T, typename Type>
684 static void updatePeak(T const & prev_peak_val, Type& peak, T const & val, Type const & data)
685 {
686 updatePeak(prev_peak_val, peak, val, data, std::less<T>());
687 }
688 template<typename T, typename Type, typename Compare>
689 static void updatePeak(T const & prev_peak_val, Type& peak, T const & val, Type const & data, Compare&& comp)
690 {
691 if (comp(val, prev_peak_val)) {
692 peak = data;
693 }
694 }
695 template<typename T>
696 static auto mergeSort(T* const begin, T* const end)
697 {
698 mergeSort(begin, end, std::less<T>());
699 }
700 template<typename T, typename Compare>
701 static auto mergeSort(T* const begin, T* const end, Compare&& comp)
702 {
703 auto ptr_diff = ptrDiff(begin, end);
704 if (ptr_diff) {
705 auto* temp = new T[ptr_diff];
706 mergeSort(begin, end, temp, comp);
707 delete[] temp;
708 }
709 }
710 template<typename T>
711 static auto copyRange(T const * begin, T const * const end, T* dst)
712 {
713 copyRangeOverwrite(begin, end, dst);
714 }
715 template<typename T>
716 static auto copyRangeOverwrite(T const * begin, T const * const end, T*& dst)
717 {
718 while (begin != end) {
719 *dst++ = *begin++;
720 }
721 }
722 template<typename T>
723 static void quickSortLessEqual(T* const begin, T* const end)
724 {
725 quickSort(begin, end, std::less_equal<T>());
726 }
727 template<typename T>
728 static void quickSortGreaterEqual(T* const begin, T* const end)
729 {
730 quickSort(begin, end, std::greater_equal<T>());
731 }
732 template<typename T>
733 struct DefaultVal
734 {
735 auto const & operator() (T const & t) { return t; }
736 };
737 template<typename T>
738 static auto mean(T const* begin, T const * const end)
739 {
740 return mean(begin, end, DefaultVal<T>());
741 }
742 template<typename T, typename GetVal, typename RetVal = float>
743 static auto mean(T const* begin, T const * const end, GetVal&& get_val)
744 {
745 static_assert(std::is_same<RetVal, float>::value || std::is_same<RetVal, double>::value, "RetVal must be float or double");
746 auto const denom = static_cast<RetVal>(end - begin);
747 auto res = get_val(*begin++) / denom;
748 while (begin != end) {
749 res += get_val(*begin++) / denom;
750 }
751 return res;
752 }
753 template<typename T, unsigned index>
754 struct Copy
755 {
756 static void call(T const * src, T* dst)
757 {
758 dst[index] = src[index];
759 Copy<T, index - 1u>::call(src, dst);
760 }
761 };
762 template<typename T>
763 struct Copy<T, 0>
764 {
765 static void call(T const * src, T* dst)
766 {
767 *dst = *src;
768 }
769 };
770 private:
771 template<typename T, typename Compare>
772 static void mergeSort(T* const begin, T* const end, T* temp, Compare&& comp)
773 {
774 auto ptr_diff = ptrDiff(begin, end);
775 if (continueSplit(ptr_diff)) {
776 auto * const mid = midPtr(begin, ptr_diff);
777 mergeSort(begin, mid, temp, comp);
778 mergeSort(mid, end, temp, comp);
779 merge(begin, mid, end, temp, comp);
780 }
781 }
782 template<typename T, typename Compare>
783 static auto merge(T* begin, T const * const mid, T const * const end, T* temp, Compare&& comp)
784 {
785 copyRange(begin, end, temp);
786 auto* right_temp = temp + ptrDiff(begin, mid);
787 auto const * const left_temp_end = right_temp;
788 auto const * const right_temp_end = temp + ptrDiff(begin, end);
789 mergeResults(temp, right_temp, right_temp_end, begin, comp);
790 copyRangeOverwrite(temp, left_temp_end, begin);
791 copyRangeOverwrite(right_temp, right_temp_end, begin);
792 }
793 template<typename T, typename Compare>
794 static auto mergeResults(T*& begin, T*& mid, T const * const end, T*& dst, Compare&& comp)
795 {
796 auto const * const mid_ptr = mid;
797 while (begin != mid_ptr && mid != end) {
798 *dst++ = comp(*begin, *mid) ? *begin++ : *mid++;
799 }
800 }
801 template<typename T, typename Compare>
802 static void quickSort(T* const begin, T* const end, Compare&& comp)
803 {
804 if (begin < end) {
805 auto const pivot = *(end - 1);
806 auto* const mid = partition(begin, end, [&](const T& a) {
807 return comp(a, pivot);
808 });
809 quickSort(begin, mid - 1, comp);
810 quickSort(mid, end, comp);
811 }
812 }
813 };
814}
815
816#endif // !ALGORITHM_H
817#ifndef BVTREE_H
818#define BVTREE_H
819
820#include <CullingParams.h>
821#include <Ray.h>
822#include <functional>
823#include <Primitive.h>
824#include <StackTrivial.h>
825#include <CsmTree.h>
826#include <BVTreeNode.h>
827#include <BVTreeNodePool.h>
828
829namespace RT
830{
831 class BVTree
832 {
833 public:
834 using BV = typename Primitive::BV;
835 using Type = typename Primitive::Type;
836 using Vector = Vector<BV::getDim(), Type>;
837 using Matrix = Matrix<BV::getDim() + 1, BV::getDim() + 1, Type>;
838 using Ray = Ray<BV::getDim(), Type>;
839 using IntersectRayResult = IntersectRayResult<Type, Matrix>;
840 BVTree() = delete;
841 BVTree(Primitive * const * begin, Primitive * const * const end) :
842 _nodePool(Algorithm::ptrDiff(begin, end))
843 {
844 StackTrivial<BVTreeNode::PrimitiveInfo> infos;
845 infos.reserve(Algorithm::ptrDiff(begin, end));
846 while (begin != end) {
847 infos.push_back_unchecked(*begin++);
848 }
849 _root = _nodePool.createNode(infos);
850 }
851 BVTree(BVTree const & other) = delete;
852 BVTree& operator=(BVTree const & other) = delete;
853 BVTree(BVTree&& other) = default;
854 BVTree& operator=(BVTree&& other) = default;
855 auto cullVisiblePrimitives(CullingParams const & cp, Callback::CbFunc const & on_intersect_frustum, Callback::CbFunc const & on_became_fully_visible, Callback::CbFunc const & on_render) const
856 {
857 _root->cullVisiblePrimitives(cp, { on_intersect_frustum, on_became_fully_visible, on_render });
858 }
859 auto cullVisiblePrimitivesWithPlaneMasking(CullingParams const & cp, Callback::CbFunc const & on_intersect_frustum, Callback::CbFunc const & on_became_fully_visible, Callback::CbFunc const & on_render) const
860 {
861 IntersectedPlanes out(0b11111111);
862 _root->cullVisiblePrimitives(cp, out, { on_intersect_frustum, on_became_fully_visible, on_render });
863 }
864 auto intersectNested(BV const & bv, Vector const & v, Vector const & v_inv, Type& min_t_min, std::function<void(Primitive const *)> const & intersect_nested) const
865 {
866 _root->intersectNested(bv, v, v_inv, min_t_min, intersect_nested);
867 }
868 auto intersectPrimitives(BV const & bv, Vector const & v, Vector const & v_inv, Type& min_t_min, Primitive const *& nearest)
869 {
870 _root->intersectPrimitives(bv, v, v_inv, min_t_min, nearest);
871 }
872 auto findNearest(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive const *& nearest, Type& nearest_t, Matrix const *& nearest_transform) const
873 {
874 _root->findNearest(ray_local, ray_world, transform, nearest, nearest_t, nearest_transform);
875 }
876 auto findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res) const
877 {
878 _root->findNearestPrecise(ray_local, ray_world, transform, res);
879 }
880 auto findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive* parent, IntersectRayResult& res, Primitive*& parent_res) const
881 {
882 _root->findNearestPrecise(ray_local, ray_world, transform, parent, res, parent_res);
883 }
884 auto findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res, StackTrivial<BVTreeNode::NodePtr>& stack) const
885 {
886 stack.push_back(_root);
887 while (stack.size()) {
888 stack.pop_back()->findNearestPrecise(ray_local, ray_world, transform, res, stack);
889 }
890 }
891 auto findNearestNested(Ray const & ray, IntersectRayResult& res, std::function<void(Primitive*)> const & find_nested) const
892 {
893 _root->findNearestNested(ray, res, find_nested);
894 }
895 auto findNearestNested(Ray const & ray, IntersectRayResult& res, StackTrivial<BVTreeNode::NodePtr>& stack, std::function<void(Primitive*)> const & find_nested) const
896 {
897 stack.push_back(_root);
898 while (stack.size()) {
899 stack.pop_back()->findNearestNested(ray, res, find_nested, stack);
900 }
901 }
902 auto queryRange(BV const & bv, Callback::CbFunc const & cb) const
903 {
904 _root->queryRange(bv, cb);
905 }
906 auto queryRange(BV const & bv, CullingParams const & cp, Callback::CbFunc const & cb) const
907 {
908 _root->queryRange(bv, cp, cb);
909 }
910 auto sizeInBytes() const
911 {
912 return _root->sizeInBytes();
913 }
914 auto sizeInKiloBytes() const
915 {
916 return static_cast<float>(sizeInBytes()) / 1024.f;
917 }
918 auto sizeInMegaBytes() const
919 {
920 return sizeInKiloBytes() / 1024.f;
921 }
922 auto sizeInGigaBytes() const
923 {
924 return sizeInMegaBytes() / 1024.f;
925 }
926 auto bv() const
927 {
928 return _root->getBV();
929 }
930 auto const & root() const
931 {
932 return _root;
933 }
934 auto countNodes(unsigned& internal_nodes, unsigned& leaf_nodes) const
935 {
936 internal_nodes = 0;
937 leaf_nodes = 0;
938 _root->countNodes(internal_nodes, leaf_nodes);
939 }
940 auto insert(Primitive* const & primitive)
941 {
942 _root->insert(primitive, _root, _nodePool);
943 }
944 auto minHeight() const
945 {
946 return _root->minHeight(0);
947 }
948 auto maxHeight() const
949 {
950 return _root->maxHeight(0);
951 }
952 auto averageHeight() const
953 {
954 unsigned num_internals, num_leafs;
955 countNodes(num_internals, num_leafs);
956 auto avg_height = 0.f;
957 _root->averageHeight(0.f, 1.f / static_cast<float>(num_leafs), avg_height);
958 return avg_height;
959 }
960 auto remove(Primitive* const & primitive)
961 {
962 bool deleted = false;
963 deleted |= _root->remove(primitive, _root, _nodePool, deleted);
964 _root->recalculateDirty();
965 return deleted;
966 }
967 auto removeIfDoesNotFit(Primitive* const & primitive, BV const & bv_old)
968 {
969 bool deleted = false;
970 deleted |= _root->removeIfDoesNotFit(primitive, bv_old, nullptr, _root, _root, _nodePool, deleted);
971 _root->recalculateDirty();
972 return deleted;
973 }
974 auto reinsertIfDoesNotFit(Primitive* const & primitive, BV const & bv_old)
975 {
976 if (removeIfDoesNotFit(primitive, bv_old)) {
977 insert(primitive);
978 }
979 }
980 private:
981 BVTreeNodePool _nodePool;
982 BVTreeNode* _root;
983 };
984}
985
986#endif
987#ifndef BVTREEINTERNALNODE_H
988#define BVTREEINTERNALNODE_H
989
990#include <BVTreeNode.h>
991#include <Descendable.h>
992
993namespace RT
994{
995 class BVTreeInternalNode : public BVTreeNode
996 {
997 public:
998 BVTreeInternalNode(PrimitiveInfo* const begin, PrimitiveInfo* const end, BVTreeNodePool& node_pool);
999 virtual ~BVTreeInternalNode() = default;
1000 virtual void cullVisiblePrimitives(CullingParams const & cp, Callback const & cb) const override;
1001 virtual void cullVisiblePrimitives(CullingParams const & cp, IntersectedPlanes const & in, Callback const & cb) const override;
1002 virtual void cullContributingPrimitives(CullingParams const & cp, Callback const & cb) const override;
1003 virtual void cullAllPrimitives(Callback::CbFunc const & on_render) const override;
1004 virtual size_t sizeInBytes() const override;
1005 virtual void intersectNested(BV const & bv, Vector const & v, Vector const & v_inv, Type& min_t_min, std::function<void(Primitive const *)> const & intersect_nested) const override;
1006 virtual void intersectPrimitives(BV const & bv, Vector const & v, Vector const & v_inv, Type& min_t_min, Primitive const *& nearest) const override;
1007 virtual void countNodes(unsigned& internal_nodes, unsigned& leaf_nodes) const override;
1008 virtual void findNearest(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive const *& nearest, Type& nearest_t, Matrix const *& nearest_transform) const override;
1009 virtual void findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res) override;
1010 virtual void findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive* parent, IntersectRayResult& res, Primitive*& parent_res) override;
1011 virtual void findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res, StackTrivial<NodePtr>& stack) override;
1012 virtual void findNearestNested(Ray const & ray, IntersectRayResult& res, std::function<void(Primitive*)> const & find_nested) override;
1013 virtual void findNearestNested(Ray const & ray, IntersectRayResult& res, std::function<void(Primitive*)> const & find_nested, StackTrivial<NodePtr>& stack) override;
1014 virtual void queryRange(BV const & bv, Callback::CbFunc const & cb) const override;
1015 virtual void queryRange(BV const & bv, CullingParams const & cp, Callback::CbFunc const & cb) const override;
1016 virtual void queryContributing(CullingParams const & cp, Callback::CbFunc const & cb) const override;
1017 virtual void queryAll(Callback::CbFunc const & cb) const override;
1018 virtual BV getBV() const override;
1019 virtual Type minSquaredDist(Vector const & point) const override;
1020 virtual Type dist(Ray const & ray) const override;
1021 virtual void destroy(BVTreeNodePool& pool) override;
1022 virtual Type cost(BV const & bv) const override;
1023 virtual void insert(PrimitiveInfo const & info, NodePtr& this_ptr, BVTreeNodePool& node_pool) override;
1024 virtual bool remove(PrimitiveInfo const & info, NodePtr& this_ptr, BVTreeNodePool& node_pool, bool& deleted) override;
1025 virtual bool removeIfDoesNotFit(PrimitiveInfo const & info, BV const & bv_old, BVTreeNode const * parent, BVTreeNode const * root, NodePtr& this_ptr, BVTreeNodePool& node_pool, bool& deleted) override;
1026 virtual void destroyTree(StackTrivial<PrimitiveInfo>& primitives, BVTreeNodePool& node_pool) override;
1027 virtual DirtyInfo recalculateDirty() override;
1028 virtual size_t minHeight(size_t const & height) const override;
1029 virtual size_t maxHeight(size_t const & height) const override;
1030 virtual void averageHeight(float const & height, float const & inv_num_leafs, float& avg_height) const override;
1031 void insert(PrimitiveInfo const & pi);
1032 NodePtr& childToDescend(BV const & bv);
1033 void markAsDirty();
1034 bool isDirty() const;
1035 void rebuild(NodePtr& this_ptr, NodePtr child, BVTreeNodePool& node_pool);
1036 void collectFromChildren(DirtyInfo const & di);
1037 virtual void descendVisible(Descendable& other, CullingParams const & cp, Callback2 const & cb) override;
1038 virtual void descendVisible(CsmInternalNode& other, CullingParams const & cp, Callback2 const & cb) override;
1039 virtual void descendVisible(CsmLeafNode& other, CullingParams const & cp, Callback2 const & cb) override;
1040 virtual void descendContributing(Descendable& other, CullingParams const & cp, Callback2 const & cb) override;
1041 virtual void descendContributing(CsmInternalNode& other, CullingParams const & cp, Callback2 const & cb) override;
1042 virtual void descendContributing(CsmLeafNode& other, CullingParams const & cp, Callback2 const & cb) override;
1043 virtual void descendAll(Descendable& other, Callback2::CbFunc const & on_render) override;
1044 virtual void descendAll(CsmInternalNode& other, Callback2::CbFunc const & on_render) override;
1045 virtual void descendAll(CsmLeafNode& other, Callback2::CbFunc const & on_render) override;
1046 void recurseVisible(Descendable& other, CullingParams const & cp, Callback2 const & cb);
1047 void recurseContributing(Descendable& other, CullingParams const & cp, Callback2 const & cb);
1048 void recurseAll(Descendable& other, Callback2::CbFunc const & on_render);
1049 private:
1050 NodePtr _left, _right;
1051 BV _bv;
1052 Type _minSquaredSize, _maxSquaredSize;
1053 void recurseVisible(CullingParams const & cp, Callback const & cb) const;
1054 void recurseVisible(CullingParams const & cp, IntersectedPlanes const & ip, Callback const & cb) const;
1055 void recurseContributing(CullingParams const & cp, Callback const & cb) const;
1056 void recurseAll(Callback::CbFunc const & on_render) const;
1057 void recurseNearest(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive const *& nearest, Type& nearest_t, Matrix const *& nearest_transform) const;
1058 void recurseNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res);
1059 bool largerThan(BVTreeInternalNode const & other) const;
1060 void recurseQueryRange(BV const & bv, Callback::CbFunc const & cb) const;
1061 void recurseQueryRange(BV const & bv, CullingParams const & cp, Callback::CbFunc const & cb) const;
1062 void recurseQueryContributing(CullingParams const & cp, Callback::CbFunc const & cb) const;
1063 void recurseQueryAll(Callback::CbFunc const & cb) const;
1064 void init(PrimitiveInfo const * begin, PrimitiveInfo const * const end);
1065 bool contributes(CullingParams const & cp) const;
1066 bool fullyContributes(CullingParams const & cp) const;
1067 IntersectResult intersectFrustum(CullingParams const & cp) const;
1068 IntersectResult intersectFrustum(CullingParams const & cp, IntersectedPlanes const & in, IntersectedPlanes& out) const;
1069 ContribResult computeContribution(CullingParams const & cp) const;
1070 };
1071}
1072
1073#endif
1074#ifndef BVTREELEAFNODE_H
1075#define BVTREELEAFNODE_H
1076
1077#include <BVTreeNode.h>
1078#include <IntersectionTests.h>
1079
1080namespace RT
1081{
1082 class BVTreeLeafNode : public BVTreeNode
1083 {
1084 public:
1085 explicit BVTreeLeafNode(Primitive* const & primitive);
1086 virtual ~BVTreeLeafNode() = default;
1087 virtual void cullVisiblePrimitives(CullingParams const & cp, Callback const & cb) const override;
1088 virtual void cullVisiblePrimitives(CullingParams const & cp, IntersectedPlanes const & in, Callback const & cb) const override;
1089 virtual void cullContributingPrimitives(CullingParams const & cp, Callback const & cb) const override;
1090 virtual void cullAllPrimitives(Callback::CbFunc const & on_render) const override;
1091 virtual size_t sizeInBytes() const override;
1092 virtual void intersectNested(BV const & bv, Vector const & v, Vector const & v_inv, Type& min_t_min, std::function<void(Primitive const *)> const & intersect_nested) const override;
1093 virtual void intersectPrimitives(BV const & bv, Vector const & v, Vector const & v_inv, Type& min_t_min, Primitive const *& nearest) const override;
1094 virtual void countNodes(unsigned& internal_nodes, unsigned& leaf_nodes) const override;
1095 virtual void findNearest(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive const *& nearest, Type& nearest_t, Matrix const *& nearest_transform) const override;
1096 virtual void findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res) override;
1097 virtual void findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive* parent, IntersectRayResult& res, Primitive*& parent_res) override;
1098 virtual void findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res, StackTrivial<NodePtr>& stack) override;
1099 virtual void findNearestNested(Ray const & ray, IntersectRayResult& res, std::function<void(Primitive*)> const & find_nested) override;
1100 virtual void findNearestNested(Ray const & ray, IntersectRayResult& res, std::function<void(Primitive*)> const & find_nested, StackTrivial<NodePtr>& stack) override;
1101 virtual void queryRange(BV const & bv, Callback::CbFunc const & cb) const override;
1102 virtual void queryRange(BV const & bv, CullingParams const & cp, Callback::CbFunc const & cb) const override;
1103 virtual void queryContributing(CullingParams const & cp, Callback::CbFunc const & cb) const override;
1104 virtual void queryAll(Callback::CbFunc const & cb) const override;
1105 virtual BV getBV() const override;
1106 virtual Type minSquaredDist(Vector const & point) const override;
1107 virtual Type dist(Ray const & ray) const override;
1108 virtual void destroy(BVTreeNodePool& pool) override;
1109 virtual Type cost(BV const & bv) const override;
1110 virtual void insert(PrimitiveInfo const & info, NodePtr& this_ptr, BVTreeNodePool& node_pool) override;
1111 virtual bool remove(PrimitiveInfo const & info, NodePtr& this_ptr, BVTreeNodePool& node_pool, bool& deleted) override;
1112 virtual bool removeIfDoesNotFit(PrimitiveInfo const & info, BV const & bv_old, BVTreeNode const * parent, BVTreeNode const * root, NodePtr& this_ptr, BVTreeNodePool& node_pool, bool& deleted)override;
1113 virtual void destroyTree(StackTrivial<PrimitiveInfo>& primitives, BVTreeNodePool& node_pool) override;
1114 virtual DirtyInfo recalculateDirty() override;
1115 virtual size_t minHeight(size_t const & height) const override;
1116 virtual size_t maxHeight(size_t const & height) const override;
1117 virtual void averageHeight(float const & height, float const & inv_num_leafs, float& avg_height) const override;
1118 virtual void descendVisible(Descendable& other, CullingParams const & cp, Callback2 const & cb) override;
1119 virtual void descendVisible(CsmInternalNode& other, CullingParams const & cp, Callback2 const & cb) override;
1120 virtual void descendVisible(CsmLeafNode& other, CullingParams const & cp, Callback2 const & cb)override;
1121 virtual void descendContributing(Descendable& other, CullingParams const & cp, Callback2 const & cb) override;
1122 virtual void descendContributing(CsmInternalNode& other, CullingParams const & cp, Callback2 const & cb) override;
1123 virtual void descendContributing(CsmLeafNode& other, CullingParams const & cp, Callback2 const & cb) override;
1124 virtual void descendAll(Descendable& other, Callback2::CbFunc const & on_render) override;
1125 virtual void descendAll(CsmInternalNode& other, Callback2::CbFunc const & on_render) override;
1126 virtual void descendAll(CsmLeafNode& other, Callback2::CbFunc const & on_render) override;
1127 private:
1128 Primitive * _primitive;
1129 bool contributes(CullingParams const & cp) const;
1130 IntersectResult intersectFrustum(CullingParams const & cp) const;
1131 };
1132}
1133
1134#endif // !BVTreeLEAFNODE_H
1135#ifndef BVTREENODE_H
1136#define BVTREENODE_H
1137
1138#include <Primitive.h>
1139#include <math/RTMath.h>
1140#include <Callback.h>
1141#include <Descendable.h>
1142
1143namespace RT
1144{
1145 class CullingParams;
1146 class BVTreeInternalNode;
1147 class BVTreeLeafNode;
1148 class BVTreeNodePool;
1149
1150 class Callback;
1151
1152 class BVTreeNode : public Descendable
1153 {
1154 public:
1155 using BV = typename Primitive::BV;
1156 using Ray = typename Primitive::Ray;
1157 using Matrix = typename Primitive::Matrix;
1158 using Type = typename Primitive::Type;
1159 static auto const Dim = BV::getDim();
1160 using Vector = Vector<Dim, Type>;
1161 using IntersectRayResult = IntersectRayResult<Type, Matrix>;
1162
1163 class PrimitiveInfo
1164 {
1165 public:
1166 PrimitiveInfo(Primitive* const & p) :
1167 _primitive(p),
1168 _bv(p->bv()),
1169 _squaredSize(p->squaredSize())
1170 {
1171 }
1172 auto const & primitive() const { return _primitive; }
1173 auto const & bv() const { return _bv; }
1174 auto const & squaredSize() const { return _squaredSize; }
1175 private:
1176 Primitive* _primitive;
1177 BV _bv;
1178 Type _squaredSize;
1179 };
1180 class DirtyInfo
1181 {
1182
1183 public:
1184 DirtyInfo(BV const & bv, Type const & min_squared_size, Type const & max_squared_size) :
1185 _bv(bv),
1186 _minSquaredSize(min_squared_size),
1187 _maxSquaredSize(max_squared_size)
1188 {}
1189 auto const & bv() const { return _bv; }
1190 auto const & minSquaredSize() const { return _minSquaredSize; }
1191 auto const & maxSquaredSize() const { return _maxSquaredSize; }
1192 private:
1193 BV _bv;
1194 Type _minSquaredSize;
1195 Type _maxSquaredSize;
1196 };
1197 using NodePtr = BVTreeNode * ;
1198
1199 using CbIntersect = std::function<void(Primitive*, Primitive*)>;
1200 BVTreeNode() = default;
1201 virtual ~BVTreeNode() = default;
1202 virtual void cullVisiblePrimitives(CullingParams const & cp, Callback const & cb) const = 0;
1203 virtual void cullVisiblePrimitives(CullingParams const & cp, IntersectedPlanes const & in, Callback const & cb) const = 0;
1204 virtual void cullContributingPrimitives(CullingParams const & cp, Callback const & cb) const = 0;
1205 virtual void cullAllPrimitives(Callback::CbFunc const & on_render) const = 0;
1206 virtual size_t sizeInBytes() const = 0;
1207 virtual void intersectNested(BV const & bv, Vector const & v, Vector const & v_inv, Type& min_t_min, std::function<void(Primitive const *)> const & intersect_nested) const = 0;
1208 virtual void intersectPrimitives(BV const & bv, Vector const & v, Vector const & v_inv, Type& min_t_min, Primitive const *& nearest) const = 0;
1209 virtual void countNodes(unsigned& internal_nodes, unsigned& leaf_nodes) const = 0;
1210 virtual void findNearest(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive const *& nearest, Type& nearest_t, Matrix const *& nearest_transform) const = 0;
1211 virtual void findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res) = 0;
1212 virtual void findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive* parent, IntersectRayResult& res, Primitive*& parent_res) = 0;
1213 virtual void findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res, StackTrivial<NodePtr>& stack) = 0;
1214 virtual void findNearestNested(Ray const & ray, IntersectRayResult& res, std::function<void(Primitive*)> const & find_nested) = 0;
1215 virtual void findNearestNested(Ray const & ray, IntersectRayResult& res, std::function<void(Primitive*)> const & find_nested, StackTrivial<NodePtr>& stack) = 0;
1216 virtual void queryRange(BV const & bv, Callback::CbFunc const & cb) const = 0;
1217 virtual void queryRange(BV const & bv, CullingParams const & cp, Callback::CbFunc const & cb) const = 0;
1218 virtual void queryContributing(CullingParams const & cp, Callback::CbFunc const & cb) const = 0;
1219 virtual void queryAll(Callback::CbFunc const & cb) const = 0;
1220 virtual BV getBV() const = 0;
1221 virtual Type minSquaredDist(const Vector& point) const = 0;
1222 virtual Type dist(Ray const & ray) const = 0;
1223 virtual void destroy(BVTreeNodePool& pool) = 0;
1224 virtual Type cost(BV const & bv) const = 0;
1225 virtual void insert(PrimitiveInfo const & info, NodePtr& this_ptr, BVTreeNodePool& node_pool) = 0;
1226 virtual bool remove(PrimitiveInfo const & info, NodePtr& this_ptr, BVTreeNodePool& node_pool, bool& deleted) = 0;
1227 virtual bool removeIfDoesNotFit(PrimitiveInfo const & info, BV const & bv_old, BVTreeNode const * parent, BVTreeNode const * root, NodePtr& this_ptr, BVTreeNodePool& node_pool, bool& deleted) = 0;
1228 virtual void destroyTree(StackTrivial<PrimitiveInfo>& primitives, BVTreeNodePool& node_pool) = 0;
1229 virtual DirtyInfo recalculateDirty() = 0;
1230 virtual size_t minHeight(size_t const & height) const = 0;
1231 virtual size_t maxHeight(size_t const & height) const = 0;
1232 virtual void averageHeight(float const & height, float const & inv_num_leafs, float& avg_height) const = 0;
1233 };
1234}
1235
1236#endif
1237#ifndef BVTREENODEPOOL_H
1238#define BVTREENODEPOOL_H
1239
1240#include <boost/pool/object_pool.hpp>
1241#include <BVTreeNode.h>
1242#include <BVTreeLeafNode.h>
1243#include <BVTreeInternalNode.h>
1244
1245namespace RT
1246{
1247 class BVTreeNode;
1248 class BVTreeNodePool
1249 {
1250 public:
1251 BVTreeNodePool(size_t num_primitives);
1252 BVTreeNodePool(BVTreeNodePool const & other) = delete;
1253 BVTreeNodePool& operator=(BVTreeNodePool const & other) = delete;
1254 BVTreeNodePool(BVTreeNodePool&& other) = delete;
1255 BVTreeNodePool& operator=(BVTreeNodePool&& other) = delete;
1256 ~BVTreeNodePool() = default;
1257 BVTreeNode* createInternalNode(BVTreeNode::PrimitiveInfo* const begin, BVTreeNode::PrimitiveInfo* const end);
1258 BVTreeNode* createLeafNode(Primitive* p);
1259 BVTreeNode* createNode(BVTreeNode::PrimitiveInfo* const begin, BVTreeNode::PrimitiveInfo* const end);
1260 BVTreeNode* createNode(StackTrivial<BVTreeNode::PrimitiveInfo>& infos);
1261 void destroy(BVTreeLeafNode* node);
1262 void destroy(BVTreeInternalNode* node);
1263 private:
1264 boost::object_pool<BVTreeInternalNode> _internalNodePool;
1265 boost::object_pool<BVTreeLeafNode> _leafNodePool;
1266 };
1267}
1268
1269#endif
1270#ifndef CONSTANTS_H
1271#define CONSTANTS_H
1272
1273namespace RT
1274{
1275 class Constants
1276 {
1277 public:
1278 template<typename T>
1279 static auto oneHundredEightyOverPi()
1280 {
1281 return static_cast<T>(57.29577951308232087679815481410517033240547246656432154916);
1282 }
1283 template<typename T>
1284 static auto piOverOneHundredEighty()
1285 {
1286 return static_cast<T>(0.017453292519943295769236907684886127134428718885417254560);
1287 }
1288 template<typename T>
1289 static auto pi()
1290 {
1291 return static_cast<T>(3.141592653589793238462643383279502884197169399375105820974);
1292 }
1293 };
1294}
1295
1296#endif
1297#ifndef CSMINTERNALNODE_H
1298#define CSMINTERNALNODE_H
1299
1300#include <CsmNode.h>
1301#include <Primitive.h>
1302#include <Descendable.h>
1303
1304namespace RT
1305{
1306 class CsmSplit;
1307 class CsmNodePool;
1308 class CsmTree;
1309
1310 class CsmInternalNode : public CsmNode
1311 {
1312 public:
1313 CsmInternalNode(CsmSplit* begin, CsmSplit* end, CsmTree& np, Matrix<4, 4, Type> const & view_matrix_light);
1314 ~CsmInternalNode();
1315 FrustumPlanes<3, Type> const & frustumPlanes() const;
1316 void recurseVisible(Descendable& other, CullingParams const & cp, Callback2 const & cb);
1317 void recurseContributing(Descendable& other, CullingParams const & cp, Callback2 const & cb);
1318 void recurseAll(Descendable& other, Callback2::CbFunc const & on_render);
1319 BV const & bvLight() const;
1320 virtual void descendVisible(Descendable& other, CullingParams const & cp, Callback2 const & cb) override;
1321 virtual void descendVisible(BVTreeInternalNode& other, CullingParams const & cp, Callback2 const & cb) override;
1322 virtual void descendVisible(BVTreeLeafNode& other, CullingParams const & cp, Callback2 const & cb) override;
1323 virtual void descendContributing(Descendable& other, CullingParams const & cp, Callback2 const & cb) override;
1324 virtual void descendContributing(BVTreeInternalNode& other, CullingParams const & cp, Callback2 const & cb) override;
1325 virtual void descendContributing(BVTreeLeafNode& other, CullingParams const & cp, Callback2 const & cb) override;
1326 virtual void descendAll(Descendable& other, Callback2::CbFunc const & on_render) override;
1327 virtual void descendAll(BVTreeInternalNode& other, Callback2::CbFunc const & on_render) override;
1328 virtual void descendAll(BVTreeLeafNode& other, Callback2::CbFunc const & on_render) override;
1329 private:
1330 CsmNode* _left;
1331 CsmNode* _right;
1332 BV _bvLight;
1333 FrustumPlanes<3, Type> _fp;
1334 };
1335}
1336
1337#endif
1338#ifndef CSMLEAFNODE_H
1339#define CSMLEAFNODE_H
1340
1341#include <CsmNode.h>
1342#include <CsmSplit.h>
1343
1344namespace RT
1345{
1346 class CsmLeafNode : public CsmNode
1347 {
1348 public:
1349 CsmLeafNode(CsmSplit* split);
1350 virtual void descendVisible(Descendable& other, CullingParams const & cp, Callback2 const & cb) override;
1351 virtual void descendVisible(BVTreeInternalNode& other, CullingParams const & cp, Callback2 const & cb) override;
1352 virtual void descendVisible(BVTreeLeafNode& other, CullingParams const & cp, Callback2 const & cb) override;
1353 virtual void descendContributing(Descendable& other, CullingParams const & cp, Callback2 const & cb) override;
1354 virtual void descendContributing(BVTreeInternalNode& other, CullingParams const & cp, Callback2 const & cb) override;
1355 virtual void descendContributing(BVTreeLeafNode& other, CullingParams const & cp, Callback2 const & cb) override;
1356 virtual void descendAll(Descendable& other, Callback2::CbFunc const & on_render) override;
1357 virtual void descendAll(BVTreeInternalNode& other, Callback2::CbFunc const & on_render) override;
1358 virtual void descendAll(BVTreeLeafNode& other, Callback2::CbFunc const & on_render) override;
1359 CsmSplit& split();
1360 private:
1361 CsmSplit* _split;
1362 };
1363}
1364
1365#endif
1366#ifndef CSMNODE_H
1367#define CSMNODE_H
1368
1369#include <Primitive.h>
1370#include <Descendable.h>
1371
1372namespace RT
1373{
1374 class CsmNode : public Descendable
1375 {
1376 public:
1377
1378 using Type = Primitive::Type;
1379 using BV = Primitive::BV;
1380 };
1381}
1382
1383#endif // !CSMNODE_H
1384#ifndef CSMNODEPOOL_H
1385#define CSMNODEPOOL_H
1386
1387#include <boost/pool/object_pool.hpp>
1388#include <Primitive.h>
1389#include <CsmInternalNode.h>
1390#include <CsmLeafNode.h>
1391
1392namespace RT
1393{
1394 class CsmNode;
1395 class CsmSplit;
1396 class CsmNodePool
1397 {
1398 using Type = Primitive::Type;
1399 public:
1400 CsmNode* createNode(CsmSplit* begin, CsmSplit* end, Matrix<4, 4, Type> const & view_matrix_light);
1401 private:
1402 boost::object_pool<CsmInternalNode> _internalNodePool;
1403 boost::object_pool<CsmLeafNode> _leafNodePool;
1404 CsmNode* createInternalNode(CsmSplit* begin, CsmSplit* end, Matrix<4, 4, Type> const & view_matrix_light);
1405 CsmNode* createLeafNode(CsmSplit * s);
1406 };
1407}
1408
1409#endif
1410#ifndef CSMSPLIT_H
1411#define CSMSPLIT_H
1412
1413#include <RenderList.h>
1414#include <AABB.h>
1415#include <Primitive.h>
1416#include <FrustumPlanes.h>
1417
1418namespace RT
1419{
1420 class CsmSplit
1421 {
1422 using BV = typename Primitive::BV;
1423 using Type = typename Primitive::Type;
1424 public:
1425 CsmSplit(BV const & bv_light, Matrix<4, 4, Type> const & view_matrix_light, Matrix<4, 4, Type>* vp);
1426 CsmSplit() = default;
1427 CsmSplit(CsmSplit const & other) = default;
1428 CsmSplit& operator=(CsmSplit const & other) = default;
1429 BV const & bvLight() const;
1430 Matrix<4, 4, Type> const & vp() const;
1431 FrustumPlanes<3, Type> const & frustumPlanes() const;
1432 RenderList& renderlist();
1433 void set(BV const & bv_light, Matrix<4, 4, Type> const & view_matrix_light, Matrix<4, 4, Type>* vp);
1434 private:
1435 RenderList _rl;
1436 BV _bvLight;
1437 Matrix<4, 4, Type>* _vp;
1438 FrustumPlanes<3, Type> _fp;
1439 void init(Matrix<4, 4, Type> const & view_matrix_light);
1440 };
1441}
1442
1443#endif
1444#ifndef CSMTREE_H
1445#define CSMTREE_H
1446
1447#include <CsmSplit.h>
1448#include <boost/pool/object_pool.hpp>
1449#include <Primitive.h>
1450#include <CsmNodePool.h>
1451
1452namespace RT
1453{
1454 class BVTree;
1455 class CsmTree
1456 {
1457 using BV = typename Primitive::BV;
1458 using Type = typename Primitive::Type;
1459 class NodePool;
1460 public:
1461 CsmTree(CsmSplit* begin, CsmSplit* end, Matrix<4, 4, Type> const & view_matrix_light);
1462 ~CsmTree();
1463 CsmNode* root();
1464 void descendVisible(BVTree& bvt, CullingParams const & cp, Callback2 const & cb);
1465 CsmNode* createNode(CsmSplit * begin, CsmSplit * end, Matrix<4, 4, Type> const & view_matrix_light);
1466 private:
1467 CsmNode* createInternalNode(CsmSplit* begin, CsmSplit* end, Matrix<4, 4, Type> const & view_matrix_light);
1468 CsmNode* createLeafNode(CsmSplit* cs);
1469 CsmNode* _root;
1470 };
1471}
1472
1473#endif
1474#ifndef DESCENDABLE_H
1475#define DESCENDABLE_H
1476
1477#include <Callback.h>
1478
1479namespace RT
1480{
1481 class BVTreeInternalNode;
1482 class BVTreeLeafNode;
1483 class CsmInternalNode;
1484 class CsmLeafNode;
1485 class CullingParams;
1486 class Descendable
1487 {
1488 public:
1489 virtual void descendVisible(Descendable& other, CullingParams const & cp, Callback2 const & cb) {};
1490 virtual void descendVisible(BVTreeInternalNode& other, CullingParams const & cp, Callback2 const & cb) {};
1491 virtual void descendVisible(BVTreeLeafNode& other, CullingParams const & cp, Callback2 const & cb) {};
1492 virtual void descendVisible(CsmInternalNode& other, CullingParams const & cp, Callback2 const & cb) {};
1493 virtual void descendVisible(CsmLeafNode& other, CullingParams const & cp, Callback2 const & cb) {};
1494 virtual void descendContributing(Descendable& other, CullingParams const & cp, Callback2 const & cb) {};
1495 virtual void descendContributing(BVTreeInternalNode& other, CullingParams const & cp, Callback2 const & cb) {};
1496 virtual void descendContributing(BVTreeLeafNode& other, CullingParams const & cp, Callback2 const & cb) {};
1497 virtual void descendContributing(CsmInternalNode& other, CullingParams const & cp, Callback2 const & cb) {};
1498 virtual void descendContributing(CsmLeafNode& other, CullingParams const & cp, Callback2 const & cb) {};
1499 virtual void descendAll(Descendable& other, Callback2::CbFunc const & cb) {};
1500 virtual void descendAll(BVTreeInternalNode& other, Callback2::CbFunc const & cb) {};
1501 virtual void descendAll(BVTreeLeafNode& other, Callback2::CbFunc const & cb) {};
1502 virtual void descendAll(CsmInternalNode& other, Callback2::CbFunc const & cb) {};
1503 virtual void descendAll(CsmLeafNode& other, Callback2::CbFunc const & cb) {};
1504 };
1505}
1506
1507#endif
1508#ifndef EULERROTATION_H
1509#define EULERROTATION_H
1510
1511namespace RT
1512{
1513 template<typename T>
1514 class EulerRotation
1515 {
1516 public:
1517 using Vec3 = Vector<3, T>;
1518 EulerRotation() = default;
1519 EulerRotation(Vec3 const & radians) : _radians(radians)
1520 {}
1521 auto rotationX() const
1522 {
1523 return rotation3Dx(radians().at<0>());
1524 }
1525 auto rotationY() const
1526 {
1527 return rotation3Dy(radians().at<1>());
1528 }
1529 auto rotation() const
1530 {
1531 return rotationY() * rotationX();
1532 }
1533 auto i(Matrix<3, 3, T> const & rot) const
1534 {
1535 return rot * Vec3::standardBasis<0>();
1536 }
1537 auto i() const
1538 {
1539 return i(rotation());
1540 }
1541 auto k(Matrix<3, 3, T> const & rot) const
1542 {
1543 return rot * Vec3::standardBasis<2>();
1544 }
1545 auto k() const
1546 {
1547 return k(rotation());
1548 }
1549 auto j(Vector<3, T> const & i, Vector<3, T> const & k) const
1550 {
1551 return cross(-i, k);
1552 }
1553 auto j() const
1554 {
1555 return j(rotation());
1556 }
1557 auto j(Matrix<3, 3, T> const & rot) const
1558 {
1559 return j(i(rot), k(rot));
1560 }
1561 auto viewMatrix(Vec3 const & origin) const
1562 {
1563 auto rot = rotation();
1564 auto i_ = i(rot);
1565 auto k_ = k(rot);
1566 return MathHelpers::changeOfBasis(origin, i_, j(i_, k_), k_);
1567 }
1568 auto viewMatrix() const
1569 {
1570 auto rot = rotation();
1571 auto i_ = i(rot);
1572 auto k_ = k(rot);
1573 return MathHelpers::changeOfBasis(i_, j(i_, k_), k_);
1574 }
1575 auto viewMatrixInverse(Vec3 const & origin) const
1576 {
1577 auto rot = rotation();
1578 auto i_ = i(rot);
1579 auto k_ = k(rot);
1580 return MathHelpers::changeOfBasisInverse(origin, i_, j(i_, k_), k_);
1581 }
1582 auto const & radians() const
1583 {
1584 return _radians;
1585 }
1586 auto degrees() const
1587 {
1588 return RT::degrees(_radians);
1589 }
1590 private:
1591 Vec3 _radians = static_cast<T>(0);
1592 };
1593}
1594
1595#endif // !EULERROTATION_H
1596#ifndef FIXEDTIMESTEPSYSTEM_H
1597#define FIXEDTIMESTEPSYSTEM_H
1598
1599#include <memory>
1600#include <System.h>
1601
1602namespace RT
1603{
1604 class Entity;
1605
1606 class FixedTimestepSystem : public System
1607 {
1608 public:
1609 FixedTimestepSystem() = default;
1610 virtual ~FixedTimestepSystem() = default;
1611 virtual bool update() override;
1612 virtual void updateSystem() = 0;
1613 private:
1614 float _acc = 0.f;
1615 protected:
1616 float _dt = 1.f / 60.f;
1617 };
1618}
1619
1620#endif
1621#ifndef FRUSTUMPLANES_H
1622#define FRUSTUMPLANES_H
1623
1624#include <math/RTMath.h>
1625#include <array>
1626#include <Plane.h>
1627
1628namespace RT
1629{
1630 template<unsigned Dim, typename T>
1631 class FrustumPlanes
1632 {
1633 public:
1634 static auto const constexpr NUM_PLANES = Dim * 2u;
1635 FrustumPlanes() = default;
1636 using Matrix = Matrix<Dim + 1, Dim + 1, T>;
1637 FrustumPlanes(Matrix const & vp)
1638 {
1639 FillPlanes<>::call(vp, *this);
1640 }
1641 template<unsigned i>
1642 auto computePlane(Matrix const & vp)
1643 {
1644 *(_planes + i) = Plane<Dim, T>((i % 2u ? vp.row<i / 2u>() : -vp.row<i / 2u>()) - vp.row<Dim>());
1645 }
1646 template<unsigned i = NUM_PLANES - 1u>
1647 struct FillPlanes
1648 {
1649 static auto call(Matrix const & vp, FrustumPlanes& fp)
1650 {
1651 fp.computePlane<i>(vp);
1652 FillPlanes<i - 1u>::call(vp, fp);
1653 }
1654 };
1655 template<>
1656 struct FillPlanes<0>
1657 {
1658 static auto call(Matrix const & vp, FrustumPlanes& fp)
1659 {
1660 fp.computePlane<0>(vp);
1661 }
1662 };
1663 FrustumPlanes(FrustumPlanes const & other) = default;
1664 FrustumPlanes& operator=(FrustumPlanes const & other) = default;
1665 template<unsigned i>
1666 auto const & plane() const
1667 {
1668 return *(_planes + i);
1669 }
1670 auto const * begin() const
1671 {
1672 return _planes;
1673 }
1674 auto const * end() const
1675 {
1676 return _planes + NUM_PLANES;
1677 }
1678 private:
1679 Plane<Dim, T> _planes [NUM_PLANES];
1680 };
1681}
1682
1683#endif
1684#ifndef FRUSTUMVERTICES_H
1685#define FRUSTUMVERTICES_H
1686
1687#include <math/RTMath.h>
1688#include <NDCCube.h>
1689
1690namespace RT
1691{
1692 template<unsigned Dim, typename T>
1693 class FrustumVertices
1694 {
1695 static unsigned const constexpr numVerts() { return 1 << Dim; }
1696 public:
1697 FrustumVertices() = default;
1698 FrustumVertices(Matrix<Dim + 1, Dim + 1, T> const & vp_inverse)
1699 {
1700 computeVertices(NDCCube<Dim, T>(), vp_inverse);
1701 }
1702 template<unsigned i>
1703 auto fillVertices(NDCCube<Dim, T> const & c_ndc, Matrix<Dim + 1, Dim + 1, T> const & vp_inverse)
1704 {
1705 *(_verts + i) = (vp_inverse * c_ndc.vert<i>().toHomogeneous()).toCartesian();
1706 }
1707 template<unsigned i = numVerts() - 1u>
1708 auto computeVertices(NDCCube<Dim, T> const & c_ndc, Matrix<Dim + 1, Dim + 1, T> const & vp_inverse)
1709 {
1710 fillVertices<i>(c_ndc, vp_inverse);
1711 computeVertices<i - 1u>(c_ndc, vp_inverse);
1712 }
1713 template<>
1714 auto computeVertices<0>(NDCCube<Dim, T> const & c_ndc, Matrix<Dim + 1, Dim + 1, T> const & vp_inverse)
1715 {
1716 fillVertices<0>(c_ndc, vp_inverse);
1717 }
1718 auto separates(AABB<Dim, T> const & aabb) const
1719 {
1720 return computeOutsideFrustum(aabb);
1721 }
1722 private:
1723 template<unsigned axis>
1724 auto outsideFrustum(AABB<Dim, T> const & aabb) const
1725 {
1726 return ComputeOutsidePlane<std::greater<T>, axis>::call(*this, aabb.max()) ||
1727 ComputeOutsidePlane<std::less<T>, axis>::call(*this, aabb.min());
1728 }
1729 template<unsigned axis = Dim - 1u>
1730 auto computeOutsideFrustum(AABB<Dim, T> const & aabb) const
1731 {
1732 return outsideFrustum<axis>(aabb) || computeOutsideFrustum<axis - 1u>(aabb);
1733 }
1734 template<>
1735 auto computeOutsideFrustum<0>(AABB<Dim, T> const & aabb) const
1736 {
1737 return outsideFrustum<0>(aabb);
1738 }
1739 template<typename Pred, unsigned axis, unsigned i>
1740 auto outsidePlane(Vector<Dim, T> const & aa_plane) const
1741 {
1742 return Pred()((_verts + i)->at<axis>(), aa_plane.at<axis>());
1743 }
1744 template<typename Pred, unsigned axis, unsigned i = numVerts() - 1u>
1745 struct ComputeOutsidePlane
1746 {
1747 static auto call(FrustumVertices const & fv, Vector<Dim, T> const & aa_plane)
1748 {
1749 return fv.outsidePlane<Pred, axis, i>(aa_plane) && ComputeOutsidePlane<Pred, axis, i - 1u>::call(fv, aa_plane);
1750 }
1751 };
1752 template<typename Pred, unsigned axis>
1753 struct ComputeOutsidePlane<Pred, axis, 0u>
1754 {
1755 static auto call(FrustumVertices const & fv, Vector<Dim, T> const & aa_plane)
1756 {
1757 return fv.outsidePlane<Pred, axis, 0>(aa_plane);
1758 }
1759 };
1760 Vector<Dim, T> _verts[numVerts()];
1761 };
1762}
1763
1764#endif
1765#ifndef GAMETIMER_H
1766#define GAMETIMER_H
1767
1768#include <chrono>
1769
1770namespace RT
1771{
1772 class GameTimer
1773 {
1774 public:
1775 GameTimer();
1776 void tick();
1777 void stop();
1778 void start();
1779 float timeSeconds() const;
1780 float deltaTimeSeconds() const;
1781 float totalTimeSeconds() const;
1782 bool stopped() const;
1783 private:
1784 using TimePoint = std::chrono::high_resolution_clock::time_point;
1785 TimePoint const _baseTime;
1786 TimePoint _currTime;
1787 TimePoint _prevTime;
1788 TimePoint _stopTime;
1789 std::chrono::nanoseconds _pausedTime = std::chrono::nanoseconds(0);
1790 std::chrono::nanoseconds _deltaTime = std::chrono::nanoseconds(0);
1791 bool _stopped = false;
1792 auto timeNow() const { return std::chrono::high_resolution_clock::now(); }
1793 auto toSeconds(long long const & nanoseconds) const { return nanoseconds / 1000000000.f; }
1794 };
1795}
1796
1797#endif // !GAMETIMER_H
1798#ifndef INTERSECTIONTESTS_H
1799#define INTERSECTIONTESTS_H
1800
1801#include <AABB.h>
1802#include <Sphere.h>
1803#include <array>
1804#include <Ray.h>
1805#include <FrustumPlanes.h>
1806#include <FrustumVertices.h>
1807
1808namespace RT
1809{
1810 class Primitive;
1811 enum class IntersectionResult
1812 {
1813 INSIDE, OUTSIDE, INTERSECTING
1814 };
1815 class IntersectResult
1816 {
1817 public:
1818 IntersectResult(IntersectionResult const & res) : _res(res)
1819 {}
1820 auto intersecting() const
1821 {
1822 return _res == IntersectionResult::INTERSECTING;
1823 }
1824 operator bool() const
1825 {
1826 return _res != IntersectionResult::OUTSIDE;
1827 }
1828 private:
1829 IntersectionResult _res;
1830 };
1831 struct IntersectedPlanes
1832 {
1833 unsigned char _mask;
1834 IntersectedPlanes() : _mask(0u)
1835 {}
1836 IntersectedPlanes(unsigned char const & mask) : _mask(mask)
1837 {}
1838 template<unsigned index>
1839 auto& set()
1840 {
1841 _mask |= 1u << index;
1842 return *this;
1843 }
1844 template<unsigned index>
1845 auto& set(bool const & should_set)
1846 {
1847 if (should_set) {
1848 _mask |= 1u << index;
1849 }
1850 return *this;
1851 }
1852 template<unsigned index>
1853 auto isSet() const
1854 {
1855 return (_mask >> index) & 1u;
1856 }
1857 bool intersects() const
1858 {
1859 return _mask != 0u;
1860 }
1861 };
1862 template<typename Type, typename Matrix>
1863 class IntersectRayResult
1864 {
1865 public:
1866 IntersectRayResult() = default;
1867 IntersectRayResult(Type const & z_far) : _minTMin(z_far)
1868 {}
1869 auto update(Type const & t, Matrix const * nearest_transform, Primitive* nearest)
1870 {
1871 _minTMin = t;
1872 _nearestTransform = nearest_transform;
1873 _nearest = nearest;
1874 }
1875 auto update(typename Ray<3, Type>::IntersectionResult const & res, Matrix const * nearest_transform, Primitive* nearest)
1876 {
1877 _uv = res.uv();
1878 _minTMin = res.t();
1879 _nearestTransform = nearest_transform;
1880 _nearest = nearest;
1881 }
1882 operator bool() const { return _nearest != nullptr; }
1883 auto const & uv() const
1884 {
1885 return _uv;
1886 }
1887 auto const & minTMin() const
1888 {
1889 return _minTMin;
1890 }
1891 auto const & nearestTransform() const
1892 {
1893 return _nearestTransform;
1894 }
1895 auto* nearest()
1896 {
1897 return _nearest;
1898 }
1899 private:
1900 Vector<2, Type> _uv;
1901 Type _minTMin = std::numeric_limits<Type>::max();
1902 Matrix const * _nearestTransform;
1903 Primitive* _nearest = nullptr;
1904 };
1905 class IntersectionTests
1906 {
1907 public:
1908 IntersectionTests() = delete;
1909 using IR = IntersectionResult;
1910 template<typename T>
1911 static auto insideOrIntersects(T const & c, T const & e)
1912 {
1913 return c < -e ? IR::INSIDE : IR::INTERSECTING;
1914 }
1915 template<unsigned Dim, typename T>
1916 static auto intersectPlane(Plane<Dim, T> const & plane, struct AABB<Dim, T>::CenterExtent const & ce)
1917 {
1918 auto c = plane.distance(ce._center);
1919 auto e = plane.absNormal().dot(ce._halfExtent);
1920 return c > e ? IR::OUTSIDE : insideOrIntersects(c, e);
1921 }
1922 template<unsigned Dim, typename T>
1923 static auto intersectPlane(Plane<Dim, T> const & plane, Sphere<Dim, T> const & sphere)
1924 {
1925 auto c = plane.distance(sphere.center());
1926 return c > sphere.radius() ? IR::OUTSIDE : insideOrIntersects(c, sphere.radius());
1927 }
1928 template<unsigned Dim, typename T>
1929 static auto outsidePlane(Plane<Dim, T> const & plane, struct AABB<Dim, T>::CenterExtent const & ce)
1930 {
1931 return plane.distance(ce._center) > plane.absNormal().dot(ce._halfExtent);
1932 }
1933 template<unsigned Dim, typename T>
1934 static auto outsidePlane(Plane<Dim, T> const & plane, Sphere<Dim, T> const & s)
1935 {
1936 return plane.distance(s.center()) > s.radius();
1937 }
1938 template<unsigned Dim, typename T>
1939 static auto outsideFrustum(AABB<Dim, T> const & aabb, FrustumPlanes<Dim, T> const & fp, FrustumVertices<Dim, T> const & fv)
1940 {
1941 return fv.separates(aabb) || FrustumCheck<Dim, T>::outside(aabb.centerExtent(), fp);
1942 }
1943 template<unsigned Dim, typename T>
1944 static auto outsideFrustum(Sphere<Dim, T> const & s, FrustumPlanes<Dim, T> const & fp)
1945 {
1946 return FrustumCheck<Dim, T>::outside(s, fp);
1947 }
1948 template<unsigned Dim, typename T>
1949 static IntersectResult intersectFrustum(AABB<Dim, T> const & aabb, FrustumPlanes<Dim, T> const & fp, FrustumVertices<Dim, T> const & fv)
1950 {
1951 return fv.separates(aabb) ? IR::OUTSIDE : FrustumCheck<Dim, T>::call(aabb.centerExtent(), fp, false);
1952 }
1953 template<unsigned Dim, typename T>
1954 static IntersectResult intersectFrustumIgnoreNear(AABB<Dim, T> const & aabb, FrustumPlanes<Dim, T> const & fp)
1955 {
1956 return FrustumCheckIgnoreNear<Dim, T>::call(aabb.centerExtent(), fp, false);
1957 }
1958 template<unsigned Dim, typename T>
1959 static IntersectResult intersectFrustum(AABB<Dim, T> const & aabb, FrustumPlanes<Dim, T> const & fp, FrustumVertices<Dim, T> const & fv, IntersectedPlanes const & in, IntersectedPlanes& out)
1960 {
1961 return fv.separates(aabb) ? IR::OUTSIDE : FrustumCheck<Dim, T>::call(aabb.centerExtent(), fp, in, out);
1962 }
1963 template<unsigned Dim, typename T>
1964 static IntersectResult intersectFrustum(Sphere<Dim, T> const & sphere, FrustumPlanes<Dim, T> const & fp)
1965 {
1966 return FrustumCheck<Dim, T>::call(sphere, fp, false);
1967 }
1968 template<unsigned Dim, typename T, unsigned index = FrustumPlanes<Dim, T>::NUM_PLANES - 1>
1969 struct FrustumCheckIgnoreNear
1970 {
1971 static auto call(struct AABB<Dim, T>::CenterExtent const & ce, FrustumPlanes<Dim, T> const & fp, bool const & intersecting)
1972 {
1973 auto result = intersectPlane(fp.plane<index>(), ce);
1974 return result == IR::OUTSIDE ? IR::OUTSIDE : FrustumCheckIgnoreNear<Dim, T, index - 1u>::call(ce, fp, intersecting || result == IR::INTERSECTING);
1975 }
1976 };
1977 template<typename T>
1978 struct FrustumCheckIgnoreNear<3, T, 4>
1979 {
1980 static auto call(struct AABB<3, T>::CenterExtent const & ce, FrustumPlanes<3, T> const & fp, bool const & intersecting)
1981 {
1982 return FrustumCheck<3, T, 3>::call(ce, fp, intersecting);
1983 }
1984 };
1985 template<unsigned Dim, typename T, unsigned index = FrustumPlanes<Dim, T>::NUM_PLANES - 1u>
1986 struct FrustumCheck
1987 {
1988 static auto call(struct AABB<Dim, T>::CenterExtent const & ce, FrustumPlanes<Dim, T> const & fp, bool const & intersecting)
1989 {
1990 auto result = intersectPlane(fp.plane<index>(), ce);
1991 return result == IR::OUTSIDE ? IR::OUTSIDE : FrustumCheck<Dim, T, index - 1u>::call(ce, fp, intersecting || result == IR::INTERSECTING);
1992 }
1993 static auto call(Sphere<Dim, T> const & s, FrustumPlanes<Dim, T> const & fp, bool const & intersecting)
1994 {
1995 auto result = intersectPlane(fp.plane<index>(), s);
1996 return result == IR::OUTSIDE ? IR::OUTSIDE : FrustumCheck<Dim, T, index - 1u>::call(s, fp, intersecting || result == IR::INTERSECTING);
1997 }
1998 static auto call(struct AABB<Dim, T>::CenterExtent const & ce, FrustumPlanes<Dim, T> const & fp, IntersectedPlanes const & in, IntersectedPlanes & out)
1999 {
2000 return in.isSet<index>() ? FrustumCheck<Dim, T, index>::checkPlane(ce, fp, in, out) : FrustumCheck<Dim, T, index - 1u>::call(ce, fp, in, out);
2001 }
2002 static auto checkPlane(struct AABB<Dim, T>::CenterExtent const & ce, FrustumPlanes<Dim, T> const & fp, IntersectedPlanes const & in, IntersectedPlanes & out)
2003 {
2004 auto result = intersectPlane(fp.plane<index>(), ce);
2005 return result == IR::OUTSIDE ? IR::OUTSIDE : FrustumCheck<Dim, T, index - 1u>::call(ce, fp, in, out.set<index>(result == IR::INTERSECTING));
2006 }
2007 static auto outside(struct AABB<Dim, T>::CenterExtent const & ce, FrustumPlanes<Dim, T> const & fp)
2008 {
2009 return outsidePlane(fp.plane<index>(), ce) || FrustumCheck<Dim, T, index - 1u>::outside(ce, fp);
2010 }
2011 static auto outside(Sphere<Dim, T> const & s, FrustumPlanes<Dim, T> const & fp)
2012 {
2013 return outsidePlane(fp.plane<index>(), s) || FrustumCheck<Dim, T, index - 1u>::outside(s, fp);
2014 }
2015 };
2016 template<unsigned Dim, typename T>
2017 struct FrustumCheck<Dim, T, 0>
2018 {
2019 static auto call(struct AABB<Dim, T>::CenterExtent const & ce, FrustumPlanes<Dim, T> const & fp, bool const & intersecting)
2020 {
2021 auto result = intersectPlane(fp.plane<0>(), ce);
2022 return result == IR::OUTSIDE ? IR::OUTSIDE : retVal(intersecting || result == IR::INTERSECTING);
2023 }
2024 static auto call(Sphere<Dim, T> const & s, FrustumPlanes<Dim, T> const & fp, bool const & intersecting)
2025 {
2026 auto result = intersectPlane(fp.plane<0>(), s);
2027 return result == IR::OUTSIDE ? IR::OUTSIDE : retVal(intersecting || result == IR::INTERSECTING);
2028 }
2029 static auto retVal(bool const & intersecting)
2030 {
2031 return intersecting ? IR::INTERSECTING : IR::INSIDE;
2032 }
2033 static auto retVal(IntersectedPlanes const & out)
2034 {
2035 return out.intersects() ? IR::INTERSECTING : IR::INSIDE;
2036 }
2037 static auto call(struct AABB<Dim, T>::CenterExtent const & ce, FrustumPlanes<Dim, T> const & fp, IntersectedPlanes const & in, IntersectedPlanes & out)
2038 {
2039 return in.isSet<0>() ? FrustumCheck<Dim, T, 0>::checkPlane(ce, fp, in, out) : retVal(out);
2040 }
2041 static auto checkPlane(struct AABB<Dim, T>::CenterExtent const & ce, FrustumPlanes<Dim, T> const & fp, IntersectedPlanes const & in, IntersectedPlanes & out)
2042 {
2043 auto result = intersectPlane(fp.plane<0>(), ce);
2044 return result == IR::OUTSIDE ? IR::OUTSIDE : retVal(out.set<0>(result == IR::INTERSECTING));
2045 }
2046 static auto outside(struct AABB<Dim, T>::CenterExtent const & ce, FrustumPlanes<Dim, T> const & fp)
2047 {
2048 return outsidePlane(fp.plane<0>(), ce);
2049 }
2050 static auto outside(Sphere<Dim, T> const & s, FrustumPlanes<Dim, T> const & fp)
2051 {
2052 return outsidePlane(fp.plane<0>(), s);
2053 }
2054 };
2055 template<unsigned Dim, typename T>
2056 static auto continueSearch(AABB<Dim, T> const & aabb, Ray<Dim, T> const & ray, T const & min_t_min)
2057 {
2058 T t_min;
2059 return aabb.intersect(ray, t_min) && t_min < min_t_min;
2060 }
2061 template<typename T, unsigned Dim, typename Matrix>
2062 static auto continueSearch(AABB<Dim, T> const & aabb, Ray<Dim, T> const & ray, IntersectRayResult<T, Matrix> const & res)
2063 {
2064 return continueSearch(aabb, ray, res.minTMin());
2065 }
2066 template<typename T, unsigned Dim, typename Matrix>
2067 static auto continueSearch(AABB<Dim, T> const & aabb_local, Ray<Dim, T> const & ray_local, Ray<Dim, T> const & ray_world,
2068 Matrix const & mat, T const & min_t_min)
2069 {
2070 T t_min;
2071 return aabb_local.intersect(ray_local, t_min) && distance(ray_world.origin(), MathHelpers::transformPoint(mat, ray_local.pos(t_min))) < min_t_min;
2072 }
2073 template<typename T, unsigned Dim, typename Matrix>
2074 static auto continueSearch(AABB<Dim, T> const & aabb_local, Ray<Dim, T> const & ray_local, Ray<Dim, T> const & ray_world,
2075 Matrix const & mat, IntersectRayResult<T, Matrix> const & res)
2076 {
2077 return continueSearch(aabb_local, ray_local, ray_world, mat, res.minTMin());
2078 }
2079 };
2080}
2081
2082#endif // !INTERSECTIONTESTS_H
2083#ifndef LIGHT_H
2084#define LIGHT_H
2085
2086#include "math/RTMath.h"
2087#include "Mesh.h"
2088#include <memory>
2089#include <StackTrivial.h>
2090#include <EulerRotation.h>
2091#include <CsmSplit.h>
2092
2093namespace RT
2094{
2095 class Light
2096 {
2097 public:
2098 Light(Vec3f const & color);
2099 Vec3f const & intensity() const;
2100 void setIntensity(Vec3f const & i);
2101 protected:
2102 Vec3f _intensity = Vec3f(1.f);
2103 };
2104
2105 class DirectionalLight : public Light
2106 {
2107 public:
2108 DirectionalLight(Vec3f const & color, Vec3f const & euler_radians);
2109 template<typename T>
2110 auto ratio(unsigned const & i, unsigned const & num_splits) const
2111 {
2112 return static_cast<T>(i) / static_cast<T>(num_splits);
2113 }
2114 template<typename T>
2115 auto splitPlaneUniform(T const & n, T const & f, unsigned const & i, unsigned const & num_splits) const
2116 {
2117 return lerp(n, f, ratio<T>(i, num_splits));
2118 }
2119 template<typename T>
2120 auto splitPlaneLog(T const & n, T const & f, unsigned const & i, unsigned const & num_splits) const
2121 {
2122 return lerpLogScale(n, f, ratio<T>(i, num_splits));
2123 }
2124 template<typename T>
2125 auto splitPlaneLerped(T const & n, T const & f, unsigned const & i, unsigned const & num_splits, T const & alpha) const
2126 {
2127 return lerp(splitPlaneUniform(n, f, i, num_splits), splitPlaneLog(n, f, i, num_splits), alpha);
2128 }
2129 template<typename T>
2130 auto csmSplits(T const & aspect_ratio, T const & n, T const & f, T const & fov_degrees, Matrix<4, 4, T> const & scene_view_inverse,
2131 T const & shadow_map_size, StackTrivial<T> & split_distances, unsigned const & num_splits, T const & alpha, CsmSplit* splits, Matrix<4, 4, T>* vp) const
2132 {
2133 split_distances.clear();
2134 split_distances.reserve(num_splits);
2135 for (unsigned i = 0; i < num_splits; ) {
2136 split_distances.push_back_unchecked(splitPlaneLerped(n, f, i + 1, num_splits, alpha));
2137 AABB<3, T> aabb_light(AABB<3, T>::fromTransform<NDCCube<3, T>::NUM_VERTS>(NDCCube<3, T>().verts(),
2138 viewMatrix() * scene_view_inverse * inverse(MathHelpers::projectionMatrixPerspective(fov_degrees, aspect_ratio, splitPlaneLerped(n, f, i++, num_splits, alpha), split_distances.back()))));
2139 auto units_per_texel = (aabb_light.max() - aabb_light.min()) / shadow_map_size;
2140 aabb_light.min() = floor(aabb_light.min() / units_per_texel) * units_per_texel;
2141 aabb_light.max() = ceil(aabb_light.max() / units_per_texel) * units_per_texel;
2142 (splits++)->set(aabb_light, viewMatrix(), vp++);
2143 }
2144 }
2145 Mat4f viewMatrix() const;
2146 Vec3f direction() const;
2147 Vec3f const & eulerRadians() const;
2148 Vec3f eulerDegrees() const;
2149 void setEulerRadians(Vec3f const & euler_radians);
2150 void setEulerDegrees(Vec3f const & euler_degrees);
2151 private:
2152 EulerRotation<float> _er;
2153 };
2154}
2155
2156#endif
2157#ifndef MESH_H
2158#define MESH_H
2159
2160#include <vector>
2161#include <array>
2162#include <memory>
2163#include <functional>
2164#include <Vertex.h>
2165#include <AABB.h>
2166#include <Sphere.h>
2167#include <Triangle.h>
2168#include <StackTrivial.h>
2169#include <boost/pool/object_pool.hpp>
2170
2171namespace RT
2172{
2173 class Material;
2174 class BVTree;
2175
2176 class Mesh
2177 {
2178 public:
2179 using Type = Primitive::Type;
2180 Mesh() = default;
2181 Mesh(StackTrivial<Vertex>&& vertices, StackTrivial<unsigned int>&& indices, std::shared_ptr<Material> const * materials, unsigned int const & material_index);
2182 ~Mesh();
2183 StackTrivial<Vertex> const & vertices() const;
2184 StackTrivial<unsigned int> const & indices() const;
2185 void setVertices(StackTrivial<Vertex>&& vertices);
2186 void setIndices(StackTrivial<unsigned>&& indices);
2187 unsigned const & materialIndex() const;
2188 AABB3f const & aabb() const;
2189 Sphere3f const & sphere() const;
2190 void setMaterialIndex(unsigned const & material_index);
2191 void setMaterial(std::shared_ptr<Material> const & material);
2192 std::shared_ptr<Material> const & material() const;
2193 BVTree * bvTree();
2194 void triangles(Vertex* vertices, boost::object_pool<Triangle>& tri_pool, StackTrivial<Primitive*>& triangles) const;
2195 std::shared_ptr<BVTree> transformedBVTree(Matrix<4, 4, Type> const & transform,
2196 Matrix<3, 3, Type> const & m_inv_transpose, boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const;
2197 void computeTangentSpace();
2198 private:
2199 StackTrivial<Vertex> _vertices;
2200 StackTrivial<unsigned int> _indices;
2201 boost::object_pool<Triangle> _trianglePool;
2202 unsigned int _materialIndex;
2203 std::shared_ptr<Material> _material;
2204 AABB3f _aabb;
2205 Sphere3f _sphere;
2206 BVTree* _bvTree;
2207 void init();
2208 };
2209}
2210
2211#endif
2212#ifndef PLANE_H
2213#define PLANE_H
2214
2215#include <math/RTMath.h>
2216
2217namespace RT
2218{
2219 template<unsigned Dim, typename T>
2220 class Plane
2221 {
2222 public:
2223 Plane() = default;
2224 Plane(Vector<Dim, T> const & normal, T const & bias) :
2225 _normal(normal),
2226 _bias(bias)
2227 {
2228 normalize();
2229 }
2230 explicit Plane(Vector<Dim + 1, T> const & normal_bias) :
2231 _normal(normal_bias.reduce<Dim>()),
2232 _bias(normal_bias.at<Dim>())
2233 {
2234 normalize();
2235 }
2236 auto normalize()
2237 {
2238 auto inv_len = static_cast<T>(1) / _normal.length();
2239 _normal *= inv_len;
2240 _bias *= inv_len;
2241 }
2242 auto const & normal() const
2243 {
2244 return _normal;
2245 }
2246 auto const & bias() const
2247 {
2248 return _bias;
2249 }
2250 auto normalBias() const
2251 {
2252 return Vector<Dim + 1, T>(normal(), bias());
2253 }
2254 auto distance(Vector<Dim, T> const & point) const
2255 {
2256 return bias() + normal().dot(point);
2257 }
2258 auto absNormal() const
2259 {
2260 return abs(normal());
2261 }
2262 private:
2263 Vector<Dim, T> _normal;
2264 T _bias;
2265 };
2266
2267 using Plane2f = Plane<2, float>;
2268 using Plane3f = Plane<3, float>;
2269
2270 using Plane2d = Plane<2, double>;
2271 using Plane3d = Plane<3, double>;
2272}
2273
2274#endif
2275#ifndef PRIMITIVE_H
2276#define PRIMITIVE_H
2277
2278#include <AABB.h>
2279#include <IntersectionTests.h>
2280#include <Ray.h>
2281#include <math/RTMath.h>
2282#include <boost/pool/object_pool.hpp>
2283
2284namespace RT
2285{
2286 class BVTree;
2287 class Renderer;
2288 class OpenGLAPI;
2289 class RenderList;
2290 class Triangle;
2291 class Particle;
2292 template<typename T>
2293 class StackTrivial;
2294 class CullingParams;
2295 class Camera;
2296 class StaticMeshRenderableTransform;
2297 class Transform;
2298
2299 class Primitive
2300 {
2301 public:
2302 Primitive() = default;
2303 virtual ~Primitive() = default;
2304 using BV = AABB3f;
2305 using Type = typename BV::Type;
2306 static auto const Dim = BV::getDim();
2307 using Matrix = Matrix<Dim + 1, Dim + 1, Type>;
2308 using Ray = Ray<Dim, Type>;
2309 virtual BV bv() const = 0;
2310 virtual BV bvLocal() const;
2311 virtual Type squaredSize() const = 0;
2312 virtual Matrix const * modelMatrix() const;
2313 virtual BVTree * nestedBVTree();
2314 virtual void add(RenderList& renderlist);
2315 virtual void addUnchecked(RenderList& renderlist);
2316 virtual void addIfContributes(const CullingParams& cp, RenderList& renderlist);
2317 virtual void addIfContributesUnchecked(const CullingParams& cp, RenderList& renderlist);
2318 virtual void addIfContributesAndVisible(const CullingParams& cp, RenderList& renderlist);
2319 virtual unsigned numTriangles() const;
2320 virtual unsigned numMeshes() const;
2321 virtual size_t sizeInBytes() const;
2322 virtual void debugTriangle(Vector<4, Type>* _debugTriangle, Matrix const & transform) const;
2323 virtual Vector<3, Type> interpolateNormal(Vector<2, Type> const & uv) const;
2324 virtual std::shared_ptr<BVTree> transformedBVTree(boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const;
2325 virtual Ray::IntersectionResult intersect(Ray const & ray_local, Ray const & ray_world, Matrix const & mat);
2326 virtual Ray::IntersectionResult intersect(Ray const & ray) = 0;
2327 virtual Ray::IntersectionResult intersect(Ray const & ray, Matrix const & matrix) = 0;
2328 virtual Triangle* toTriangle();
2329 virtual StaticMeshRenderableTransform* toStaticMeshRenderableTransform();
2330 virtual Vector<2, Type> barycentric(Vector<3, Type> const & p);
2331 virtual Transform const * transform() const;
2332 private:
2333 };
2334}
2335
2336#endif // !PRIMITIVE_H
2337#ifndef RAY_H
2338#define RAY_H
2339
2340#include <math/RTMath.h>
2341
2342namespace RT
2343{
2344 template<unsigned Dim, typename T>
2345 class Ray
2346 {
2347 public:
2348 Ray(Vector<Dim, T> const & origin, Vector<Dim, T> const & dir) :
2349 _origin(origin),
2350 _invDir(invDir(dir))
2351 {
2352 }
2353 Ray(Ray const & other, Matrix<Dim + 1, Dim + 1, T> const & m) :
2354 _origin(MathHelpers::transformPoint(m, other.origin())),
2355 _invDir(invDir(MathHelpers::transformVector(m, other.dir())))
2356 {}
2357 auto const & origin() const
2358 {
2359 return _origin;
2360 }
2361 auto const & invDir() const
2362 {
2363 return _invDir;
2364 }
2365 auto invDir(Vector<Dim, T> const & dir) const
2366 {
2367 return normalize(static_cast<T>(1) / dir);
2368 }
2369 auto dir() const
2370 {
2371 return normalize(static_cast<T>(1) / _invDir);
2372 }
2373 auto pos(T const & t) const
2374 {
2375 return _origin + dir() * t;
2376 }
2377 class IntersectionResult
2378 {
2379 public:
2380 IntersectionResult() = default;
2381 IntersectionResult(Vector<2, T> const & uv, T const & t) :
2382 _uv(uv),
2383 _t(t)
2384 {
2385 }
2386 auto const & uv() const
2387 {
2388 return _uv;
2389 }
2390 auto const & t() const
2391 {
2392 return _t;
2393 }
2394 auto setU(T const & u)
2395 {
2396 _uv.at<0>() = u;
2397 }
2398 auto setV(T const & v)
2399 {
2400 _uv.at<1>() = v;
2401 }
2402 auto setT(T const & t)
2403 {
2404 _t = t;
2405 }
2406 operator bool() const { return _t >= static_cast<T>(0); }
2407 private:
2408 Vector<2, T> _uv;
2409 T _t = std::numeric_limits<T>::lowest();
2410 };
2411 friend auto& operator << (std::ostream& os, Ray const & ray)
2412 {
2413 os << "Origin: " << ray.origin() << " dir:" << ray.dir();
2414 return os;
2415 }
2416 private:
2417 Vector<Dim, T> _origin;
2418 Vector<Dim, T> _invDir;
2419 };
2420
2421 using Ray2f = Ray<2, float>;
2422 using Ray3f = Ray<3, float>;
2423
2424 using Ray2d = Ray<2, double>;
2425 using Ray3d = Ray<3, double>;
2426}
2427
2428#endif
2429#ifndef STACKTRIVIAL_H
2430#define STACKTRIVIAL_H
2431
2432#include <cstdlib>
2433#include <type_traits>
2434#include <new>
2435#include <cstring>
2436
2437namespace RT
2438{
2439 template<typename T>
2440 class StackTrivial
2441 {
2442 static_assert(std::is_trivially_copyable<T>::value, "T must be trivially_copyable");
2443 static_assert(std::is_trivially_destructible<T>::value, "T must be trivially_destructible");
2444
2445 public:
2446 StackTrivial() = default;
2447 StackTrivial(std::initializer_list<T>&& list)
2448 {
2449 reserve(list.size());
2450 for (auto ptr = list.begin(); ptr != list.end();) {
2451 push_back_unchecked(*ptr++);
2452 }
2453 }
2454 StackTrivial(StackTrivial const & other)
2455 {
2456 append(other);
2457 }
2458 StackTrivial& operator=(StackTrivial const & other)
2459 {
2460 if (this != &other) {
2461 clear();
2462 append(other);
2463 }
2464 return *this;
2465 }
2466 StackTrivial(StackTrivial&& other) :
2467 _begin(other._begin),
2468 _end(other._end),
2469 _capacity(other._capacity)
2470 {
2471 invalidate(std::move(other));
2472 }
2473 StackTrivial& operator=(StackTrivial&& other)
2474 {
2475 if (this != &other) {
2476 deallocate();
2477 _begin = other._begin;
2478 _end = other._end;
2479 _capacity = other._capacity;
2480 invalidate(std::move(other));
2481 }
2482 return *this;
2483 }
2484 ~StackTrivial()
2485 {
2486 deallocate();
2487 }
2488 auto append(StackTrivial const & other)
2489 {
2490 auto const other_size = other.size();
2491 auto const new_size = size() + other_size;
2492 reserve(new_size);
2493 std::memcpy(_end, other._begin, other_size * sizeof(T));
2494 _end += other_size;
2495 }
2496 auto reserveToFit(size_t const & chunk_size)
2497 {
2498 reserve(_capacity + chunk_size);
2499 }
2500 auto reserve(size_t const & new_capacity)
2501 {
2502 if (new_capacity > _capacity) {
2503 allocate(new_capacity);
2504 }
2505 }
2506 auto grow(size_t const & new_size)
2507 {
2508 reserve(new_size);
2509 _end = _begin + new_size;
2510 }
2511 auto clear()
2512 {
2513 _end = _begin;
2514 }
2515 auto push_back_unchecked(T const & element)
2516 {
2517 *_end++ = element;
2518 }
2519 auto push_back_unchecked(T&& element)
2520 {
2521 *_end++ = element;
2522 }
2523 auto& pop_back()
2524 {
2525 return *--_end;
2526 }
2527 auto push_back(T const & element)
2528 {
2529 if (size() == _capacity) {
2530 allocate(_capacity ? _capacity * 2u : 1u);
2531 }
2532 push_back_unchecked(element);
2533 }
2534 auto push_back(T&& element)
2535 {
2536 if (size() == _capacity) {
2537 allocate(_capacity ? _capacity * 2u : 1u);
2538 }
2539 push_back_unchecked(element);
2540 }
2541 auto* data()
2542 {
2543 return _begin;
2544 }
2545 auto* begin()
2546 {
2547 return _begin;
2548 }
2549 auto* end()
2550 {
2551 return _end;
2552 }
2553 const auto* begin() const
2554 {
2555 return _begin;
2556 }
2557 const auto* end() const
2558 {
2559 return _end;
2560 }
2561 auto capacity() const
2562 {
2563 return _capacity;
2564 }
2565 auto size() const
2566 {
2567 return _end - _begin;
2568 }
2569 auto& operator[] (size_t i)
2570 {
2571 return _begin[i];
2572 }
2573 const T& operator[] (size_t i) const
2574 {
2575 return _begin[i];
2576 }
2577 auto& front()
2578 {
2579 return *_begin;
2580 }
2581 const auto& front() const
2582 {
2583 return *_begin;
2584 }
2585 auto& back()
2586 {
2587 return *(_end - 1);
2588 }
2589 const auto& back() const
2590 {
2591 return *(_end - 1);
2592 }
2593 auto* find(T const & element)
2594 {
2595 auto* ptr = _begin;
2596 while (ptr != _end) {
2597 if (*ptr++ == element) {
2598 return --ptr;
2599 }
2600 }
2601 return ptr;
2602 }
2603 private:
2604 T * _begin = nullptr;
2605 T * _end = nullptr;
2606 size_t _capacity = 0;
2607
2608 auto allocate(size_t new_capacity)
2609 {
2610 auto size_prev = size();
2611 if (!(_begin = reinterpret_cast<T*>(std::realloc(_begin, new_capacity * sizeof(T))))) {
2612 throw std::bad_alloc();
2613 }
2614 _capacity = new_capacity;
2615 _end = _begin + size_prev;
2616 }
2617 auto deallocate()
2618 {
2619 if (_begin) {
2620 std::free(_begin);
2621 }
2622 _begin = nullptr;
2623 }
2624 auto invalidate(StackTrivial&& other)
2625 {
2626 other._begin = nullptr;
2627 other._end = nullptr;
2628 other._capacity = 0u;
2629 }
2630 };
2631}
2632#endif
2633#ifndef TRANSFORM_H
2634#define TRANSFORM_H
2635
2636#include <math/RTMath.h>
2637
2638namespace RT
2639{
2640 class Transform
2641 {
2642 public:
2643 Transform(Vec3f const & translation = Vec3f(0.f), Vec3f const & scale = Vec3f(1.f), Vec3f const & degrees = Vec3f(0.f));
2644 Transform(Transform const & other) = default;
2645 Transform& operator=(Transform const & other) = default;
2646 Mat4f matrix() const;
2647 Mat3f inverseMatrix() const;
2648 void setTranslation(Vec3f const & translation);
2649 void setScale(Vec3f const & scale);
2650 void setDegrees(Vec3f const & degrees);
2651 Vec3f const & translation() const;
2652 Vec3f const & scale() const;
2653 Vec3f const & degrees() const;
2654 private:
2655 Vec3f _translation;
2656 Vec3f _scale;
2657 Vec3f _degrees;
2658 };
2659}
2660
2661#endif
2662#ifndef TRIANGLE_H
2663#define TRIANGLE_H
2664
2665#include <Primitive.h>
2666#include <vector>
2667#include <Vertex.h>
2668
2669namespace RT
2670{
2671 class Particle;
2672 class Triangle : public Primitive
2673 {
2674 public:
2675 Triangle() = default;
2676 Triangle(Vec3u const & indices, Vertex* vertices) :
2677 _indices(indices),
2678 _vertices(vertices)
2679 {
2680 }
2681 using Vec3 = Vector<3, Type>;
2682 Triangle& operator=(Triangle const & other) = default;
2683 template<unsigned index>
2684 auto vertex() const
2685 {
2686 static_assert(index <= 2, "Invalid index");
2687 return _vertices[_indices[index]].position();
2688 }
2689 template<unsigned index>
2690 auto normal() const
2691 {
2692 static_assert(index <= 2, "Invalid index");
2693 return _vertices[_indices[index]].normal();
2694 }
2695 auto center() const
2696 {
2697 return interpolatePos(static_cast<Type>(1.0 / 3.0));
2698 }
2699 auto centerNormal() const
2700 {
2701 return interpolateNormal(static_cast<Type>(1.0 / 3.0));
2702 }
2703 Vector<3, Type> interpolatePos(Vector<2, Type> const & uv) const
2704 {
2705 return interpolateBary(uv, vertex<0>(), vertex<1>(), vertex<2>());
2706 }
2707 virtual Vector<3, Type> interpolateNormal(Vector<2, Type> const & uv) const override
2708 {
2709 return interpolateBary(uv, normal<0>(), normal<1>(), normal<2>());
2710 }
2711 virtual Vector<2, Type> barycentric(Vector<3, Type> const & p)
2712 {
2713 return barycentric(vertex<0>(), vertex<1>(), vertex<2>(), p);
2714 }
2715 template<unsigned Dim>
2716 static auto barycentric(Vector<Dim, Type> const & p0, Vector<Dim, Type> const & p1, Vector<Dim, Type> const & p2, Vector<Dim, Type> const & p)
2717 {
2718 auto e0 = p1 - p0;
2719 auto e1 = p2 - p0;
2720 auto one_over_a = static_cast<Type>(1) / triAreaTimesTwo(e0, e1);
2721 return Vector<2, Type>(triAreaTimesTwo(p - p0, e1), triAreaTimesTwo(e0, p - p1)) * one_over_a;
2722 }
2723
2724 std::array<Vec3f, 3u> vertices() const
2725 {
2726 return { vertex<0>(), vertex<1>(), vertex<2>() };
2727 }
2728 virtual BV bv() const override;
2729 virtual Type squaredSize() const override;
2730 Ray::IntersectionResult intersect(Ray const & ray, Vector<3, Type> const & p0, Vector<3, Type> const & p1, Vector<3, Type> const & p2);
2731 virtual Ray::IntersectionResult intersect(Ray const & ray_local, Ray const & ray_world, Matrix const & mat) override;
2732 virtual Ray::IntersectionResult intersect(Ray const & ray) override;
2733 virtual Ray::IntersectionResult intersect(Ray const & ray, Matrix const & matrix) override;
2734 virtual void debugTriangle(Vector<4, Type>* _debugTriangle, Matrix const & transform) const override;
2735 virtual Triangle* toTriangle() override;
2736 private:
2737 Vec3u _indices;
2738 Vertex* _vertices;
2739 };
2740}
2741
2742#endif
2743#ifndef VERTEX_H
2744#define VERTEX_H
2745
2746#include <math/RTMath.h>
2747
2748namespace RT
2749{
2750 struct CompressedNormal
2751 {
2752 int _x : 10;
2753 int _y : 10;
2754 int _z : 10;
2755 int _w : 2;
2756 CompressedNormal() = default;
2757 explicit CompressedNormal(Vec3f const & normal)
2758 {
2759 Vec3i compressed(normal.normalize() * 511.f);
2760 _x = compressed.at<0>();
2761 _y = compressed.at<1>();
2762 _z = compressed.at<2>();
2763 _w = 1;
2764 }
2765 explicit CompressedNormal(Vec3f const & tangent, int const & handedness)
2766 {
2767 Vec3i compressed(tangent.normalize() * 511.f);
2768 _x = compressed.at<0>();
2769 _y = compressed.at<1>();
2770 _z = compressed.at<2>();
2771 _w = handedness;
2772 }
2773 auto uncompress() const
2774 {
2775 return Vec3f(Vec3i(_x, _y, _z)) / 511.f;
2776 }
2777 auto const & w() const
2778 {
2779 return _w;
2780 }
2781 };
2782 class Vertex
2783 {
2784 public:
2785 Vertex() = default;
2786 Vertex(Vec3f const & position) :
2787 _position(position)
2788 {
2789 }
2790 Vertex(Vec3f const & position, CompressedNormal const & normal) :
2791 _position(position),
2792 _normal(normal)
2793 {
2794 }
2795 Vertex(Vec3f const & position, Vec2f const & uv) :
2796 _position(position),
2797 _uv(uv)
2798 {
2799 }
2800 Vertex(Vec3f const & position, CompressedNormal const & normal, Vec2f const & uv) :
2801 _position(position),
2802 _normal(normal),
2803 _uv(uv)
2804 {
2805 }
2806 Vertex(Vec3f const & position, CompressedNormal const & normal, Vec2f const & uv, CompressedNormal const & tangent) :
2807 _position(position),
2808 _normal(normal),
2809 _uv(uv),
2810 _tangent(tangent)
2811 {
2812 }
2813 auto const & position() const
2814 {
2815 return _position;
2816 }
2817 auto normal() const
2818 {
2819 return _normal.uncompress();
2820 }
2821 auto const & uv() const
2822 {
2823 return _uv;
2824 }
2825 auto tangent() const
2826 {
2827 return _tangent.uncompress();
2828 }
2829 auto bitangent() const
2830 {
2831 return cross(normal(), tangent()) * static_cast<float>(_tangent.w());
2832 }
2833 auto setPosition(Vec3f const & position)
2834 {
2835 _position = position;
2836 }
2837 auto setNormal(CompressedNormal const & normal)
2838 {
2839 _normal = normal;
2840 }
2841 auto setNormal(Vec3f const & normal)
2842 {
2843 _normal = CompressedNormal(normal);
2844 }
2845 auto setUV(Vec2f const & uv)
2846 {
2847 _uv = uv;
2848 }
2849 auto setTangent(CompressedNormal const & tangent)
2850 {
2851 _tangent = tangent;
2852 }
2853 auto setTangent(Vec3f const & tangent)
2854 {
2855 _tangent = CompressedNormal(tangent);
2856 }
2857 auto set(Vec3f const & t, int const & handedness, Vec3f const & n)
2858 {
2859 setTangent(CompressedNormal(t, handedness));
2860 setNormal(n);
2861 }
2862 static size_t positionMemOffset()
2863 {
2864 return offsetof(Vertex, _position);
2865 }
2866 static size_t normalMemOffset()
2867 {
2868 return offsetof(Vertex, _normal);
2869 }
2870 static size_t uvMemOffset()
2871 {
2872 return offsetof(Vertex, _uv);
2873 }
2874 static size_t tangentMemOffset()
2875 {
2876 return offsetof(Vertex, _tangent);
2877 }
2878 private:
2879 Vec3f _position;
2880 CompressedNormal _normal = CompressedNormal(0.f);
2881 Vec2f _uv;
2882 CompressedNormal _tangent = CompressedNormal(0.f);
2883 };
2884
2885 class VertexUncompressed
2886 {
2887 public:
2888 auto interpolate(Vec3f const & v, Vec3f& res)
2889 {
2890 res = normalize(v + res);
2891 }
2892 auto addTangent(Vec3f const & t)
2893 {
2894 interpolate(t, _t);
2895 }
2896 auto addBitangent(Vec3f const & b)
2897 {
2898 interpolate(b, _b);
2899 }
2900 auto addNormal(Vec3f const & n)
2901 {
2902 interpolate(n, _n);
2903 }
2904 auto add(Vec3f const & t, Vec3f const & b, Vec3f const & n)
2905 {
2906 addTangent(t);
2907 addBitangent(b);
2908 addNormal(n);
2909 }
2910 auto const & tangent() const
2911 {
2912 return _t;
2913 }
2914 auto const & bitangent() const
2915 {
2916 return _b;
2917 }
2918 auto const & normal() const
2919 {
2920 return _n;
2921 }
2922 auto const & t() const
2923 {
2924 return tangent();
2925 }
2926 auto const & b() const
2927 {
2928 return bitangent();
2929 }
2930 auto const & n() const
2931 {
2932 return normal();
2933 }
2934 private:
2935 Vec3f _t = 0.f;
2936 Vec3f _b = 0.f;
2937 Vec3f _n = 0.f;
2938 };
2939}
2940
2941#endif
2942#ifndef MATHHELPERS_H
2943#define MATHHELPERS_H
2944
2945#include <math/RTMath.h>
2946#define GLM_ENABLE_EXPERIMENTAL
2947#include <glm/gtc/matrix_transform.hpp>
2948#include <array>
2949
2950namespace RT
2951{
2952 template<unsigned Dim, typename T>
2953 class AABB;
2954 class MathHelpers
2955 {
2956 public:
2957 template<typename T>
2958 static auto projectionMatrixPerspective(T const & fov_degrees, T const & aspect_ratio, T const & z_near, T const & z_far)
2959 {
2960 auto const t = tan(radians(fov_degrees) * static_cast<T>(0.5));
2961 auto const sx = static_cast<T>(1) / (aspect_ratio * t);
2962 auto const sy = static_cast<T>(1) / t;
2963 auto const sz = static_cast<T>(1) / (z_far - z_near);
2964 return Matrix<4, 4, T>({ sx, static_cast<T>(0), static_cast<T>(0), static_cast<T>(0),
2965 static_cast<T>(0), sy, static_cast<T>(0), static_cast<T>(0),
2966 static_cast<T>(0), static_cast<T>(0), (z_far + z_near) * sz, static_cast<T>(1),
2967 static_cast<T>(0), static_cast<T>(0), -(static_cast<T>(2) * z_far * z_near) * sz, static_cast<T>(0) });
2968 }
2969 template<unsigned Dim, typename T>
2970 static auto projectionMatrixOrtho(AABB<Dim, T> const & aabb)
2971 {
2972 return scale(static_cast<T>(1) / aabb.halfExtent()) * translate(-aabb.center());
2973 }
2974 template<typename T>
2975 static auto changeOfBasis(Vector<3, T> const & o, Vector<3, T> const & i, Vector<3, T> const & j, Vector<3, T> const & k)
2976 {
2977 return changeOfBasis(i, j, k) * translate(-o);
2978 }
2979 template<typename T>
2980 static auto changeOfBasis(Vector<3, T> const & i, Vector<3, T> const & j, Vector<3, T> const & k)
2981 {
2982 return Matrix<4, 4, T>({ i.appendZero(), j.appendZero(), k.appendZero(), Vector<4, T>::standardBasis<3>() }).transpose();
2983 }
2984 template<typename T>
2985 static auto changeOfBasisInverse(Vector<3, T> const & o, Vector<3, T> const & i, Vector<3, T> const & j, Vector<3, T> const & k)
2986 {
2987 return Matrix<4, 4, T>({ i.appendZero(), j.appendZero(), k.appendZero(), o.toHomogeneous() });
2988 }
2989 template<typename T>
2990 static auto changeOfBasisInverse(Vector<3, T> const & i, Vector<3, T> const & j, Vector<3, T> const & k)
2991 {
2992 return Matrix<3, 3, T>({ i, j, k });
2993 }
2994 template<typename T>
2995 static auto hash(Vector<2, T> const & p, Vector<3, T> const & seed = Vector<3, T>(static_cast<T>(24.33), static_cast<T>(52.23), static_cast<T>(14721.28)))
2996 {
2997 return fract(std::sin(dot(p, seed.xy())) * seed.z());
2998 }
2999 template<typename T>
3000 static auto valueNoise(Vector<2, T> const & p, Vector<3, T> const & seed = Vector<3, T>(static_cast<T>(24.33), static_cast<T>(52.23), static_cast<T>(14721.28)))
3001 {
3002 auto start = floor(p);
3003 auto end = start + static_cast<T>(1);
3004 auto weights = smoothstep(start, end, p);
3005 return lerp(lerp(hash(start, seed), hash(Vector<2, T>(end.x(), start.y()), seed), weights.x()), lerp(hash(Vector<2, T>(start.x(), end.y()), seed), hash(end, seed), weights.x()), weights.y());
3006 }
3007 template<typename T>
3008 static auto hash(T const & p)
3009 {
3010 return fract(std::sin(p) * static_cast<T>(14721.28));
3011 }
3012 template<typename T>
3013 static auto valueNoise(T const & p)
3014 {
3015 auto start = std::floor(p);
3016 auto end = start + static_cast<T>(1);
3017 return lerp(hash(start), hash(end), smoothstep(start, end, p));
3018 }
3019 template<typename T>
3020 static auto fract(T const & val)
3021 {
3022 return val - std::floor(val);
3023 }
3024 template<typename T>
3025 static auto elementsPerThread(T const & num_elements, T const & num_threads)
3026 {
3027 return static_cast<T>(std::ceil(static_cast<float>(num_elements) / static_cast<float>(num_threads)));
3028 }
3029 template <typename T, unsigned index>
3030 struct ComputePow
3031 {
3032 static auto call(const T& base)
3033 {
3034 return base * ComputePow<T, index - 1>::call(base);
3035 }
3036 };
3037 template <typename T>
3038 struct ComputePow<T, 0>
3039 {
3040 static auto call(const T& base)
3041 {
3042 return base;
3043 }
3044 };
3045 template <unsigned exponent, typename T>
3046 static auto pow(T const & base)
3047 {
3048 return exponent ? ComputePow<T, exponent - 1>::call(base) : static_cast<T>(1);
3049 }
3050 template<unsigned Dim, typename T>
3051 static auto transformVector(Matrix<Dim + 1, Dim + 1, T> const & mat, Vector<Dim, T> const & vec)
3052 {
3053 return transform<Dim, T, 0>(mat, vec);
3054 }
3055 template<unsigned Dim, typename T>
3056 static auto transformPoint(Matrix<Dim + 1, Dim + 1, T> const & mat, Vector<Dim, T> const & point)
3057 {
3058 return transform<Dim, T, 1>(mat, point);
3059 }
3060 template<unsigned Dim, typename T, unsigned Hom>
3061 static auto transform(Matrix<Dim + 1, Dim + 1, T> const & mat, Vector<Dim, T> const & v)
3062 {
3063 return (mat * Vector<Dim + 1, T>(v, static_cast<T>(Hom))).reduce<>();
3064 }
3065 template<unsigned Dim, typename T>
3066 static auto transformReduce(Matrix<Dim + 1, Dim + 1, T> const & mat, Vector<Dim, T> const & v)
3067 {
3068 return Matrix<Dim, Dim, T>(mat) * v;
3069 }
3070 };
3071}
3072
3073#endif
3074#ifndef MATVECHELPERS_H
3075#define MATVECHELPERS_H
3076
3077#include <math/RTVector.h>
3078#include <math/RTMatrix.h>
3079#include <math/Meta.h>
3080#include <algorithm>
3081#include <Constants.h>
3082
3083namespace RT
3084{
3085 template<typename T>
3086 static auto dot(T const & a, T const & b)
3087 {
3088 return b.dot(a);
3089 }
3090 template<typename T>
3091 static auto cross(Vector<3, T> const & a, Vector<3, T> const & b)
3092 {
3093 return Vector<3, T>(a.y() * b.z() - a.z() * b.y(),
3094 a.z() * b.x() - a.x() * b.z(),
3095 a.x() * b.y() - a.y() * b.x());
3096 }
3097 template<typename T>
3098 static auto cross(Vector<2, T> const & a, Vector<2, T> const & b)
3099 {
3100 return a.x() * b.y() - b.x() * a.y();
3101 }
3102 template<typename T>
3103 static auto triAreaTimesTwo(Vector<3, T> const & e0, Vector<3, T> const & e1)
3104 {
3105 return cross(e0, e1).length();
3106 }
3107 template<typename T>
3108 static auto triAreaTimesTwo(Vector<2, T> const & e0, Vector<2, T> const & e1)
3109 {
3110 return cross(e0, e1);
3111 }
3112 template<typename T, typename Type>
3113 auto toScreen(Vector<3, T> const & vec, Matrix<4, 4, T> const & vp, Vector<2, Type> const & win_size)
3114 {
3115 return (vp * vec).homogeneousDivide().NDCToUV().UVToScreen(win_size);
3116 }
3117 template<typename S, typename T>
3118 auto interpolateBary(Vector<2, S> const & uv, T const & p0, T const & p1, T const & p2)
3119 {
3120 return (static_cast<S>(1) - uv.at<0>() - uv.at<1>()) * p0 + uv.at<0>() * p1 + uv.at<1>() * p2;
3121 }
3122 template<typename T>
3123 static auto reflect(T const & d, T const & n)
3124 {
3125 return d.reflect(n);
3126 }
3127 template<typename T>
3128 static auto radians(T const & degrees)
3129 {
3130 return degrees * Constants::piOverOneHundredEighty<T>();
3131 }
3132 template<typename T>
3133 static auto degrees(T const & radians)
3134 {
3135 return radians * Constants::oneHundredEightyOverPi<T>();
3136 }
3137 template<typename T>
3138 static auto& minimize(T const & other, T& out)
3139 {
3140 out = std::min(out, other);
3141 return out;
3142 }
3143 template<typename T>
3144 static auto& maximize(T const & other, T& out)
3145 {
3146 out = std::max(out, other);
3147 return out;
3148 }
3149 template<typename T>
3150 static auto minimum(T const & a, T const & b)
3151 {
3152 return a.minimum(b);
3153 }
3154 template<typename T>
3155 static auto maximum(T const & a, T const & b)
3156 {
3157 return a.maximum(b);
3158 }
3159 template<typename T>
3160 static auto round(T const & a)
3161 {
3162 return a.round();
3163 }
3164 template<typename T>
3165 static auto floor(T const & a)
3166 {
3167 return a.floor();
3168 }
3169 template<typename T>
3170 static auto ceil(T const & a)
3171 {
3172 return a.ceil();
3173 }
3174 template<typename T>
3175 static auto abs(T const & a)
3176 {
3177 return a.abs();
3178 }
3179 template<typename T>
3180 static auto minReduce(T const & a)
3181 {
3182 return a.minReduce();
3183 }
3184 template<typename T>
3185 static auto maxReduce(T const & a)
3186 {
3187 return a.maxReduce();
3188 }
3189 template<unsigned Dim, typename T>
3190 static auto clamp(Vector<Dim, T> const & a, Vector<Dim, T> const & min, Vector<Dim, T> const & max)
3191 {
3192 return minimum(max, maximum(min, a));
3193 }
3194 template<typename T>
3195 static auto clamp(T const & a, T const & min, T const & max)
3196 {
3197 return std::min(max, std::max(min, a));
3198 }
3199 template<typename T>
3200 static auto distance(T const & a, T const & b)
3201 {
3202 return (a - b).length();
3203 }
3204 template<typename T>
3205 static auto squaredDistance(T const & a, T const & b)
3206 {
3207 return (a - b).squaredLength();
3208 }
3209 template<typename T>
3210 static auto normalize(T const & a)
3211 {
3212 return a / a.length();
3213 }
3214 template<typename T, typename Pred1 = std::plus<T>, typename Pred2 = std::minus<T>, typename Pred3 = std::multiplies<T>>
3215 static auto genLerp(T const & a, T const & b, T const & alpha)
3216 {
3217 return Pred1()(a, Pred3()(Pred2()(b, a), alpha));
3218 }
3219 template<typename T>
3220 static auto lerp(T const & a, T const & b, T const & alpha)
3221 {
3222 return genLerp(a, b, alpha);
3223 }
3224 template<typename T>
3225 static auto lerpLogScale(T const & a, T const & b, T const & alpha)
3226 {
3227 return genLerp<T, std::multiplies<T>, std::divides<T>, Pow<T>>(a, b, alpha);
3228 }
3229 template<typename T>
3230 static auto smoothstep(T const & edge0, T const & edge1, T const & x)
3231 {
3232 auto t = clamp((x - edge0) / (edge1 - edge0), T(0), T(1));
3233 return t * t * (static_cast<T>(3) - static_cast<T>(2) * t);
3234 }
3235 template<unsigned Dim, typename T>
3236 static auto identity()
3237 {
3238 return Matrix<Dim, Dim, T>::identity();
3239 }
3240 template<unsigned Rows, unsigned Cols, typename T>
3241 static auto transpose(Matrix<Rows, Cols, T> const & m)
3242 {
3243 return m.transpose();
3244 }
3245 template<unsigned Dim, typename T>
3246 static auto translate(Vector<Dim, T> const & t)
3247 {
3248 return Matrix<Dim + 1, Dim + 1, T>::translate(t);
3249 }
3250 template<unsigned Dim, typename T>
3251 static auto scale(Vector<Dim, T> const & s)
3252 {
3253 return Matrix<Dim + 1, Dim + 1, T>::scale(s);
3254 }
3255 template<typename T>
3256 static auto determinant(Matrix<2, 2, T> const & a)
3257 {
3258 return subDet<0, 0, 1, 1, 1, 0, 0, 1>(a);
3259 }
3260 template<typename T>
3261 static auto determinant(Matrix<3, 3, T> const a)
3262 {
3263 return determinantUpper3x3(a);
3264 }
3265 template<unsigned Dim, typename T>
3266 static auto determinantUpper3x3(Matrix<Dim, Dim, T> const & a)
3267 {
3268 return determinantUpper3x3(a, subDet0_3x3(a), subDet1_3x3(a), subDet2_3x3(a));
3269 }
3270 template<unsigned Dim, typename T>
3271 static auto determinantUpper3x3(Matrix<Dim, Dim, T> const & a, T const & s0, T const & s1, T const & s2)
3272 {
3273 return
3274 a.at<0, 0>() * s0 -
3275 a.at<1, 0>() * s1 +
3276 a.at<2, 0>() * s2;
3277 }
3278 template<typename T>
3279 static auto determinant(Matrix<4, 4, T> const & a)
3280 {
3281 return determinant(a, subDet0(a), subDet1(a), subDet2(a), subDet3(a), subDet4(a), subDet5(a));
3282 }
3283 template<typename T>
3284 static auto determinant(Matrix<4, 4, T> const & a, T const & s0, T const & s1, T const & s2, T const & s3, T const & s4, T const & s5)
3285 {
3286 return
3287 a.at<0, 0>() * (a.at<1, 1>() * s0 - a.at<2, 1>() * s1 + a.at<3, 1>() * s2) -
3288 a.at<1, 0>() * (a.at<0, 1>() * s0 - a.at<2, 1>() * s3 + a.at<3, 1>() * s5) +
3289 a.at<2, 0>() * (a.at<0, 1>() * s1 - a.at<1, 1>() * s3 + a.at<3, 1>() * s4) -
3290 a.at<3, 0>() * (a.at<0, 1>() * s2 - a.at<1, 1>() * s5 + a.at<2, 1>() * s4);
3291 }
3292 template<typename T>
3293 static auto validDeterminant(T const & det)
3294 {
3295 return det <= -std::numeric_limits<T>::epsilon() || det >= std::numeric_limits<T>::epsilon();
3296 }
3297 template<unsigned Dim, typename T>
3298 static auto validDeterminant(Matrix<Dim, Dim, T> const & m)
3299 {
3300 return validDeterminant(determinant(m));
3301 }
3302 template<unsigned i0, unsigned i1, unsigned i2, unsigned i3, unsigned i4, unsigned i5, unsigned i6, unsigned i7, unsigned Dim, typename T>
3303 static auto subDet(Matrix<Dim, Dim, T> const & a)
3304 {
3305 return a.at<i0, i1>() * a.at<i2, i3>() - a.at<i4, i5>() * a.at<i6, i7>();
3306 }
3307 template<unsigned Dim, typename T>
3308 static auto subDet0_3x3(Matrix<Dim, Dim, T> const & a)
3309 {
3310 return subDet<1, 1, 2, 2, 2, 1, 1, 2>(a);
3311 }
3312 template<unsigned Dim, typename T>
3313 static auto subDet1_3x3(Matrix<Dim, Dim, T> const & a)
3314 {
3315 return subDet<2, 1, 0, 2, 0, 1, 2, 2>(a);
3316 }
3317 template<unsigned Dim, typename T>
3318 static auto subDet2_3x3(Matrix<Dim, Dim, T> const & a)
3319 {
3320 return subDet<0, 1, 1, 2, 1, 1, 0, 2>(a);
3321 }
3322 template<typename T>
3323 static auto subDet0(Matrix<4, 4, T> const & a)
3324 {
3325 return subDet<2, 2, 3, 3, 3, 2, 2, 3>(a);
3326 }
3327 template<typename T>
3328 static auto subDet1(Matrix<4, 4, T> const & a)
3329 {
3330 return subDet<1, 2, 3, 3, 3, 2, 1, 3>(a);
3331 }
3332 template<typename T>
3333 static auto subDet2(Matrix<4, 4, T> const & a)
3334 {
3335 return subDet<1, 2, 2, 3, 2, 2, 1, 3>(a);
3336 }
3337 template<typename T>
3338 static auto subDet3(Matrix<4, 4, T> const & a)
3339 {
3340 return subDet<0, 2, 3, 3, 3, 2, 0, 3>(a);
3341 }
3342 template<typename T>
3343 static auto subDet4(Matrix<4, 4, T> const & a)
3344 {
3345 return subDet<0, 2, 1, 3, 1, 2, 0, 3>(a);
3346 }
3347 template<typename T>
3348 static auto subDet5(Matrix<4, 4, T> const & a)
3349 {
3350 return subDet<0, 2, 2, 3, 2, 2, 0, 3>(a);
3351 }
3352 template<typename T>
3353 static auto subDet6(Matrix<4, 4, T> const & a)
3354 {
3355 return subDet<2, 1, 3, 3, 3, 1, 2, 3>(a);
3356 }
3357 template<typename T>
3358 static auto subDet7(Matrix<4, 4, T> const & a)
3359 {
3360 return subDet<1, 1, 3, 3, 3, 1, 1, 3>(a);
3361 }
3362 template<typename T>
3363 static auto subDet8(Matrix<4, 4, T> const & a)
3364 {
3365 return subDet<1, 1, 2, 3, 2, 1, 1, 3>(a);
3366 }
3367 template<typename T>
3368 static auto subDet9(Matrix<4, 4, T> const & a)
3369 {
3370 return subDet<0, 1, 1, 3, 1, 1, 0, 3>(a);
3371 }
3372 template<typename T>
3373 static auto subDet10(Matrix<4, 4, T> const & a)
3374 {
3375 return subDet<2, 1, 3, 2, 3, 1, 2, 2>(a);
3376 }
3377 template<typename T>
3378 static auto subDet11(Matrix<4, 4, T> const & a)
3379 {
3380 return subDet<1, 1, 3, 2, 3, 1, 1, 2>(a);
3381 }
3382 template<typename T>
3383 static auto subDet12(Matrix<4, 4, T> const & a)
3384 {
3385 return subDet<1, 1, 2, 2, 2, 1, 1, 2>(a);
3386 }
3387 template<typename T>
3388 static auto subDet13(Matrix<4, 4, T> const & a)
3389 {
3390 return subDet<0, 1, 3, 2, 3, 1, 0, 2>(a);
3391 }
3392 template<typename T>
3393 static auto subDet14(Matrix<4, 4, T> const & a)
3394 {
3395 return subDet<0, 1, 2, 2, 2, 1, 0, 2>(a);
3396 }
3397 template<typename T>
3398 static auto subDet15(Matrix<4, 4, T> const & a)
3399 {
3400 return subDet<0, 1, 1, 2, 1, 1, 0, 2>(a);
3401 }
3402 template<typename T>
3403 static auto subDet16(Matrix<4, 4, T> const & a)
3404 {
3405 return subDet<0, 1, 3, 3, 3, 1, 0, 3>(a);
3406 }
3407 template<typename T>
3408 static auto subDet17(Matrix<4, 4, T> const & a)
3409 {
3410 return subDet<0, 1, 2, 3, 2, 1, 0, 3>(a);
3411 }
3412 template<typename T>
3413 static auto adjugate(Matrix<3, 3, T> const & a, T const & s0, T const & s1, T const & s2)
3414 {
3415 return Matrix<3, 3, T>({ s0,
3416 s1,
3417 s2,
3418 subDet<2, 0, 1, 2, 1, 0, 2, 2>(a),
3419 subDet<0, 0, 2, 2, 2, 0, 0, 2>(a),
3420 subDet<1, 0, 0, 2, 0, 0, 1, 2>(a),
3421 subDet<1, 0, 2, 1, 2, 0, 1, 1>(a),
3422 subDet<2, 0, 0, 1, 0, 0, 2, 1>(a),
3423 subDet<0, 0, 1, 1, 1, 0, 0, 1>(a) });
3424 }
3425 template<typename T>
3426 static auto adjugate(Matrix<3, 3, T> const & a)
3427 {
3428 return adjugate(a, subDet0_3x3(a), subDet1_3x3(a), subDet2_3x3(a));
3429 }
3430 template<typename T>
3431 static auto adjugate(Matrix<4, 4, T> const & a)
3432 {
3433 return adjugate(a, subDet0(a), subDet1(a), subDet2(a), subDet3(a), subDet4(a), subDet5(a),
3434 subDet6(a), subDet7(a), subDet8(a), subDet9(a), subDet10(a), subDet11(a), subDet12(a),
3435 subDet13(a), subDet14(a), subDet15(a), subDet16(a), subDet17(a));
3436 }
3437 template<typename T>
3438 static auto adjugate(Matrix<4, 4, T> const & a, T const & s0, T const & s1, T const & s2, T const & s3, T const & s4, T const & s5, T const & s6, T const & s7,
3439 T const & s8, T const & s9, T const & s10, T const & s11, T const & s12, T const & s13, T const & s14, T const & s15, T const & s16, T const & s17)
3440 {
3441 return Matrix<4, 4, T>({
3442 a.at<1, 1>() * s0 - a.at<2, 1>() * s1 + a.at<3, 1>() * s2,
3443 -a.at<0, 1>() * s0 + a.at<2, 1>() * s3 - a.at<3, 1>() * s5,
3444 a.at<0, 1>() * s1 - a.at<1, 1>() * s3 + a.at<3, 1>() * s4,
3445 -a.at<0, 1>() * s2 + a.at<1, 1>() * s5 - a.at<2, 1>() * s4,
3446 -a.at<1, 0>() * s0 + a.at<2, 0>() * s1 - a.at<3, 0>() * s2,
3447 a.at<0, 0>() * s0 - a.at<2, 0>() * s3 + a.at<3, 0>() * s5,
3448 -a.at<0, 0>() * s1 + a.at<1, 0>() * s3 - a.at<3, 0>() * s4,
3449 a.at<0, 0>() * s2 - a.at<1, 0>() * s5 + a.at<2, 0>() * s4,
3450 a.at<1, 0>() * s6 - a.at<2, 0>() * s7 + a.at<3, 0>() * s8,
3451 -a.at<0, 0>() * s6 + a.at<2, 0>() * s16 - a.at<3, 0>() * s17,
3452 a.at<0, 0>() * s7 - a.at<1, 0>() * s16 + a.at<3, 0>() * s9,
3453 -a.at<0, 0>() * s8 + a.at<1, 0>() * s17 - a.at<2, 0>() * s9,
3454 -a.at<1, 0>() * s10 + a.at<2, 0>() * s11 - a.at<3, 0>() * s12,
3455 a.at<0, 0>() * s10 - a.at<2, 0>() * s13 + a.at<3, 0>() * s14,
3456 -a.at<0, 0>() * s11 + a.at<1, 0>() * s13 - a.at<3, 0>() * s15,
3457 a.at<0, 0>() * s12 - a.at<1, 0>() * s14 + a.at<2, 0 >() * s15 });
3458 }
3459 template<typename T>
3460 static auto adjugate(Matrix<2, 2, T> const & a)
3461 {
3462 return Matrix<2, 2, T>({
3463 a.at<1, 1>(), -a.at<0, 1>(),
3464 -a.at<1, 0>(), a.at<0, 0>() });
3465 }
3466 template<typename T>
3467 static auto inverse(Matrix<3, 3, T> const & a)
3468 {
3469 return inverseUpper3x3(a);
3470 }
3471 template<unsigned Dim, typename T>
3472 static auto inverseUpper3x3(Matrix<Dim, Dim, T> const & a)
3473 {
3474 auto s0 = subDet0_3x3(a);
3475 auto s1 = subDet1_3x3(a);
3476 auto s2 = subDet2_3x3(a);
3477 auto one_over_det = static_cast<T>(1) / determinantUpper3x3(a, s0, s1, s2);
3478 return Matrix<3, 3, T>({
3479 s0 * one_over_det,
3480 s1 * one_over_det,
3481 s2 * one_over_det,
3482 subDet<2, 0, 1, 2, 1, 0, 2, 2>(a) * one_over_det,
3483 subDet<0, 0, 2, 2, 2, 0, 0, 2>(a) * one_over_det,
3484 subDet<1, 0, 0, 2, 0, 0, 1, 2>(a) * one_over_det,
3485 subDet<1, 0, 2, 1, 2, 0, 1, 1>(a) * one_over_det,
3486 subDet<2, 0, 0, 1, 0, 0, 2, 1>(a) * one_over_det,
3487 subDet<0, 0, 1, 1, 1, 0, 0, 1>(a) * one_over_det });
3488 }
3489 template<typename T>
3490 static auto inverse(Matrix<4, 4, T> const & a)
3491 {
3492 auto s0 = subDet0(a);
3493 auto s1 = subDet1(a);
3494 auto s2 = subDet2(a);
3495 auto s3 = subDet3(a);
3496 auto s4 = subDet4(a);
3497 auto s5 = subDet5(a);
3498 auto one_over_det = static_cast<T>(1) / determinant(a, s0, s1, s2, s3, s4, s5);
3499 auto s6 = subDet6(a);
3500 auto s7 = subDet7(a);
3501 auto s8 = subDet8(a);
3502 auto s9 = subDet9(a);
3503 auto s10 = subDet10(a);
3504 auto s11 = subDet11(a);
3505 auto s12 = subDet12(a);
3506 auto s13 = subDet13(a);
3507 auto s14 = subDet14(a);
3508 auto s15 = subDet15(a);
3509 auto s16 = subDet16(a);
3510 auto s17 = subDet17(a);
3511 return Matrix<4, 4, T>({
3512 ( a.at<1, 1>() * s0 - a.at<2, 1>() * s1 + a.at<3, 1>() * s2) * one_over_det,
3513 (-a.at<0, 1>() * s0 + a.at<2, 1>() * s3 - a.at<3, 1>() * s5) * one_over_det,
3514 ( a.at<0, 1>() * s1 - a.at<1, 1>() * s3 + a.at<3, 1>() * s4) * one_over_det,
3515 (-a.at<0, 1>() * s2 + a.at<1, 1>() * s5 - a.at<2, 1>() * s4) * one_over_det,
3516 (-a.at<1, 0>() * s0 + a.at<2, 0>() * s1 - a.at<3, 0>() * s2) * one_over_det,
3517 ( a.at<0, 0>() * s0 - a.at<2, 0>() * s3 + a.at<3, 0>() * s5) * one_over_det,
3518 (-a.at<0, 0>() * s1 + a.at<1, 0>() * s3 - a.at<3, 0>() * s4) * one_over_det,
3519 ( a.at<0, 0>() * s2 - a.at<1, 0>() * s5 + a.at<2, 0>() * s4) * one_over_det,
3520 ( a.at<1, 0>() * s6 - a.at<2, 0>() * s7 + a.at<3, 0>() * s8) * one_over_det,
3521 (-a.at<0, 0>() * s6 + a.at<2, 0>() * s16 - a.at<3, 0>() * s17) * one_over_det,
3522 ( a.at<0, 0>() * s7 - a.at<1, 0>() * s16 + a.at<3, 0>() * s9) * one_over_det,
3523 (-a.at<0, 0>() * s8 + a.at<1, 0>() * s17 - a.at<2, 0>() * s9) * one_over_det,
3524 (-a.at<1, 0>() * s10 + a.at<2, 0>() * s11 - a.at<3, 0>() * s12) * one_over_det,
3525 ( a.at<0, 0>() * s10 - a.at<2, 0>() * s13 + a.at<3, 0>() * s14) * one_over_det,
3526 (-a.at<0, 0>() * s11 + a.at<1, 0>() * s13 - a.at<3, 0>() * s15) * one_over_det,
3527 ( a.at<0, 0>() * s12 - a.at<1, 0>() * s14 + a.at<2, 0 >() * s15) * one_over_det });
3528 }
3529 template<unsigned Dim, typename T>
3530 static auto inverse(Matrix<Dim, Dim, T> const & m, T const & det)
3531 {
3532 return adjugate(m) * (static_cast<T>(1) / det);
3533 }
3534 template<unsigned Dim, typename T>
3535 static auto inverse(Matrix<Dim, Dim, T> const & m)
3536 {
3537 return inverse(m, determinant(m));
3538 }
3539 template<typename T>
3540 static auto rotation3Dx(T const & rad)
3541 {
3542 return Matrix<3, 3, T>({
3543 static_cast<T>(1), static_cast<T>(0), static_cast<T>(0),
3544 static_cast<T>(0), cos(rad), sin(rad),
3545 static_cast<T>(0), -sin(rad), cos(rad) });
3546 }
3547 template<typename T>
3548 static auto rotation3Dy(T const & rad)
3549 {
3550 return Matrix<3, 3, T>({
3551 cos(rad), static_cast<T>(0), -sin(rad),
3552 static_cast<T>(0), static_cast<T>(1), static_cast<T>(0),
3553 sin(rad), static_cast<T>(0), cos(rad) });
3554 }
3555 template<typename T>
3556 static auto rotation3Dz(T const & rad)
3557 {
3558 return Matrix<3, 3, T>({
3559 cos(rad), sin(rad), static_cast<T>(0),
3560 -sin(rad), cos(rad), static_cast<T>(0),
3561 static_cast<T>(0), static_cast<T>(0), static_cast<T>(1) });
3562 }
3563 template<typename T>
3564 static auto rotation3DxHom(T const & rad)
3565 {
3566 return Matrix<4, 4, T>({
3567 static_cast<T>(1), static_cast<T>(0), static_cast<T>(0), static_cast<T>(0),
3568 static_cast<T>(0), cos(rad), sin(rad), static_cast<T>(0),
3569 static_cast<T>(0), -sin(rad), cos(rad), static_cast<T>(0),
3570 static_cast<T>(0), static_cast<T>(0), static_cast<T>(0), static_cast<T>(1) });
3571 }
3572 template<typename T>
3573 static auto rotation3DyHom(T const & rad)
3574 {
3575 return Matrix<4, 4, T>({
3576 cos(rad), static_cast<T>(0), -sin(rad), static_cast<T>(0),
3577 static_cast<T>(0), static_cast<T>(1), static_cast<T>(0), static_cast<T>(0),
3578 sin(rad), static_cast<T>(0), cos(rad), static_cast<T>(0),
3579 static_cast<T>(0), static_cast<T>(0), static_cast<T>(0), static_cast<T>(1) });
3580 }
3581 template<typename T>
3582 static auto rotation3DzHom(T const & rad)
3583 {
3584 return Matrix<4, 4, T>({
3585 cos(rad), sin(rad), static_cast<T>(0), static_cast<T>(0),
3586 -sin(rad), cos(rad), static_cast<T>(0), static_cast<T>(0),
3587 static_cast<T>(0), static_cast<T>(0), static_cast<T>(1), static_cast<T>(0),
3588 static_cast<T>(0), static_cast<T>(0), static_cast<T>(0), static_cast<T>(1) });
3589 }
3590}
3591
3592#endif
3593#ifndef META_H
3594#define META_H
3595
3596#include <math/RTVector.h>
3597#include <math/RTMatrix.h>
3598
3599namespace RT
3600{
3601 template<typename T> struct Min : std::binary_function<T, T, T>
3602 {
3603 T operator() (T const & a, T const & b)
3604 {
3605 return std::min(a, b);
3606 }
3607 };
3608 template<typename T> struct Max : std::binary_function<T, T, T>
3609 {
3610 T operator() (T const & a, T const & b)
3611 {
3612 return std::max(a, b);
3613 }
3614 };
3615 template<typename T> struct Round : std::unary_function<T, T>
3616 {
3617 T operator() (T const & a)
3618 {
3619 return std::round(a);
3620 }
3621 };
3622 template<typename T> struct Floor : std::unary_function<T, T>
3623 {
3624 T operator() (T const & a)
3625 {
3626 return std::floor(a);
3627 }
3628 };
3629 template<typename T> struct Ceil : std::unary_function<T, T>
3630 {
3631 T operator() (T const & a)
3632 {
3633 return std::ceil(a);
3634 }
3635 };
3636 template<typename T> struct Abs : std::unary_function<T, T>
3637 {
3638 T operator() (T const & a)
3639 {
3640 return std::abs(a);
3641 }
3642 };
3643 template<typename T> struct Pow : std::binary_function<T, T, T>
3644 {
3645 T operator()(T const & base, T const & exponent)
3646 {
3647 return std::pow(base, exponent);
3648 }
3649 };
3650}
3651
3652#endif
3653#ifndef RTMATH_H
3654#define RTMATH_H
3655
3656#include <math/MatVecHelpers.h>
3657#include <math/RTMatrix.h>
3658
3659#endif
3660#ifndef RTMATRIX_H
3661#define RTMATRIX_H
3662
3663#include <glm/glm.hpp>
3664#include <iostream>
3665
3666namespace RT
3667{
3668 template<unsigned Rows, unsigned Cols, typename T>
3669 class Matrix
3670 {
3671 public:
3672 static unsigned const constexpr cols() { return Cols; }
3673 static unsigned const constexpr rows() { return Rows; }
3674 static unsigned const constexpr maxCol() { return cols() - 1u; }
3675 static unsigned const constexpr maxRow() { return rows() - 1u; }
3676 static unsigned const constexpr elements() { return cols() * rows(); }
3677 static unsigned const constexpr maxIdx() { return elements() - 1u; }
3678 Matrix() = default;
3679 Matrix(Matrix const & other) = default;
3680 Matrix& operator=(Matrix const & other) = default;
3681 Matrix(const Vector<Rows, T>(&cols)[cols()])
3682 {
3683 construct(cols);
3684 }
3685 Matrix(const T(&vals)[elements()])
3686 {
3687 construct(vals);
3688 }
3689 Matrix(T const * const ptr)
3690 {
3691 Algorithm::Copy<T, maxIdx()>::call(ptr, _cols);
3692 }
3693 static auto scale(Vector<Cols - 1u, T> const & s)
3694 {
3695 Matrix res;
3696 res.computeScale(s.toHomogeneous());
3697 return res;
3698 }
3699 static auto translate(Vector<Cols - 1u, T> const & t)
3700 {
3701 Matrix res;
3702 res.computeIdentity<maxIdx() - rows()>();
3703 res.col<maxCol()>() = t.toHomogeneous();
3704 return res;
3705 }
3706 static auto identity()
3707 {
3708 Matrix res;
3709 res.computeIdentity();
3710 return res;
3711 }
3712 auto transpose() const
3713 {
3714 Matrix<Cols, Rows, T> res;
3715 res.computeTranspose(*this);
3716 return res;
3717 }
3718 template<unsigned i>
3719 auto fillTranspose(Matrix<Cols, Rows, T> const & other)
3720 {
3721 at<i>() = other.at<rowIdx<i>(), colIdx<i>()>();
3722 }
3723 template<unsigned i = maxIdx()>
3724 auto computeTranspose(Matrix<Cols, Rows, T> const & other)
3725 {
3726 fillTranspose<i>(other);
3727 computeTranspose<i - 1>(other);
3728 }
3729 template<>
3730 auto computeTranspose<0>(Matrix<Cols, Rows, T> const & other)
3731 {
3732 fillTranspose<0>(other);
3733 }
3734 template<unsigned OtherRows, unsigned OtherCols>
3735 Matrix(Matrix<OtherRows, OtherCols, T> const & other)
3736 {
3737 static_assert(OtherRows >= Rows && OtherCols >= Cols, "Matrix dimensions must be smaller");
3738 ComputeFillCol<OtherRows, OtherCols>::call(other, *this);
3739 }
3740 template<unsigned OtherRows, unsigned OtherCols, unsigned col = Cols - 1u>
3741 struct ComputeFillCol
3742 {
3743 static auto call(Matrix<OtherRows, OtherCols, T> const & other, Matrix& res)
3744 {
3745 ComputeFillRow<OtherRows, OtherCols, col>::call(other, res);
3746 ComputeFillCol<OtherRows, OtherCols, col - 1u>::call(other, res);
3747 }
3748 };
3749 template<unsigned OtherRows, unsigned OtherCols>
3750 struct ComputeFillCol<OtherRows, OtherCols, 0>
3751 {
3752 static auto call(Matrix<OtherRows, OtherCols, T> const & other, Matrix& res)
3753 {
3754 ComputeFillRow<OtherRows, OtherCols, 0>::call(other, res);
3755 }
3756 };
3757 template<unsigned OtherRows, unsigned OtherCols, unsigned const col, unsigned row = Rows - 1u>
3758 struct ComputeFillRow
3759 {
3760 static auto call(Matrix<OtherRows, OtherCols, T> const & other, Matrix& res)
3761 {
3762 res.col<col>().at<row>() = other.col<col>().at<row>();
3763 ComputeFillRow<OtherRows, OtherCols, col, row - 1u>::call(other, res);
3764 }
3765 };
3766 template<unsigned OtherRows, unsigned OtherCols, unsigned const col>
3767 struct ComputeFillRow<OtherRows, OtherCols, col, 0>
3768 {
3769 static auto call(Matrix<OtherRows, OtherCols, T> const & other, Matrix& res)
3770 {
3771 res.col<col>().at<0>() = other.col<col>().at<0>();
3772 }
3773 };
3774 auto& operator [] (unsigned const & col)
3775 {
3776 return *(_cols + col);
3777 }
3778 auto const & operator [] (unsigned const & col) const
3779 {
3780 return *(_cols + col);
3781 }
3782 template<unsigned row>
3783 auto row() const
3784 {
3785 Vector<Cols, T> res;
3786 ComputeRow<row>::call(*this, res);
3787 return res;
3788 }
3789 auto row(unsigned const & row) const
3790 {
3791 Vector<Cols, T> res;
3792 ComputeRowDyn<>::call(*this, row, res);
3793 return res;
3794 }
3795 template<unsigned col = Cols - 1u>
3796 struct ComputeRowDyn
3797 {
3798 static auto call(Matrix const & m, unsigned const & row, Vector<Cols, T>& res)
3799 {
3800 res.at<col>() = m.col<col>()[row];
3801 ComputeRowDyn<col - 1u>::call(m, row, res);
3802 }
3803 };
3804 template<>
3805 struct ComputeRowDyn<0>
3806 {
3807 static auto call(Matrix const & m, unsigned const & row, Vector<Cols, T>& res)
3808 {
3809 res.at<0>() = m.col<0>()[row];
3810 }
3811 };
3812 template<unsigned row, unsigned col = Cols - 1u>
3813 struct ComputeRow
3814 {
3815 static auto call(Matrix const & m, Vector<Cols, T>& res)
3816 {
3817 res.at<col>() = m.col<col>().at<row>();
3818 ComputeRow<row, col - 1>::call(m, res);
3819 }
3820 };
3821 template<unsigned row>
3822 struct ComputeRow<row, 0>
3823 {
3824 static auto call(Matrix const & m, Vector<Cols, T>& res)
3825 {
3826 res.at<0>() = m.col<0>().at<row>();
3827 }
3828 };
3829 template<unsigned col>
3830 auto & col()
3831 {
3832 static_assert(col < Cols, "Invalid index");
3833 return *(_cols + col);
3834 }
3835 template<unsigned col>
3836 auto const & col() const
3837 {
3838 static_assert(col < Cols, "Invalid index");
3839 return *(_cols + col);
3840 }
3841 T const * ptr() const
3842 {
3843 return _cols->ptr();
3844 }
3845 template<unsigned col_, unsigned row_>
3846 auto const & at() const
3847 {
3848 return col<col_>().at<row_>();
3849 }
3850 template<unsigned col_, unsigned row_>
3851 auto & at()
3852 {
3853 return col<col_>().at<row_>();
3854 }
3855 template<unsigned i>
3856 auto const & at() const
3857 {
3858 return at<colIdx<i>(), rowIdx<i>()>();
3859 }
3860 template<unsigned i>
3861 auto & at()
3862 {
3863 return at<colIdx<i>(), rowIdx<i>()>();
3864 }
3865 template<unsigned i>
3866 static auto const constexpr colIdx()
3867 {
3868 return i / Rows;
3869 }
3870 template<unsigned i>
3871 static auto const constexpr rowIdx()
3872 {
3873 return i % Rows;
3874 }
3875 template<unsigned row, unsigned col>
3876 static auto const constexpr idx()
3877 {
3878 return row + col * Rows;
3879 }
3880 template<unsigned i>
3881 static auto isDiagonalElement()
3882 {
3883 return colIdx<i>() == rowIdx<i>();
3884 }
3885 template<unsigned i>
3886 auto fillScale(Vector<Cols, T> const & s)
3887 {
3888 at<i>() = isDiagonalElement<i>() ? s.at<rowIdx<i>()>() : static_cast<T>(0);
3889 }
3890 template<unsigned i = maxIdx()>
3891 auto computeScale(Vector<Cols, T> const & s)
3892 {
3893 fillScale<i>(s);
3894 computeScale<i - 1u>(s);
3895 }
3896 template<>
3897 auto computeScale<0>(Vector<Cols, T> const & s)
3898 {
3899 fillScale<0>(s);
3900 }
3901 template<unsigned i>
3902 auto fillIdentity()
3903 {
3904 at<i>() = static_cast<T>(isDiagonalElement<i>() ? 1 : 0);
3905 }
3906 template<unsigned i = maxIdx()>
3907 auto computeIdentity()
3908 {
3909 fillIdentity<i>();
3910 computeIdentity<i - 1u>();
3911 }
3912 template<>
3913 auto computeIdentity<0>()
3914 {
3915 fillIdentity<0>();
3916 }
3917 template<unsigned Cols2>
3918 auto operator * (Matrix<Cols, Cols2, T> const & other) const
3919 {
3920 Matrix<Rows, Cols2, T> res;
3921 ComputeMatMultiply<Cols2>::call(*this, other, res);
3922 return res;
3923 }
3924 private:
3925 template<unsigned row, unsigned col>
3926 auto dotMatrixMultiply(Vector<Cols, T> const & v) const
3927 {
3928 return at<col, row>() * v.at<col>();
3929 }
3930 template<unsigned row, unsigned col = maxCol()>
3931 struct ComputeDotMatrixMultiply
3932 {
3933 static auto call(Matrix const & m, Vector<Cols, T> const & v)
3934 {
3935 return m.dotMatrixMultiply<row, col>(v) + ComputeDotMatrixMultiply<row, col - 1>::call(m, v);
3936 }
3937 };
3938 template<unsigned row>
3939 struct ComputeDotMatrixMultiply<row, 0>
3940 {
3941 static auto call(Matrix const & m, Vector<Cols, T> const & v)
3942 {
3943 return m.dotMatrixMultiply<row, 0>(v);
3944 }
3945 };
3946 template<unsigned Cols2, unsigned i>
3947 auto dotMatrixMultiply(Matrix<Cols, Cols2, T> const & b, Matrix<Rows, Cols2, T>& res) const
3948 {
3949 res.at<i>() = ComputeDotMatrixMultiply<res.rowIdx<i>()>::call(*this, b.col<res.colIdx<i>()>());
3950 }
3951 template<unsigned Cols2, unsigned i = Rows * Cols2 - 1u>
3952 struct ComputeMatMultiply
3953 {
3954 static auto call(Matrix const & a, Matrix<Cols, Cols2, T> const & b, Matrix<Rows, Cols2, T>& res)
3955 {
3956 a.dotMatrixMultiply<Cols2, i>(b, res);
3957 ComputeMatMultiply<Cols2, i - 1>::call(a, b, res);
3958 }
3959 };
3960 template<unsigned Cols2>
3961 struct ComputeMatMultiply<Cols2, 0>
3962 {
3963 static auto call(Matrix const & a, Matrix<Cols, Cols2, T> const & b, Matrix<Rows, Cols2, T>& res)
3964 {
3965 a.dotMatrixMultiply<Cols2, 0>(b, res);
3966 }
3967 };
3968 public:
3969 auto operator*(Vector<Cols, T> const & v) const
3970 {
3971 Vector<Rows, T> res;
3972 computeVecMultiply(v, res);
3973 return res;
3974 }
3975 auto operator*(Vector<Cols - 1, T> const & v) const
3976 {
3977 return *this * v.toHomogeneous();
3978 }
3979 private:
3980 template<unsigned row>
3981 auto vecMultiply(Vector<Cols, T> const & v, Vector<Rows, T>& res) const
3982 {
3983 res.at<row>() = ComputeDotMatrixMultiply<row>::call(*this, v);
3984 }
3985 template<unsigned row = maxRow()>
3986 auto computeVecMultiply(Vector<Cols, T> const & v, Vector<Rows, T>& res) const
3987 {
3988 vecMultiply<row>(v, res);
3989 computeVecMultiply<row - 1>(v, res);
3990 }
3991 template<>
3992 auto computeVecMultiply<0>(Vector<Cols, T> const & v, Vector<Rows, T>& res) const
3993 {
3994 vecMultiply<0>(v, res);
3995 }
3996 template<unsigned col_>
3997 auto fillConstruct(const Vector<Rows, T>(&cols)[Cols])
3998 {
3999 col<col_>() = *(cols + col_);
4000 }
4001 template<unsigned col = maxCol()>
4002 auto construct(const Vector<Rows, T>(&cols)[Cols])
4003 {
4004 fillConstruct<col>(cols);
4005 construct<col - 1>(cols);
4006 }
4007 template<>
4008 auto construct<0>(const Vector<Rows, T>(&cols)[Cols])
4009 {
4010 fillConstruct<0>(cols);
4011 }
4012 template<unsigned i>
4013 auto fillConstruct(const T(&vals)[elements()])
4014 {
4015 at<i>() = *(vals + i);
4016 }
4017 template<unsigned i = maxIdx()>
4018 auto construct(const T(&vals)[elements()])
4019 {
4020 fillConstruct<i>(vals);
4021 construct<i - 1>(vals);
4022 }
4023 template<>
4024 auto construct<0>(const T(&vals)[elements()])
4025 {
4026 fillConstruct<0>(vals);
4027 }
4028 public:
4029 auto operator*(T const & s) const
4030 {
4031 Matrix res;
4032 res.computeScalarMult(*this, s);
4033 return res;
4034 }
4035 template<unsigned i>
4036 auto scalarMult(Matrix const & m, T const & s)
4037 {
4038 at<i>() = m.at<i>() * s;
4039 }
4040 template<unsigned i = maxIdx()>
4041 auto computeScalarMult(Matrix const & m, T const & s)
4042 {
4043 scalarMult<i>(m, s);
4044 computeScalarMult<i - 1>(m, s);
4045 }
4046 template<>
4047 auto computeScalarMult<0>(Matrix const & m, T const & s)
4048 {
4049 scalarMult<0>(m, s);
4050 }
4051 /**
4052 * Conversion from/to glm
4053 */
4054 public:
4055 explicit Matrix(glm::mat<Cols, Rows, T> const & m)
4056 {
4057 Algorithm::Copy<T, Rows * Cols - 1u>::call(&m[0][0], _cols->begin());
4058 }
4059 operator glm::mat<Cols, Rows, T>() const
4060 {
4061 glm::mat<Cols, Rows, T> res;
4062 Algorithm::Copy<T, Rows * Cols - 1u>::call(_cols->begin(), &res[0][0]);
4063 return res;
4064 }
4065 /**
4066 * Debug output
4067 */
4068 friend auto& operator << (std::ostream& os, Matrix const & m)
4069 {
4070 os << "[";
4071 ComputeDebugRow<>::call(m, os);
4072 os << "]";
4073 return os;
4074 }
4075 template<unsigned row = Rows - 1u>
4076 struct ComputeDebugRow
4077 {
4078 static void call(Matrix const & m, std::ostream& os)
4079 {
4080 ComputeDebugCol<row>::call(m, os);
4081 os << std::endl;
4082 ComputeDebugRow<row - 1u>::call(m, os);
4083 }
4084 };
4085 template<>
4086 struct ComputeDebugRow<0>
4087 {
4088 static void call(Matrix const & m, std::ostream& os)
4089 {
4090 ComputeDebugCol<0>::call(m, os);
4091 }
4092 };
4093 template<unsigned row, unsigned col = Cols - 1u>
4094 struct ComputeDebugCol
4095 {
4096 static void call(Matrix const & m, std::ostream& os)
4097 {
4098 os << m.col<Cols - col - 1u>().at<Rows - row - 1u>() << " ";
4099 ComputeDebugCol<row, col - 1u>::call(m, os);
4100 }
4101 };
4102 template<unsigned row>
4103 struct ComputeDebugCol<row, 0>
4104 {
4105 static void call(Matrix const & m, std::ostream& os)
4106 {
4107 os << m.col<Cols - 1u>().at<Rows - row - 1u>();
4108 }
4109 };
4110 private:
4111 Vector<Rows, T> _cols[Cols];
4112 };
4113
4114 using Mat2f = Matrix<2, 2, float>;
4115 using Mat3f = Matrix<3, 3, float>;
4116 using Mat4f = Matrix<4, 4, float>;
4117
4118 using Mat2u = Matrix<2, 2, unsigned>;
4119 using Mat3u = Matrix<3, 3, unsigned>;
4120 using Mat4u = Matrix<4, 4, unsigned>;
4121
4122 using Mat2i = Matrix<2, 2, int>;
4123 using Mat3i = Matrix<3, 3, int>;
4124 using Mat4i = Matrix<4, 4, int>;
4125}
4126
4127#endif
4128#ifndef RTVECTOR_H
4129#define RTVECTOR_H
4130
4131#include <glm/glm.hpp>
4132#include <ostream>
4133#include <Algorithm.h>
4134
4135namespace RT
4136{
4137 template<unsigned Dim, typename T>
4138 class Vector
4139 {
4140 public:
4141 Vector() = default;
4142 Vector(T const & scalar)
4143 {
4144 computeScalar(scalar);
4145 }
4146 template<typename TOther>
4147 Vector(TOther const & scalar) :
4148 Vector(static_cast<T>(scalar))
4149 {
4150 }
4151 template<typename ...Args>
4152 Vector(Args... args) : _data{ args... }
4153 {
4154 }
4155 Vector(Vector const & other) = default;
4156 template<typename TOther>
4157 Vector(Vector<Dim, TOther> const & other)
4158 {
4159 Convert<TOther>::call(other, *this);
4160 }
4161 Vector(Vector<Dim - 1, T> const & other, T const & scalar)
4162 {
4163 Algorithm::Copy<T, Dim - 2u>::call(other.begin(), _data);
4164 back() = scalar;
4165 }
4166 template<unsigned axis>
4167 static auto standardBasis()
4168 {
4169 Vector res;
4170 ComputeStandardBasis<axis>::call(res);
4171 return res;
4172 }
4173 template<unsigned Dim1>
4174 Vector(Vector<Dim1, T> const & v1, Vector<Dim - Dim1, T> const & v2)
4175 {
4176 Algorithm::Copy<T, Dim1 - 1>::call(v1.begin(), _data);
4177 Algorithm::Copy<T, Dim - Dim1 - 1>::call(v2.begin(), _data + Dim1);
4178 }
4179 auto & operator [] (unsigned const & i)
4180 {
4181 return *(_data + i);
4182 }
4183 auto const & operator [] (unsigned const & i) const
4184 {
4185 return *(_data + i);
4186 }
4187 auto const * ptr() const
4188 {
4189 return _data;
4190 }
4191 auto xyz() const
4192 {
4193 return Vector<3, T>(x(), y(), z());
4194 }
4195 auto xz() const
4196 {
4197 return Vector<2, T>(x(), z());
4198 }
4199 auto xy() const
4200 {
4201 return Vector<2, T>(x(), y());
4202 }
4203 auto yz() const
4204 {
4205 return Vector<2, T>(y(), z());
4206 }
4207 auto const & x() const
4208 {
4209 return at<0>();
4210 }
4211 auto const & y() const
4212 {
4213 return at<1>();
4214 }
4215 auto const & z() const
4216 {
4217 return at<2>();
4218 }
4219 auto const & w() const
4220 {
4221 return at<3>();
4222 }
4223 auto const & r() const
4224 {
4225 return x();
4226 }
4227 auto const & g() const
4228 {
4229 return y();
4230 }
4231 auto const & b() const
4232 {
4233 return z();
4234 }
4235 auto const & a() const
4236 {
4237 return w();
4238 }
4239 auto const & u() const
4240 {
4241 return x();
4242 }
4243 auto const & v() const
4244 {
4245 return y();
4246 }
4247 template<unsigned i>
4248 auto const & at() const
4249 {
4250 static_assert(i < Dim, "Invalid i");
4251 return *(_data + i);
4252 }
4253 template<unsigned i>
4254 auto& at()
4255 {
4256 static_assert(i < Dim, "Invalid i");
4257 return *(_data + i);
4258 }
4259 auto append(T const & scalar) const
4260 {
4261 return Vector<Dim + 1, T>(*this, scalar);
4262 }
4263 template<unsigned Dim2>
4264 auto append(Vector<Dim2, T> const & other)
4265 {
4266 return Vector<Dim + Dim2, T>(*this, other);
4267 }
4268 auto appendZero() const
4269 {
4270 return append(static_cast<T>(0));
4271 }
4272 auto appendOne() const
4273 {
4274 return append(static_cast<T>(1));
4275 }
4276 auto appendMinusOne() const
4277 {
4278 return append(static_cast<T>(-1));
4279 }
4280 auto* begin()
4281 {
4282 return _data;
4283 }
4284 auto* end()
4285 {
4286 return _data + Dim;
4287 }
4288 auto const* begin() const
4289 {
4290 return _data;
4291 }
4292 auto const* end() const
4293 {
4294 return begin() + Dim;
4295 }
4296 auto const & front() const
4297 {
4298 return *begin();
4299 }
4300 auto const & back() const
4301 {
4302 return *(end() - 1);
4303 }
4304 auto & front()
4305 {
4306 return *begin();
4307 }
4308 auto & back()
4309 {
4310 return *(end() - 1);
4311 }
4312 auto toHomogeneous() const
4313 {
4314 return appendOne();
4315 }
4316 auto homogeneousDivide() const
4317 {
4318 return *this / back();
4319 }
4320 auto toCartesian() const
4321 {
4322 return homogeneousDivide().reduce<>();
4323 }
4324 auto NDCToUV() const
4325 {
4326 return *this * static_cast<T>(0.5) + static_cast<T>(0.5);
4327 }
4328 auto UVToNDC() const
4329 {
4330 return *this * static_cast<T>(2) - static_cast<T>(1);
4331 }
4332 auto UVToScreen(Vector<2, T> const & screen_size) const
4333 {
4334 return Vector<2, T>(u(), static_cast<T>(1) - v()) * screen_size;
4335 }
4336 auto validU() const
4337 {
4338 return u() >= static_cast<T>(0);
4339 }
4340 auto validV() const
4341 {
4342 return v() >= static_cast<T>(0);
4343 }
4344 auto validW() const
4345 {
4346 return u() + v() <= static_cast<T>(1);
4347 }
4348 auto validUV() const
4349 {
4350 return validU() && validV();
4351 }
4352 auto validUVW() const
4353 {
4354 return validU() && validV() && validW();
4355 }
4356 auto validVW() const
4357 {
4358 return validV() && validW();
4359 }
4360 auto aspectRatio() const
4361 {
4362 return x() / y();
4363 }
4364 auto operator + (Vector const & other) const
4365 {
4366 Vector res;
4367 Compute<std::plus<T>>::call(*this, other, res);
4368 return res;
4369 }
4370 auto operator - (Vector const & other) const
4371 {
4372 Vector res;
4373 Compute<std::minus<T>>::call(*this, other, res);
4374 return res;
4375 }
4376 auto operator * (Vector const & other) const
4377 {
4378 Vector res;
4379 Compute<std::multiplies<T>>::call(*this, other, res);
4380 return res;
4381 }
4382 auto operator / (Vector const & other) const
4383 {
4384 Vector res;
4385 Compute<std::divides<T>>::call(*this, other, res);
4386 return res;
4387 }
4388 auto& operator += (Vector const & other)
4389 {
4390 Compute<std::plus<T>>::call(*this, other, *this);
4391 return *this;
4392 }
4393 auto& operator -= (Vector const & other)
4394 {
4395 Compute<std::minus<T>>::call(*this, other, *this);
4396 return *this;
4397 }
4398 auto& operator *= (Vector const & other)
4399 {
4400 Compute<std::multiplies<T>>::call(*this, other, *this);
4401 return *this;
4402 }
4403 auto& operator /= (Vector const & other)
4404 {
4405 Compute<std::divides<T>>::call(*this, other, *this);
4406 return *this;
4407 }
4408 auto operator - () const
4409 {
4410 Vector res;
4411 ComputePred<std::negate<T>>::call(*this, res);
4412 return res;
4413 }
4414 auto minimum(Vector const & other) const
4415 {
4416 Vector res;
4417 Compute<Min<T>>::call(*this, other, res);
4418 return res;
4419 }
4420 auto maximum(Vector const & other) const
4421 {
4422 Vector res;
4423 Compute<Max<T>>::call(*this, other, res);
4424 return res;
4425 }
4426 auto round() const
4427 {
4428 Vector res;
4429 ComputePred<Round<T>>::call(*this, res);
4430 return res;
4431 }
4432 auto floor() const
4433 {
4434 Vector res;
4435 ComputePred<Floor<T>>::call(*this, res);
4436 return res;
4437 }
4438 auto ceil() const
4439 {
4440 Vector res;
4441 ComputePred<Ceil<T>>::call(*this, res);
4442 return res;
4443 }
4444 auto abs() const
4445 {
4446 Vector res;
4447 ComputePred<Abs<T>>::call(*this, res);
4448 return res;
4449 }
4450 auto minReduce() const
4451 {
4452 return ComputePredReduce<Min<T>>::call(*this);
4453 }
4454 auto maxReduce() const
4455 {
4456 return ComputePredReduce<Max<T>>::call(*this);
4457 }
4458 auto operator == (Vector const & other) const
4459 {
4460 return ComputeReduce<std::equal_to<T>, std::logical_and<T>>::call(*this, other);
4461 }
4462 auto operator != (Vector const & other) const
4463 {
4464 return ComputeReduce<std::not_equal_to<T>, std::logical_or<T>>::call(*this, other);
4465 }
4466 auto operator < (Vector const & other) const
4467 {
4468 return ComputeReduce<std::less<T>, std::logical_and<T>>::call(*this, other);
4469 }
4470 auto operator > (Vector const & other) const
4471 {
4472 return ComputeReduce<std::greater<T>, std::logical_and<T>>::call(*this, other);
4473 }
4474 auto operator <= (Vector const & other) const
4475 {
4476 return ComputeReduce<std::less_equal<T>, std::logical_and<T>>::call(*this, other);
4477 }
4478 auto operator >= (Vector const & other) const
4479 {
4480 return ComputeReduce<std::greater_equal<T>, std::logical_and<T>>::call(*this, other);
4481 }
4482 auto& minimize(Vector const & other)
4483 {
4484 Compute<Min<T>>::call(*this, other, *this);
4485 return *this;
4486 }
4487 auto& maximize(Vector const & other)
4488 {
4489 Compute<Max<T>>::call(*this, other, *this);
4490 return *this;
4491 }
4492 auto dot(Vector const & other) const
4493 {
4494 return ComputeReduce<std::multiplies<T>, std::plus<T>>::call(*this, other);
4495 }
4496 auto scalarTriple(Vector const & b, Vector const & c) const
4497 {
4498 return dot(cross(b, c));
4499 }
4500 auto isRightHanded(Vector const & b, Vector const & c) const
4501 {
4502 return scalarTriple(b, c) > static_cast<T>(0);
4503 }
4504 auto isLeftHanded(Vector const & b, Vector const & c) const
4505 {
4506 return !isRightHanded(b, c);
4507 }
4508 auto handedness(Vector const & b, Vector const & c) const
4509 {
4510 return isRightHanded(b, c) ? 1 : -1;
4511 }
4512 auto orthogonalize(Vector const & b) const
4513 {
4514 return *this - b * dot(b);
4515 }
4516 auto reflect(Vector const & n) const
4517 {
4518 return *this - static_cast<T>(2) * dot(n) * n;
4519 }
4520 auto length() const
4521 {
4522 return std::sqrt(squaredLength());
4523 }
4524 auto normalize() const
4525 {
4526 return RT::normalize(*this);
4527 }
4528 auto squaredLength() const
4529 {
4530 return dot(*this);
4531 }
4532 auto volume() const
4533 {
4534 return ComputePredReduce<std::multiplies<T>>::call(*this);
4535 }
4536 auto shortestAxis() const
4537 {
4538 auto best = Dim - 1;
4539 ComputeBestAxis<std::less<T>>::call(*this, best);
4540 return best;
4541 }
4542 auto longestAxis() const
4543 {
4544 auto best = Dim - 1;
4545 ComputeBestAxis<std::greater<T>>::call(*this, best);
4546 return best;
4547 }
4548 Vector(glm::vec<Dim, T> const & vec)
4549 {
4550 Algorithm::Copy<T, Dim - 1>::call(&vec[0], _data);
4551 }
4552 operator glm::vec<Dim, T>() const
4553 {
4554 glm::vec<Dim, T> vec;
4555 Algorithm::Copy<T, Dim - 1>::call(_data, &vec[0]);
4556 return vec;
4557 }
4558 template<unsigned N = Dim - 1>
4559 auto reduce() const
4560 {
4561 static_assert(N < Dim, "N must be smaller to reduce vector dimension.");
4562 Vector<N, T> ret;
4563 Algorithm::Copy<T, N - 1>::call(_data, ret.begin());
4564 return ret;
4565 }
4566 friend auto& operator << (std::ostream& os, Vector const & vec)
4567 {
4568 os << "[";
4569 ComputeDebug<>::call(vec, os);
4570 os << "]";
4571 return os;
4572 }
4573 template<unsigned i = 0>
4574 struct ComputeDebug
4575 {
4576 static void call(Vector const & vec, std::ostream& os)
4577 {
4578 os << vec.at<i>() << " ";
4579 ComputeDebug<i + 1>::call(vec, os);
4580 }
4581 };
4582 template<>
4583 struct ComputeDebug<Dim - 1>
4584 {
4585 static void call(Vector const & vec, std::ostream& os)
4586 {
4587 os << vec.back();
4588 }
4589 };
4590 private:
4591 T _data[Dim];
4592
4593 template<unsigned axis, unsigned i>
4594 auto fillStandardBasis()
4595 {
4596 at<i>() = static_cast<T>(i == axis ? 1 : 0);
4597 }
4598 template<unsigned axis, unsigned i = Dim - 1u>
4599 struct ComputeStandardBasis
4600 {
4601 static auto call(Vector& res)
4602 {
4603 res.fillStandardBasis<axis, i>();
4604 ComputeStandardBasis<axis, i - 1>::call(res);
4605 }
4606 };
4607 template<unsigned axis>
4608 struct ComputeStandardBasis<axis, 0>
4609 {
4610 static auto call(Vector& res)
4611 {
4612 res.fillStandardBasis<axis, 0>();
4613 }
4614 };
4615 template<typename Pred, unsigned i>
4616 auto fill(Vector const & a, Vector const & b)
4617 {
4618 at<i>() = Pred()(a.at<i>(), b.at<i>());
4619 }
4620 template<typename Pred, unsigned i = Dim - 1>
4621 struct Compute
4622 {
4623 static auto call(Vector const & a, Vector const & b, Vector& res)
4624 {
4625 res.fill<Pred, i>(a, b);
4626 Compute<Pred, i - 1>::call(a, b, res);
4627 }
4628 };
4629 template<typename Pred>
4630 struct Compute<Pred, 0>
4631 {
4632 static auto call(Vector const & a, Vector const & b, Vector& res)
4633 {
4634 res.fill<Pred, 0>(a, b);
4635 }
4636 };
4637 template<typename Pred, unsigned i>
4638 auto fill(Vector const & v)
4639 {
4640 at<i>() = Pred()(v.at<i>());
4641 }
4642 template<typename Pred, unsigned i = Dim - 1>
4643 struct ComputePred
4644 {
4645 static auto call(Vector const & v, Vector& res)
4646 {
4647 res.fill<Pred, i>(v);
4648 ComputePred<Pred, i - 1>::call(v, res);
4649 }
4650 };
4651 template<typename Pred>
4652 struct ComputePred<Pred, 0>
4653 {
4654 static auto call(Vector const & v, Vector& res)
4655 {
4656 res.fill<Pred, 0>(v);
4657 }
4658 };
4659 template<typename Pred, unsigned i = Dim - 1>
4660 struct ComputePredReduce
4661 {
4662 static auto call(Vector const & v)
4663 {
4664 return Pred()(v.at<i>(), ComputePredReduce<Pred, i - 1>::call(v));
4665 }
4666 };
4667 template<typename Pred>
4668 struct ComputePredReduce<Pred, 0>
4669 {
4670 static auto call(Vector const & v)
4671 {
4672 return v.at<0>();
4673 }
4674 };
4675 template<typename BinaryOp, typename ReduceOp, unsigned i = Dim - 1>
4676 struct ComputeReduce
4677 {
4678 static auto call(Vector const & a, Vector const & b)
4679 {
4680 return ReduceOp()(BinaryOp()(a.at<i>(), b.at<i>()), ComputeReduce<BinaryOp, ReduceOp, i - 1>::call(a, b));
4681 }
4682 };
4683 template<typename BinaryOp, typename ReduceOp>
4684 struct ComputeReduce<BinaryOp, ReduceOp, 0>
4685 {
4686 static auto call(Vector const & a, Vector const & b)
4687 {
4688 return BinaryOp()(a.at<0>(), b.at<0>());
4689 }
4690 };
4691 template<unsigned i>
4692 auto fillScalar(T const & scalar)
4693 {
4694 at<i>() = scalar;
4695 }
4696 template<unsigned i = Dim - 1>
4697 auto computeScalar(T const & scalar)
4698 {
4699 fillScalar<i>(scalar);
4700 computeScalar<i - 1>(scalar);
4701 }
4702 template<>
4703 auto computeScalar<0>(T const & scalar)
4704 {
4705 fillScalar<0>(scalar);
4706 }
4707 template<typename TOther, unsigned i>
4708 auto fillConvert(Vector<Dim, TOther> const & other)
4709 {
4710 at<i>() = static_cast<T>(other.at<i>());
4711 }
4712 template<typename TOther, unsigned i = Dim - 1>
4713 struct Convert
4714 {
4715 static auto call(Vector<Dim, TOther> const & other, Vector& res)
4716 {
4717 res.fillConvert<TOther, i>(other);
4718 Convert<TOther, i - 1>::call(other, res);
4719 }
4720 };
4721 template<typename TOther>
4722 struct Convert<TOther, 0>
4723 {
4724 static auto call(Vector<Dim, TOther> const & other, Vector& res)
4725 {
4726 res.fillConvert<TOther, 0>(other);
4727 }
4728 };
4729 template<typename Pred, unsigned i>
4730 auto bestAxis(unsigned& best) const
4731 {
4732 if (Pred()(at<i>(), *(_data + best))) {
4733 best = i;
4734 }
4735 }
4736 template<typename Pred, unsigned i = Dim - 2u>
4737 struct ComputeBestAxis
4738 {
4739 static auto call(Vector const & v, unsigned& best)
4740 {
4741 v.bestAxis<Pred, i>(best);
4742 ComputeBestAxis<Pred, i - 1>::call(v, best);
4743 }
4744 };
4745 template<typename Pred>
4746 struct ComputeBestAxis<Pred, 0>
4747 {
4748 static auto call(Vector const & v, unsigned& best)
4749 {
4750 v.bestAxis<Pred, 0>(best);
4751 }
4752 };
4753 };
4754
4755 template<unsigned Dim, typename T>
4756 auto operator + (T const & s, Vector<Dim, T> const & v)
4757 {
4758 return Vector<Dim, T>(s) + v;
4759 }
4760 template<unsigned Dim, typename T>
4761 auto operator - (T const & s, Vector<Dim, T> const & v)
4762 {
4763 return Vector<Dim, T>(s) - v;
4764 }
4765 template<unsigned Dim, typename T>
4766 auto operator * (T const & s, Vector<Dim, T> const & v)
4767 {
4768 return Vector<Dim, T>(s) * v;
4769 }
4770 template<unsigned Dim, typename T>
4771 auto operator / (T const & s, Vector<Dim, T> const & v)
4772 {
4773 return Vector<Dim, T>(s) / v;
4774 }
4775
4776 using Vec2f = Vector<2, float>;
4777 using Vec3f = Vector<3, float>;
4778 using Vec4f = Vector<4, float>;
4779
4780 using Vec2u = Vector<2, unsigned>;
4781 using Vec3u = Vector<3, unsigned>;
4782 using Vec4u = Vector<4, unsigned>;
4783
4784 using Vec2i = Vector<2, int>;
4785 using Vec3i = Vector<3, int>;
4786 using Vec4i = Vector<4, int>;
4787
4788 using Point2f = Vec2f;
4789 using Point3f = Vec3f;
4790 using Point4f = Vec4f;
4791
4792 using Point2u = Vec2u;
4793 using Point3u = Vec3u;
4794 using Point4u = Vec4u;
4795
4796 using Point2i = Vec2i;
4797 using Point3i = Vec3i;
4798 using Point4i = Vec4i;
4799}
4800
4801#endif
4802#ifndef OPENGLAPI_H
4803#define OPENGLAPI_H
4804
4805#include <GL/glew.h>
4806#include <opengl/OpenGLUtils.h>
4807#include <math/RTMath.h>
4808#include <memory>
4809#include <vector>
4810#include <functional>
4811#include <opengl/GLTexture.h>
4812#include <opengl/GLVertexArray.h>
4813#include <opengl/GLShaderSource.h>
4814#include <StackTrivial.h>
4815#include <opengl/GLMaterialSetup.h>
4816#include <opengl/GLShaderSetup.h>
4817#include <opengl/GLSLShaderGenerator.h>
4818#include <opengl/GLShaderProgram.h>
4819#include <opengl/GLFramebuffer.h>
4820#include <opengl/GLSampler.h>
4821#include <opengl/GLBuffer.h>
4822#include <cstdint>
4823#include <opengl/GLShaderInterface.h>
4824#include <opengl/GLMaterialSetup.h>
4825#include <boost/pool/object_pool.hpp>
4826#include <AABB.h>
4827#include <deque>
4828#include <Plane.h>
4829#include <Sphere.h>
4830#include <RenderContext.h>
4831
4832namespace RT
4833{
4834 class Mesh;
4835 class Material;
4836 class GLSLShaderGenerator;
4837 struct GlobalShaderParams;
4838 class GLSampler;
4839 class GraphicsSettings;
4840
4841 class OpenGLAPI : public RenderContext
4842 {
4843 public:
4844 OpenGLAPI(Vec4f const & clear_color);
4845 OpenGLAPI(OpenGLAPI const & other) = delete;
4846 OpenGLAPI& operator=(OpenGLAPI const & other) = delete;
4847 OpenGLAPI(OpenGLAPI&& other) = default;
4848 OpenGLAPI& operator=(OpenGLAPI&& other) = default;
4849 ~OpenGLAPI();
4850 virtual void setViewport(Vec2u const & size) const override;
4851 auto clearRendertarget(bool color, bool depth, bool stencil) const
4852 {
4853 GLbitfield flag = 0;
4854 if (color) {
4855 flag |= GL_COLOR_BUFFER_BIT;
4856 }
4857 if (depth) {
4858 flag |= GL_DEPTH_BUFFER_BIT;
4859 }
4860 if (stencil) {
4861 flag |= GL_STENCIL_BUFFER_BIT;
4862 }
4863 GL_CHECK(glClear(flag));
4864 }
4865 virtual void clearRendertarget(bool const & color, bool const & depth, bool const & stencil) const override
4866 {
4867 GLbitfield flag = 0;
4868 if (color) {
4869 flag |= GL_COLOR_BUFFER_BIT;
4870 }
4871 if (depth) {
4872 flag |= GL_DEPTH_BUFFER_BIT;
4873 }
4874 if (stencil) {
4875 flag |= GL_STENCIL_BUFFER_BIT;
4876 }
4877 GL_CHECK(glClear(flag));
4878 }
4879 static const size_t _maxRendertargets = 8;
4880 virtual void setDepthTestEnabled(bool const & enabled) const override { GL_CHECK(enabled ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST)); }
4881 virtual void setFaceCullingEnabled(bool const & enabled) const { GL_CHECK(enabled ? glEnable(GL_CULL_FACE) : glDisable(GL_CULL_FACE)); }
4882 virtual void setDepthClampEnabled(bool const & enabled) const { GL_CHECK(enabled ? glEnable(GL_DEPTH_CLAMP) : glDisable(GL_DEPTH_CLAMP)); }
4883 virtual void setDepthWriteEnabled(bool const & enabled) const { GL_CHECK(glDepthMask(enabled)); }
4884 virtual void setDepthFunc(DepthFunc const & f) const override
4885 {
4886 GLenum func;
4887 if (f == DepthFunc::NEVER) {
4888 func = GL_NEVER;
4889 }
4890 else if (f == DepthFunc::LESS) {
4891 func = GL_LESS;
4892 }
4893 else if (f == DepthFunc::EQUAL) {
4894 func = GL_EQUAL;
4895 }
4896 else if (f == DepthFunc::LEQUAL) {
4897 func = GL_LEQUAL;
4898 }
4899 else if (f == DepthFunc::GREATER) {
4900 func = GL_GREATER;
4901 }
4902 else if (f == DepthFunc::NOTEQUAL) {
4903 func = GL_NOTEQUAL;
4904 }
4905 else if (f == DepthFunc::GEQUAL) {
4906 func = GL_GEQUAL;
4907 }
4908 else if (f == DepthFunc::ALWAYS) {
4909 func = GL_ALWAYS;
4910 }
4911 GL_CHECK(glDepthFunc(func));
4912 }
4913 virtual void setCullMode(CullMode const & m) const override
4914 {
4915 GL_CHECK(glCullFace(m == CullMode::BACK ? GL_BACK : GL_FRONT));
4916 }
4917 using ShaderGenerator = GLSLShaderGenerator;
4918 virtual std::shared_ptr<Texture> createRenderToTexture(Vec2u const & size, Texture::TexFilter const & tf) const override
4919 {
4920 auto tex = std::make_shared<GLTexture>(GL_TEXTURE_2D);
4921 tex->bind();
4922 tex->setTexMinFilter(tf);
4923 tex->setTexMagFilter<GLTexture::TexFilter::LINEAR>();
4924 tex->param(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
4925 tex->param(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
4926 tex->image2D(0, GL_RGBA16F, size, 0, GL_RGBA, GL_FLOAT, nullptr);
4927 return tex;
4928 }
4929 virtual Rendertarget* createRendertarget() const override
4930 {
4931 return new GLFramebuffer();
4932 }
4933 virtual Rendertarget* createRendertarget(std::vector<std::shared_ptr<Texture>> const & color_attachments, std::shared_ptr<Texture> const & depth_attachment) const override
4934 {
4935 return new GLFramebuffer(color_attachments, depth_attachment);
4936 }
4937 virtual Rendertarget* createRendertarget(std::vector<std::shared_ptr<Texture>> const & color_attachments, std::shared_ptr<Texture> const & depth_attachment, int const & depth_layer) const override
4938 {
4939 return new GLFramebuffer(color_attachments, depth_attachment, depth_layer);
4940 }
4941 class GLMeshData : public GPUMeshData
4942 {
4943 public:
4944 explicit GLMeshData(Mesh& mesh);
4945 GLMeshData(GLMeshData const & other) = delete;
4946 GLMeshData& operator=(GLMeshData const & other) = delete;
4947 GLMeshData(GLMeshData&& other) noexcept = default;
4948 GLMeshData& operator=(GLMeshData&& other) noexcept = default;
4949 virtual int const & count() const override { return _count; }
4950 auto type() const { return _type; }
4951 auto const & vao() const { return _vao; }
4952 virtual void draw() const override;
4953 virtual Mesh& mesh() override { return _mesh; }
4954 private:
4955 GLVertexArray _vao;
4956 GLBuffer _vbo;
4957 GLBuffer _ibo;
4958 GLsizei _count;
4959 GLenum _type;
4960 Mesh& _mesh;
4961 };
4962 // Texture unit bindings
4963 static constexpr const int diffuseTexUnit = 0;
4964 static constexpr const int alphaTexUnit = 1;
4965 static constexpr const int normalTexUnit = 2;
4966 static constexpr const int heightTexUnit = 3;
4967 static constexpr const int miscTexUnit0 = 4;
4968 static constexpr const int miscTexUnit1 = 5;
4969 static constexpr const int miscTexUnit2 = 6;
4970 static constexpr const int miscTexUnit3 = 7;
4971 static constexpr const int miscTexUnit4 = 8;
4972 static constexpr const int miscTexUnit5 = 9;
4973 virtual void beginFrame() const;
4974 virtual void bindShader(Shader const * shader) override;
4975 virtual void bindShadowmap(const Texture& shadowmap) const override;
4976 virtual void renderMesh(const GPUMeshData& gmd) const override;
4977 virtual void renderMesh(const GPUMeshData& gmd, const Mat4f& model_matrix) const override;
4978 virtual void renderMesh(const GPUMeshData& gmd, const Mat4f& model_matrix, const Mat3f& model_matrix_inverse) const override;
4979 virtual void render2DBillboard(const Vec2f& pos_ndc, const Vec2f& scale, const Texture& texture, const Vec3f& color, float depth_ndc) override;
4980 virtual void renderDebugTriangle(const Vec4f* first, const Mat4f& mvp, const Vec3f& color) override;
4981 virtual void renderDebugFrustum(const Mat4f& vp_debug_frustum, const Mat4f& mvp) override;
4982 virtual void bindBackbuffer(unsigned const & id) const override;
4983 virtual void ssr(const Texture& lighting_buffer, const Texture& view_space_normals, const Texture& depth_buffer,
4984 const Mat4f& projection_matrix, const Vec4f& blend_weight, Texture& lighting_buffer_copy) override;
4985 virtual void separableBlur(Texture const & in, std::array<std::shared_ptr<Rendertarget>, 2> const & out) override;
4986 virtual void renderGodRays(const Texture& depth_buffer, const Texture& lighting_buffer, const Vec2f& light_pos_uv) override;
4987 virtual void renderBrightPass(const Texture& lighting_buffer) override;
4988 virtual void additiveBlend(const Texture& texture);
4989 virtual void endFrame() const;
4990 virtual void setAnisotropy(unsigned anisotropy);
4991 virtual void enablePolygonOffset(float factor, float units) const;
4992 virtual void disablePolygonOffset() const;
4993 virtual void renderSkydome(const Mat4f& view_projection_matrix, const GPUMeshData& gs);
4994 virtual Texture* createTexture(std::string const & path) const;
4995 virtual void deleteTexture(Texture const * texture) const;
4996 // virtual Shader* createShader(GLShaderSource& vs, GLShaderSource& fs, GLShaderSource& gs = GLShaderSource());
4997 // virtual void deleteShader(Shader* shader);
4998 virtual std::shared_ptr<Texture> createDepthbuffer(Vec2u const & size);
4999 virtual std::shared_ptr<Texture> createShadowmap(GraphicsSettings const & settings);
5000 virtual void setupCompositing(Texture const & lighting_buffer) const override;
5001 // virtual void setupFog(Vec2f const & fog_start_end) const override;
5002 virtual void setupDepthOfField(const GlobalShaderParams & params, Texture const & dof_buffer, Texture const & depth_buffer, Vec3f const & near_center_far) const override;
5003 virtual void setupGodRays(const Vec3f& god_ray_intensity, Texture const & god_ray_buffer) const override;
5004 virtual void setupBloom(Texture const & bloom_buffer) const override;
5005 virtual void setupAutoExposure(const Texture& lighting_buffer) const override;
5006 virtual void resizeShadowmap(Texture& shadow_map, GraphicsSettings const & settings) override;
5007 virtual void createBlurShader(const GraphicsSettings& gs) override;
5008 virtual void createCompositeShader(const GraphicsSettings& gs) override;
5009 virtual void createScreenSpaceReflectionsShader(const GraphicsSettings& gs) override;
5010 virtual void createGodRayShader(const GraphicsSettings& gs) override;
5011 virtual void createBrightnessShader(const GraphicsSettings& gs) override;
5012 virtual MaterialDesc* createMaterialDesc(std::shared_ptr<Material> const & material, GraphicsSettings const & settings,
5013 PtrCache<std::string, Texture>* texture_cache,
5014 PtrCache<std::shared_ptr<Shader>, ShaderDesc>* shader_desc_cache,
5015 PtrCache<std::string, Shader>* shader_cache) const override;
5016 virtual GPUMeshData* createMeshData(Mesh& mesh) const override;
5017 ShaderGenerator const & shaderGenerator() const;
5018 auto activateTexture(Texture const & texture, char const * key, GLint const & tex_unit) const
5019 {
5020 GL_CHECK(glActiveTexture(GL_TEXTURE0 + tex_unit));
5021 texture.bind();
5022 setScalar(_activeShader->uniformLocation(key), tex_unit);
5023 }
5024 virtual Shader const & compositeShader() const override;
5025 virtual Shader const & compositeShaderWithGodRays() const override;
5026 auto renderQuad() const
5027 {
5028 GL_CHECK(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
5029 }
5030 virtual void composite() const override;
5031 private:
5032 struct GlewInit
5033 {
5034 GlewInit();
5035 };
5036 void checkFramebufferStatus();
5037 GlewInit _glewInit;
5038 GLShaderProgram _compositeShader;
5039 GLShaderProgram _compositeShaderWithGodRays;
5040 GLShaderProgram _skydomeShader;
5041 GLShaderProgram _ssrShader;
5042 GLShaderProgram _blurShader;
5043 GLShaderProgram _brightnessShader;
5044 GLShaderProgram _boxShader;
5045 GLShaderProgram _copyShader;
5046 GLShaderProgram _triangleDebugShader;
5047 GLShaderProgram _trianglesDebugShader;
5048 GLShaderProgram _springParticleDebugShader;
5049 GLShaderProgram _springDebugShader;
5050 GLShaderProgram _2DBillboardShader;
5051 ShaderGenerator _shaderGenerator;
5052 GLSampler _samplerAnisotropic;
5053 GLint _glVersionMajor, _glVersionMinor;
5054 GLShaderProgram _debugFrustumShader;
5055 GLShaderProgram _godRayShader;
5056 GLShaderProgram _particleShader;
5057 unsigned _anisotropy = 1u;
5058 GLShaderProgram createMiscShader(GLShaderSource& vs, GLShaderSource& fs, GLShaderSource& gs = GLShaderSource()) const;
5059 //boost::object_pool<GLTexture> _texturePool;
5060 // boost::object_pool<GLShaderProgram> _shaderPool;
5061 static void setupVertexFormat();
5062 template<typename T>
5063 static GLenum fillIndexBuffer(T const * verts_begin, T const * verts_end, unsigned const * inds_begin, unsigned const * inds_end, GLBuffer& index_buffer)
5064 {
5065 if (static_cast<size_t>(verts_end - verts_begin - 1u) <= static_cast<size_t>(std::numeric_limits<unsigned short>::max())) {
5066 StackTrivial<unsigned short> indices;
5067 indices.reserve(inds_end - inds_begin);
5068 while (inds_begin != inds_end) {
5069 indices.push_back_unchecked(static_cast<unsigned short>(*inds_begin++));
5070 }
5071 index_buffer.setData(indices.begin(), indices.size());
5072 return GL_UNSIGNED_SHORT;
5073 }
5074 else {
5075 index_buffer.setData(inds_begin, inds_end - inds_begin);
5076 return GL_UNSIGNED_INT;
5077 }
5078 }
5079 };
5080}
5081
5082#endif
5083#ifndef PHYSICSCAMERACONTROLLER_H
5084#define PHYSICSCAMERACONTROLLER_H
5085
5086#include <memory>
5087#include <math/RTMath.h>
5088#include <FixedTimestepSystem.h>
5089#include <Primitive.h>
5090
5091namespace RT
5092{
5093 class Camera;
5094 class BVTree;
5095
5096 class PhysicsCameraController : public FixedTimestepSystem
5097 {
5098 private:
5099 using Type = Primitive::Type;
5100 using Vector = Vector<3, Type>;
5101 public:
5102 PhysicsCameraController(Camera* const & camera, BVTree*& BVTree);
5103 virtual ~PhysicsCameraController() = default;
5104 virtual void updateSystem() override;
5105 virtual unsigned getID() override;
5106 virtual const char* getName() override;
5107 void setAcceleration(Vector const & dir, Type const & amount);
5108 void setAngularAcceleration(Vector const & aa);
5109 Camera * const & getCamera() const;
5110 void setCamera(Camera * const & camera);
5111 void setDamping(Type const & damping);
5112 Vector const & gravity() const;
5113 void setGravity(Vector const & gravity);
5114 bool const & collisions() const;
5115 void setCollisions(bool const & collisions);
5116 private:
5117 Camera* _c;
5118 Vector _acceleration = static_cast<Type>(0);
5119 Vector _velocity = static_cast<Type>(0);
5120 Type _damp = DAMP_DEFAULT;
5121 Vector _angularAcceleration = static_cast<Type>(0);
5122 Vector _angularVelocity = static_cast<Type>(0);
5123 Vector _gravity = static_cast<Type>(0);
5124 BVTree*& _BVTree;
5125 bool _collisions = true;
5126 static constexpr const Type DAMP_DEFAULT = static_cast<Type>(0.95);
5127 static constexpr const Type DAMP_INTERIOR = static_cast<Type>(0.7);
5128 };
5129}
5130
5131#endif
5132#ifndef MESHRENDERABLES_H
5133#define MESHRENDERABLES_H
5134
5135#include <memory>
5136#include <functional>
5137#include <Primitive.h>
5138#include <Transform.h>
5139
5140#define DYNAMIC_INVERSE 1
5141
5142namespace RT
5143{
5144 class Renderer;
5145 class RenderList;
5146 class CullingParams;
5147 class Transform;
5148 class RenderContext;
5149 class ShaderDesc;
5150 class MaterialDesc;
5151 class GPUMeshData;
5152 class Material;
5153
5154 class LodRenderable
5155 {
5156 public:
5157 LodRenderable() = default;
5158 virtual ~LodRenderable() = default;
5159 virtual void selectLod(CullingParams const & cp) = 0;
5160 };
5161 class GPURenderable
5162 {
5163 public:
5164 GPURenderable() = default;
5165 virtual ~GPURenderable() = default;
5166 virtual void cullGPU(const RenderContext& api) = 0;
5167 };
5168
5169 class IMeshRenderable : public Primitive
5170 {
5171 public:
5172 IMeshRenderable() = default;
5173 virtual ~IMeshRenderable() = default;
5174
5175 std::shared_ptr<ShaderDesc> const * shaderDesc() const;
5176 std::shared_ptr<ShaderDesc> const * shaderDescDepth() const;
5177 MaterialDesc* materialDesc() const;
5178
5179 virtual void renderDepth(RenderContext const & rc) const = 0;
5180 virtual void render(RenderContext const & api) const = 0;
5181 virtual GPUMeshData* gpuMeshData() const = 0;
5182 virtual void setModelMatrix(Mat4f const & m);
5183 virtual void add(RenderList& renderlist) override;
5184 virtual void addUnchecked(RenderList& renderlist) override;
5185 virtual void addIfContributes(const CullingParams& cp, RenderList& renderlist) override;
5186 virtual void addIfContributesUnchecked(const CullingParams& cp, RenderList& renderlist) override;
5187 virtual void addIfContributesAndVisible(const CullingParams& cp, RenderList& renderlist) override;
5188 virtual unsigned numMeshes() const override;
5189 protected:
5190 std::shared_ptr<ShaderDesc> const * _shaderDesc;
5191 std::shared_ptr<ShaderDesc> const * _shaderDescDepth;
5192 std::shared_ptr<MaterialDesc> _materialDesc;
5193 void createBV(const Mesh& mesh, const Transform& transform, Sphere3f& result);
5194 void createBV(Mesh const & mesh, Transform const & transform, AABB3f& result);
5195 bool contributes(CullingParams const & cp) const;
5196 bool intersectFrustum(CullingParams const & cp) const;
5197 };
5198 class SkydomeRenderable
5199 {
5200 public:
5201 SkydomeRenderable(Renderer& renderer, const std::shared_ptr<Mesh>& mesh);
5202 std::shared_ptr<GPUMeshData> const & storage() const;
5203 private:
5204 std::shared_ptr<GPUMeshData> _gmd;
5205 };
5206 class StaticMeshRenderable : public IMeshRenderable
5207 {
5208 public:
5209 StaticMeshRenderable(Renderer& renderer, std::shared_ptr<Mesh> const & mesh,
5210 std::shared_ptr<Material> const & material, Transform const & transform);
5211 virtual ~StaticMeshRenderable() = default;
5212 virtual void render(RenderContext const & rc) const override;
5213 virtual void renderDepth(RenderContext const & rc) const override;
5214 virtual unsigned numTriangles() const override;
5215 virtual BVTree * nestedBVTree() override;
5216 virtual std::shared_ptr<BVTree> transformedBVTree(boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const override;
5217 virtual GPUMeshData* gpuMeshData() const override;
5218 virtual Mat4f const * modelMatrix() const override;
5219 virtual void setModelMatrix(Mat4f const & m);
5220 virtual BV bv() const override;
5221 virtual BV bvLocal() const override;
5222 virtual Type squaredSize() const override;
5223 virtual Ray::IntersectionResult intersect(Ray const & ray) override;
5224 virtual Ray::IntersectionResult intersect(Ray const & ray, Matrix const & matrix) override;
5225 virtual size_t sizeInBytes() const override;
5226 protected:
5227 std::shared_ptr<GPUMeshData> _gmd;
5228 Mat4f _modelMatrix;
5229#if !DYNAMIC_INVERSE
5230 Mat3f _modelMatrixInverse;
5231#endif
5232 };
5233
5234 class StaticMeshRenderableTransform : public StaticMeshRenderable
5235 {
5236 public:
5237 StaticMeshRenderableTransform(Renderer& renderer, std::shared_ptr<Mesh> const & mesh,
5238 std::shared_ptr<Material> const & material, Transform const & transform);
5239 void setTransform(Transform const & t);
5240 virtual Transform const * transform() const override;
5241 private:
5242 Transform _transform;
5243 };
5244
5245 class StaticMeshRenderableShared : public IMeshRenderable
5246 {
5247 public:
5248 StaticMeshRenderableShared(Renderer& renderer, const std::shared_ptr<Mesh>& mesh,
5249 const std::shared_ptr<Material>& material, const std::shared_ptr<Mat4f>& model_matrix);
5250 virtual ~StaticMeshRenderableShared() = default;
5251 virtual void render(RenderContext const & rc) const override;
5252 virtual void renderDepth(RenderContext const & rc) const override;
5253 virtual unsigned numTriangles() const override;
5254 virtual GPUMeshData* gpuMeshData() const override;
5255 virtual Mat4f const * modelMatrix() const override;
5256 virtual BVTree * nestedBVTree() override;
5257 virtual std::shared_ptr<BVTree> transformedBVTree(boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const override;
5258 virtual BV bv() const override;
5259 virtual Type squaredSize() const override;
5260 virtual Ray::IntersectionResult intersect(Ray const & ray) override;
5261 virtual Ray::IntersectionResult intersect(Ray const & ray, Matrix const & matrix) override;
5262 virtual size_t sizeInBytes() const override;
5263 protected:
5264 std::shared_ptr<GPUMeshData> _gmd;
5265 std::shared_ptr<Mat4f> _modelMatrix;
5266 };
5267 class StaticMeshRenderableLod : public IMeshRenderable, public LodRenderable
5268 {
5269 public:
5270 StaticMeshRenderableLod(Renderer& renderer, std::vector<std::shared_ptr<Mesh>> const & meshes,
5271 std::shared_ptr<Material> const & material, Transform const & transform);
5272 virtual ~StaticMeshRenderableLod() = default;
5273 virtual void render(RenderContext const & rc) const override;
5274 virtual void renderDepth(RenderContext const & rc) const override;
5275 virtual unsigned numTriangles() const override;
5276 virtual void add(RenderList& renderlist) override;
5277 virtual void addUnchecked(RenderList& renderlist) override;
5278 virtual void selectLod(const CullingParams& cp) override;
5279 virtual GPUMeshData* gpuMeshData() const override;
5280 virtual Mat4f const * modelMatrix() const override;
5281 virtual BV bv() const override;
5282 virtual BVTree * nestedBVTree() override;
5283 virtual std::shared_ptr<BVTree> transformedBVTree(boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const override;
5284 virtual Type squaredSize() const override;
5285 virtual Ray::IntersectionResult intersect(Ray const & ray) override;
5286 virtual Ray::IntersectionResult intersect(Ray const & ray, Matrix const & matrix) override;
5287 virtual size_t sizeInBytes() const override;
5288 protected:
5289 std::vector<std::shared_ptr<GPUMeshData>> _gmd;
5290 Mat4f _modelMatrix;
5291#if !DYNAMIC_INVERSE
5292 Mat3f _modelMatrixInverse;
5293#endif
5294 unsigned _lod = 0;
5295 };
5296
5297 class MeshRenderablePool
5298 {
5299 public:
5300 MeshRenderablePool() = default;
5301 StaticMeshRenderable* createStaticMeshRenderable(Renderer& renderer, std::shared_ptr<Mesh> const & mesh,
5302 std::shared_ptr<Material> const & material, Transform const & transform)
5303 {
5304 return new(_poolSmr.malloc()) StaticMeshRenderable(renderer, mesh, material, transform);
5305 }
5306 StaticMeshRenderableShared* createStaticMeshRenderableShared(Renderer& renderer, std::shared_ptr<Mesh> const & mesh,
5307 std::shared_ptr<Material> const & material, std::shared_ptr<Mat4f> const & model_matrix)
5308 {
5309 return new(_poolSmrShared.malloc()) StaticMeshRenderableShared(renderer, mesh, material, model_matrix);
5310 }
5311 StaticMeshRenderableLod* createStaticMeshRenderableLod(Renderer& renderer, std::vector<std::shared_ptr<Mesh>> const & meshes,
5312 std::shared_ptr<Material> const & material, Transform const & transform)
5313 {
5314 return new(_poolSmrLod.malloc()) StaticMeshRenderableLod(renderer, meshes, material, transform);
5315 }
5316 StaticMeshRenderableTransform* createStaticMeshRenderableTransform(Renderer& renderer, std::shared_ptr<Mesh> const & mesh,
5317 std::shared_ptr<Material> const & material, Transform const & transform)
5318 {
5319 return new(_poolSmrTransform.malloc()) StaticMeshRenderableTransform(renderer, mesh, material, transform);
5320 }
5321 private:
5322 boost::object_pool<StaticMeshRenderable> _poolSmr;
5323 boost::object_pool<StaticMeshRenderableShared> _poolSmrShared;
5324 boost::object_pool<StaticMeshRenderableLod> _poolSmrLod;
5325 boost::object_pool<StaticMeshRenderableTransform> _poolSmrTransform;
5326 };
5327}
5328
5329#endif // !MESHRENDERABLES_H
5330#ifndef RENDERER_H
5331#define RENDERER_H
5332
5333#include <math/MathHelpers.h>
5334#include <System.h>
5335#include <math/RTMath.h>
5336#include <glm/gtx/quaternion.hpp>
5337#include <map>
5338#include <Model.h>
5339#include <memory>
5340#include <Camera.h>
5341#include <Light.h>
5342#include <iostream>
5343#include <Settings.h>
5344#include <functional>
5345#include <GraphicsSettings.h>
5346#include <Timing.h>
5347#include <StackTrivial.h>
5348#include <Flags.h>
5349#include <renderer/MeshRenderables.h>
5350#include <set>
5351#include <GameTimer.h>
5352#include <GlobalShaderParams.h>
5353#include <future>
5354#include <BVTree.h>
5355#include <RenderList.h>
5356#include <PtrCache.h>
5357#include <boost/pool/object_pool.hpp>
5358#include <deque>
5359#include <StringHelper.h>
5360#include <Ray.h>
5361#include <renderer/Rendertargets.h>
5362#include <RenderContext.h>
5363#include <BVTreeLeafNode.h>
5364#include <BVTreeInternalNode.h>
5365#include <FrustumVertices.h>
5366
5367#define RENDERER_STATS 1
5368
5369namespace RT
5370{
5371 class Renderer : public System, public GraphicsSettings::Listener
5372 {
5373 public:
5374 using BV = typename Primitive::BV;
5375 using BVTree = BVTree;
5376 using Type = typename Primitive::Type;
5377 using Vec2 = Vector<2, Type>;
5378 using Vec3 = Vector<3, Type>;
5379 using Vec4 = Vector<4, Type>;
5380 using Matrix = typename Primitive::Matrix;
5381 using Ray = typename Primitive::Ray;
5382 using MeshRenderable = IMeshRenderable;
5383 using MeshRenderablePtr = MeshRenderable * ;
5384 using MaterialDescCache = PtrCache<std::shared_ptr<Material>, MaterialDesc>;
5385 using MeshCache = PtrCache<std::shared_ptr<Mesh>, GPUMeshData>;
5386#if RENDERER_STATS
5387 struct CullingStats
5388 {
5389 unsigned _BVTreeTraversalMicroSeconds;
5390 unsigned _fineCullingMicroSeconds;
5391 };
5392 struct RendererStats
5393 {
5394 unsigned _renderedTriangles;
5395 unsigned _renderedTrianglesShadow;
5396 unsigned _renderedMeshes;
5397 unsigned _renderedMeshesShadow;
5398 unsigned _sceneRenderingCPUMicroSeconds;
5399 unsigned _shadowMapRenderCPUMicroSeconds;
5400 unsigned _sceneMeshGroupingMicroSeconds;
5401 unsigned _shadowMapGroupingMicroSeconds;
5402 unsigned _rendererIdleTimeMicroSeconds;
5403 CullingStats _cullStats;
5404 CullingStats _cullStatsSM;
5405 };
5406
5407 auto const & stats() const { return _stats; }
5408#endif
5409 Renderer(GraphicsSettings * gs, RenderContext& rc) : _rc(rc), _gs(gs)
5410 {
5411 _mainRendertarget = std::unique_ptr<Rendertarget>(rc.createRendertarget());
5412 onResize(_viewPortSize);
5413 _blurredCircleTexture = _rc.createTexture("assets/circle.png");
5414 _blurredCircleTexture2 = _rc.createTexture("assets/circle2.png");
5415 }
5416 virtual ~Renderer()
5417 {
5418 delete _BVTreeStatic;
5419 _rc.deleteTexture(_blurredCircleTexture);
5420 _rc.deleteTexture(_blurredCircleTexture2);
5421 std::cout << "~Renderer()" << std::endl;
5422 _skydomeRenderable = nullptr;
5423 if (_shaderCache.size() || _shaderDescCache.size() || _materialDescCache.size() || _textureCache.size() || _meshCache.size()) {
5424 std::cout << "Error: Potential space leak detected!" << std::endl;
5425 std::cout << "Num shader descriptions:" << _shaderDescCache.size() << std::endl;
5426 std::cout << "Num material descriptions:" << _materialDescCache.size() << std::endl;
5427 std::cout << "Num shaders:" << _shaderCache.size() << std::endl;
5428 std::cout << "Num textures:" << _textureCache.size() << std::endl;
5429 std::cout << "Num meshes:" << _meshCache.size() << std::endl;
5430 abort();
5431 }
5432 }
5433 virtual unsigned getID() override
5434 {
5435 return 2;
5436 }
5437 virtual const char* getName() override
5438 {
5439 return "Renderer";
5440 }
5441 virtual void normalMappingChanged(GraphicsSettings const * gs) override
5442 {
5443 }
5444 virtual void depthOfFieldChanged(GraphicsSettings const * gs) override
5445 {
5446 for (unsigned i = 0; i < _rt._dofBuffer.size(); i++) {
5447 _rt._dofBuffer[i] = nullptr;
5448 _dofRendertargets[i] = nullptr;
5449 }
5450 if (gs->depthOfField()) {
5451 for (unsigned i = 0; i < _rt._dofBuffer.size(); i++) {
5452 _rt._dofBuffer[i] = _rc.createRenderToTexture(_viewPortSize * gs->depthOfFieldScaleFactor(), Texture::TexFilter::LINEAR);
5453 std::vector<std::shared_ptr<Texture>> color_attachments = { _rt._dofBuffer[i] };
5454 _dofRendertargets[i] = std::shared_ptr<Rendertarget>(_rc.createRendertarget(color_attachments, nullptr));
5455 }
5456 _rc.createBlurShader(*gs);
5457 }
5458 compositingChanged(gs);
5459 }
5460 virtual void bloomChanged(GraphicsSettings const * gs) override
5461 {
5462 _bloomRendertargets.clear();
5463 _rt._bloomTextures.clear();
5464 if (_gs->bloom()) {
5465 _rt._bloomTextures.resize(_gs->bloomSteps());
5466 _bloomRendertargets.resize(_gs->bloomSteps());
5467 for (unsigned i = 0; i < _gs->bloomSteps(); i++) {
5468 for (unsigned j = 0; j < 2; j++) {
5469 _rt._bloomTextures[i][j] = _rc.createRenderToTexture(_viewPortSize * (std::pow(gs->bloomScaleFactor(), static_cast<float>(i + 1))), Texture::TexFilter::LINEAR);
5470 std::vector<std::shared_ptr<Texture>> color_attachments = { _rt._bloomTextures[i][j] };
5471 _bloomRendertargets[i][j] = std::shared_ptr<Rendertarget>(_rc.createRendertarget(color_attachments, nullptr));
5472 }
5473 }
5474 _rc.createBrightnessShader(*gs);
5475 }
5476 compositingChanged(gs);
5477 }
5478 virtual void screenSpaceReflectionsChanged(GraphicsSettings const * gs) override
5479 {
5480 std::vector<std::shared_ptr<Texture>> color_attachments = { _rt._lightingBuffer };
5481 if (gs->screenSpaceReflections()) {
5482 _rc.createScreenSpaceReflectionsShader(*gs);
5483 _rt._lightingBufferCopy = std::shared_ptr<Texture>(_rt._lightingBuffer->copy());
5484 _rt._viewSpaceNormals = _rc.createRenderToTexture(_viewPortSize, Texture::TexFilter::NEAREST);
5485 color_attachments.push_back(_rt._viewSpaceNormals);
5486 std::vector<std::shared_ptr<Texture>> color_attachments_ssr = { _rt._lightingBuffer };
5487 _ssrRendertarget = std::unique_ptr<Rendertarget>(_rc.createRendertarget(color_attachments_ssr, nullptr));
5488 }
5489 else {
5490 _rt._lightingBufferCopy = nullptr;
5491 _rt._viewSpaceNormals = nullptr;
5492 _ssrRendertarget = nullptr;
5493 }
5494 _mainRendertarget = std::unique_ptr<Rendertarget>(_rc.createRendertarget(color_attachments, _rt._depthBuffer));
5495 }
5496 virtual void shadowsChanged(GraphicsSettings const * gs) override
5497 {
5498 _shadowMapping = gs->shadows() || gs->shadowsPCF() || gs->softShadows();
5499 _rt._shadowMap = _shadowMapping ? _rc.createShadowmap(*_gs) : nullptr;
5500 _shadowRendertargets.clear();
5501 if (_rt._shadowMap) {
5502 for (int i = 0; i < static_cast<int>(_gs->numFrustumSplits()); i++) {
5503 _shadowRendertargets.push_back(std::unique_ptr<Rendertarget>(_rc.createRendertarget({}, _rt._shadowMap, i)));
5504 }
5505 }
5506 }
5507 virtual void shadowMapSizeChanged(GraphicsSettings const * gs) override
5508 {
5509 if (_rt._shadowMap) {
5510 _rc.resizeShadowmap(*_rt._shadowMap, *_gs);
5511 }
5512 }
5513 virtual void compositingChanged(GraphicsSettings const * gs) override
5514 {
5515 if (gs->postProcessingEnabled()) {
5516 _rc.createCompositeShader(*_gs);
5517 }
5518 }
5519 virtual void gammaChanged(GraphicsSettings const * gs) override
5520 {
5521 compositingChanged(gs);
5522 }
5523 virtual void anisotropyChanged(GraphicsSettings const * gs) override
5524 {
5525 _rc.setAnisotropy(gs->getAnisotropy());
5526 }
5527 virtual void godRaysChanged(GraphicsSettings const * gs) override
5528 {
5529 if (gs->godRays()) {
5530 _rt._godRayBuffer = _rc.createRenderToTexture(_viewPortSize * gs->godRayScale(), Texture::TexFilter::LINEAR);
5531 std::vector<std::shared_ptr<Texture>> color_attachments = { _rt._godRayBuffer };
5532 _godRayRendertarget = std::unique_ptr<Rendertarget>(_rc.createRendertarget(color_attachments, nullptr));
5533 _rc.createGodRayShader(*gs);
5534 }
5535 else {
5536 _rt._godRayBuffer = nullptr;
5537 _godRayRendertarget = nullptr;
5538 }
5539 compositingChanged(gs);
5540 }
5541 virtual void fogChanged(GraphicsSettings const * gs) override
5542 {
5543 }
5544 auto updateBounds(Primitive* p)
5545 {
5546 _sceneBounds.unify(p->bv());
5547 }
5548 auto updateBounds(std::vector<Primitive*> const & primitives)
5549 {
5550 for (auto const & p : primitives) {
5551 _sceneBounds.unify(p->bv());
5552 }
5553 }
5554 auto setSkydome(std::shared_ptr<SkydomeRenderable> const & sdr)
5555 {
5556 _skydomeRenderable = sdr;
5557 }
5558 auto const & skydome() const
5559 {
5560 return _skydomeRenderable;
5561 }
5562 auto setCamera(std::shared_ptr<Camera> const & camera)
5563 {
5564 _camera = camera;
5565 }
5566 auto setDirectionalLight(std::shared_ptr<DirectionalLight> const & dl)
5567 {
5568 _directionalLight = dl;
5569 }
5570 auto ndcNear(Vec2 const & ndc) const
5571 {
5572 return ndc.appendMinusOne();
5573 }
5574 auto ndcFar(Vec2 const & ndc) const
5575 {
5576 return ndc.appendOne();
5577 }
5578 auto rayFromNdc(Vec2 const & ndc) const
5579 {
5580 auto vp_inverse = _camera->viewMatrixInverse() * inverse(_gsp._projectionMatrix);
5581 auto ray_near_world = (vp_inverse * ndcNear(ndc)).toCartesian();
5582 return Ray(ray_near_world, (vp_inverse * ndcFar(ndc)).toCartesian() - ray_near_world);
5583 }
5584 auto rayFromUV(Vec2 const & uv) const
5585 {
5586 return rayFromNdc(uv.UVToNDC());
5587 }
5588 auto uvFromWindowPos(Vec2 const & window_pos) const
5589 {
5590 return Vec2(window_pos.at<0>() / _viewPortSize.at<0>(),
5591 static_cast<Type>(1) - window_pos.at<1>() / _viewPortSize.at<1>());
5592 }
5593 auto ray(Vec2 const & window_pos) const
5594 {
5595 return rayFromUV(uvFromWindowPos(window_pos));
5596 }
5597 auto const & camParams() const
5598 {
5599 return _camera->params();
5600 }
5601 auto const & viewMatrixOrtho() const
5602 {
5603 return _gsp._viewMatrixOrtho;
5604 }
5605 auto const & viewMatrix() const
5606 {
5607 return _gsp._viewMatrix;
5608 }
5609 virtual bool update() override
5610 {
5611#if RENDERER_STATS
5612 _stats = {};
5613#endif
5614 _multiThreadedCulling = _gs->multithreadedCulling() && _shadowMapping;
5615 _renderListScene = _multiThreadedCulling ? &_renderListAsync : &_renderList;
5616 _rc.beginFrame();
5617 _gsp._camPosworld = &_camera->pos();
5618 _gsp._viewMatrix = _camera->viewMatrix();
5619 _gsp._projectionMatrix = MathHelpers::projectionMatrixPerspective<Type>(_camera->params()._fovDegrees, _viewPortSize.aspectRatio(), _camera->params()._near, _camera->params()._far);
5620 _gsp._viewMatrixOrtho = _camera->viewMatrixOrtho();
5621 _vpScene = _gsp._projectionMatrix * _gsp._viewMatrix;
5622 _rc.setDepthTestEnabled(true);
5623 _rc.setFaceCullingEnabled(true);
5624 _rc.setCullMode(RenderContext::CullMode::FRONT);
5625 _rc.setDepthFunc(RenderContext::DepthFunc::LEQUAL);
5626 _rc.setDepthWriteEnabled(true);
5627 _gsp._lightDirWorld = &_directionalLight->direction();
5628 _gsp._lightIntensity = &_directionalLight->intensity();
5629 _gsp._time = _gameTimer->timeSeconds();
5630 _gsp._exposure = _gs->exposure();
5631 _gsp._gamma = _gs->gamma();
5632 _gsp._fogStartEnd = &_gs->fogStartEnd();
5633 _gsp._fogColor = &_gs->fogColor();
5634 std::future<void> async;
5635 auto cull_vp = _gsp._projectionMatrix * (*_cullCamera)->viewMatrix();
5636 if (_multiThreadedCulling) {
5637 async = std::async(std::launch::async, [this, cull_vp]() {
5638 _stats._cullStats = cullMeshes(cull_vp, **_cullCamera, *_renderListScene, _fullyVisibleMeshesAsync);
5639 });
5640 }
5641 if (_shadowMapping) {
5642 renderShadowMap();
5643 }
5644 if (_multiThreadedCulling) {
5645 {
5646#if RENDERER_STATS
5647 Timing timing;
5648#endif
5649 async.get();
5650#if RENDERER_STATS
5651 _stats._rendererIdleTimeMicroSeconds = timing.duration<std::chrono::microseconds>();
5652#endif
5653 }
5654 selectLod(*_renderListScene, **_cullCamera, cull_vp);
5655 }
5656 else {
5657 _stats._cullStats = cullMeshes(cull_vp, **_cullCamera, *_renderListScene, _fullyVisibleMeshes);
5658 selectLod(*_renderListScene, **_cullCamera, cull_vp);
5659 }
5660 _rc.setViewport(_viewPortSize);
5661 _gsp._VP = &_vpScene;
5662 _mainRendertarget ? _mainRendertarget->bind() : _rc.bindBackbuffer(_defaultRenderTarget);
5663 _rc.clearRendertarget(_skydomeRenderable == nullptr, !_gs->depthPrepassEnabled(), false);
5664 if (_rt._shadowMap) {
5665 _rc.bindShadowmap(*_rt._shadowMap);
5666 }
5667 renderScene();
5668 _rc.setCullMode(RenderContext::CullMode::BACK);
5669 if (_skydomeRenderable) {
5670 auto skydome_vp = _gsp._projectionMatrix * _camera->viewMatrixOrtho();
5671 _rc.renderSkydome(skydome_vp, *_skydomeRenderable->storage());
5672 }
5673 if (_debugTriangle) {
5674 _rc.setCullMode(RenderContext::CullMode::FRONT);
5675 _rc.renderDebugTriangle(_debugTriangle, _vpScene, Vector<3, Type>(static_cast<Type>(0), static_cast<Type>(1), static_cast<Type>(1)));
5676 _rc.setCullMode(RenderContext::CullMode::BACK);
5677 }
5678 if (_gs->autoExposure()) {
5679 _rt._lightingBuffer->generateMipmap();
5680 }
5681 auto light_pos_ndc = (_vpScene * Vector<4, Type>(*_gsp._camPosworld + *_gsp._lightDirWorld * -_camera->params()._far, static_cast<Type>(1))).toCartesian().reduce<>();
5682 _rc.render2DBillboard(light_pos_ndc, Vector<2, Type>(0.05) * Vector<2, Type>(static_cast<Type>(1), aspectRatio()), *_blurredCircleTexture, *_gsp._lightIntensity, static_cast<Type>(1));
5683 _rc.setDepthTestEnabled(false);
5684 if (_debugCamera) {
5685 _rc.renderDebugFrustum(_gsp._projectionMatrix * _debugCamera->viewMatrix(), _vpScene);
5686 }
5687 if (_ssrRendertarget) {
5688 _rt._depthBuffer->setTexMinFilter(Texture::TexFilter::LINEAR_MIPMAP_LINEAR);
5689 _rt._lightingBuffer->copyAssign(_rt._lightingBufferCopy.get());
5690 _rt._lightingBufferCopy->setTexMinFilter(Texture::TexFilter::LINEAR);
5691 _ssrRendertarget->bind();
5692 _rc.ssr(*_rt._lightingBuffer, *_rt._viewSpaceNormals, *_rt._depthBuffer, _gsp._projectionMatrix, Vector<4, Type>(_gs->SSRBlendWeight()), *_rt._lightingBufferCopy);
5693 _rt._depthBuffer->setTexMinFilter(Texture::TexFilter::NEAREST);
5694 }
5695 if (_gs->depthOfField()) {
5696 _rc.setViewport(_viewPortSize * _gs->depthOfFieldScaleFactor());
5697 _rt._lightingBuffer->setTexMinFilter(Texture::TexFilter::LINEAR);
5698 _rc.separableBlur(*_rt._lightingBuffer, _dofRendertargets);
5699 _rt._lightingBuffer->setTexMinFilter(Texture::TexFilter::NEAREST);
5700 _rc.setViewport(_viewPortSize);
5701 }
5702 if (_gs->bloom()) {
5703 _rc.setViewport(_viewPortSize * _gs->bloomScaleFactor());
5704 _bloomRendertargets[0][0]->bind();
5705 _rt._lightingBuffer->setTexMinFilter(Texture::TexFilter::LINEAR);
5706 _rc.renderBrightPass(*_rt._lightingBuffer);
5707 _rc.separableBlur(*_rt._bloomTextures[0][0], _bloomRendertargets[0]);
5708 for (unsigned i = 1; i < _gs->bloomSteps(); i++) {
5709 _rc.setViewport(_viewPortSize * std::powf(_gs->bloomScaleFactor(), static_cast<float>(i + 1)));
5710 _rc.separableBlur(*_rt._bloomTextures[i - 1][0], _bloomRendertargets[i]);
5711 }
5712 for (int i = static_cast<int>(_gs->bloomSteps()) - 2; i >= 0; i--) {
5713 _rc.setViewport(_viewPortSize * std::powf(_gs->bloomScaleFactor(), static_cast<float>(i + 1)));
5714 _bloomRendertargets[i][0]->bind();
5715 _rc.additiveBlend(*_rt._bloomTextures[i + 1][0]);
5716 }
5717 _rc.setViewport(_viewPortSize);
5718 }
5719 Vector<3, Type> god_ray_intensity(0);
5720 if (_gs->godRays() && light_pos_ndc >= static_cast<Type>(-1) && light_pos_ndc <= static_cast<Type>(1)) {
5721 auto light_pos_uv = light_pos_ndc.NDCToUV();
5722 _rc.setViewport(_viewPortSize * _gs->godRayScale());
5723 _rt._lightingBuffer->setTexMinFilter(Texture::TexFilter::LINEAR);
5724 _rt._depthBuffer->setTexMinFilter(Texture::TexFilter::LINEAR);
5725 _godRayRendertarget->bind();
5726 _rc.renderGodRays(*_rt._depthBuffer, *_rt._lightingBuffer, light_pos_uv);
5727 _rt._depthBuffer->setTexMinFilter(Texture::TexFilter::NEAREST);
5728 _rc.setViewport(_viewPortSize);
5729 god_ray_intensity = *_gsp._lightIntensity * glm::smoothstep(static_cast<Type>(0), _gs->godRayFadeDist(), std::min(light_pos_uv.minReduce(), (static_cast<Type>(1) - light_pos_uv).minReduce()));
5730 }
5731 _rc.bindBackbuffer(_defaultRenderTarget);
5732 _gs->autoExposure() ? _rt._lightingBuffer->setTexMinFilter(Texture::TexFilter::LINEAR_MIPMAP_LINEAR) : _rt._lightingBuffer->setTexMinFilter(Texture::TexFilter::NEAREST);
5733 bool render_god_rays = _godRayRendertarget && god_ray_intensity > static_cast<Type>(0);
5734 render_god_rays ? _rc.bindShader(&_rc.compositeShaderWithGodRays()) : _rc.bindShader(&_rc.compositeShader());
5735 _rc.setupCompositing(*_rt._lightingBuffer);
5736 if (_gs->depthOfField()) {
5737 _rc.setupDepthOfField(_gsp, *_rt._dofBuffer[0], *_rt._depthBuffer, _gs->dofNearCenterFar());
5738 }
5739 if (render_god_rays) {
5740 _rc.setupGodRays(god_ray_intensity, *_rt._godRayBuffer);
5741 }
5742 if (_gs->bloom()) {
5743 _rc.setupBloom(*_rt._bloomTextures[0][0]);
5744 }
5745 if (_gs->autoExposure()) {
5746 _rc.setupAutoExposure(*_rt._lightingBuffer);
5747 }
5748 _rc.composite();
5749 if (_gs->renderCrossHair()) {
5750 _rc.render2DBillboard(_mousePosNDC, Vector<2, Type>(0.025) * Vector<2, Type>(static_cast<Type>(1), aspectRatio()), *_blurredCircleTexture2,
5751 Vector<3, Type>(std::pow(static_cast<Type>(0.811), static_cast<Type>(1.0 / 2.2)), std::pow(static_cast<Type>(0.027), static_cast<Type>(1.0 / 2.2)), std::pow( static_cast<Type>(0.027), static_cast<Type>(1.0 / 2.2))), static_cast<Type>(-1.0));
5752 }
5753 _rc.endFrame();
5754 return true;
5755 }
5756 void onResize(Vec2u const & window_size)
5757 {
5758 _viewPortSize = window_size;
5759 _rt._lightingBuffer = _gs->autoExposure() ? _rc.createRenderToTexture(_viewPortSize, Texture::TexFilter::LINEAR_MIPMAP_LINEAR) : _rc.createRenderToTexture(_viewPortSize, Texture::TexFilter::NEAREST);
5760 _rt._depthBuffer = _rc.createDepthbuffer(_viewPortSize);
5761 godRaysChanged(_gs);
5762 depthOfFieldChanged(_gs);
5763 bloomChanged(_gs);
5764 screenSpaceReflectionsChanged(_gs);
5765 }
5766 Type aspectRatio() const
5767 {
5768 return _viewPortSize.aspectRatio();
5769 }
5770 auto setDefaultRendertarget(unsigned const & rt) { _defaultRenderTarget = rt; }
5771 auto* renderContext() { return &_rc; }
5772 auto const & viewProjectionMatrix() const
5773 {
5774 return _vpScene;
5775 }
5776 auto findNearestPrimitive(Ray const & ray)
5777 {
5778 return findNearestPrimitive(ray, *_BVTreeStatic);
5779 }
5780 IntersectRayResult<Type, Matrix> findNearestPrimitive(Ray const & ray, BVTree& BVTree)
5781 {
5782 IntersectRayResult<Type, Matrix> res(camParams()._far);
5783 if (_recursiveRayTrace) {
5784 BVTree.findNearestNested(ray, res, [&ray, &res](Primitive* mr) {
5785 mr->nestedBVTree()->findNearestPrecise(Ray(ray, inverse(*mr->modelMatrix())), ray, mr->modelMatrix(), res);
5786 });
5787 }
5788 else {
5789 StackTrivial<BVTreeNode::NodePtr> stack;
5790 stack.reserve(16u);
5791 StackTrivial<BVTreeNode::NodePtr> s;
5792 s.reserve(16u);
5793 BVTree.findNearestNested(ray, res, stack, [&ray, &res, &s](Primitive* mr) {
5794 mr->nestedBVTree()->findNearestPrecise(Ray(ray, inverse(*mr->modelMatrix())), ray, mr->modelMatrix(), res, s);
5795 });
5796 }
5797 return res;
5798 }
5799 auto findNearestPrimitive(Ray const & ray, BVTree& BVTree, Primitive*& parent)
5800 {
5801 IntersectRayResult<Type, Matrix> res(camParams()._far);
5802 BVTree.findNearestNested(ray, res, [&ray, &res, &parent](Primitive* mr) {
5803 mr->nestedBVTree()->findNearestPrecise(Ray(ray, inverse(*mr->modelMatrix())), ray, mr->modelMatrix(), mr, res, parent);
5804 });
5805 return res;
5806 }
5807 BVTree*& staticBVTree()
5808 {
5809 return _BVTreeStatic;
5810 }
5811 BV const & sceneBounds() const
5812 {
5813 return _sceneBounds;
5814 }
5815 auto createMaterialDesc(std::shared_ptr<Material> const & material)
5816 {
5817 auto ret = _materialDescCache.getOrCreate(material, [this, material]() {
5818 return _rc.createMaterialDesc(material, *_gs, &_textureCache, &_shaderDescCache, &_shaderCache);
5819 }, [this](MaterialDesc* material_desc) {
5820 delete material_desc;
5821 });
5822 if (!std::get<1>(ret)) { // Only add to listeners if it was not in the cache
5823 _gs->addListener(std::get<0>(ret));
5824 }
5825 return std::get<0>(ret);
5826 }
5827 auto addMesh(std::shared_ptr<Mesh> const & mesh)
5828 {
5829 return std::get<0>(_meshCache.getOrCreate(mesh, [this, mesh]() {
5830 return _rc.createMeshData(*mesh);
5831 }, [this](GPUMeshData* gmd) {
5832 delete gmd;
5833 }));
5834 }
5835 auto setDebugCamera(std::shared_ptr<Camera> const & camera)
5836 {
5837 _debugCamera = camera;
5838 _cullCamera = _debugCamera ? &_debugCamera : &_camera;
5839 }
5840 auto const & debugCamera() const
5841 {
5842 return _debugCamera;
5843 }
5844 auto buildBVTree(Primitive** const begin, Primitive** const end)
5845 {
5846 std::cout << "Mesh renderables:" << StringHelper::formatNumber(static_cast<unsigned>(end - begin)) << std::endl;
5847 if (!(end - begin)) {
5848 throw std::exception("No meshes were added to the renderer.");
5849 }
5850 if (!_camera) {
5851 throw std::exception("No camera was added to the renderer.");
5852 }
5853 if (!_directionalLight) {
5854 throw std::exception("No directional light was added to the renderer.");
5855 }
5856 Timing timing;
5857 _BVTreeStatic = new BVTree(begin, end);
5858 std::cout << "BVTree construction took " << timing.duration<std::chrono::milliseconds>() << " milliseconds." << std::endl;
5859 std::cout << "BVTree takes " << _BVTreeStatic->sizeInMegaBytes() << " MB memory" << std::endl;
5860 std::cout << "Scene bounds:" << _BVTreeStatic->bv() << std::endl;
5861 unsigned internal_nodes, leaf_nodes;
5862 _BVTreeStatic->countNodes(internal_nodes, leaf_nodes);
5863 std::cout << "BVTree internal nodes:" << StringHelper::formatNumber(internal_nodes) << std::endl;
5864 std::cout << "BVTree leaf nodes:" << StringHelper::formatNumber(leaf_nodes) << std::endl;
5865 unsigned triangles = 0;
5866 for (auto ptr = begin; ptr != end;) {
5867 triangles += (*ptr++)->numTriangles();
5868 }
5869 std::cout << "Triangles:" << StringHelper::formatNumber(triangles) << std::endl;
5870 size_t size_in_bytes = 0;
5871 for (auto ptr = begin; ptr != end;) {
5872 size_in_bytes += (*ptr++)->sizeInBytes();
5873 }
5874 std::cout << "Renderables take " << static_cast<float>(size_in_bytes) / 1024.f / 1024.f << " MB memory" << std::endl;
5875
5876 std::cout << "BVTree internal node takes " << sizeof(BVTreeInternalNode) << " bytes memory" << std::endl;
5877 std::cout << "BVTree leaf node takes " << sizeof(BVTreeLeafNode) << " bytes memory" << std::endl;
5878 }
5879 auto const & viewPortSize() const
5880 {
5881 return _viewPortSize;
5882 }
5883 auto setDebugTriangle(Vector<4, Type> const * triangle)
5884 {
5885 _debugTriangle = triangle;
5886 }
5887 auto setMousePos(Vector<2, Type> const & window_pos)
5888 {
5889 auto uv = window_pos / _viewPortSize;
5890 uv.at<1>() = static_cast<Type>(1) - uv.at<1>();
5891 _mousePosNDC = uv.UVToNDC();
5892 }
5893 auto toggleRecursiveRayTrace()
5894 {
5895 _recursiveRayTrace = !_recursiveRayTrace;
5896 }
5897 private:
5898 RenderContext& _rc;
5899 std::vector<CsmSplit> _splits;
5900 GlobalShaderParams _gsp;
5901 Vector<2, Type> _viewPortSize = Vector<2, Type>( static_cast<Type>(640), static_cast<Type>(480));
5902 std::shared_ptr<Camera> _camera;
5903 std::shared_ptr<DirectionalLight> _directionalLight;
5904 std::shared_ptr<Camera> _debugCamera;
5905 std::shared_ptr<Camera>* _cullCamera = &_camera;
5906 GraphicsSettings * const _gs;
5907 std::array<std::shared_ptr<Rendertarget>, 2> _dofRendertargets;
5908 std::vector<std::array<std::shared_ptr<Rendertarget>, 2u>> _bloomRendertargets;
5909 std::unique_ptr<Rendertarget> _godRayRendertarget;
5910 std::unique_ptr<Rendertarget> _mainRendertarget;
5911 std::unique_ptr<Rendertarget> _ssrRendertarget;
5912 std::vector<std::shared_ptr<Rendertarget>> _shadowRendertargets;
5913 Rendertargets _rt;
5914 StackTrivial<Matrix> _vpLightVolume;
5915 unsigned _defaultRenderTarget = 0;
5916 Matrix _vpScene;
5917 bool _shadowMapping;
5918 bool _multiThreadedCulling;
5919 BV _sceneBounds;
5920 Vec2f _mousePosNDC;
5921 Texture* _blurredCircleTexture;
5922 Texture* _blurredCircleTexture2;
5923#if RENDERER_STATS
5924 RendererStats _stats;
5925#endif
5926 std::vector<MeshRenderablePtr> _meshRenderables;
5927 StackTrivial<Primitive*> _fullyVisibleMeshes;
5928 StackTrivial<Primitive*> _fullyVisibleMeshesAsync;
5929 RenderList _renderList;
5930 RenderList _renderListAsync;
5931 RenderList* _renderListScene;
5932 std::map<ShaderDesc const *, std::map<MaterialDesc const *, StackTrivial<MeshRenderable const*>>> _displayList;
5933 BVTree* _BVTreeStatic;
5934 PtrCache<std::string, Texture> _textureCache;
5935 PtrCache<std::string, Shader> _shaderCache;
5936 PtrCache<std::shared_ptr<Shader>, ShaderDesc> _shaderDescCache;
5937 MaterialDescCache _materialDescCache;
5938 MeshCache _meshCache;
5939 boost::object_pool<GPUMeshData> _meshPool;
5940 boost::object_pool<MaterialDesc> _materialDescPool;
5941 boost::object_pool<ShaderDesc> _shaderDescPool;
5942 std::shared_ptr<SkydomeRenderable> _skydomeRenderable;
5943 Vector<4, Type> const * _debugTriangle = nullptr;
5944 bool _recursiveRayTrace = true;
5945 void renderScene()
5946 {
5947#if RENDERER_STATS
5948 Timing timing;
5949#endif
5950 groupMeshes(_renderListScene->visibleMeshes());
5951#if RENDERER_STATS
5952 _stats._sceneMeshGroupingMicroSeconds = timing.duration<std::chrono::microseconds>();
5953 timing.start();
5954#endif
5955 auto stats = renderMeshes();
5956#if RENDERER_STATS
5957 _stats._renderedMeshes = stats._renderedMeshes;
5958 _stats._renderedTriangles = stats._renderedTriangles;
5959 _stats._sceneRenderingCPUMicroSeconds = timing.duration<std::chrono::microseconds>();
5960#endif
5961 }
5962 void renderShadowMap()
5963 {
5964 _gsp._worldToLight.clear();
5965 _gsp._worldToLight.grow(_gs->numFrustumSplits());
5966 _splits.resize(_gs->numFrustumSplits());
5967 for (auto & s : _splits) {
5968 s.renderlist().clear();
5969 }
5970 _directionalLight->csmSplits<Type>(aspectRatio(), (*_cullCamera)->params()._near, (*_cullCamera)->params()._far, (*_cullCamera)->params()._fovDegrees, ((*_cullCamera)->viewMatrixInverse()),
5971 static_cast<Type>(_gs->shadowMapSize()), _gsp._smFrustumSplits, _gs->numFrustumSplits(), _gs->frustumSplitLogAlpha(), _splits.data(), _gsp._worldToLight.begin());
5972 _rc.setDepthClampEnabled(true);
5973 _rc.enablePolygonOffset(_gs->shadowPolygonOffsetFactor(), _gs->shadowPolygonOffsetUnits());
5974 _rc.setViewport(Vec2u(_gs->shadowMapSize()));
5975 auto const * world_to_light = _gsp._worldToLight.begin();
5976 auto const * shadow_render_target = _shadowRendertargets.data();
5977 auto cp = (*_cullCamera)->cullingParams(frustumPlanes(Mat4f()), frustumVertices(Mat4f()));
5978 auto on_intersect_frustum = [&cp](Primitive* ptr, RenderList& rl) {
5979 ptr->addIfContributesAndVisible(cp, rl);
5980 };
5981 auto on_became_fully_visible = [&cp](Primitive* ptr, RenderList& rl) {
5982 ptr->addIfContributes(cp, rl);
5983 };
5984 auto on_render = [](Primitive* ptr, RenderList& rl) {
5985 ptr->add(rl);
5986 };
5987#if RENDERER_STATS
5988 Timing t;
5989#endif
5990 CsmTree ct(_splits.data(), _splits.data() + _splits.size(), _directionalLight->viewMatrix());
5991 ct.descendVisible(*_BVTreeStatic, cp, { on_intersect_frustum, on_became_fully_visible, on_render });
5992#if RENDERER_STATS
5993 _stats._cullStatsSM._BVTreeTraversalMicroSeconds += t.duration<std::chrono::microseconds>();
5994#endif
5995 for (auto& s : _splits) {
5996 {
5997 selectLod(s.renderlist(), **_cullCamera, s.vp());
5998 }
5999#if RENDERER_STATS
6000 Timing timing;
6001#endif
6002 groupMeshes<true>(s.renderlist().visibleMeshes());
6003#if RENDERER_STATS
6004 _stats._shadowMapGroupingMicroSeconds += timing.duration<std::chrono::microseconds>();
6005 timing.start();
6006#endif
6007 (*shadow_render_target++)->bind();
6008 _rc.clearRendertarget(false, true, false);
6009 _gsp._VP = world_to_light++;
6010 auto const stats = renderMeshes<true>();
6011#if RENDERER_STATS
6012 _stats._shadowMapRenderCPUMicroSeconds += timing.duration<std::chrono::microseconds>();
6013 _stats._renderedMeshesShadow += stats._renderedMeshes;
6014 _stats._renderedTrianglesShadow += stats._renderedTriangles;
6015#endif
6016 }
6017 _rc.disablePolygonOffset();
6018 // _gsp._smFrustumSplits = &_gs->frustumSplits();
6019 _rc.setDepthClampEnabled(false);
6020 _gsp._viewMatrixThirdRow = (*_cullCamera)->viewMatrix().row<2>();
6021 }
6022 FrustumPlanes<3u, Type> frustumPlanes(Matrix const & vp)
6023 {
6024 return FrustumPlanes<3u, Type>(vp);
6025 }
6026 FrustumVertices<3u, Type> frustumVertices(Matrix const & vp)
6027 {
6028 return FrustumVertices<3u, Type>(inverse(vp));
6029 }
6030 CullingStats cullMeshes(Matrix const & vp, Camera camera,
6031 RenderList& renderlist, StackTrivial<Primitive*>& fully_visible_meshes)
6032 {
6033 renderlist.clear();
6034 fully_visible_meshes.clear();
6035 auto cp = camera.cullingParams(frustumPlanes(vp), frustumVertices(vp));
6036 CullingStats stats;
6037 {
6038#if RENDERER_STATS
6039 Timing timing;
6040#endif
6041 auto on_intersect_frustum = [&cp, &renderlist](Primitive* ptr) {
6042 ptr->addIfContributesAndVisible(cp, renderlist);
6043 };
6044 auto on_became_fully_visible = [&cp, &fully_visible_meshes](Primitive* ptr) {
6045 fully_visible_meshes.push_back(ptr);
6046 };
6047 auto on_render = [&renderlist](Primitive* ptr) {
6048 ptr->add(renderlist);
6049 };
6050 _gs->HVFCPlaneMasking() ? _BVTreeStatic->cullVisiblePrimitivesWithPlaneMasking(cp, on_intersect_frustum, on_became_fully_visible, on_render) : _BVTreeStatic->cullVisiblePrimitives(cp, on_intersect_frustum, on_became_fully_visible, on_render);
6051#if RENDERER_STATS
6052 stats._BVTreeTraversalMicroSeconds = timing.duration<std::chrono::microseconds>();
6053#endif
6054 }
6055#if RENDERER_STATS
6056 Timing timing;
6057#endif
6058 auto num_threads = std::thread::hardware_concurrency();
6059 auto num_meshes = static_cast<unsigned>(fully_visible_meshes.size());
6060 auto elements_per_thread = MathHelpers::elementsPerThread(num_meshes, num_threads);
6061 if (_gs->multithreadedDetailCulling() && elements_per_thread >= 256u) {
6062 std::vector<std::future<RenderList>> futures;
6063 futures.reserve(num_threads);
6064 auto* begin = fully_visible_meshes.begin();
6065 for (unsigned i = 0; i < num_threads; i++) {
6066 auto* end = std::min(begin + elements_per_thread, fully_visible_meshes.end());
6067 futures.push_back(std::async(std::launch::async, [begin, end, &cp]() {
6068 RenderList renderlist;
6069 renderlist.reserve(end - begin);
6070 for (auto* ptr = begin; ptr != end;) {
6071 (*ptr++)->addIfContributesUnchecked(cp, renderlist);
6072 }
6073 return renderlist;
6074 }));
6075 begin += elements_per_thread;
6076 }
6077 for (auto& f : futures) {
6078 renderlist.append(f.get());
6079 }
6080 }
6081 else {
6082 for (auto* ptr = fully_visible_meshes.begin(); ptr != fully_visible_meshes.end();) {
6083 (*ptr++)->addIfContributes(cp, renderlist);
6084 }
6085 }
6086#if RENDERER_STATS
6087 stats._fineCullingMicroSeconds = timing.duration<std::chrono::microseconds>();
6088#endif
6089 return stats;
6090 }
6091 void selectLod(RenderList const & renderlist, Camera const & camera, Mat4f const & vp)
6092 {
6093 if (renderlist.cpuLodList().size()) {
6094 auto cp = camera.cullingParams(frustumPlanes(vp), frustumVertices(vp));
6095 for (const auto& m : renderlist.cpuLodList()) {
6096 m->selectLod(cp);
6097 }
6098 }
6099 }
6100 template<bool depth = false>
6101 void groupMeshes(MeshRenderable const * const * begin, MeshRenderable const * const * const end)
6102 {
6103 while (begin != end) {
6104 _displayList[depth ? (*begin)->shaderDescDepth()->get() : (*begin)->shaderDesc()->get()][(*begin)->materialDesc()].push_back(*begin);
6105 ++begin;
6106 }
6107 }
6108 template<bool depth = false>
6109 void groupMeshes(typename RenderList::Stack const & meshes)
6110 {
6111 groupMeshes<depth>(meshes.begin(), meshes.end());
6112 }
6113 struct MeshRenderStats
6114 {
6115 unsigned _renderedTriangles;
6116 unsigned _renderedMeshes;
6117 };
6118 template<bool depth = false>
6119 auto renderMeshes()
6120 {
6121 MeshRenderStats stats = {};
6122 for (auto const & shader : _displayList) {
6123 shader.first->setup(_gsp, _rc);
6124 for (auto const & material : shader.second) {
6125 depth ? material.first->setupDepth(*_rc.activeShader()) : material.first->setup(*_rc.activeShader());
6126 for (auto const & mr : material.second) {
6127 depth ? mr->renderDepth(_rc) : mr->render(_rc);
6128#if RENDERER_STATS
6129 stats._renderedTriangles += mr->numTriangles();
6130 stats._renderedMeshes += mr->numMeshes();
6131#endif
6132 }
6133 }
6134 }
6135 _displayList.clear();
6136 return stats;
6137 }
6138 };
6139}
6140
6141#endif
6142#include <physics/PhysicsCameraController.h>
6143#include <GameTimer.h>
6144#include <Camera.h>
6145#include <iostream>
6146#include <BVTree.h>
6147#include <Triangle.h>
6148#include <set>
6149
6150namespace RT
6151{
6152 PhysicsCameraController::PhysicsCameraController(Camera* const & camera, BVTree*& BVTree) :
6153 _c(camera),
6154 _BVTree(BVTree)
6155 {
6156 }
6157 void PhysicsCameraController::updateSystem()
6158 {
6159 setDamping(DAMP_DEFAULT);
6160 _velocity += ((_acceleration + _gravity) * _dt);
6161 _velocity *= _damp;
6162 if (_collisions) {
6163 auto const v_constant = _velocity * _dt;
6164 auto v_inv = Vector(static_cast<Type>(1)) / v_constant;
6165 auto min_t_min = std::numeric_limits<Type>::max();
6166 Primitive const * nearest = nullptr;
6167 _BVTree->intersectNested(_c->collisionShape(), v_constant, v_inv, min_t_min, [this, &min_t_min, &nearest, &v_constant, &v_inv](Primitive const * imr) {
6168 boost::object_pool<Triangle> tri_pool;
6169 StackTrivial<Vertex> vertices;
6170 imr->transformedBVTree(tri_pool, vertices)->intersectPrimitives(_c->collisionShape(), v_constant, v_inv, min_t_min, nearest);
6171 setDamping(DAMP_INTERIOR);
6172 });
6173 if (nearest) {
6174 _c->setPosition(_c->pos() + v_constant * min_t_min);
6175 }
6176 else {
6177 _c->setPosition(_c->pos() + v_constant);
6178 }
6179 }
6180 else {
6181 _c->setPosition(_c->pos() + _velocity * _dt);
6182 }
6183 _angularVelocity += _angularAcceleration * _dt;
6184 _c->setEulerRadians(_c->eulerRadians() - _angularVelocity * _dt);
6185 _angularVelocity *= DAMP_DEFAULT;
6186 }
6187 unsigned PhysicsCameraController::getID()
6188 {
6189 return 0;
6190 }
6191 const char * PhysicsCameraController::getName()
6192 {
6193 return "PhysicsCameraController";
6194 }
6195 void PhysicsCameraController::setAcceleration(Vector const & dir, Type const & amount)
6196 {
6197 _acceleration = dir.length() > static_cast<Type>(0) ? normalize(dir) * amount : static_cast<Type>(0);
6198 }
6199 void PhysicsCameraController::setAngularAcceleration(Vector const & aa)
6200 {
6201 _angularAcceleration = aa;
6202 }
6203 Camera* const & PhysicsCameraController::getCamera() const
6204 {
6205 return _c;
6206 }
6207 void PhysicsCameraController::setCamera(Camera* const & camera)
6208 {
6209 _c = camera;
6210 }
6211 void PhysicsCameraController::setDamping(Type const & damping)
6212 {
6213 _damp = damping;
6214 }
6215 PhysicsCameraController::Vector const & PhysicsCameraController::gravity() const
6216 {
6217 return _gravity;
6218 }
6219 void PhysicsCameraController::setGravity(Vector const & gravity)
6220 {
6221 _gravity = gravity;
6222 }
6223 bool const & PhysicsCameraController::collisions() const
6224 {
6225 return _collisions;
6226 }
6227 void PhysicsCameraController::setCollisions(bool const & collisions)
6228 {
6229 _collisions = collisions;
6230 }
6231}
6232#include <bv_treeNodePool.h>
6233#include <StackTrivial.h>
6234#include <bv_treeInternalNode.h>
6235#include <bv_treeLeafNode.h>
6236
6237namespace RT
6238{
6239 bv_treeNodePool::bv_treeNodePool(size_t num_primitives)
6240 {
6241 auto const height = static_cast<size_t>(std::floor(log2(static_cast<double>(num_primitives))));
6242 auto const num_nodes = static_cast<size_t>(std::pow(2.0, static_cast<double>(height) + 1.0) - 1.0);
6243 auto num_internal_nodes = num_nodes - num_primitives;
6244 maximize<size_t>(32u, num_primitives);
6245 maximize<size_t>(32u, num_internal_nodes);
6246 _internalNodePool.set_next_size(num_internal_nodes);
6247 _leafNodePool.set_next_size(num_primitives);
6248 }
6249 bv_treeNode* bv_treeNodePool::createInternalNode(bv_treeNode::PrimitiveInfo* const begin, bv_treeNode::PrimitiveInfo* const end)
6250 {
6251 return new (_internalNodePool.malloc()) bv_treeInternalNode(begin, end, *this);
6252 }
6253 bv_treeNode* bv_treeNodePool::createLeafNode(Primitive* p)
6254 {
6255 return new (_leafNodePool.malloc()) bv_treeLeafNode(p);
6256 }
6257 bv_treeNode* bv_treeNodePool::createNode(bv_treeNode::PrimitiveInfo* const begin, bv_treeNode::PrimitiveInfo* const end)
6258 {
6259 return Algorithm::continueSplit(begin, end) ? createInternalNode(begin, end) : createLeafNode(begin->primitive());
6260 }
6261 bv_treeNode* bv_treeNodePool::createNode(StackTrivial<bv_treeNode::PrimitiveInfo>& infos)
6262 {
6263 return createNode(infos.begin(), infos.end());
6264 }
6265 void bv_treeNodePool::destroy(bv_treeLeafNode* node)
6266 {
6267 _leafNodePool.destroy(node);
6268 }
6269 void bv_treeNodePool::destroy(bv_treeInternalNode* node)
6270 {
6271 _internalNodePool.destroy(node);
6272 }
6273}
6274#include <BVTreeInternalNode.h>
6275#include <CullingParams.h>
6276#include <BVTreeNodePool.h>
6277#include <StackTrivial.h>
6278#include <BVTreeLeafNode.h>
6279#include <CsmInternalNode.h>
6280#include <CsmLeafNode.h>
6281
6282namespace RT
6283{
6284 void BVTreeInternalNode::init(PrimitiveInfo const * begin, PrimitiveInfo const * const end)
6285 {
6286 while (begin != end) {
6287 insert(*begin++);
6288 }
6289 }
6290 bool BVTreeInternalNode::contributes(CullingParams const & cp) const
6291 {
6292 return _bv.contributes(cp.pEye(), cp.alpha(), _maxSquaredSize);
6293 }
6294 bool BVTreeInternalNode::fullyContributes(CullingParams const & cp) const
6295 {
6296 return _bv.fullyContributes(cp.pEye(), cp.alpha(), _minSquaredSize);
6297 }
6298 IntersectResult BVTreeInternalNode::intersectFrustum(CullingParams const & cp) const
6299 {
6300 return IntersectionTests::intersectFrustum(_bv, cp.frustumPlanes(), cp.frustumVertices());
6301 }
6302 IntersectResult BVTreeInternalNode::intersectFrustum(CullingParams const & cp, IntersectedPlanes const & in, IntersectedPlanes& out) const
6303 {
6304 return IntersectionTests::intersectFrustum(_bv, cp.frustumPlanes(), cp.frustumVertices(), in, out);
6305 }
6306 ContribResult BVTreeInternalNode::computeContribution(CullingParams const & cp) const
6307 {
6308 return _bv.computeContribution(cp.pEye(), cp.alpha(), _minSquaredSize, _maxSquaredSize);
6309 }
6310 BVTreeInternalNode::BVTreeInternalNode(PrimitiveInfo* const begin, PrimitiveInfo* const end, BVTreeNodePool& np)
6311 : BVTreeNode(),
6312 _bv(begin->bv()),
6313 _minSquaredSize(begin->squaredSize()),
6314 _maxSquaredSize(begin->squaredSize())
6315 {
6316 init(begin + 1u, end);
6317 auto const axis = _bv.longestAxis();
6318 auto const bv_center = _bv.center(axis);
6319 auto* const mid = Algorithm::partitionForceSplit(begin, end, [&axis, &bv_center](PrimitiveInfo const & p) {
6320 return p.bv().center(axis) < bv_center;
6321 });
6322 _left = np.createNode(begin, mid);
6323 _right = np.createNode(mid, end);
6324 }
6325 void BVTreeInternalNode::recurseVisible(CullingParams const & cp, Callback const & cb) const
6326 {
6327 _left->cullVisiblePrimitives(cp, cb);
6328 _right->cullVisiblePrimitives(cp, cb);
6329 }
6330 void BVTreeInternalNode::recurseVisible(CullingParams const & cp, IntersectedPlanes const & ip, Callback const & cb) const
6331 {
6332 _left->cullVisiblePrimitives(cp, ip, cb);
6333 _right->cullVisiblePrimitives(cp, ip, cb);
6334 }
6335 void BVTreeInternalNode::recurseContributing(CullingParams const & cp, Callback const & cb) const
6336 {
6337 _left->cullContributingPrimitives(cp, cb);
6338 _right->cullContributingPrimitives(cp, cb);
6339 }
6340 void BVTreeInternalNode::recurseAll(Callback::CbFunc const & on_render) const
6341 {
6342 _left->cullAllPrimitives(on_render);
6343 _right->cullAllPrimitives(on_render);
6344 }
6345 void BVTreeInternalNode::cullVisiblePrimitives(CullingParams const & cp, Callback const & cb) const
6346 {
6347 if (contributes(cp)) {
6348 if (auto const result = intersectFrustum(cp)) {
6349 result.intersecting() ? recurseVisible(cp, cb) : recurseContributing(cp, cb);
6350 }
6351 }
6352 }
6353 void BVTreeInternalNode::cullVisiblePrimitives(CullingParams const & cp, IntersectedPlanes const & in, Callback const & cb) const
6354 {
6355 if (contributes(cp)) {
6356 IntersectedPlanes out;
6357 if (auto const result = intersectFrustum(cp, in, out)) {
6358 result.intersecting() ? recurseVisible(cp, out, cb) : recurseContributing(cp, cb);
6359 }
6360 }
6361 }
6362 void BVTreeInternalNode::cullContributingPrimitives(CullingParams const & cp, Callback const & cb) const
6363 {
6364 if (auto const result = computeContribution(cp)) {
6365 result.intersecting() ? recurseContributing(cp, cb) : recurseAll(cb.onRender());
6366 }
6367 }
6368 void BVTreeInternalNode::cullAllPrimitives(Callback::CbFunc const & on_render) const
6369 {
6370 recurseAll(on_render);
6371 }
6372 size_t BVTreeInternalNode::sizeInBytes() const
6373 {
6374 return sizeof *this + _left->sizeInBytes() + _right->sizeInBytes();
6375 }
6376 void BVTreeInternalNode::intersectNested(BV const & bv, Vector const & v, Vector const & v_inv, Type& min_t_min, std::function<void(Primitive const *)> const & intersect_nested) const
6377 {
6378 Type t_min;
6379 if (_bv.intersects(bv, v, v_inv, t_min) && t_min < min_t_min) {
6380 _left->intersectNested(bv, v, v_inv, min_t_min, intersect_nested);
6381 _right->intersectNested(bv, v, v_inv, min_t_min, intersect_nested);
6382 }
6383 }
6384 void BVTreeInternalNode::intersectPrimitives(BV const & bv, Vector const & v, Vector const & v_inv, Type& min_t_min, Primitive const *& nearest) const
6385 {
6386 Type t_min;
6387 if (_bv.intersects(bv, v, v_inv, t_min) && t_min < min_t_min) {
6388 _left->intersectPrimitives(bv, v, v_inv, min_t_min, nearest);
6389 _right->intersectPrimitives(bv, v, v_inv, min_t_min, nearest);
6390 }
6391 }
6392 void BVTreeInternalNode::countNodes(unsigned& internal_nodes, unsigned& leaf_nodes) const
6393 {
6394 _left->countNodes(++internal_nodes, leaf_nodes);
6395 _right->countNodes(internal_nodes, leaf_nodes);
6396 }
6397
6398 void BVTreeInternalNode::recurseNearest(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive const *& nearest, Type& nearest_t, Matrix const *& nearest_transform) const
6399 {
6400 _left->findNearest(ray_local, ray_world, transform, nearest, nearest_t, nearest_transform);
6401 _right->findNearest(ray_local, ray_world, transform, nearest, nearest_t, nearest_transform);
6402 }
6403 void BVTreeInternalNode::recurseNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res)
6404 {
6405 _left->findNearestPrecise(ray_local, ray_world, transform, res);
6406 _right->findNearestPrecise(ray_local, ray_world, transform, res);
6407 }
6408
6409 void BVTreeInternalNode::findNearest(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive const *& nearest, Type& nearest_t, Matrix const *& nearest_transform) const
6410 {
6411 if (IntersectionTests::continueSearch(_bv, ray_local, ray_world, *transform, nearest_t)) {
6412 recurseNearest(ray_local, ray_world, transform, nearest, nearest_t, nearest_transform);
6413 }
6414 }
6415 void BVTreeInternalNode::findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res)
6416 {
6417 if (IntersectionTests::continueSearch(_bv, ray_local, ray_world, *transform, res)) {
6418 recurseNearestPrecise(ray_local, ray_world, transform, res);
6419 }
6420 }
6421 void BVTreeInternalNode::findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive* parent, IntersectRayResult& res, Primitive*& parent_res)
6422 {
6423 if (IntersectionTests::continueSearch(_bv, ray_local, ray_world, *transform, res)) {
6424 _left->findNearestPrecise(ray_local, ray_world, transform, parent, res, parent_res);
6425 _right->findNearestPrecise(ray_local, ray_world, transform, parent, res, parent_res);
6426 }
6427 }
6428 void BVTreeInternalNode::findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res, StackTrivial<NodePtr>& stack)
6429 {
6430 if (IntersectionTests::continueSearch(_bv, ray_local, ray_world, *transform, res)) {
6431 stack.push_back(_right);
6432 stack.push_back(_left);
6433 }
6434 }
6435 void BVTreeInternalNode::findNearestNested(Ray const & ray, IntersectRayResult& res, std::function<void(Primitive*)> const & find_nested)
6436 {
6437 if (IntersectionTests::continueSearch(_bv, ray, res)) {
6438 NodePtr nodes[2] = { _left, _right };
6439 if (_right->dist(ray) < _left->dist(ray)) {
6440 Algorithm::swap(*nodes, *(nodes + 1u));
6441 }
6442 (*nodes)->findNearestNested(ray, res, find_nested);
6443 (*(nodes + 1u))->findNearestNested(ray, res, find_nested);
6444 }
6445 }
6446 void BVTreeInternalNode::findNearestNested(Ray const & ray, IntersectRayResult& res, std::function<void(Primitive*)> const & find_nested, StackTrivial<NodePtr>& stack)
6447 {
6448 if (IntersectionTests::continueSearch(_bv, ray, res)) {
6449 stack.push_back(_right);
6450 stack.push_back(_left);
6451 if (_right->dist(ray) < _left->dist(ray)) {
6452 Algorithm::swap(stack.back(), *(&stack.back() - 1u));
6453 }
6454 }
6455 }
6456 bool BVTreeInternalNode::largerThan(BVTreeInternalNode const & other) const
6457 {
6458 return _bv.largerThan(other._bv);
6459 }
6460 void BVTreeInternalNode::recurseQueryRange(BV const & bv, Callback::CbFunc const & cb) const
6461 {
6462 _left->queryRange(bv, cb);
6463 _right->queryRange(bv, cb);
6464 }
6465 void BVTreeInternalNode::recurseQueryRange(BV const & bv, CullingParams const & cp, Callback::CbFunc const & cb) const
6466 {
6467 _left->queryRange(bv, cp, cb);
6468 _right->queryRange(bv, cp, cb);
6469 }
6470 void BVTreeInternalNode::recurseQueryContributing(CullingParams const & cp, Callback::CbFunc const & cb) const
6471 {
6472 _left->queryContributing(cp, cb);
6473 _right->queryContributing(cp, cb);
6474 }
6475 void BVTreeInternalNode::recurseQueryAll(Callback::CbFunc const & cb) const
6476 {
6477 _left->queryAll(cb);
6478 _right->queryAll(cb);
6479 }
6480 void BVTreeInternalNode::queryRange(BV const & bv, Callback::CbFunc const & cb) const
6481 {
6482 if (bv.contains(_bv)) {
6483 recurseQueryAll(cb);
6484 }
6485 else if (bv.intersects(_bv)) {
6486 recurseQueryRange(bv, cb);
6487 }
6488 }
6489 void BVTreeInternalNode::queryRange(BV const & bv, CullingParams const & cp, Callback::CbFunc const & cb) const
6490 {
6491 if (contributes(cp)) {
6492 if (bv.contains(_bv)) {
6493 recurseQueryContributing(cp, cb);
6494 }
6495 else if (bv.intersects(_bv)) {
6496 recurseQueryRange(bv, cp, cb);
6497 }
6498 }
6499 }
6500 void BVTreeInternalNode::queryContributing(CullingParams const & cp, Callback::CbFunc const & cb) const
6501 {
6502 if (auto const result = computeContribution(cp)) {
6503 result.intersecting() ? recurseQueryContributing(cp, cb) : recurseQueryAll(cb);
6504 }
6505 }
6506 void BVTreeInternalNode::queryAll(Callback::CbFunc const & cb) const
6507 {
6508 recurseQueryAll(cb);
6509 }
6510 BVTreeInternalNode::BV BVTreeInternalNode::getBV() const
6511 {
6512 return _bv;
6513 }
6514 BVTreeInternalNode::Type BVTreeInternalNode::minSquaredDist(Vector const & point) const
6515 {
6516 return _bv.minSquaredDist(point);
6517 }
6518 BVTreeInternalNode::Type BVTreeInternalNode::dist(Ray const & ray) const
6519 {
6520 return minSquaredDist(ray.origin());
6521 }
6522 void BVTreeInternalNode::destroy(BVTreeNodePool& pool)
6523 {
6524 pool.destroy(this);
6525 }
6526 BVTreeInternalNode::Type BVTreeInternalNode::cost(BV const & bv) const
6527 {
6528 return _bv.cost(bv);
6529 }
6530 void BVTreeInternalNode::insert(PrimitiveInfo const & info, NodePtr& this_ptr, BVTreeNodePool& node_pool)
6531 {
6532 insert(info);
6533 auto& child = childToDescend(info.bv());
6534 child->insert(info, child, node_pool);
6535 }
6536 bool BVTreeInternalNode::remove(PrimitiveInfo const & info, NodePtr& this_ptr, BVTreeNodePool& node_pool, bool& deleted)
6537 {
6538 bool dirty = false;
6539 if (_bv.intersects(info.bv())) {
6540 bool deleted_left = false;
6541 dirty = dirty || _left->remove(info, _left, node_pool, deleted_left);
6542 bool deleted_right = false;
6543 dirty = dirty || _right->remove(info, _right, node_pool, deleted_right);
6544 if (deleted_left) {
6545 rebuild(this_ptr, _right, node_pool);
6546 }
6547 else if (deleted_right) {
6548 rebuild(this_ptr, _left, node_pool);
6549 }
6550 }
6551 if (dirty) {
6552 markAsDirty();
6553 }
6554 return dirty;
6555 }
6556 bool BVTreeInternalNode::removeIfDoesNotFit(PrimitiveInfo const & info, BV const & bv_old, BVTreeNode const * parent, BVTreeNode const * root, NodePtr& this_ptr, BVTreeNodePool& node_pool, bool& deleted)
6557 {
6558 bool dirty = false;
6559 if (_bv.intersects(bv_old)) {
6560 bool deleted_left = false;
6561 dirty = dirty || _left->removeIfDoesNotFit(info, bv_old, this, root, _left, node_pool, deleted_left);
6562 bool deleted_right = false;
6563 dirty = dirty || _right->removeIfDoesNotFit(info, bv_old, this, root, _right, node_pool, deleted_right);
6564 if (deleted_left) {
6565 rebuild(this_ptr, _right, node_pool);
6566 }
6567 else if (deleted_right) {
6568 rebuild(this_ptr, _left, node_pool);
6569 }
6570 }
6571 if (dirty) {
6572 markAsDirty();
6573 }
6574 return dirty;
6575 }
6576 void BVTreeInternalNode::destroyTree(StackTrivial<PrimitiveInfo>& primitives, BVTreeNodePool& node_pool)
6577 {
6578 _left->destroyTree(primitives, node_pool);
6579 _right->destroyTree(primitives, node_pool);
6580 destroy(node_pool);
6581 }
6582 BVTreeInternalNode::DirtyInfo BVTreeInternalNode::recalculateDirty()
6583 {
6584 if (isDirty()) {
6585 collectFromChildren(_left->recalculateDirty());
6586 collectFromChildren(_right->recalculateDirty());
6587 }
6588 return { _bv, _minSquaredSize, _maxSquaredSize };
6589 }
6590 size_t BVTreeInternalNode::minHeight(size_t const & height) const
6591 {
6592 return std::min(_left->minHeight(height + 1u), _right->minHeight(height + 1u));
6593 }
6594 size_t BVTreeInternalNode::maxHeight(size_t const & height) const
6595 {
6596 return std::max(_left->maxHeight(height + 1u), _right->maxHeight(height + 1u));
6597 }
6598 void BVTreeInternalNode::averageHeight(float const & height, float const & inv_num_leafs, float& avg_height) const
6599 {
6600 _left->averageHeight(height + 1.f, inv_num_leafs, avg_height);
6601 _right->averageHeight(height + 1.f, inv_num_leafs, avg_height);
6602 }
6603 void BVTreeInternalNode::insert(BVTreeInternalNode::PrimitiveInfo const & pi)
6604 {
6605 _bv.unify(pi.bv());
6606 minimize(pi.squaredSize(), _minSquaredSize);
6607 maximize(pi.squaredSize(), _maxSquaredSize);
6608 }
6609 BVTreeInternalNode::NodePtr& BVTreeInternalNode::childToDescend(BV const & bv)
6610 {
6611 return _left->cost(bv) < _right->cost(bv) ? _left : _right;
6612 }
6613 void BVTreeInternalNode::markAsDirty()
6614 {
6615 _bv = BV();
6616 _minSquaredSize = std::numeric_limits<Type>::max();
6617 _maxSquaredSize = std::numeric_limits<Type>::lowest();
6618 }
6619 bool BVTreeInternalNode::isDirty() const
6620 {
6621 return _maxSquaredSize == std::numeric_limits<Type>::lowest();
6622 }
6623 void BVTreeInternalNode::rebuild(NodePtr& this_ptr, NodePtr child, BVTreeNodePool& node_pool)
6624 {
6625 StackTrivial<PrimitiveInfo> infos;
6626 child->destroyTree(infos, node_pool);
6627 this_ptr = node_pool.createNode(infos);
6628 destroy(node_pool);
6629 }
6630 void BVTreeInternalNode::collectFromChildren(DirtyInfo const & di)
6631 {
6632 _bv.unify(di.bv());
6633 minimize(di.minSquaredSize(), _minSquaredSize);
6634 maximize(di.maxSquaredSize(), _maxSquaredSize);
6635 }
6636 void BVTreeInternalNode::descendVisible(Descendable & other, CullingParams const & cp, Callback2 const & cb)
6637 {
6638 other.descendVisible(*this, cp, cb);
6639 }
6640 void BVTreeInternalNode::descendVisible(CsmInternalNode & other, CullingParams const & cp, Callback2 const & cb)
6641 {
6642 if (contributes(cp)) {
6643 if (auto const result = IntersectionTests::intersectFrustumIgnoreNear(_bv, other.frustumPlanes())) {
6644 if (result.intersecting()) {
6645 _bv.largerThan(other.bvLight()) ? recurseVisible(other, cp, cb) : other.recurseVisible(*this, cp, cb);
6646 }
6647 else {
6648 _bv.largerThan(other.bvLight()) ? recurseContributing(other, cp, cb) : other.recurseContributing(*this, cp, cb);
6649 }
6650 }
6651 }
6652 }
6653 void BVTreeInternalNode::descendVisible(CsmLeafNode & other, CullingParams const & cp, Callback2 const & cb)
6654 {
6655 if (contributes(cp)) {
6656 if (auto const result = IntersectionTests::intersectFrustumIgnoreNear(_bv, other.split().frustumPlanes())) {
6657 result.intersecting() ? recurseVisible(other, cp, cb) : recurseContributing(other, cp, cb);
6658 }
6659 }
6660 }
6661 void BVTreeInternalNode::descendContributing(Descendable & other, CullingParams const & cp, Callback2 const & cb)
6662 {
6663 other.descendContributing(*this, cp, cb);
6664 }
6665 void BVTreeInternalNode::descendContributing(CsmInternalNode & other, CullingParams const & cp, Callback2 const & cb)
6666 {
6667 if (auto const result = computeContribution(cp)) {
6668 if (result.intersecting()) {
6669 _bv.largerThan(other.bvLight()) ? recurseContributing(other, cp, cb) : other.recurseContributing(*this, cp, cb);
6670 }
6671 else {
6672 descendAll(other, cb.onRender());
6673 }
6674 }
6675 }
6676 void BVTreeInternalNode::descendContributing(CsmLeafNode & other, CullingParams const & cp, Callback2 const & cb)
6677 {
6678 if (auto const result = computeContribution(cp)) {
6679 result.intersecting() ? recurseContributing(other, cp, cb) : descendAll(other, cb.onRender());
6680 }
6681 }
6682 void BVTreeInternalNode::descendAll(Descendable & other, Callback2::CbFunc const & on_render)
6683 {
6684 other.descendAll(*this, on_render);
6685 }
6686 void BVTreeInternalNode::descendAll(CsmInternalNode & other, Callback2::CbFunc const & on_render)
6687 {
6688 recurseAll(other, on_render);
6689 }
6690 void BVTreeInternalNode::descendAll(CsmLeafNode & other, Callback2::CbFunc const & on_render)
6691 {
6692 recurseAll(other, on_render);
6693 }
6694 void BVTreeInternalNode::recurseVisible(Descendable & other, CullingParams const & cp, Callback2 const & cb)
6695 {
6696 _left->descendVisible(other, cp, cb);
6697 _right->descendVisible(other, cp, cb);
6698 }
6699 void BVTreeInternalNode::recurseContributing(Descendable & other, CullingParams const & cp, Callback2 const & cb)
6700 {
6701 _left->descendContributing(other, cp, cb);
6702 _right->descendContributing(other, cp, cb);
6703 }
6704 void BVTreeInternalNode::recurseAll(Descendable & other, Callback2::CbFunc const & on_render)
6705 {
6706 _left->descendAll(other, on_render);
6707 _right->descendAll(other, on_render);
6708 }
6709}
6710#include <BVTreeLeafNode.h>
6711#include <BVTreeInternalNode.h>
6712#include <BVTreeNodePool.h>
6713#include <StackTrivial.h>
6714#include <CullingParams.h>
6715#include <CsmInternalNode.h>
6716#include <CsmLeafNode.h>
6717
6718namespace RT
6719{
6720 BVTreeLeafNode::BVTreeLeafNode(Primitive* const & primitive)
6721 : BVTreeNode(),
6722 _primitive(primitive)
6723 {
6724 }
6725 void BVTreeLeafNode::cullVisiblePrimitives(CullingParams const & cp, Callback const & cb) const
6726 {
6727 cb.onIntersectFrustum()(_primitive);
6728 }
6729 void BVTreeLeafNode::cullVisiblePrimitives(CullingParams const & cp, IntersectedPlanes const & in, Callback const & cb) const
6730 {
6731 cb.onIntersectFrustum()(_primitive);
6732 }
6733 void BVTreeLeafNode::cullContributingPrimitives(CullingParams const & cp, Callback const & cb) const
6734 {
6735 cb.onBecameFullyVisible()(_primitive);
6736 }
6737 void BVTreeLeafNode::cullAllPrimitives(Callback::CbFunc const & on_render) const
6738 {
6739 on_render(_primitive);
6740 }
6741 size_t BVTreeLeafNode::sizeInBytes() const
6742 {
6743 return sizeof *this;
6744 }
6745 void BVTreeLeafNode::intersectNested(BV const & bv, Vector const & v, Vector const & v_inv, Type& min_t_min, std::function<void(Primitive const *)> const & intersect_nested) const
6746 {
6747 Type t_min;
6748 if (getBV().intersects(bv, v, v_inv, t_min) && t_min < min_t_min) {
6749 intersect_nested(_primitive);
6750 }
6751 }
6752 void BVTreeLeafNode::intersectPrimitives(BV const & bv, Vector const & v, Vector const & v_inv, Type& min_t_min, Primitive const *& nearest) const
6753 {
6754 Type t_min;
6755 if (getBV().intersects(bv, v, v_inv, t_min) && t_min < min_t_min) {
6756 min_t_min = t_min;
6757 nearest = _primitive;
6758 }
6759 }
6760 void BVTreeLeafNode::countNodes(unsigned& internal_nodes, unsigned& leaf_nodes) const
6761 {
6762 ++leaf_nodes;
6763 }
6764 void BVTreeLeafNode::findNearest(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive const *& nearest, Type& nearest_t, Matrix const *& nearest_transform) const
6765 {
6766 Type t_min;
6767 if (getBV().intersect(ray_local, t_min)) {
6768 auto const t_world = distance(ray_world.origin(), MathHelpers::transformPoint(*transform, ray_local.pos(t_min)));
6769 if (t_world < nearest_t) {
6770 nearest = _primitive;
6771 nearest_t = t_world;
6772 nearest_transform = transform;
6773 }
6774 }
6775 }
6776 void BVTreeLeafNode::findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res)
6777 {
6778 if (IntersectionTests::continueSearch(getBV(), ray_local, ray_world, *transform, res)) {
6779 if (auto const result = _primitive->intersect(ray_local, ray_world, *transform)) {
6780 if (result.t() < res.minTMin()) {
6781 res.update(result, transform, _primitive);
6782 }
6783 }
6784 }
6785 }
6786 void BVTreeLeafNode::findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive* parent, IntersectRayResult& res, Primitive*& parent_res)
6787 {
6788 if (IntersectionTests::continueSearch(getBV(), ray_local, ray_world, *transform, res)) {
6789 if (auto const result = _primitive->intersect(ray_local, ray_world, *transform)) {
6790 if (result.t() < res.minTMin()) {
6791 res.update(result, transform, _primitive);
6792 parent_res = parent;
6793 }
6794 }
6795 }
6796 }
6797 void BVTreeLeafNode::findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res, StackTrivial<NodePtr>& stack)
6798 {
6799 findNearestPrecise(ray_local, ray_world, transform, res);
6800 }
6801 void BVTreeLeafNode::findNearestNested(Ray const & ray, IntersectRayResult& res, std::function<void(Primitive*)> const & find_nested)
6802 {
6803 find_nested(_primitive);
6804 }
6805 void BVTreeLeafNode::findNearestNested(Ray const & ray, IntersectRayResult& res, std::function<void(Primitive*)> const & find_nested, StackTrivial<NodePtr>& stack)
6806 {
6807 findNearestNested(ray, res, find_nested);
6808 }
6809 void BVTreeLeafNode::queryRange(BV const & bv, Callback::CbFunc const & cb) const
6810 {
6811 if (bv.intersects(getBV())) {
6812 cb(_primitive);
6813 }
6814 }
6815 void BVTreeLeafNode::queryRange(BV const & bv, CullingParams const & cp, Callback::CbFunc const & cb) const
6816 {
6817 if (contributes(cp) && bv.intersects(getBV())) {
6818 cb(_primitive);
6819 }
6820 }
6821 void BVTreeLeafNode::queryContributing(CullingParams const & cp, Callback::CbFunc const & cb) const
6822 {
6823 if (contributes(cp)) {
6824 cb(_primitive);
6825 }
6826 }
6827 void BVTreeLeafNode::queryAll(Callback::CbFunc const & cb) const
6828 {
6829 cb(_primitive);
6830 }
6831 BVTreeLeafNode::BV BVTreeLeafNode::getBV() const
6832 {
6833 return _primitive->bv();
6834 }
6835 BVTreeLeafNode::Type BVTreeLeafNode::minSquaredDist(Vector const & point) const
6836 {
6837 return getBV().minSquaredDist(point);
6838 }
6839 BVTreeLeafNode::Type BVTreeLeafNode::dist(Ray const & ray) const
6840 {
6841 return minSquaredDist(ray.origin());
6842 }
6843 void BVTreeLeafNode::destroy(BVTreeNodePool& pool)
6844 {
6845 pool.destroy(this);
6846 }
6847 BVTreeLeafNode::Type BVTreeLeafNode::cost(BV const & bv) const
6848 {
6849 return getBV().cost(bv);
6850 }
6851 void BVTreeLeafNode::insert(PrimitiveInfo const & info, NodePtr& this_ptr, BVTreeNodePool& node_pool)
6852 {
6853 PrimitiveInfo infos[2] = { info, _primitive };
6854 this_ptr = node_pool.createNode(infos, infos + 2);
6855 destroy(node_pool);
6856 }
6857 bool BVTreeLeafNode::remove(PrimitiveInfo const & info, NodePtr& this_ptr, BVTreeNodePool& node_pool, bool& deleted)
6858 {
6859 deleted = info.primitive() == _primitive;
6860 if (deleted) {
6861 destroy(node_pool);
6862 }
6863 return deleted;
6864 }
6865 bool BVTreeLeafNode::removeIfDoesNotFit(PrimitiveInfo const & info, BV const & bv_old, BVTreeNode const * parent, BVTreeNode const * root, NodePtr& this_ptr, BVTreeNodePool& node_pool, bool& deleted)
6866 {
6867 deleted = this != root && info.primitive() == _primitive && !parent->getBV().contains(info.bv());
6868 if (deleted) {
6869 destroy(node_pool);
6870 }
6871 return deleted;
6872 }
6873 void BVTreeLeafNode::destroyTree(StackTrivial<PrimitiveInfo>& primitives, BVTreeNodePool& node_pool)
6874 {
6875 primitives.push_back(_primitive);
6876 destroy(node_pool);
6877 }
6878 BVTreeLeafNode::DirtyInfo BVTreeLeafNode::recalculateDirty()
6879 {
6880 return { _primitive->bv(), _primitive->squaredSize(), _primitive->squaredSize() };
6881 }
6882 size_t BVTreeLeafNode::minHeight(size_t const & height) const
6883 {
6884 return height;
6885 }
6886 size_t BVTreeLeafNode::maxHeight(size_t const & height) const
6887 {
6888 return height;
6889 }
6890 void BVTreeLeafNode::averageHeight(float const & height, float const & inv_num_leafs, float& avg_height) const
6891 {
6892 avg_height += height * inv_num_leafs;
6893 }
6894 void BVTreeLeafNode::descendVisible(Descendable & other, CullingParams const & cp, Callback2 const & cb)
6895 {
6896 other.descendVisible(*this, cp, cb);
6897 }
6898 void BVTreeLeafNode::descendVisible(CsmInternalNode & other, CullingParams const & cp, Callback2 const & cb)
6899 {
6900 if (contributes(cp)) {
6901 if (auto const result = IntersectionTests::intersectFrustumIgnoreNear(getBV(), other.frustumPlanes())) {
6902 result.intersecting() ? other.recurseVisible(*this, cp, cb) : other.recurseContributing(*this, cp, cb);
6903 }
6904 }
6905 }
6906 void BVTreeLeafNode::descendVisible(CsmLeafNode & other, CullingParams const & cp, Callback2 const & cb)
6907 {
6908 cb.onIntersectFrustum()(_primitive, other.split().renderlist());
6909 }
6910 void BVTreeLeafNode::descendContributing(Descendable & other, CullingParams const & cp, Callback2 const & cb)
6911 {
6912 other.descendContributing(*this, cp, cb);
6913 }
6914 void BVTreeLeafNode::descendContributing(CsmInternalNode & other, CullingParams const & cp, Callback2 const & cb)
6915 {
6916 if (contributes(cp)) {
6917 other.recurseContributing(*this, cp, cb);
6918 }
6919 }
6920 void BVTreeLeafNode::descendContributing(CsmLeafNode & other, CullingParams const & cp, Callback2 const & cb)
6921 {
6922 cb.onBecameFullyVisible()(_primitive, other.split().renderlist());
6923 }
6924 void BVTreeLeafNode::descendAll(Descendable & other, Callback2::CbFunc const & on_render)
6925 {
6926 other.descendAll(*this, on_render);
6927 }
6928 void BVTreeLeafNode::descendAll(CsmInternalNode & other, Callback2::CbFunc const & on_render)
6929 {
6930 other.recurseAll(*this, on_render);
6931 }
6932 void BVTreeLeafNode::descendAll(CsmLeafNode & other, Callback2::CbFunc const & on_render)
6933 {
6934 on_render(_primitive, other.split().renderlist());
6935 }
6936 bool BVTreeLeafNode::contributes(CullingParams const & cp) const
6937 {
6938 return getBV().contributes(cp.pEye(), cp.alpha());
6939 }
6940 IntersectResult BVTreeLeafNode::intersectFrustum(CullingParams const & cp) const
6941 {
6942 return IntersectionTests::intersectFrustum(getBV(), cp.frustumPlanes(), cp.frustumVertices());
6943 }
6944}
6945#include <BVTreeNodePool.h>
6946#include <StackTrivial.h>
6947#include <BVTreeInternalNode.h>
6948#include <BVTreeLeafNode.h>
6949
6950namespace RT
6951{
6952 BVTreeNodePool::BVTreeNodePool(size_t num_primitives)
6953 {
6954 auto const height = static_cast<size_t>(std::floor(log2(static_cast<double>(num_primitives))));
6955 auto const num_nodes = static_cast<size_t>(std::pow(2.0, static_cast<double>(height) + 1.0) - 1.0);
6956 auto num_internal_nodes = num_nodes - num_primitives;
6957 maximize<size_t>(32u, num_primitives);
6958 maximize<size_t>(32u, num_internal_nodes);
6959 _internalNodePool.set_next_size(num_internal_nodes);
6960 _leafNodePool.set_next_size(num_primitives);
6961 }
6962 BVTreeNode* BVTreeNodePool::createInternalNode(BVTreeNode::PrimitiveInfo* const begin, BVTreeNode::PrimitiveInfo* const end)
6963 {
6964 return new (_internalNodePool.malloc()) BVTreeInternalNode(begin, end, *this);
6965 }
6966 BVTreeNode* BVTreeNodePool::createLeafNode(Primitive* p)
6967 {
6968 return new (_leafNodePool.malloc()) BVTreeLeafNode(p);
6969 }
6970 BVTreeNode* BVTreeNodePool::createNode(BVTreeNode::PrimitiveInfo* const begin, BVTreeNode::PrimitiveInfo* const end)
6971 {
6972 return Algorithm::continueSplit(begin, end) ? createInternalNode(begin, end) : createLeafNode(begin->primitive());
6973 }
6974 BVTreeNode* BVTreeNodePool::createNode(StackTrivial<BVTreeNode::PrimitiveInfo>& infos)
6975 {
6976 return createNode(infos.begin(), infos.end());
6977 }
6978 void BVTreeNodePool::destroy(BVTreeLeafNode* node)
6979 {
6980 _leafNodePool.destroy(node);
6981 }
6982 void BVTreeNodePool::destroy(BVTreeInternalNode* node)
6983 {
6984 _internalNodePool.destroy(node);
6985 }
6986}
6987#include <CsmInternalNode.h>
6988#include <CsmNodePool.h>
6989#include <CsmSplit.h>
6990#include <CsmNode.h>
6991#include <BVTreeInternalNode.h>
6992#include <BVTreeLeafNode.h>
6993#include <CsmTree.h>
6994
6995namespace RT
6996{
6997 CsmInternalNode::CsmInternalNode(CsmSplit * const begin, CsmSplit * const end, CsmTree & np, Matrix<4, 4, Type> const & view_matrix_light) :
6998 _bvLight(begin->bvLight())
6999 {
7000 for (auto const * ptr = begin + 1; ptr != end; ) {
7001 _bvLight.unify((ptr++)->bvLight());
7002 }
7003 _fp = FrustumPlanes<3, Type>(MathHelpers::projectionMatrixOrtho(_bvLight) * view_matrix_light);
7004 auto axis = _bvLight.longestAxis();
7005 auto center = _bvLight.center(axis);
7006 auto* const mid = Algorithm::partitionForceSplit(begin, end, [&axis, ¢er](CsmSplit const & split) {
7007 return split.bvLight().center(axis) < center;
7008 });
7009 _left = np.createNode(begin, mid, view_matrix_light);
7010 _right = np.createNode(mid, end, view_matrix_light);
7011 }
7012 CsmInternalNode::~CsmInternalNode()
7013 {
7014 delete _left;
7015 delete _right;
7016 }
7017 FrustumPlanes<3, CsmInternalNode::Type> const & CsmInternalNode::frustumPlanes() const
7018 {
7019 return _fp;
7020 }
7021 void CsmInternalNode::recurseVisible(Descendable & other, CullingParams const & cp, Callback2 const & cb)
7022 {
7023 _left->descendVisible(other, cp, cb);
7024 _right->descendVisible(other, cp, cb);
7025 }
7026 void CsmInternalNode::recurseContributing(Descendable & other, CullingParams const & cp, Callback2 const & cb)
7027 {
7028 _left->descendContributing(other, cp, cb);
7029 _right->descendContributing(other, cp, cb);
7030 }
7031 void CsmInternalNode::recurseAll(Descendable & other, Callback2::CbFunc const & on_render)
7032 {
7033 _left->descendAll(other, on_render);
7034 _right->descendAll(other, on_render);
7035 }
7036 CsmInternalNode::BV const & CsmInternalNode::bvLight() const
7037 {
7038 return _bvLight;
7039 }
7040 void CsmInternalNode::descendVisible(Descendable & other, CullingParams const & cp, Callback2 const & cb)
7041 {
7042 other.descendVisible(*this, cp, cb);
7043 }
7044 void CsmInternalNode::descendVisible(BVTreeInternalNode & other, CullingParams const & cp, Callback2 const & cb)
7045 {
7046 other.descendVisible(*this, cp, cb);
7047 }
7048 void CsmInternalNode::descendVisible(BVTreeLeafNode & other, CullingParams const & cp, Callback2 const & cb)
7049 {
7050 other.descendVisible(*this, cp, cb);
7051 }
7052 void CsmInternalNode::descendContributing(Descendable & other, CullingParams const & cp, Callback2 const & cb)
7053 {
7054 other.descendContributing(*this, cp, cb);
7055 }
7056 void CsmInternalNode::descendContributing(BVTreeInternalNode & other, CullingParams const & cp, Callback2 const & cb)
7057 {
7058 other.descendContributing(*this, cp, cb);
7059 }
7060 void CsmInternalNode::descendContributing(BVTreeLeafNode & other, CullingParams const & cp, Callback2 const & cb)
7061 {
7062 other.descendContributing(*this, cp, cb);
7063 }
7064 void CsmInternalNode::descendAll(Descendable & other, Callback2::CbFunc const & on_render)
7065 {
7066 other.descendAll(*this, on_render);
7067 }
7068 void CsmInternalNode::descendAll(BVTreeInternalNode & other, Callback2::CbFunc const & on_render)
7069 {
7070 other.descendAll(*this, on_render);
7071 }
7072 void CsmInternalNode::descendAll(BVTreeLeafNode & other, Callback2::CbFunc const & on_render)
7073 {
7074 other.descendAll(*this, on_render);
7075 }
7076}
7077#include <CsmLeafNode.h>
7078#include <BVTreeInternalNode.h>
7079#include <BVTreeLeafNode.h>
7080
7081namespace RT
7082{
7083 CsmLeafNode::CsmLeafNode(CsmSplit * split) :
7084 _split(split)
7085 {
7086 }
7087 void CsmLeafNode::descendVisible(Descendable & other, CullingParams const & cp, Callback2 const & cb)
7088 {
7089 other.descendVisible(*this, cp, cb);
7090 }
7091 void CsmLeafNode::descendVisible(BVTreeInternalNode & other, CullingParams const & cp, Callback2 const & cb)
7092 {
7093 other.descendVisible(*this, cp, cb);
7094 }
7095 void CsmLeafNode::descendVisible(BVTreeLeafNode & other, CullingParams const & cp, Callback2 const & cb)
7096 {
7097 other.descendVisible(*this, cp, cb);
7098 }
7099 void CsmLeafNode::descendContributing(Descendable & other, CullingParams const & cp, Callback2 const & cb)
7100 {
7101 other.descendContributing(*this, cp, cb);
7102 }
7103 void CsmLeafNode::descendContributing(BVTreeInternalNode & other, CullingParams const & cp, Callback2 const & cb)
7104 {
7105 other.descendContributing(*this, cp, cb);
7106 }
7107 void CsmLeafNode::descendContributing(BVTreeLeafNode & other, CullingParams const & cp, Callback2 const & cb)
7108 {
7109 other.descendContributing(*this, cp, cb);
7110 }
7111 void CsmLeafNode::descendAll(Descendable & other, Callback2::CbFunc const & on_render)
7112 {
7113 other.descendAll(*this, on_render);
7114 }
7115 void CsmLeafNode::descendAll(BVTreeInternalNode & other, Callback2::CbFunc const & on_render)
7116 {
7117 other.descendAll(*this, on_render);
7118 }
7119 void CsmLeafNode::descendAll(BVTreeLeafNode & other, Callback2::CbFunc const & on_render)
7120 {
7121 other.descendAll(*this, on_render);
7122 }
7123 CsmSplit& CsmLeafNode::split()
7124 {
7125 return *_split;
7126 }
7127}
7128#include <CsmNodePool.h>
7129
7130namespace RT
7131{
7132 CsmNode * CsmNodePool::createNode(CsmSplit * begin, CsmSplit * end, Matrix<4, 4, Type> const & view_matrix_light)
7133 {
7134 return Algorithm::continueSplit(begin, end) ? createInternalNode(begin, end, view_matrix_light) : createLeafNode(begin);
7135 }
7136 CsmNode * CsmNodePool::createInternalNode(CsmSplit * begin, CsmSplit * end, Matrix<4, 4, Type> const & view_matrix_light)
7137 {
7138 return nullptr;
7139 //return new (_internalNodePool.malloc()) CsmInternalNode(begin, end, *this, view_matrix_light);
7140 }
7141 CsmNode * CsmNodePool::createLeafNode(CsmSplit * s)
7142 {
7143 return new (_leafNodePool.malloc()) CsmLeafNode(s);
7144 }
7145}
7146#include <CsmSplit.h>
7147
7148namespace RT
7149{
7150 CsmSplit::CsmSplit(BV const & bv_light, Matrix<4, 4, Type> const & view_matrix_light, Matrix<4, 4, Type>* vp) :
7151 _bvLight(bv_light),
7152 _vp(vp)
7153 {
7154 init(view_matrix_light);
7155 }
7156 CsmSplit::BV const & CsmSplit::bvLight() const
7157 {
7158 return _bvLight;
7159 }
7160 Matrix<4, 4, CsmSplit::Type> const & CsmSplit::vp() const
7161 {
7162 return *_vp;
7163 }
7164 FrustumPlanes<3, CsmSplit::Type> const & CsmSplit::frustumPlanes() const
7165 {
7166 return _fp;
7167 }
7168 RenderList & CsmSplit::renderlist()
7169 {
7170 return _rl;
7171 }
7172 void CsmSplit::set(BV const & bv_light, Matrix<4, 4, Type> const & view_matrix_light, Matrix<4, 4, Type>* vp)
7173 {
7174 _bvLight = bv_light;
7175 _vp = vp;
7176 init(view_matrix_light);
7177 }
7178 void CsmSplit::init(Matrix<4, 4, Type> const & view_matrix_light)
7179 {
7180 *_vp = MathHelpers::projectionMatrixOrtho(_bvLight) * view_matrix_light;
7181 _fp = FrustumPlanes<3, Type>(*_vp);
7182 }
7183}
7184#include <CsmTree.h>
7185#include <BVTree.h>
7186#include <CsmInternalNode.h>
7187#include <CsmLeafNode.h>
7188
7189namespace RT
7190{
7191 CsmTree::CsmTree(CsmSplit * begin, CsmSplit * end, Matrix<4, 4, Type> const & view_matrix_light)
7192 {
7193 _root = createNode(begin, end, view_matrix_light);
7194 }
7195 CsmTree::~CsmTree()
7196 {
7197 delete _root;
7198 }
7199 CsmNode * CsmTree::root()
7200 {
7201 return _root;
7202 }
7203 void CsmTree::descendVisible(BVTree& bvt, CullingParams const & cp, Callback2 const & cb)
7204 {
7205 _root->descendVisible(*bvt.root(), cp, cb);
7206 }
7207 CsmNode * CsmTree::createNode(CsmSplit * begin, CsmSplit * end, Matrix<4, 4, Type> const & view_matrix_light)
7208 {
7209 return Algorithm::continueSplit(begin, end) ? createInternalNode(begin, end, view_matrix_light) : createLeafNode(begin);
7210 }
7211 CsmNode * CsmTree::createInternalNode(CsmSplit * begin, CsmSplit * end, Matrix<4, 4, Type> const & view_matrix_light)
7212 {
7213 return new CsmInternalNode(begin, end, *this, view_matrix_light);
7214 }
7215 CsmNode * CsmTree::createLeafNode(CsmSplit * cs)
7216 {
7217 return new CsmLeafNode(cs);
7218 }
7219}
7220#include <FixedTimestepSystem.h>
7221#include <GameTimer.h>
7222#include <iostream>
7223
7224namespace RT
7225{
7226 bool FixedTimestepSystem::update()
7227 {
7228 _acc += _gameTimer->deltaTimeSeconds();
7229 bool did_update = false;
7230 while (_acc >= _dt) {
7231 updateSystem();
7232 _acc -= _dt;
7233 did_update = true;
7234 }
7235 return did_update;
7236 }
7237}
7238#include <GameTimer.h>
7239
7240namespace RT
7241{
7242 GameTimer::GameTimer() :
7243 _baseTime(timeNow()),
7244 _prevTime(_baseTime)
7245 {
7246 }
7247 void GameTimer::tick()
7248 {
7249 _currTime = timeNow();
7250 _deltaTime = _currTime - _prevTime;
7251 _prevTime = _currTime;
7252 }
7253 void GameTimer::stop()
7254 {
7255 if (!stopped()) {
7256 _stopTime = timeNow();
7257 _stopped = true;
7258 }
7259 }
7260 void GameTimer::start()
7261 {
7262 _currTime = timeNow();
7263 if (stopped()) {
7264 _pausedTime += _currTime - _stopTime;
7265 _prevTime = _currTime;
7266 _stopped = false;
7267 }
7268 }
7269 float GameTimer::timeSeconds() const
7270 {
7271 return toSeconds(((stopped() ? _stopTime : _currTime) - _baseTime - _pausedTime).count());
7272 }
7273 float GameTimer::deltaTimeSeconds() const
7274 {
7275 return stopped() ? 0.f : toSeconds(_deltaTime.count());
7276 }
7277 float GameTimer::totalTimeSeconds() const
7278 {
7279 return toSeconds((_currTime - _baseTime).count());
7280 }
7281 bool GameTimer::stopped() const
7282 {
7283 return _stopped;
7284 }
7285}
7286#define GLM_ENABLE_EXPERIMENTAL
7287#include "Mesh.h"
7288#include <fstream>
7289#include <sstream>
7290#include <iostream>
7291#include <glm/gtx/string_cast.hpp>
7292#include <AABB.h>
7293#include <math/RTMath.h>
7294#include <BVTree.h>
7295
7296namespace RT
7297{
7298 Mesh::Mesh(StackTrivial<Vertex>&& vertices, StackTrivial<unsigned int>&& indices, std::shared_ptr<Material> const * materials, unsigned int const & material_index) :
7299 _vertices(std::move(vertices)),
7300 _indices(std::move(indices)),
7301 _material(*(materials + material_index)),
7302 _materialIndex(material_index)
7303 {
7304 init();
7305 }
7306 Mesh::~Mesh()
7307 {
7308 delete _bvTree;
7309 }
7310 StackTrivial<Vertex> const & Mesh::vertices() const
7311 {
7312 return _vertices;
7313 }
7314 StackTrivial<unsigned int> const & Mesh::indices() const
7315 {
7316 return _indices;
7317 }
7318 void Mesh::setVertices(StackTrivial<Vertex>&& vertices)
7319 {
7320 _vertices = std::move(vertices);
7321 init();
7322 }
7323 void Mesh::setIndices(StackTrivial<unsigned>&& indices)
7324 {
7325 _indices = std::move(indices);
7326 init();
7327 }
7328 unsigned const & Mesh::materialIndex() const
7329 {
7330 return _materialIndex;
7331 }
7332 AABB3f const & Mesh::aabb() const
7333 {
7334 return _aabb;
7335 }
7336 Sphere3f const & Mesh::sphere() const
7337 {
7338 return _sphere;
7339 }
7340 void Mesh::setMaterialIndex(unsigned const & material_index)
7341 {
7342 _materialIndex = material_index;
7343 }
7344 void Mesh::setMaterial(std::shared_ptr<Material> const & material)
7345 {
7346 _material = material;
7347 }
7348 std::shared_ptr<Material> const & Mesh::material() const
7349 {
7350 return _material;
7351 }
7352 BVTree * Mesh::bvTree()
7353 {
7354 return _bvTree;
7355 }
7356
7357 void Mesh::triangles(Vertex * vertices, boost::object_pool<Triangle>& tri_pool, StackTrivial<Primitive*>& triangles) const
7358 {
7359 triangles.reserveToFit(_indices.size() / 3u);
7360 auto const * begin = _indices.begin();
7361 auto const * end = _indices.end();
7362 while (begin != end) {
7363 triangles.push_back_unchecked(new (tri_pool.malloc()) Triangle(Vec3u(*begin, *(begin + 1), *(begin + 2)), vertices));
7364 begin += 3;
7365 }
7366 }
7367
7368 std::shared_ptr<BVTree> Mesh::transformedBVTree(Matrix<4, 4, Type> const & transform,
7369 Matrix<3, 3, Type> const & m_inv_transpose, boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const
7370 {
7371 vertices.clear();
7372 vertices.reserve(_vertices.size());
7373 for (auto const * ptr = _vertices.begin(); ptr != _vertices.end();) {
7374 vertices.push_back_unchecked(Vertex(MathHelpers::transformPoint(transform, ptr->position()), CompressedNormal(m_inv_transpose * ptr->normal()), ptr->uv(),
7375 CompressedNormal(m_inv_transpose * ptr->tangent())));
7376 ++ptr;
7377 }
7378 StackTrivial<Primitive*> tris;
7379 triangles(vertices.begin(), tri_pool, tris);
7380 return std::make_shared<BVTree>(tris.begin(), tris.end());
7381 }
7382
7383 void Mesh::computeTangentSpace()
7384 {
7385 auto * begin = new VertexUncompressed[_vertices.size()]();
7386 for (auto const * i = _indices.begin(); i != _indices.end(); i += 3) {
7387 auto& v0 = _vertices[*i];
7388 auto& v1 = _vertices[*(i + 1)];
7389 auto& v2 = _vertices[*(i + 2)];
7390 auto const & uv0 = v0.uv();
7391 auto const & uv1 = v1.uv();
7392 auto const & uv2 = v2.uv();
7393 auto const s1 = uv1.u() - uv0.u();
7394 auto const t1 = uv1.v() - uv0.v();
7395 auto const s2 = uv2.u() - uv0.u();
7396 auto const t2 = uv2.v() - uv0.v();
7397 auto const e1 = v1.position() - v0.position();
7398 auto const e2 = v2.position() - v0.position();
7399 auto const one_over_det = static_cast<Type>(1) / (s1 * t2 - t1 * s2);
7400 auto t = one_over_det * (e1 * t2 - e2 * t1);
7401 auto b = one_over_det * (e2 * s1 - e1 * s2);
7402 auto n = cross(e1, e2);
7403 begin[*i].add(t, b, n);
7404 begin[*(i + 1)].add(t, b, n);
7405 begin[*(i + 2)].add(t, b, n);
7406 }
7407 auto const * end = begin + _vertices.size();
7408 auto * v = _vertices.begin();
7409 for (; begin != end; ++begin) {
7410 (v++)->set(begin->t().orthogonalize(begin->n()), begin->t().handedness(begin->b(), begin->n()), begin->n());
7411 }
7412 delete[](begin - _vertices.size());
7413 }
7414
7415 void Mesh::init()
7416 {
7417 computeTangentSpace();
7418 _aabb = AABB3f(*this);
7419 _sphere = Sphere3f(*this);
7420 StackTrivial<Primitive*> tris;
7421 triangles(_vertices.begin(), _trianglePool, tris);
7422 _bvTree = new BVTree(tris.begin(), tris.end());
7423 }
7424}
7425#include <renderer/MeshRenderables.h>
7426#include <RenderList.h>
7427#include <Mesh.h>
7428#include <renderer/Renderer.h>
7429
7430namespace RT
7431{
7432 std::shared_ptr<ShaderDesc> const * IMeshRenderable::shaderDesc() const { return _shaderDesc; }
7433 std::shared_ptr<ShaderDesc> const * IMeshRenderable::shaderDescDepth() const { return _shaderDescDepth; }
7434 MaterialDesc * IMeshRenderable::materialDesc() const { return _materialDesc.get(); }
7435 void IMeshRenderable::setModelMatrix(Mat4f const & m)
7436 {
7437 }
7438 void IMeshRenderable::add(RenderList& renderlist)
7439 {
7440 renderlist.addVisibleMesh(this);
7441 }
7442 void IMeshRenderable::addUnchecked(RenderList& renderlist)
7443 {
7444 renderlist.addVisibleMeshUnchecked(this);
7445 }
7446 void IMeshRenderable::addIfContributes(const CullingParams& cp, RenderList& renderlist)
7447 {
7448 if (contributes(cp)) {
7449 add(renderlist);
7450 }
7451 }
7452 void IMeshRenderable::addIfContributesUnchecked(const CullingParams& cp, RenderList& renderlist)
7453 {
7454 if (contributes(cp)) {
7455 addUnchecked(renderlist);
7456 }
7457 }
7458 void IMeshRenderable::addIfContributesAndVisible(const CullingParams& cp, RenderList& renderlist)
7459 {
7460 if (contributes(cp) && intersectFrustum(cp)) {
7461 add(renderlist);
7462 }
7463 }
7464 unsigned IMeshRenderable::numMeshes() const
7465 {
7466 return 1;
7467 }
7468 void IMeshRenderable::createBV(const Mesh& mesh, const Transform& transform, Sphere3f& result)
7469 {
7470 //result = Sphere3f(mesh, transform);
7471 }
7472 void IMeshRenderable::createBV(Mesh const & mesh, Transform const & transform, AABB3f& result)
7473 {
7474 result = AABB3f(mesh.aabb(), transform.matrix());
7475 }
7476 bool IMeshRenderable::contributes(CullingParams const & cp) const
7477 {
7478 return bv().contributes(cp.pEye(), cp.alpha());
7479 }
7480 bool IMeshRenderable::intersectFrustum(CullingParams const & cp) const
7481 {
7482 return !IntersectionTests::outsideFrustum(bv(), cp.frustumPlanes(), cp.frustumVertices());
7483 }
7484 SkydomeRenderable::SkydomeRenderable(Renderer& renderer, const std::shared_ptr<Mesh>& mesh) :
7485 _gmd(renderer.addMesh(mesh))
7486 {
7487 }
7488 const std::shared_ptr<GPUMeshData>& SkydomeRenderable::storage() const
7489 {
7490 return _gmd;
7491 }
7492 StaticMeshRenderable::StaticMeshRenderable(Renderer& renderer, std::shared_ptr<Mesh> const & mesh,
7493 std::shared_ptr<Material> const & material, Transform const & transform) :
7494 _gmd(renderer.addMesh(mesh)),
7495 _modelMatrix(transform.matrix())
7496#if !DYNAMIC_INVERSE
7497 , _modelMatrixInverse(transform.getModelMatrixInverse())
7498#endif
7499 {
7500 _materialDesc = renderer.createMaterialDesc(material);
7501 _shaderDesc = _materialDesc->shaderDesc(MaterialDesc::ShaderKey::DEFAULT);
7502 _shaderDescDepth = _materialDesc->shaderDesc(MaterialDesc::ShaderKey::DEPTH);
7503 }
7504 void StaticMeshRenderable::render(RenderContext const & rc) const
7505 {
7506 rc.renderMesh(*_gmd, _modelMatrix,
7507#if DYNAMIC_INVERSE
7508 inverseUpper3x3(_modelMatrix)
7509#else
7510 _modelMatrixInverse
7511#endif
7512 );
7513 }
7514 void StaticMeshRenderable::renderDepth(RenderContext const & rc) const
7515 {
7516 rc.renderMesh(*_gmd, _modelMatrix);
7517 }
7518 unsigned StaticMeshRenderable::numTriangles() const
7519 {
7520 return _gmd->count() / 3;
7521 }
7522 BVTree * StaticMeshRenderable::nestedBVTree()
7523 {
7524 return _gmd->mesh().bvTree();
7525 }
7526 std::shared_ptr<BVTree> StaticMeshRenderable::transformedBVTree(boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const
7527 {
7528 return _gmd->mesh().transformedBVTree(_modelMatrix, transpose(inverseUpper3x3(_modelMatrix)), tri_pool, vertices);
7529 }
7530 GPUMeshData* StaticMeshRenderable::gpuMeshData() const
7531 {
7532 return _gmd.get();
7533 }
7534 Mat4f const * StaticMeshRenderable::modelMatrix() const
7535 {
7536 return &_modelMatrix;
7537 }
7538 void StaticMeshRenderable::setModelMatrix(Mat4f const & m)
7539 {
7540 _modelMatrix = m;
7541 }
7542 Primitive::BV StaticMeshRenderable::bv() const
7543 {
7544 return BV(_gmd->mesh().aabb(), _modelMatrix);
7545 }
7546 Primitive::BV StaticMeshRenderable::bvLocal() const
7547 {
7548 return _gmd->mesh().aabb();
7549 }
7550 Primitive::Type StaticMeshRenderable::squaredSize() const
7551 {
7552 return bv().squaredSize();
7553 }
7554 Primitive::Ray::IntersectionResult StaticMeshRenderable::intersect(Ray const & ray)
7555 {
7556 return Primitive::Ray::IntersectionResult();
7557 }
7558 Primitive::Ray::IntersectionResult StaticMeshRenderable::intersect(Ray const & ray, Matrix const & matrix)
7559 {
7560 return Ray::IntersectionResult();
7561 }
7562 size_t StaticMeshRenderable::sizeInBytes() const
7563 {
7564 return sizeof *this;
7565 }
7566 StaticMeshRenderableTransform::StaticMeshRenderableTransform(Renderer& renderer, std::shared_ptr<Mesh> const & mesh,
7567 std::shared_ptr<Material> const & material, Transform const & transform) :
7568 StaticMeshRenderable(renderer, mesh, material, transform),
7569 _transform(transform)
7570 {
7571 }
7572 void StaticMeshRenderableTransform::setTransform(Transform const & t)
7573 {
7574 _transform = t;
7575 _modelMatrix = _transform.matrix();
7576 }
7577
7578 Transform const * StaticMeshRenderableTransform::transform() const
7579 {
7580 return &_transform;
7581 }
7582
7583 StaticMeshRenderableShared::StaticMeshRenderableShared(Renderer& renderer, const std::shared_ptr<Mesh>& mesh,
7584 const std::shared_ptr<Material>& material, const std::shared_ptr<Mat4f>& model_matrix) :
7585 _gmd(renderer.addMesh(mesh)),
7586 _modelMatrix(model_matrix)
7587 {
7588 _materialDesc = renderer.createMaterialDesc(material);
7589 _shaderDesc = _materialDesc->shaderDesc(MaterialDesc::ShaderKey::DEFAULT);
7590 _shaderDescDepth = _materialDesc->shaderDesc(MaterialDesc::ShaderKey::DEPTH);
7591 }
7592 void StaticMeshRenderableShared::render(RenderContext const & rc) const
7593 {
7594 rc.renderMesh(*_gmd, *_modelMatrix, inverseUpper3x3(*_modelMatrix));
7595 }
7596 void StaticMeshRenderableShared::renderDepth(RenderContext const & rc) const
7597 {
7598 rc.renderMesh(*_gmd, *_modelMatrix);
7599 }
7600 unsigned StaticMeshRenderableShared::numTriangles() const
7601 {
7602 return _gmd->count() / 3;
7603 }
7604 GPUMeshData* StaticMeshRenderableShared::gpuMeshData() const
7605 {
7606 return _gmd.get();
7607 }
7608 Mat4f const * StaticMeshRenderableShared::modelMatrix() const
7609 {
7610 return _modelMatrix.get();
7611 }
7612 BVTree * StaticMeshRenderableShared::nestedBVTree()
7613 {
7614 return _gmd->mesh().bvTree();
7615 }
7616 std::shared_ptr<BVTree> StaticMeshRenderableShared::transformedBVTree(boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const
7617 {
7618 return _gmd->mesh().transformedBVTree(*_modelMatrix, transpose(inverseUpper3x3(*_modelMatrix)), tri_pool, vertices);
7619 }
7620 Primitive::BV StaticMeshRenderableShared::bv() const
7621 {
7622 return BV(_gmd->mesh().aabb(), *_modelMatrix);
7623 }
7624 Primitive::Type StaticMeshRenderableShared::squaredSize() const
7625 {
7626 return bv().squaredSize();
7627 }
7628 Primitive::Ray::IntersectionResult StaticMeshRenderableShared::intersect(Ray const & ray)
7629 {
7630 return Ray::IntersectionResult();
7631 }
7632 Primitive::Ray::IntersectionResult StaticMeshRenderableShared::intersect(Ray const & ray, Matrix const & matrix)
7633 {
7634 return Ray::IntersectionResult();
7635 }
7636 size_t StaticMeshRenderableShared::sizeInBytes() const
7637 {
7638 return sizeof *this;
7639 }
7640 StaticMeshRenderableLod::StaticMeshRenderableLod(Renderer& renderer, std::vector<std::shared_ptr<Mesh>> const & meshes,
7641 std::shared_ptr<Material> const & material, Transform const & transform) :
7642 _modelMatrix(transform.matrix())
7643#if !DYNAMIC_INVERSE
7644 , _modelMatrixInverse(transform.getModelMatrixInverse())
7645#endif
7646 {
7647 _materialDesc = renderer.createMaterialDesc(material);
7648 _shaderDesc = _materialDesc->shaderDesc(MaterialDesc::ShaderKey::DEFAULT);
7649 _shaderDescDepth = _materialDesc->shaderDesc(MaterialDesc::ShaderKey::DEPTH);
7650 _gmd.reserve(meshes.size());
7651 for (const auto& m : meshes) {
7652 _gmd.push_back(renderer.addMesh(m));
7653 }
7654 }
7655 void StaticMeshRenderableLod::render(RenderContext const & rc) const
7656 {
7657 rc.renderMesh(*_gmd[_lod], _modelMatrix,
7658#if DYNAMIC_INVERSE
7659 inverseUpper3x3(_modelMatrix)
7660#else
7661 _modelMatrixInverse
7662#endif
7663 );
7664 }
7665 void StaticMeshRenderableLod::renderDepth(RenderContext const & rc) const
7666 {
7667 rc.renderMesh(*_gmd[_lod], _modelMatrix);
7668 }
7669 unsigned StaticMeshRenderableLod::numTriangles() const
7670 {
7671 return _gmd[_lod]->count() / 3u;
7672 }
7673 void StaticMeshRenderableLod::add(RenderList& renderlist)
7674 {
7675 renderlist.addVisibleMesh(this);
7676 renderlist.addToCPULodList(this);
7677 }
7678 void StaticMeshRenderableLod::addUnchecked(RenderList& renderlist)
7679 {
7680 renderlist.addVisibleMeshUnchecked(this);
7681 renderlist.addToCPULodListUnchecked(this);
7682 }
7683 void StaticMeshRenderableLod::selectLod(CullingParams const & cp)
7684 {
7685 using Type = typename BV::Type;
7686 auto b = bv();
7687 auto ratio = b.squaredSize() / b.minSquaredDist(cp.pEye());
7688 auto alpha = static_cast<Type>(1) - std::min((ratio - cp.alpha()) / cp.lodRange(), static_cast<Type>(1));
7689 _lod = static_cast<unsigned>(std::round(alpha * (_gmd.size() - 1u)));
7690 }
7691 GPUMeshData* StaticMeshRenderableLod::gpuMeshData() const
7692 {
7693 return _gmd.front().get();
7694 }
7695 Mat4f const * StaticMeshRenderableLod::modelMatrix() const
7696 {
7697 return &_modelMatrix;
7698 }
7699 Primitive::BV StaticMeshRenderableLod::bv() const
7700 {
7701 BV bv = _gmd[0]->mesh().aabb();
7702 for (unsigned i = 1; i < _gmd.size(); i++) {
7703 bv.unify(_gmd[i]->mesh().aabb());
7704 }
7705 return BV(bv, _modelMatrix);
7706 }
7707 BVTree * StaticMeshRenderableLod::nestedBVTree()
7708 {
7709 return _gmd[0]->mesh().bvTree();
7710 }
7711 std::shared_ptr<BVTree> StaticMeshRenderableLod::transformedBVTree(boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const
7712 {
7713 return _gmd[0]->mesh().transformedBVTree(_modelMatrix, transpose(inverseUpper3x3(_modelMatrix)), tri_pool, vertices);
7714 }
7715 Primitive::Type StaticMeshRenderableLod::squaredSize() const
7716 {
7717 return bv().squaredSize();
7718 }
7719 Primitive::Ray::IntersectionResult StaticMeshRenderableLod::intersect(Ray const & ray)
7720 {
7721 return Ray::IntersectionResult();
7722 }
7723 Primitive::Ray::IntersectionResult StaticMeshRenderableLod::intersect(Ray const & ray, Matrix const & matrix)
7724 {
7725 return Ray::IntersectionResult();
7726 }
7727 size_t StaticMeshRenderableLod::sizeInBytes() const
7728 {
7729 return sizeof *this;
7730 }
7731}
7732#include <Transform.h>
7733#define GLM_ENABLE_EXPERIMENTAL
7734#include <glm/gtc/matrix_transform.hpp>
7735#include <glm/gtx/transform.hpp>
7736
7737namespace RT
7738{
7739 Transform::Transform(Vec3f const & translation, Vec3f const & scale, Vec3f const & degrees) :
7740 _translation(translation),
7741 _scale(scale),
7742 _degrees(degrees)
7743 {
7744 }
7745 Mat4f Transform::matrix() const
7746 {
7747 return RT::translate(_translation) *
7748 rotation3DxHom(radians(_degrees.at<0>())) *
7749 rotation3DzHom(radians(_degrees.at<2>())) *
7750 rotation3DyHom(radians(_degrees.at<1>())) *
7751 RT::scale(_scale);
7752 }
7753 Mat3f Transform::inverseMatrix() const
7754 {
7755 return inverse(Mat3f(matrix()));
7756 }
7757 void Transform::setTranslation(Vec3f const & translation)
7758 {
7759 _translation = translation;
7760 }
7761 void Transform::setScale(Vec3f const & scale)
7762 {
7763 _scale = _scale;
7764 }
7765 void Transform::setDegrees(Vec3f const & degrees)
7766 {
7767 _degrees = degrees;
7768 }
7769 Vec3f const & Transform::translation() const
7770 {
7771 return _translation;
7772 }
7773 Vec3f const & Transform::scale() const
7774 {
7775 return _scale;
7776 }
7777 Vec3f const & Transform::degrees() const
7778 {
7779 return _degrees;
7780 }
7781}
7782#include <Triangle.h>
7783#include <Camera.h>
7784#include <physics/Particle.h>
7785
7786namespace RT
7787{
7788 Triangle::BV Triangle::bv() const
7789 {
7790 return BV::fromVertices<3>(vertices().data());
7791 }
7792 Triangle::Type Triangle::squaredSize() const
7793 {
7794 return bv().squaredSize();
7795 }
7796 Triangle::Ray::IntersectionResult Triangle::intersect(Ray const & ray, Vec3 const & p0, Vec3 const & p1, Vec3 const & p2)
7797 {
7798 Ray::IntersectionResult res;
7799 auto e1 = p1 - p0;
7800 auto e2 = p2 - p0;
7801 auto d = ray.dir();
7802 auto a = -d.z() * e2.y() + d.y() * e2.z();
7803 auto b = -d.z() * e1.y() + d.y() * e1.z();
7804 auto c = e1.y() * e2.z() - e2.y() * e1.z();
7805 auto det = e1.x() * a - e2.x() * b - d.x() * c;
7806 if (validDeterminant(det)) {
7807 auto one_over_det = static_cast<Type>(1) / det;
7808 auto q = ray.origin() - p0;
7809 res.setU(one_over_det * q.dot(Vec3(a, d.z() * e2.x() - d.x() * e2.z(), -d.y() * e2.x() + d.x() * e2.y())));
7810 if (res.uv().validU()) {
7811 res.setV(one_over_det * q.dot(Vec3(-b, -d.z() * e1.x() + d.x() * e1.z(), d.y() * e1.x() - d.x() * e1.y())));
7812 if (res.uv().validVW()) {
7813 res.setT(one_over_det * q.dot(Vec3(c, -e1.x() * e2.z() + e2.x() * e1.z(), e1.x() * e2.y() - e2.x() * e1.y())));
7814 return res;
7815 }
7816 }
7817 }
7818 return res;
7819 }
7820 Triangle::Ray::IntersectionResult Triangle::intersect(Ray const & ray_local, Ray const & ray_world, Matrix const & mat)
7821 {
7822 if (auto res = intersect(ray_local)) {
7823 res.setT(distance(ray_world.origin(), MathHelpers::transformPoint(mat, ray_local.pos(res.t()))));
7824 return res;
7825 }
7826 return Triangle::Ray::IntersectionResult();
7827 }
7828 Triangle::Ray::IntersectionResult Triangle::intersect(Ray const & ray)
7829 {
7830 return intersect(ray, vertex<0>(), vertex<1>(), vertex<2>());
7831 }
7832 Triangle::Ray::IntersectionResult Triangle::intersect(Ray const & ray, Matrix const & mat)
7833 {
7834 return intersect(ray, MathHelpers::transformPoint(mat, vertex<0>()), MathHelpers::transformPoint(mat, vertex<1>()), MathHelpers::transformPoint(mat, vertex<2>()));
7835 }
7836 void Triangle::debugTriangle(Vector<4, Type> * _debugTriangle, Matrix const & transform) const
7837 {
7838 *_debugTriangle++ = transform * vertex<0>().toHomogeneous();
7839 *_debugTriangle++ = transform * vertex<1>().toHomogeneous();
7840 *_debugTriangle = transform * vertex<2>().toHomogeneous();
7841 }
7842 Triangle * Triangle::toTriangle()
7843 {
7844 return this;
7845 }
7846}
7847#include <opengl/OpenGLAPI.h>
7848#include <iostream>
7849#include <opengl/GLVertexArray.h>
7850#include <opengl/GLBuffer.h>
7851#include <Model.h>
7852#include <Vertex.h>
7853#include <Mesh.h>
7854#include <Timing.h>
7855#include <SOIL/SOIL.h>
7856#include <Material.h>
7857#include <Settings.h>
7858#include <GraphicsSettings.h>
7859#include <opengl/GLMaterialSetup.h>
7860#include <fstream>
7861#include <Flags.h>
7862#include <GLShaderDesc.h>
7863#include <GlobalShaderParams.h>
7864#include <math/MathHelpers.h>
7865#include <Ray.h>
7866#include <GLMaterialDesc.h>
7867#include <NDCCube.h>
7868
7869namespace RT
7870{
7871 OpenGLAPI::OpenGLAPI(Vec4f const & clear_color) :
7872 _boxShader(createMiscShader(GLShaderSource("assets/opengl/vs_box.glsl", GL_VERTEX_SHADER),
7873 GLShaderSource("assets/opengl/fs_box.glsl", GL_FRAGMENT_SHADER), GLShaderSource("assets/opengl/gs_box.glsl", GL_GEOMETRY_SHADER))),
7874 _debugFrustumShader(createMiscShader(GLShaderSource("assets/opengl/vs_debug_frustum.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_debug_frustum.glsl", GL_FRAGMENT_SHADER))),
7875 _skydomeShader(createMiscShader(GLShaderSource("assets/opengl/vs_skybox.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_skydome_new.glsl", GL_FRAGMENT_SHADER))),
7876 _trianglesDebugShader(createMiscShader(GLShaderSource("assets/opengl/vs_triangles_debug.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_triangle.glsl", GL_FRAGMENT_SHADER))),
7877 _triangleDebugShader(createMiscShader(GLShaderSource("assets/opengl/vs_triangle_debug.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_triangle.glsl", GL_FRAGMENT_SHADER))),
7878 _particleShader(createMiscShader(GLShaderSource("assets/opengl/vs_particles.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_particles.glsl", GL_FRAGMENT_SHADER))),
7879 _copyShader(createMiscShader(GLShaderSource("assets/opengl/vs_screen.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_copy.glsl", GL_FRAGMENT_SHADER))),
7880 _springParticleDebugShader(createMiscShader(GLShaderSource("assets/opengl/vs_debug_spring_particle.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_debug_spring_particle.glsl", GL_FRAGMENT_SHADER))),
7881 _springDebugShader(createMiscShader(GLShaderSource("assets/opengl/vs_debug_spring.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_debug_spring_particle.glsl", GL_FRAGMENT_SHADER))),
7882 _2DBillboardShader(createMiscShader(GLShaderSource("assets/opengl/vs_2d_billboard.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_2d_billboard.glsl", GL_FRAGMENT_SHADER)))
7883 {
7884 GL_CHECK(glGetIntegerv(GL_MAJOR_VERSION, &_glVersionMajor));
7885 GL_CHECK(glGetIntegerv(GL_MINOR_VERSION, &_glVersionMinor));
7886 std::cout << ", GL Version: " << _glVersionMajor << "." << _glVersionMinor << std::endl;
7887
7888 GL_CHECK(glClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]));
7889 }
7890 OpenGLAPI::~OpenGLAPI()
7891 {
7892 }
7893 /*ZNearMapping OpenGLAPI::getZNearMapping() const
7894 {
7895 return ZNearMapping::MINUS_ONE;
7896 }*/
7897 void OpenGLAPI::setViewport(Vec2u const & size) const
7898 {
7899 GL_CHECK(glViewport(0, 0, size.at<0>(), size.at<1>()));
7900 }
7901 void OpenGLAPI::beginFrame() const
7902 {
7903 for (unsigned i = 0; _anisotropy > 1 && i <= static_cast<unsigned>(heightTexUnit); i++) {
7904 _samplerAnisotropic.bind(i);
7905 }
7906 }
7907 void OpenGLAPI::bindShader(Shader const * shader)
7908 {
7909 _activeShader = shader;
7910 _activeShader->bind();
7911 }
7912 void OpenGLAPI::bindShadowmap(const Texture & shadowmap) const
7913 {
7914 GL_CHECK(glActiveTexture(GL_TEXTURE0 + miscTexUnit0));
7915 shadowmap.bind();
7916 }
7917 void OpenGLAPI::renderMesh(GPUMeshData const & gmd) const
7918 {
7919 gmd.draw();
7920 }
7921 void OpenGLAPI::renderMesh(const GPUMeshData& gmd, const Mat4f & model_matrix) const
7922 {
7923 setMatrix(_activeShader->uniformLocation(GLSLShaderGenerator::modelMatrix), model_matrix);
7924 renderMesh(gmd);
7925 }
7926 void OpenGLAPI::renderMesh(const GPUMeshData& gmd, const Mat4f& model_matrix, const Mat3f& model_matrix_inverse) const
7927 {
7928 setMatrixTranspose(_activeShader->uniformLocation(GLSLShaderGenerator::modelMatrixTransposeInverse), model_matrix_inverse);
7929 renderMesh(gmd, model_matrix);
7930 }
7931 void OpenGLAPI::render2DBillboard(const Vec2f & pos_ndc, const Vec2f & scale, const Texture& texture, const Vec3f& color, float depth_ndc)
7932 {
7933 GL_CHECK(glEnable(GL_BLEND));
7934 GL_CHECK(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
7935 bindShader(&_2DBillboardShader);
7936 setVector(_activeShader->uniformLocation("pos_ndc"), pos_ndc);
7937 setVector(_activeShader->uniformLocation("scale"), scale);
7938 setVector(_activeShader->uniformLocation("color"), color);
7939 setScalar(_activeShader->uniformLocation("depth_ndc"), depth_ndc);
7940 activateTexture(texture, "ts", miscTexUnit0);
7941 renderQuad();
7942 GL_CHECK(glDisable(GL_BLEND));
7943 }
7944 void OpenGLAPI::renderDebugTriangle(const Vec4f * triangle, const Mat4f & mvp, const Vec3f & color)
7945 {
7946 GL_CHECK(glPolygonMode(GL_FRONT_AND_BACK, GL_LINE));
7947 bindShader(&_triangleDebugShader);
7948 setVector(_activeShader->uniformLocation("color"), color);
7949 setMatrix(_activeShader->uniformLocation("MVP"), mvp);
7950 setVectorArray(_activeShader->uniformLocation("position"), *triangle, 3);
7951 GL_CHECK(glDrawArrays(GL_TRIANGLES, 0, 3));
7952 GL_CHECK(glPolygonMode(GL_FRONT_AND_BACK, GL_FILL));
7953 }
7954 void OpenGLAPI::renderDebugFrustum(const Mat4f & vp_debug_frustum, const Mat4f & vp)
7955 {
7956 GL_CHECK(glLineWidth(4.f));
7957 bindShader(&_debugFrustumShader);
7958 auto mat = vp * inverse(vp_debug_frustum);
7959 auto cube_ndc = NDCCube<3, float>();
7960 setMatrix(_activeShader->uniformLocation("t"), mat);
7961 GLVertexArray vao;
7962 vao.bind();
7963 GLBuffer vbo(GL_ARRAY_BUFFER);
7964 vbo.setData(cube_ndc.verts(), cube_ndc.numVerts());
7965 GLBuffer ibo(GL_ELEMENT_ARRAY_BUFFER);
7966 std::array<unsigned short, 24> indices = { 0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 1, 3, 7, 7, 5, 7, 6, 6, 4, 6, 2 };
7967 ibo.setData(indices.data(), indices.size());
7968 GL_CHECK(glEnableVertexAttribArray(0));
7969 GL_CHECK(glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(Vec3f), 0));
7970 GL_CHECK(glDrawElements(GL_LINES, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_SHORT, nullptr));
7971 GL_CHECK(glLineWidth(1.f));
7972 }
7973 void OpenGLAPI::bindBackbuffer(unsigned const & id) const
7974 {
7975 GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, id));
7976 }
7977 void OpenGLAPI::ssr(const Texture & lighting_buffer, const Texture& view_space_normals, const Texture& depth_buffer,
7978 const Mat4f& projection_matrix, const Vec4f& blend_weight, Texture& lighting_buffer_copy)
7979 {
7980 depth_buffer.generateMipmap();
7981 GL_CHECK(glEnable(GL_BLEND));
7982 GL_CHECK(glBlendColor(blend_weight.at<0>(), blend_weight.at<1>(), blend_weight.at<2>(), blend_weight.at<3>()));
7983 GL_CHECK(glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR));
7984 bindShader(&_ssrShader);
7985 activateTexture(view_space_normals, GLSLShaderGenerator::viewSpaceNormalsSampler, miscTexUnit0);
7986 activateTexture(lighting_buffer_copy, GLSLShaderGenerator::lightingSampler, miscTexUnit1);
7987 activateTexture(depth_buffer, GLSLShaderGenerator::depthSampler, miscTexUnit2);
7988 setMatrix(_ssrShader.uniformLocation(GLSLShaderGenerator::projectionMatrix), projection_matrix);
7989 auto p_inverse = inverse(projection_matrix);
7990 setMatrix(_ssrShader.uniformLocation(GLSLShaderGenerator::projectionMatrixInverse), p_inverse);
7991 setVector(_ssrShader.uniformLocation(GLSLShaderGenerator::projectionMatrixInverseThirdRow), p_inverse.row<2>());
7992 setVector(_ssrShader.uniformLocation(GLSLShaderGenerator::projectionMatrixInverseFourthRow), p_inverse.row<3>());
7993 renderQuad();
7994 GL_CHECK(glDisable(GL_BLEND));
7995 }
7996 void OpenGLAPI::separableBlur(Texture const & in, std::array<std::shared_ptr<Rendertarget>, 2> const & out)
7997 {
7998 bindShader(&_blurShader);
7999 auto const & dim = out[0]->colorAttachment(0).dim();
8000 for (unsigned i = 0; i < 2; i++) {
8001 out[!i]->bind();
8002 setVector(_activeShader->uniformLocation(GLSLShaderGenerator::texelSize), Vec2f(1.f / dim.at<0>() * i, 1.f / dim.at<1>() * !i));
8003 activateTexture(i ? out[1]->colorAttachment(0) : in, GLSLShaderGenerator::toBlurSampler, miscTexUnit1);
8004 renderQuad();
8005 }
8006 }
8007 void OpenGLAPI::renderGodRays(Texture const & depth_buffer, Texture const & lighting_buffer, const Vec2f & light_pos_uv)
8008 {
8009 bindShader(&_godRayShader);
8010 activateTexture(depth_buffer, GLSLShaderGenerator::depthSampler, miscTexUnit0);
8011 activateTexture(lighting_buffer, GLSLShaderGenerator::lightingSampler, miscTexUnit1);
8012 setVector(_activeShader->uniformLocation(GLSLShaderGenerator::lightPosUV), light_pos_uv);
8013 renderQuad();
8014 }
8015 void OpenGLAPI::renderBrightPass(const Texture & lighting_buffer)
8016 {
8017 bindShader(&_brightnessShader);
8018 activateTexture(lighting_buffer, GLSLShaderGenerator::lightingSampler, miscTexUnit0);
8019 renderQuad();
8020 }
8021 void OpenGLAPI::additiveBlend(const Texture & texture)
8022 {
8023 GL_CHECK(glEnable(GL_BLEND));
8024 GL_CHECK(glBlendFunc(GL_ONE, GL_ONE));
8025 bindShader(&_copyShader);
8026 activateTexture(texture, GLSLShaderGenerator::lightingSampler, miscTexUnit0);
8027 renderQuad();
8028 GL_CHECK(glDisable(GL_BLEND));
8029 }
8030 void OpenGLAPI::endFrame() const
8031 {
8032 for (unsigned i = 0; i <= static_cast<unsigned>(heightTexUnit); i++) {
8033 _samplerAnisotropic.unbind(i);
8034 }
8035 }
8036 void OpenGLAPI::setAnisotropy(unsigned anisotropy)
8037 {
8038 if (_glVersionMajor >= 4 && _glVersionMinor >= 6) {
8039 float max_ani;
8040 GL_CHECK(glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &max_ani));
8041 _anisotropy = glm::clamp(anisotropy, 1u, static_cast<unsigned>(max_ani));
8042 _samplerAnisotropic.param(GL_TEXTURE_MAX_ANISOTROPY, static_cast<float>(_anisotropy));
8043 }
8044 }
8045 void OpenGLAPI::enablePolygonOffset(float factor, float units) const
8046 {
8047 GL_CHECK(glEnable(GL_POLYGON_OFFSET_FILL));
8048 GL_CHECK(glPolygonOffset(factor, units));
8049 }
8050 void OpenGLAPI::disablePolygonOffset() const
8051 {
8052 GL_CHECK(glDisable(GL_POLYGON_OFFSET_FILL));
8053 }
8054 void OpenGLAPI::renderSkydome(Mat4f const & view_projection_matrix, const GPUMeshData& gs)
8055 {
8056 bindShader(&_skydomeShader);
8057 setMatrix(_activeShader->uniformLocation(GLSLShaderGenerator::viewProjectionMatrix), view_projection_matrix);
8058 renderMesh(gs);
8059 }
8060 Texture* OpenGLAPI::createTexture(std::string const & path) const
8061 {
8062 if (auto tex = SOIL_load_OGL_texture(path.c_str(), SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_COMPRESS_TO_DXT)) {
8063 // return new (_texturePool.malloc()) GLTexture(tex, GL_TEXTURE_2D);
8064 return new GLTexture(tex, GL_TEXTURE_2D);
8065 }
8066 throw std::exception((std::string("Could not create texture ") + path).c_str());
8067 }
8068 void OpenGLAPI::deleteTexture(Texture const * texture) const
8069 {
8070 // _texturePool.destroy(texture);
8071 delete texture;
8072 }
8073 /*Shader* OpenGLAPI::createShader(GLShaderSource& vs, GLShaderSource& fs, GLShaderSource& gs)
8074 {
8075 //auto ret = new(_shaderPool.malloc()) Shader();
8076 auto ret = new GLShaderProgram();
8077 ret->add(vs);
8078 if (gs._key != "") { ret->add(gs); }
8079 ret->add(fs);
8080 ret->link();
8081 return ret;
8082 }*/
8083 /* void OpenGLAPI::deleteShader(Shader * shader)
8084 {
8085 //_shaderPool.destroy(shader);
8086 delete shader;
8087 }*/
8088
8089 std::shared_ptr<Texture> OpenGLAPI::createDepthbuffer(const Vec2u & size)
8090 {
8091 auto tex = std::make_shared<GLTexture>(GL_TEXTURE_2D);
8092 tex->bind();
8093 tex->param(GL_TEXTURE_MIN_FILTER, GL_NEAREST);
8094 tex->param(GL_TEXTURE_MAG_FILTER, GL_NEAREST);
8095 tex->param(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
8096 tex->param(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
8097 tex->image2D(0, GL_DEPTH_COMPONENT24, size, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
8098 return tex;
8099 }
8100 std::shared_ptr<Texture> OpenGLAPI::createShadowmap(const GraphicsSettings& settings)
8101 {
8102 auto tex = std::make_shared<GLTexture>(GL_TEXTURE_2D_ARRAY);
8103 tex->bind();
8104 GLint filter = settings.shadowsPCF() ? GL_LINEAR : GL_NEAREST;
8105 tex->param(GL_TEXTURE_MIN_FILTER, filter);
8106 tex->param(GL_TEXTURE_MAG_FILTER, filter);
8107 tex->param(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
8108 tex->param(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
8109 tex->param(GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
8110 tex->param(GL_TEXTURE_BORDER_COLOR, Vec4f(std::numeric_limits<float>::max()).ptr());
8111 if (settings.shadowsPCF()) {
8112 tex->param(GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
8113 tex->param(GL_TEXTURE_COMPARE_FUNC, GL_GREATER);
8114 }
8115 resizeShadowmap(*tex, settings);
8116 return tex;
8117 }
8118 void OpenGLAPI::setupCompositing(Texture const & lighting_buffer) const
8119 {
8120 activateTexture(lighting_buffer, GLSLShaderGenerator::lightingSampler, miscTexUnit1);
8121 }
8122 //void OpenGLAPI::setupFog(Vec2f const & fog_start_end) const
8123 // {
8124 // setVector(_activeShader->uniformLocation(GLSLShaderGenerator::fogStartEnd), fog_start_end);
8125 //}
8126 void OpenGLAPI::setupDepthOfField(GlobalShaderParams const & params, Texture const & dof_buffer, Texture const & depth_buffer, Vec3f const & near_center_far) const
8127 {
8128 activateTexture(dof_buffer, GLSLShaderGenerator::dofSampler, miscTexUnit2);
8129 activateTexture(depth_buffer, GLSLShaderGenerator::depthSampler, miscTexUnit3);
8130 auto p_inverse = inverse(params._projectionMatrix);
8131 setVector(_activeShader->uniformLocation(GLSLShaderGenerator::projectionMatrixInverseThirdRow), p_inverse.row<2>());
8132 setVector(_activeShader->uniformLocation(GLSLShaderGenerator::projectionMatrixInverseFourthRow), p_inverse.row<3>());
8133 setVector(_activeShader->uniformLocation(GLSLShaderGenerator::dofNearCenterFar), near_center_far);
8134 }
8135 void OpenGLAPI::setupGodRays(const Vec3f& god_ray_intensity, Texture const & god_ray_buffer) const
8136 {
8137 activateTexture(god_ray_buffer, GLSLShaderGenerator::godRaySampler, miscTexUnit4);
8138 setVector(_activeShader->uniformLocation(GLSLShaderGenerator::godRayIntensity), god_ray_intensity);
8139 }
8140 void OpenGLAPI::setupBloom(Texture const & bloom_buffer) const
8141 {
8142 activateTexture(bloom_buffer, GLSLShaderGenerator::bloomSampler, miscTexUnit5);
8143 }
8144 void OpenGLAPI::setupAutoExposure(const Texture & lighting_buffer) const
8145 {
8146 setScalar(_activeShader->uniformLocation(GLSLShaderGenerator::maxMipLevel), lighting_buffer.maxMipLevel());
8147 }
8148 void OpenGLAPI::resizeShadowmap(Texture& shadow_map, GraphicsSettings const & settings)
8149 {
8150 shadow_map.image3D(0, GL_DEPTH_COMPONENT24, Vec3u(Vec2u(settings.shadowMapSize()), static_cast<unsigned>(settings.numFrustumSplits())), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
8151 }
8152 void OpenGLAPI::createBlurShader(const GraphicsSettings & gs)
8153 {
8154 GLShaderSource vs, fs;
8155 _shaderGenerator.createBlurShaderSource(gs, vs, fs);
8156 _blurShader = createMiscShader(vs, fs);
8157 }
8158 void OpenGLAPI::createCompositeShader(const GraphicsSettings & gs)
8159 {
8160 GLShaderSource vs, fs;
8161 _shaderGenerator.createCompositeShaderSource(gs, vs, fs, false);
8162 _compositeShader = createMiscShader(vs, fs);
8163 _shaderGenerator.createCompositeShaderSource(gs, vs, fs, gs.godRays());
8164 _compositeShaderWithGodRays = createMiscShader(vs, fs);
8165 }
8166 void OpenGLAPI::createScreenSpaceReflectionsShader(const GraphicsSettings & gs)
8167 {
8168 GLShaderSource vs, fs;
8169 _shaderGenerator.createSSRShaderSource(gs, vs, fs);
8170 _ssrShader = createMiscShader(vs, fs);
8171 }
8172 void OpenGLAPI::createGodRayShader(const GraphicsSettings & gs)
8173 {
8174 GLShaderSource vs, fs;
8175 _shaderGenerator.createGodRayShaderSource(gs, vs, fs);
8176 _godRayShader = createMiscShader(vs, fs);
8177 }
8178 void OpenGLAPI::createBrightnessShader(const GraphicsSettings & gs)
8179 {
8180 GLShaderSource vs, fs;
8181 _shaderGenerator.createBrightnessShaderSource(gs, vs, fs);
8182 _brightnessShader = createMiscShader(vs, fs);
8183 }
8184 MaterialDesc * OpenGLAPI::createMaterialDesc(std::shared_ptr<Material> const & material, GraphicsSettings const & settings, PtrCache<std::string, Texture>* texture_cache, PtrCache<std::shared_ptr<Shader>, ShaderDesc>* shader_desc_cache, PtrCache<std::string, Shader>* shader_cache) const
8185 {
8186 return new GLMaterialDesc(material, settings, texture_cache, shader_desc_cache, shader_cache, *this);
8187 }
8188 GPUMeshData * OpenGLAPI::createMeshData(Mesh & mesh) const
8189 {
8190 return new GLMeshData(mesh);
8191 }
8192 OpenGLAPI::ShaderGenerator const & OpenGLAPI::shaderGenerator() const
8193 {
8194 return _shaderGenerator;
8195 }
8196 //Shader const *& OpenGLAPI::activeShader()
8197 // {
8198 // return _activeShader;
8199 //}
8200 Shader const & OpenGLAPI::compositeShader() const
8201 {
8202 return _compositeShader;
8203 }
8204 Shader const & OpenGLAPI::compositeShaderWithGodRays() const
8205 {
8206 return _compositeShaderWithGodRays;
8207 }
8208 void OpenGLAPI::composite() const
8209 {
8210 renderQuad();
8211 }
8212 void OpenGLAPI::checkFramebufferStatus()
8213 {
8214 if (GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
8215 std::cout << "Framebuffer imcomplete" << std::endl;
8216 }
8217 }
8218 GLShaderProgram OpenGLAPI::createMiscShader(GLShaderSource & vs, GLShaderSource & fs, GLShaderSource& gs) const
8219 {
8220 GLShaderProgram shader;
8221 shader.add(vs);
8222 if (gs._key != "") {
8223 shader.add(gs);
8224 }
8225 shader.add(fs);
8226 shader.link();
8227 return shader;
8228 }
8229 template<unsigned index>
8230 struct EnableVertexAttribArrays
8231 {
8232 static auto call()
8233 {
8234 GL_CHECK(glEnableVertexAttribArray(index));
8235 EnableVertexAttribArrays<index - 1u>::call();
8236 }
8237 };
8238 template<>
8239 struct EnableVertexAttribArrays<0>
8240 {
8241 static auto call()
8242 {
8243 GL_CHECK(glEnableVertexAttribArray(0));
8244 }
8245 };
8246 void OpenGLAPI::setupVertexFormat()
8247 {
8248 EnableVertexAttribArrays<3>::call();
8249 GL_CHECK(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(Vertex::positionMemOffset())));
8250 GL_CHECK(glVertexAttribPointer(1, 4, GL_INT_2_10_10_10_REV, GL_TRUE, sizeof(Vertex), reinterpret_cast<void*>(Vertex::normalMemOffset())));
8251 GL_CHECK(glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(Vertex::uvMemOffset())));
8252 GL_CHECK(glVertexAttribPointer(3, 4, GL_INT_2_10_10_10_REV, GL_TRUE, sizeof(Vertex), reinterpret_cast<void*>(Vertex::tangentMemOffset())));
8253 GL_CHECK(glBindVertexArray(0));
8254 }
8255 OpenGLAPI::GlewInit::GlewInit()
8256 {
8257 glewExperimental = true;
8258 auto result = glewInit();
8259 if (result == GLEW_OK) {
8260 std::cout << "OpenGLAPI::OpenGLAPI(): Initialized GLEW";
8261 }
8262 else {
8263 std::cout << "OpenGLAPI::OpenGLAPI() Failed to initialized GLEW: " << glewGetErrorString(result) << std::endl;
8264 }
8265 }
8266 OpenGLAPI::GLMeshData::GLMeshData(Mesh& mesh) :
8267 _vbo(GL_ARRAY_BUFFER),
8268 _ibo(GL_ELEMENT_ARRAY_BUFFER),
8269 _mesh(mesh)
8270 {
8271 auto const & mesh_verts = mesh.vertices();
8272 auto const & mesh_inds = mesh.indices();
8273 _count = static_cast<GLsizei>(mesh_inds.size());
8274 _vao.bind();
8275 _vbo.setData(mesh_verts.begin(), mesh_verts.size());
8276 _type = fillIndexBuffer(mesh_verts.begin(), mesh_verts.end(), mesh_inds.begin(), mesh_inds.end(), _ibo);
8277 setupVertexFormat();
8278 }
8279 void OpenGLAPI::GLMeshData::draw() const
8280 {
8281 _vao.bind();
8282 GL_CHECK(glDrawElements(GL_TRIANGLES, count(), type(), nullptr));
8283 }
8284}
8285#include <opengl/GLSLShaderGenerator.h>
8286#include <GraphicsSettings.h>
8287#include <Flags.h>
8288#include <iostream>
8289
8290namespace RT
8291{
8292 GLSLShaderGenerator::GLSLShaderGenerator() :
8293 _compositeVertexSource(std::string(vertexFileComposite), GL_VERTEX_SHADER)
8294 {
8295 _windParamString = "uniform float " + std::string(time) + "; \n\
8296uniform vec3 " + std::string(bbMin) + "; // AABB min xz\n\
8297uniform vec3 " + std::string(bbMax) + "; // AABB max xz\n" + std::string(noiseCodeGLSL());
8298
8299 _springParticleDataStr = "layout (std430, binding = " + str(bufferBindingSpringSkinnedInitPos) + ") readonly buffer init_pos_buffer \n\
8300{ \n\
8301 vec4 init_pos[]; \n\
8302};\n\
8303layout(std430, binding = " + str(bufferBindingSpringSkinnedPos) + ") readonly buffer pos_buffer \n\
8304{ \n\
8305 vec4 pos[]; \n\
8306};\n";
8307 }
8308 GLShaderSource GLSLShaderGenerator::createMeshVertexShaderSource(unsigned const & flags, GraphicsSettings const & gs)const
8309 {
8310 std::string key = "vs";
8311 if (flags & MeshRenderFlag::MR_SPRING_SKINNED) {
8312 key += "_spring_skinned";
8313 }
8314 key += ".glsl";
8315 GLShaderSource src;
8316 src._key = key;
8317 src._source = createMeshVertexSource(flags, gs);
8318 src._type = GL_VERTEX_SHADER;
8319 return src;
8320 }
8321 GLShaderSource GLSLShaderGenerator::createMeshFragmentShaderSource(unsigned const & flags, GraphicsSettings const & gs)const
8322 {
8323 std::string key = "fs";
8324 if (flags & MeshRenderFlag::MR_DIFFUSE_MAP) {
8325 key += "_albedo";
8326 }
8327 if (flags & MeshRenderFlag::MR_NORMAL_MAP) {
8328 key += "_normal";
8329 if (flags & MeshRenderFlag::MR_HEIGHT_MAP) {
8330 key += "_parallax";
8331 }
8332 }
8333 if (flags & MeshRenderFlag::MR_ALPHA_MAP) {
8334 key += "_alpha";
8335 }
8336 if (flags & MeshRenderFlag::MR_REFLECTIVE) {
8337 key += "_reflective";
8338 }
8339 if (gs.screenSpaceReflections()) {
8340 key += "_ssr";
8341 }
8342 if (gs.shadows() || gs.shadowsPCF()) {
8343 key += "_shadows";
8344 }
8345 if (gs.shadowsPCF()) {
8346 key += "_pcf";
8347 }
8348 if (gs.softShadows()) {
8349 key += "_soft_shadows";
8350 }
8351 if (gs.gammaEnabled()) {
8352 key += "_gamma";
8353 }
8354 if (gs.fog()) {
8355 key += "_fog";
8356 }
8357 key += ".glsl";
8358 GLShaderSource src;
8359 src._key = key;
8360 src._source = createMeshFragmentSource(flags, gs);
8361 src._type = GL_FRAGMENT_SHADER;
8362 return src;
8363 }
8364 GLShaderSource GLSLShaderGenerator::createMeshVertexShaderDepthSource(unsigned const & flags, GraphicsSettings const & gs)const
8365 {
8366 std::string key = "vs_depth";
8367 if (flags & MeshRenderFlag::MR_SPRING_SKINNED) {
8368 key += "_spring_skinned";
8369 }
8370 key += ".glsl";
8371 GLShaderSource src;
8372 src._key = key;
8373 src._source = createMeshVertexDepthSource(flags, gs);
8374 src._type = GL_VERTEX_SHADER;
8375 return src;
8376 }
8377 GLShaderSource GLSLShaderGenerator::createMeshFragmentShaderDepthSource(unsigned const & flags, GraphicsSettings const & gs)const
8378 {
8379 std::string key = "fs_depth";
8380 if (flags & MeshRenderFlag::MR_ALPHA_MAP) {
8381 key += "_alpha";
8382 }
8383 key += ".glsl";
8384 GLShaderSource src;
8385 src._key = key;
8386 src._source = createMeshFragmentDepthSource(flags, gs);
8387 src._type = GL_FRAGMENT_SHADER;
8388 return src;
8389 }
8390 void GLSLShaderGenerator::createCompositeShaderSource(GraphicsSettings const & gs, GLShaderSource& vertex_src, GLShaderSource& fragment_src, bool god_rays)const
8391 {
8392 vertex_src = _compositeVertexSource;
8393 std::string key = "fs_composite";
8394 if (gs.depthOfField()) {
8395 key += "_dof";
8396 }
8397 if (gs.exposureEnabled()) {
8398 key += "_exposure";
8399 }
8400 if (gs.gammaEnabled()) {
8401 key += "_gamma";
8402 }
8403 if (god_rays) {
8404 key += "_god_rays";
8405 }
8406 if (gs.bloom()) {
8407 key += "_bloom";
8408 }
8409 key += ".glsl";
8410 fragment_src._key = key;
8411 fragment_src._source = createCompositeShaderSource(gs, god_rays);
8412 fragment_src._type = GL_FRAGMENT_SHADER;
8413 }
8414 void GLSLShaderGenerator::createBlurShaderSource(GraphicsSettings const & gs, GLShaderSource & vertex_src, GLShaderSource & fragment_src)const
8415 {
8416 vertex_src = _compositeVertexSource;
8417 fragment_src._source = "#version 330 \n\
8418layout(location = 0) out vec3 fragmentColor;\n\
8419in vec2 uv;\n\
8420uniform sampler2D " + std::string(toBlurSampler) + ";\n\
8421uniform vec2 " + std::string(texelSize) + ";\n";
8422 fragment_src._source += blurSource(gs.blurWeights(gs.blurRadius(), gs.blurSigma()));
8423 fragment_src._source += "void main()\n\
8424{\n\
8425 fragmentColor = vec3(0.f);\n\
8426 for (int i = -" + str(gs.blurRadius()) + "; i <= " + str(gs.blurRadius()) + "; i++){\n\
8427 fragmentColor += texture(" + std::string(toBlurSampler) + ", uv + i * " + std::string(texelSize) + ").rgb * blur_weights[i + " + str(gs.blurRadius()) + "];\n\
8428 }\n\
8429}\n";
8430 fragment_src._key = "fs_blur";
8431 fragment_src._type = GL_FRAGMENT_SHADER;
8432 }
8433 void GLSLShaderGenerator::createSSRShaderSource(const GraphicsSettings & gs, GLShaderSource & vertex_src, GLShaderSource & fragment_src)const
8434 {
8435 vertex_src = _compositeVertexSource;
8436 fragment_src._source = "#version 330 \n\
8437layout(location = 0) out vec3 fragmentColor;\n\
8438in vec2 uv;\n\
8439uniform sampler2D " + std::string(lightingSampler) + ";\n\
8440uniform sampler2D " + std::string(viewSpaceNormalsSampler) + ";\n\
8441uniform sampler2D " + std::string(depthSampler) + ";\n\
8442uniform mat4 " + std::string(projectionMatrixInverse) + "; // Inverse projection matrix\n\
8443uniform mat4 " + std::string(projectionMatrix) + "; // Projection matrix\n\
8444uniform vec4 " + std::string(projectionMatrixInverseThirdRow) + "; // Third row of inverse projection matrix\n\
8445uniform vec4 " + std::string(projectionMatrixInverseFourthRow) + "; // Fourth row of inverse projection matrix\n"
8446+ std::string(commonHelpers()) + "void main()\n\
8447{\n\
8448 vec3 normal_view = textureLod(" + std::string(viewSpaceNormalsSampler) + ", uv, 0.f).xyz;\n\
8449 if (normal_view != vec3(0.f)) {\n\
8450 vec4 pos_view_h = " + std::string(projectionMatrixInverse) + " * vec4(uv_to_ndc(vec3(uv, texture(" + std::string(depthSampler) + ", uv).r)), 1.f);\n\
8451 vec3 pos_view = pos_view_h.xyz / pos_view_h.w;\n\
8452 vec3 ray = reflect_(normalize(pos_view), normal_view) * max(-pos_view.z * " + str(gs.SSRRayLenScale()) + "f, " + str(gs.SSRMinRayLen()) + ");\n\
8453 vec3 delta = ray / " + str(gs.SSRSteps()) + "f;\n\
8454 vec3 ray_pos_view = pos_view + delta;\n\
8455 for (float i = 0.f; i < " + str(gs.SSRSteps()) + "f; i++, ray_pos_view += delta) {\n\
8456 vec4 ray_pos_h = " + std::string(projectionMatrix) + " * vec4(ray_pos_view, 1.f);\n\
8457 vec2 ray_pos_ndc = ray_pos_h.xy / ray_pos_h.w;\n\
8458 vec2 uv = ndc_to_uv(ray_pos_ndc);\n\
8459 vec4 comp_ndc = vec4(uv_to_ndc(vec3(uv, texture(" + std::string(depthSampler) + ", uv).r)), 1.f);\n\
8460 float comp_depth = dot(comp_ndc, " + std::string(projectionMatrixInverseThirdRow) + ") / dot(comp_ndc, " + std::string(projectionMatrixInverseFourthRow) + ");\n\
8461 if (ray_pos_view.z > comp_depth) { \n\
8462 float sign;\n\
8463 for (uint i = 0u; i < " + str(gs.SSRBinarySteps()) + "u; i++, delta *= 0.5f, ray_pos_view += delta * sign) { \n\
8464 ray_pos_h = " + std::string(projectionMatrix) + " * vec4(ray_pos_view, 1.f);\n\
8465 ray_pos_ndc = ray_pos_h.xy / ray_pos_h.w;\n\
8466 uv = ndc_to_uv(ray_pos_ndc);\n\
8467 vec4 comp_ndc = vec4(uv_to_ndc(vec3(uv, texture(" + std::string(depthSampler) + ", uv).r)), 1.f);\n\
8468 float comp_depth = dot(comp_ndc, " + std::string(projectionMatrixInverseThirdRow) + ") / dot(comp_ndc, " + std::string(projectionMatrixInverseFourthRow) + ");\n\
8469 sign = ray_pos_view.z > comp_depth ? -1.f : 1.f;\n\
8470 }\n\
8471 fragmentColor = textureLod(" + std::string(lightingSampler) + ", uv, 0.f).rgb;\n\
8472 return;\n\
8473 }\n\
8474 }\n\
8475 }\n\
8476 fragmentColor = textureLod(" + std::string(lightingSampler) + ", uv, 0.f).rgb;\n\
8477}\n";
8478 fragment_src._key = "fs_ssr";
8479 fragment_src._type = GL_FRAGMENT_SHADER;
8480 }
8481 void GLSLShaderGenerator::createGodRayShaderSource(const GraphicsSettings& gs, GLShaderSource & vertex_src, GLShaderSource & fragment_src) const
8482 {
8483 vertex_src = _compositeVertexSource;
8484 fragment_src._source = "#version 330\n\
8485layout(location = 0) out vec3 fragmentColor;\n\
8486uniform sampler2D " + std::string(lightingSampler) + ";\n\
8487uniform sampler2D " + std::string(depthSampler) + ";\n\
8488uniform vec2 " + std::string(lightPosUV) + ";\n\
8489in vec2 uv;\n\
8490void main()\n\
8491{\n\
8492 fragmentColor = vec3(0.f);\n\
8493 vec2 delta = (" + std::string(lightPosUV) + " - uv) / " + str(gs.godRaySteps()) + ";\n\
8494 vec2 tex_coord = uv;\n\
8495 float decay = 1.f;\n\
8496 for (float i = 0.f; i < " + str(gs.godRaySteps()) + "; i++, tex_coord += delta, decay *= " + str(gs.godRayDecay()) + ") { \n\
8497 fragmentColor += decay * texture(" + std::string(lightingSampler) + ", tex_coord).rgb * float(texture(" + std::string(depthSampler) + ", tex_coord).r == 1.f);\n\
8498 }\n\
8499 fragmentColor /= " + str(gs.godRaySteps()) + ";\n\
8500}\n";
8501 fragment_src._key = "fs_god_ray";
8502 fragment_src._type = GL_FRAGMENT_SHADER;
8503 }
8504 void GLSLShaderGenerator::createBrightnessShaderSource(const GraphicsSettings & gs, GLShaderSource & vertex_src, GLShaderSource & fragment_src) const
8505 {
8506 vertex_src = _compositeVertexSource;
8507 fragment_src._source = "#version 330\n\
8508layout (location = 0) out vec3 fragmentColor;\n\
8509uniform sampler2D " + std::string(lightingSampler) + ";\n\
8510in vec2 uv;\n\
8511void main() \n\
8512{\n\
8513 vec3 col = texture(" + std::string(lightingSampler) + ", uv).rgb; \n\
8514 fragmentColor = col * smoothstep(0.85f, 1.f, dot(col, vec3(0.2126f, 0.7152f, 0.0722f)));\n\
8515}";
8516 fragment_src._type = GL_FRAGMENT_SHADER;
8517 }
8518 std::string GLSLShaderGenerator::createMeshVertexSource(unsigned const & flags, GraphicsSettings const & gs) const
8519 {
8520 std::string version = (flags & MR_SPRING_SKINNED) ? "450" : "330";
8521 std::string shader_src;
8522 shader_src += "#version " + version + "\n\
8523layout(location = 0) in vec3 position;\n\
8524layout(location = 1) in vec3 normal;\n\
8525layout(location = 2) in vec2 uv;\n\
8526layout(location = 3) in vec4 tangent;\n\
8527layout (location = 4) in uvec4 p_indices;\n\
8528layout(location = 5) in vec4 weights;\n\
8529// Shader constants\n\
8530uniform mat4 VP; \n\
8531// Model constants\n\
8532uniform mat4 " + std::string(modelMatrix) + ";\n\
8533out vec3 pos_world;\n\
8534out vec3 normal_local;\n\
8535out vec2 uv_out;\n\
8536out vec4 tangent_local;\n";
8537 if (flags & MeshRenderFlag::MR_SPRING_SKINNED) {
8538 shader_src += _springParticleDataStr;
8539 }
8540 if (gs.depthPrepassEnabled()) {
8541 shader_src += "invariant gl_Position; \n";
8542 }
8543 shader_src += "void main()\n\
8544{\n";
8545 if (flags & MeshRenderFlag::MR_SPRING_SKINNED) {
8546 shader_src += " vec3 offs = vec3(0.f);\n\
8547 for (uint i = 0; i < 4; i++) { \n\
8548 offs += (pos[p_indices[i]].xyz - init_pos[p_indices[i]].xyz) * weights[i]; \n\
8549 }\n";
8550 shader_src += " pos_world = (" + std::string(modelMatrix) + " * vec4(position + offs, 1.f)).xyz;\n";
8551 }
8552 else {
8553 shader_src += " pos_world = (" + std::string(modelMatrix) + " * vec4(position, 1.f)).xyz;\n";
8554 }
8555 shader_src += " gl_Position = VP * vec4(pos_world, 1.f);\n\
8556 normal_local = normal;\n\
8557 uv_out = uv;\n\
8558 tangent_local = tangent;\n";
8559 shader_src += "}\n";
8560 return shader_src;
8561 }
8562 std::string GLSLShaderGenerator::createMeshVertexDepthSource(unsigned const & flags, GraphicsSettings const & gs) const
8563 {
8564 std::string version = (flags & MR_SPRING_SKINNED) ? "450" : "330";
8565 std::string shader_src = "#version " + version + "\n\
8566layout(location = 0) in vec3 position;\n\
8567layout(location = 2) in vec2 uv;\n\
8568layout(location = 5) in uvec4 p_indices; \n\
8569layout(location = 6) in vec4 weights; \n";
8570 if (gs.depthPrepassEnabled()) {
8571 shader_src += "invariant gl_Position; \n";
8572 }
8573 shader_src += "uniform mat4 " + std::string(modelMatrix) + ";\n";
8574 shader_src += "uniform mat4 " + std::string(viewProjectionMatrix) + "; \n";
8575 shader_src += _windParamString;
8576 shader_src += "out vec2 uv_out;\n";
8577 if (flags & MR_SPRING_SKINNED) {
8578 shader_src += _springParticleDataStr;
8579 }
8580 shader_src += "void main()\n\
8581{\n";
8582 if (flags & MR_SPRING_SKINNED) {
8583 shader_src += " vec3 offs = vec3(0.f);\n\
8584 for (uint i = 0; i < 4; i++) { \n\
8585 offs += (pos[p_indices[i]].xyz - init_pos[p_indices[i]].xyz) * weights[i]; \n\
8586 }\n";
8587 shader_src += " vec4 pos_world = " + std::string(modelMatrix) + " * vec4(position + offs, 1.f);\n";
8588 }
8589 else {
8590 shader_src += " vec4 pos_world = " + std::string(modelMatrix) + " * vec4(position, 1.f);\n";
8591 }
8592 shader_src += " gl_Position = " + std::string(viewProjectionMatrix) + " * pos_world;\n";
8593 shader_src += " uv_out = uv;\n\
8594}\n";
8595 return shader_src;
8596 }
8597 std::string GLSLShaderGenerator::createMeshFragmentSource(unsigned const & flags, GraphicsSettings const & gs) const
8598 {
8599 std::string version = "330";
8600 bool tangent_space = (flags & MR_NORMAL_MAP) || (flags & MR_HEIGHT_MAP);
8601 std::string shader_src = "#version " + version + " \n\
8602layout(location = 0) out vec3 fragmentColor;\n";
8603 unsigned rt_index = 1;
8604 if (gs.screenSpaceReflections()) {
8605 shader_src += "layout(location = " + str(rt_index) + ") out vec3 viewSpaceNormal; \n";
8606 rt_index++;
8607 }
8608 shader_src += "in vec3 pos_world;\n\
8609in vec2 uv_out;\n\
8610uniform vec3 " + std::string(diffuseColor) + ";\n\
8611uniform sampler2D " + std::string(diffuseSampler) + ";\n\
8612uniform sampler2D " + std::string(alphaSampler) + ";\n\
8613uniform sampler2D " + std::string(normalSampler) + ";\n\
8614uniform sampler2D " + std::string(heightSampler) + ";\n\
8615uniform float " + std::string(parallaxHeightScale) + "; // Parallax ray scale\n\
8616uniform float " + std::string(shadowMapBias) + "; // Shadow map bias\n\
8617uniform float " + std::string(parallaxMinSteps) + "; // Parallax min steps\n\
8618uniform float " + std::string(parallaxMaxSteps) + "; // Parallax max steps\n\
8619uniform float " + std::string(parallaxBinarySearchSteps) + "; // Parallax binary search steps\n\
8620uniform vec3 " + std::string(lightDirWorld) + "; // light direction world space\n\
8621uniform vec3 " + std::string(cameraPositionWorld) + "; // camera position world space\n\
8622uniform vec3 " + std::string(lightIntensity) + "; // light intensity\n\
8623uniform mat4 " + std::string(worldToLightMatrices) + " [" + str(gs.numFrustumSplits()) + "]; // world space to light space\n\
8624uniform float " + std::string(frustumSplits) + " [" + str(gs.numFrustumSplits()) + "]; // frustum_splits\n\
8625uniform int " + std::string(numfrustumSplits) + "; // num frustum splits\n";
8626 shader_src += (gs.shadowsPCF() ? "uniform sampler2DArrayShadow " : "uniform sampler2DArray ") + std::string(shadowSampler) + ";\n";
8627 shader_src += "// Material constants\n\
8628uniform float " + std::string(ambientConstant) + ";\n\
8629uniform float " + std::string(diffuseConstant) + ";\n\
8630uniform float " + std::string(specularConstant) + ";\n\
8631uniform float " + std::string(specularExponent) + ";\n\
8632uniform float " + std::string(gamma) + ";\n\
8633uniform mat3 " + std::string(modelMatrixTransposeInverse) + ";\n\
8634uniform mat3 " + std::string(viewMatrixOrtho) + ";\n\
8635uniform vec4 " + std::string(viewMatrixThirdRow) + ";\n\
8636uniform vec2 " + std::string(fogStartEnd) + ";\n\
8637uniform vec3 " + std::string(fogColor) + ";\n\
8638in vec3 normal_local;\n\
8639in vec4 tangent_local;\n";
8640 shader_src += blurSource(gs.blurWeights2D(gs.shadowBlurRadius(), gs.shadowBlurSigma()));
8641 shader_src += "void main()\n\
8642{\n\
8643 vec2 uv = uv_out;\n";
8644 if (tangent_space) {
8645 shader_src += " vec3 bitangent_local = tangent_local.w * cross(normal_local, tangent_local.xyz);\n";
8646 shader_src += " mat3 world_to_tangent = mat3(normalize(" + std::string(modelMatrixTransposeInverse) + " * vec3(tangent_local.x, bitangent_local.x, normal_local.x)), normalize(" + std::string(modelMatrixTransposeInverse) + " * vec3(tangent_local.y, bitangent_local.y, normal_local.y)), normalize(" + std::string(modelMatrixTransposeInverse) + " * vec3(tangent_local.z, bitangent_local.z, normal_local.z)));\n";
8647 }
8648 shader_src += " vec3 e =" + std::string(tangent_space ? " world_to_tangent *" : "") + " normalize(" + std::string(cameraPositionWorld) + " - pos_world); \n";
8649 if ((flags & MR_NORMAL_MAP) && (flags & MR_HEIGHT_MAP)) {
8650 if (!gs.reliefMapping()) {
8651 shader_src += " uv -= e.xy / e.z * (1.f - textureLod(" + std::string(heightSampler) + ", uv, 0.f).r) * " + std::string(parallaxHeightScale) + "; \n";
8652 }
8653 else {
8654 shader_src += " float steps = mix(" + std::string(parallaxMaxSteps) + ", " + std::string(parallaxMinSteps) + ", clamp(dot(vec3(0.f, 0.f, 1.f), e), 0.f, 1.f));\n\
8655 vec2 ray = e.xy * " + std::string(parallaxHeightScale) + ";\n\
8656 vec2 delta = ray / steps;\n\
8657 float layer_delta = 1.f / steps;\n\
8658 float layer_depth = 1.f - layer_delta;\n\
8659 uv -= delta;\n\
8660 for (float i = 0.f; i < steps; i++, uv -= delta, layer_depth -= layer_delta) {\n\
8661 if(textureLod(" + std::string(heightSampler) + ", uv, 0.f).r > layer_depth){\n\
8662 delta *= 0.5f;\n\
8663 layer_delta *= 0.5f;\n\
8664 uv += delta;\n\
8665 layer_depth += layer_delta;\n\
8666 for (float i = 0.f, sign; i < " + std::string(parallaxBinarySearchSteps) + "; i++, uv += delta * sign, layer_depth += layer_delta * sign){\n\
8667 sign = (textureLod(" + std::string(heightSampler) + ", uv, 0.f).r > layer_depth) ? 1.f : -1.f;\n\
8668 delta *= 0.5f;\n\
8669 layer_delta *= 0.5f;\n\
8670 }\n\
8671 break;\n\
8672 }\n\
8673 }\n";
8674 }
8675 }
8676 if (flags & MeshRenderFlag::MR_ALPHA_MAP) {
8677 shader_src += " if (texture(" + std::string(alphaSampler) + ", uv).r < 0.5f) {\n\
8678 discard;\n\
8679 return;\n\
8680 }\n";
8681 }
8682 shader_src += " vec3 l = " + std::string((tangent_space ? "world_to_tangent *" : "")) + std::string(lightDirWorld) + ";\n";
8683 if (flags & MeshRenderFlag::MR_NORMAL_MAP) {
8684 shader_src += " vec3 n = normalize((texture(" + std::string(normalSampler) + ", uv).xyz * 2.f - 1.f));\n";
8685 }
8686 else {
8687 shader_src += " vec3 n = normalize(" + std::string(modelMatrixTransposeInverse) + " * normal_local);\n";
8688 }
8689 shader_src += " float diffuse = max(dot(l, n), 0.f);\n\
8690 float specular = pow(max(dot(normalize(e + l), n), 0.f), " + std::string(specularExponent) + ");\n";
8691
8692 if (flags & MeshRenderFlag::MR_DIFFUSE_MAP) {
8693 shader_src += " vec3 albedo = texture(" + std::string(diffuseSampler) + ", uv).rgb;\n";
8694 }
8695 else {
8696 shader_src += " vec3 albedo = " + std::string(diffuseColor) + ";\n";
8697 }
8698 if (gs.gammaEnabled()) {
8699 shader_src += " albedo = pow(albedo, vec3(" + std::string(gamma) + "));\n";
8700 }
8701 if (gs.shadows() || gs.fog()) {
8702 shader_src += " float depth_view = dot(" + std::string(viewMatrixThirdRow) + ", vec4(pos_world, 1.f));\n";
8703 }
8704 if (gs.shadows() || gs.shadowsPCF()) {
8705 shader_src += " int index = " + std::string(numfrustumSplits) + "-1;\n\
8706 for (int i = " + std::string(numfrustumSplits) + "-2; i >= 0; i--) {\n\
8707 index -= int(depth_view < " + std::string(frustumSplits) + "[i]);\n\
8708 }\n";
8709 shader_src += " vec4 shadow_coord = " + std::string(worldToLightMatrices) + "[index] * vec4(pos_world, 1.f);\n\
8710 shadow_coord.xyz /= shadow_coord.w;\n\
8711 shadow_coord = shadow_coord * 0.5f + 0.5f;\n";
8712 if (!gs.shadowsPCF()) {
8713 shader_src += " if (all(greaterThanEqual(shadow_coord.xyz, vec3(0.f))) && all(lessThanEqual(shadow_coord.xyz, vec3(1.f)))) {\n ";
8714 }
8715 if (gs.softShadows()) {
8716 auto rad = str(gs.shadowBlurRadius());
8717 shader_src += " float light_factor = 1.f;\n\
8718 vec2 offs = 1.f / textureSize(" + std::string(shadowSampler) + ", 0).xy;\n\
8719 for (int u = -" + rad + "; u <= " + rad + "; u++) {\n\
8720 for(int v = -" + rad + "; v <= " + rad + "; v++) {\n\
8721 light_factor -= texture(" + std::string(shadowSampler) + ", vec4(shadow_coord.xy + vec2(u, v) * offs, index, shadow_coord.z)) * blur_weights[((v + " + rad + ") * " + rad + ") + u + " + rad + "];\n\
8722 }\n\
8723}\n";
8724 }
8725 else {
8726 shader_src += std::string(" float light_factor = 1.f - ") + (gs.shadowsPCF() ? "texture(" + std::string(shadowSampler) + ", vec4(shadow_coord.xy, index, shadow_coord.z))" : "float(shadow_coord.z > texture(" + std::string(shadowSampler) + ", vec3(shadow_coord.xy, index)).r)") + ";\n";
8727 }
8728 shader_src += " specular *= light_factor;\n\
8729 diffuse *= light_factor;\n";
8730 if (!gs.shadowsPCF()) {
8731 shader_src += " }\n";
8732 }
8733 }
8734 shader_src += " fragmentColor = " + std::string(lightIntensity) + " * albedo * (" + std::string(ambientConstant) + " + " + std::string(diffuseConstant) + " * diffuse + " + std::string(specularConstant) + " * specular);\n";
8735 if (gs.fog()) {
8736 shader_src += " fragmentColor = mix(fragmentColor, " + std::string(fogColor) + ", smoothstep(" + std::string(fogStartEnd) + ".x, " + std::string(fogStartEnd) + ".y, depth_view)); \n";
8737 }
8738 if (gs.screenSpaceReflections()) {
8739 if (flags & MR_REFLECTIVE) {
8740 shader_src += " mat3 mv_inverse = " + std::string(viewMatrixOrtho) + " * " + std::string(modelMatrixTransposeInverse) + ";\n";
8741 if (tangent_space) {
8742 shader_src += " mat3 tangent_to_view = mat3(normalize(mv_inverse * tangent_local.xyz), normalize(mv_inverse * bitangent_local), normalize(mv_inverse * normal_local));\n\
8743 viewSpaceNormal = normalize(tangent_to_view * n);\n";
8744 }
8745 else {
8746 shader_src += " viewSpaceNormal = normalize(mv_inverse * normal_local);\n";
8747 }
8748 }
8749 else {
8750 shader_src += " viewSpaceNormal = vec3(0.f);\n";
8751 }
8752 }
8753 shader_src += "}\n";
8754 return shader_src;
8755 }
8756 std::string GLSLShaderGenerator::createMeshFragmentDepthSource(unsigned const & flags, GraphicsSettings const & gs) const
8757 {
8758 std::string shader_src = "#version 330\n\
8759in vec2 uv_out;\n";
8760 if (flags & MR_ALPHA_MAP) {
8761 shader_src += "uniform sampler2D " + std::string(alphaSampler) + ";\n";
8762 }
8763 shader_src += "void main()\n\
8764{\n";
8765 if (flags & MR_ALPHA_MAP) {
8766 shader_src += " if (texture(" + std::string(alphaSampler) + ", uv_out).r < 0.5f){\n\
8767 discard;\n\
8768 }\n";
8769 }
8770 shader_src += "}";
8771 return shader_src;
8772 }
8773 std::string GLSLShaderGenerator::createCompositeShaderSource(GraphicsSettings const & gs, bool const & god_rays) const
8774 {
8775 std::string shader_src = "#version 330\n\
8776layout(location = 0) out vec3 fragmentColor;\n\
8777uniform sampler2D " + std::string(lightingSampler) + ";\n\
8778uniform sampler2D " + std::string(depthSampler) + ";\n\
8779uniform sampler2D " + std::string(dofSampler) + ";\n\
8780uniform sampler2D " + std::string(godRaySampler) + ";\n\
8781uniform sampler2D " + std::string(bloomSampler) + ";\n\
8782uniform vec4 " + std::string(projectionMatrixInverseThirdRow) + ";\n\
8783uniform vec4 " + std::string(projectionMatrixInverseFourthRow) + ";\n\
8784uniform vec3 " + godRayIntensity + ";\n\
8785uniform float " + std::string(maxMipLevel) + ";\n\
8786uniform vec3 " + std::string(dofNearCenterFar) + ";\n\
8787in vec2 uv;\n\
8788void main()\n\
8789{\n\
8790 fragmentColor = textureLod(" + std::string(lightingSampler) + ", uv, 0.f).rgb;\n";
8791 if (gs.depthOfField()) {
8792 shader_src += " vec4 pos_ndc = vec4(vec3(uv, texture(" + std::string(depthSampler) + ", uv).r) * 2.f - 1.f, 1.f);\n\
8793 float depth_view = dot(" + std::string(projectionMatrixInverseThirdRow) + ", pos_ndc) / dot(" + std::string(projectionMatrixInverseFourthRow) + ", pos_ndc);\n\
8794 vec3 blur_color = texture(" + std::string(dofSampler) + ", uv).rgb;\n\
8795 fragmentColor = (depth_view >= " + std::string(dofNearCenterFar) + ".y) ? \n\
8796 mix(fragmentColor, blur_color, smoothstep(" + std::string(dofNearCenterFar) + ".y, " + std::string(dofNearCenterFar) + ".z, depth_view)) : \n\
8797 mix(blur_color, fragmentColor, smoothstep(" + std::string(dofNearCenterFar) + ".x, " + std::string(dofNearCenterFar) + ".y, depth_view));\n";
8798 }
8799 if (gs.autoExposure()) {
8800 shader_src += " float scene_brightness = dot(textureLod(" + std::string(lightingSampler) + ", vec2(0.5f), " + std::string(maxMipLevel) + ").rgb , vec3(0.2126f, 0.7152f, 0.0722f));\n";
8801 }
8802 if (god_rays) {
8803 shader_src += " fragmentColor += texture(" + std::string(godRaySampler) + ", uv).rgb * " + godRayIntensity + ";\n";
8804 }
8805 if (gs.bloom()) {
8806 shader_src += " fragmentColor += texture(" + std::string(bloomSampler) + ", uv).rgb" + (gs.autoExposure() ? " * (1.f - smoothstep(0.f, " + str(gs.refBrightness()) + ", scene_brightness))" : "") + ";\n";
8807 }
8808 if (gs.exposureEnabled()) {
8809 shader_src += " fragmentColor *= " + str(gs.exposure()) + (gs.autoExposure() ? " * clamp(0.25f / scene_brightness, 0.5f, 3.f)" : "") + ";\n";
8810 }
8811 shader_src += " fragmentColor /= 1.f + fragmentColor;\n";
8812 if (gs.gammaEnabled()) {
8813 shader_src += " fragmentColor = pow(fragmentColor, vec3(" + str(1.f / gs.gamma()) + "));\n";
8814 }
8815 return shader_src + "}\n";
8816 }
8817 std::string GLSLShaderGenerator::blurSource(StackTrivial<float> const & weights) const
8818 {
8819 std::string res = " const float blur_weights[" + str(weights.size()) + "] = float[](";
8820 for (auto* ptr = weights.begin(); ptr != weights.end(); ptr++) {
8821 res += str(*ptr);
8822 res += ptr == weights.end() - 1u ? ");\n" : ",";
8823 }
8824 return res;
8825 }
8826}