· 6 years ago · Dec 18, 2019, 12:00 AM
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 SPHERE_H
2430#define SPHERE_H
2431
2432#include <math/RTMath.h>
2433#include <Algorithm.h>
2434#include <math/MathHelpers.h>
2435#include <limits>
2436#include <Ray.h>
2437
2438namespace RT
2439{
2440 class Mesh;
2441
2442 template<unsigned Dim, typename T>
2443 class Sphere
2444 {
2445 public:
2446 using Vector = Vector<Dim, T>;
2447 Sphere() = default;
2448 Sphere(Sphere const & other) = default;
2449 Sphere(Vector const & center, T const & radius) :
2450 _center(center),
2451 _radius(radius)
2452 {}
2453 Sphere(Mesh const & mesh)
2454 {
2455 auto const & vertices = mesh.vertices();
2456 _center = Algorithm::mean(vertices.begin(), vertices.end(), [](Vertex const & v) {
2457 return v.position();
2458 });
2459 for (auto const * ptr = vertices.begin(); ptr != vertices.end();) {
2460 maximize(squaredDistance((ptr++)->position(), _center), _radius);
2461 }
2462 _radius = std::sqrt(_radius);
2463 }
2464 auto& unify(Sphere const & other)
2465 {
2466 auto d = other._center - _center;
2467 auto squared_dist = d.squaredLength();
2468 if (MathHelpers::pow<2>(other._radius - _radius) >= squared_dist) {
2469 if (other._radius >= _radius) {
2470 *this = other;
2471 }
2472 }
2473 else {
2474 auto dist = std::sqrt(squared_dist);
2475 _radius = (dist + _radius + other._radius) * static_cast<T>(0.5);
2476 if (dist > std::numeric_limits<T>::epsilon()) {
2477 _center += d * ((_radius - other._radius) / dist);
2478 }
2479 }
2480 return *this;
2481 }
2482 auto const & center() const
2483 {
2484 return _center;
2485 }
2486 auto const & radius() const
2487 {
2488 return _radius;
2489 }
2490 auto squaredRadius() const
2491 {
2492 return radius() * radius();
2493 }
2494 auto intersect(Ray<Dim, T> const & ray, T& t_min) const
2495 {
2496 auto o_c = ray.origin() - center();
2497 return MathHelpers::solveQuadratic(o_c.dot(ray.dir()), o_c.squaredLength() - squaredRadius(), t_min);
2498 }
2499 private:
2500 Vector _center = Vector(static_cast<T>(0));
2501 T _radius = static_cast<T>(0);
2502 };
2503
2504 using Sphere2f = Sphere<2, float>;
2505 using Sphere3f = Sphere<3, float>;
2506 using Sphere4f = Sphere<4, float>;
2507
2508 using Sphere2i = Sphere<2, int>;
2509 using Sphere3i = Sphere<3, int>;
2510 using Sphere4i = Sphere<4, int>;
2511
2512 using Sphere2u = Sphere<2, unsigned>;
2513 using Sphere3u = Sphere<3, unsigned>;
2514 using Sphere4u = Sphere<4, unsigned>;
2515}
2516
2517#endif // !SPHERE_H
2518
2519#ifndef STACKTRIVIAL_H
2520#define STACKTRIVIAL_H
2521
2522#include <cstdlib>
2523#include <type_traits>
2524#include <new>
2525#include <cstring>
2526
2527namespace RT
2528{
2529 template<typename T>
2530 class StackTrivial
2531 {
2532 static_assert(std::is_trivially_copyable<T>::value, "T must be trivially_copyable");
2533 static_assert(std::is_trivially_destructible<T>::value, "T must be trivially_destructible");
2534
2535 public:
2536 StackTrivial() = default;
2537 StackTrivial(std::initializer_list<T>&& list)
2538 {
2539 reserve(list.size());
2540 for (auto ptr = list.begin(); ptr != list.end();) {
2541 push_back_unchecked(*ptr++);
2542 }
2543 }
2544 StackTrivial(StackTrivial const & other)
2545 {
2546 append(other);
2547 }
2548 StackTrivial& operator=(StackTrivial const & other)
2549 {
2550 if (this != &other) {
2551 clear();
2552 append(other);
2553 }
2554 return *this;
2555 }
2556 StackTrivial(StackTrivial&& other) :
2557 _begin(other._begin),
2558 _end(other._end),
2559 _capacity(other._capacity)
2560 {
2561 invalidate(std::move(other));
2562 }
2563 StackTrivial& operator=(StackTrivial&& other)
2564 {
2565 if (this != &other) {
2566 deallocate();
2567 _begin = other._begin;
2568 _end = other._end;
2569 _capacity = other._capacity;
2570 invalidate(std::move(other));
2571 }
2572 return *this;
2573 }
2574 ~StackTrivial()
2575 {
2576 deallocate();
2577 }
2578 auto append(StackTrivial const & other)
2579 {
2580 auto const other_size = other.size();
2581 auto const new_size = size() + other_size;
2582 reserve(new_size);
2583 std::memcpy(_end, other._begin, other_size * sizeof(T));
2584 _end += other_size;
2585 }
2586 auto reserveToFit(size_t const & chunk_size)
2587 {
2588 reserve(_capacity + chunk_size);
2589 }
2590 auto reserve(size_t const & new_capacity)
2591 {
2592 if (new_capacity > _capacity) {
2593 allocate(new_capacity);
2594 }
2595 }
2596 auto grow(size_t const & new_size)
2597 {
2598 reserve(new_size);
2599 _end = _begin + new_size;
2600 }
2601 auto clear()
2602 {
2603 _end = _begin;
2604 }
2605 auto push_back_unchecked(T const & element)
2606 {
2607 *_end++ = element;
2608 }
2609 auto push_back_unchecked(T&& element)
2610 {
2611 *_end++ = element;
2612 }
2613 auto& pop_back()
2614 {
2615 return *--_end;
2616 }
2617 auto push_back(T const & element)
2618 {
2619 if (size() == _capacity) {
2620 allocate(_capacity ? _capacity * 2u : 1u);
2621 }
2622 push_back_unchecked(element);
2623 }
2624 auto push_back(T&& element)
2625 {
2626 if (size() == _capacity) {
2627 allocate(_capacity ? _capacity * 2u : 1u);
2628 }
2629 push_back_unchecked(element);
2630 }
2631 auto* data()
2632 {
2633 return _begin;
2634 }
2635 auto* begin()
2636 {
2637 return _begin;
2638 }
2639 auto* end()
2640 {
2641 return _end;
2642 }
2643 const auto* begin() const
2644 {
2645 return _begin;
2646 }
2647 const auto* end() const
2648 {
2649 return _end;
2650 }
2651 auto capacity() const
2652 {
2653 return _capacity;
2654 }
2655 auto size() const
2656 {
2657 return _end - _begin;
2658 }
2659 auto& operator[] (size_t i)
2660 {
2661 return _begin[i];
2662 }
2663 const T& operator[] (size_t i) const
2664 {
2665 return _begin[i];
2666 }
2667 auto& front()
2668 {
2669 return *_begin;
2670 }
2671 const auto& front() const
2672 {
2673 return *_begin;
2674 }
2675 auto& back()
2676 {
2677 return *(_end - 1);
2678 }
2679 const auto& back() const
2680 {
2681 return *(_end - 1);
2682 }
2683 auto* find(T const & element)
2684 {
2685 auto* ptr = _begin;
2686 while (ptr != _end) {
2687 if (*ptr++ == element) {
2688 return --ptr;
2689 }
2690 }
2691 return ptr;
2692 }
2693 private:
2694 T * _begin = nullptr;
2695 T * _end = nullptr;
2696 size_t _capacity = 0;
2697
2698 auto allocate(size_t new_capacity)
2699 {
2700 auto size_prev = size();
2701 if (!(_begin = reinterpret_cast<T*>(std::realloc(_begin, new_capacity * sizeof(T))))) {
2702 throw std::bad_alloc();
2703 }
2704 _capacity = new_capacity;
2705 _end = _begin + size_prev;
2706 }
2707 auto deallocate()
2708 {
2709 if (_begin) {
2710 std::free(_begin);
2711 }
2712 _begin = nullptr;
2713 }
2714 auto invalidate(StackTrivial&& other)
2715 {
2716 other._begin = nullptr;
2717 other._end = nullptr;
2718 other._capacity = 0u;
2719 }
2720 };
2721}
2722#endif
2723#ifndef TRANSFORM_H
2724#define TRANSFORM_H
2725
2726#include <math/RTMath.h>
2727
2728namespace RT
2729{
2730 class Transform
2731 {
2732 public:
2733 Transform(Vec3f const & translation = Vec3f(0.f), Vec3f const & scale = Vec3f(1.f), Vec3f const & degrees = Vec3f(0.f));
2734 Transform(Transform const & other) = default;
2735 Transform& operator=(Transform const & other) = default;
2736 Mat4f matrix() const;
2737 Mat3f inverseMatrix() const;
2738 void setTranslation(Vec3f const & translation);
2739 void setScale(Vec3f const & scale);
2740 void setDegrees(Vec3f const & degrees);
2741 Vec3f const & translation() const;
2742 Vec3f const & scale() const;
2743 Vec3f const & degrees() const;
2744 private:
2745 Vec3f _translation;
2746 Vec3f _scale;
2747 Vec3f _degrees;
2748 };
2749}
2750
2751#endif
2752#ifndef TRIANGLE_H
2753#define TRIANGLE_H
2754
2755#include <Primitive.h>
2756#include <vector>
2757#include <Vertex.h>
2758
2759namespace RT
2760{
2761 class Particle;
2762 class Triangle : public Primitive
2763 {
2764 public:
2765 Triangle() = default;
2766 Triangle(Vec3u const & indices, Vertex* vertices) :
2767 _indices(indices),
2768 _vertices(vertices)
2769 {
2770 }
2771 using Vec3 = Vector<3, Type>;
2772 Triangle& operator=(Triangle const & other) = default;
2773 template<unsigned index>
2774 auto vertex() const
2775 {
2776 static_assert(index <= 2, "Invalid index");
2777 return _vertices[_indices[index]].position();
2778 }
2779 template<unsigned index>
2780 auto normal() const
2781 {
2782 static_assert(index <= 2, "Invalid index");
2783 return _vertices[_indices[index]].normal();
2784 }
2785 auto center() const
2786 {
2787 return interpolatePos(static_cast<Type>(1.0 / 3.0));
2788 }
2789 auto centerNormal() const
2790 {
2791 return interpolateNormal(static_cast<Type>(1.0 / 3.0));
2792 }
2793 Vector<3, Type> interpolatePos(Vector<2, Type> const & uv) const
2794 {
2795 return interpolateBary(uv, vertex<0>(), vertex<1>(), vertex<2>());
2796 }
2797 virtual Vector<3, Type> interpolateNormal(Vector<2, Type> const & uv) const override
2798 {
2799 return interpolateBary(uv, normal<0>(), normal<1>(), normal<2>());
2800 }
2801 virtual Vector<2, Type> barycentric(Vector<3, Type> const & p)
2802 {
2803 return barycentric(vertex<0>(), vertex<1>(), vertex<2>(), p);
2804 }
2805 template<unsigned Dim>
2806 static auto barycentric(Vector<Dim, Type> const & p0, Vector<Dim, Type> const & p1, Vector<Dim, Type> const & p2, Vector<Dim, Type> const & p)
2807 {
2808 auto e0 = p1 - p0;
2809 auto e1 = p2 - p0;
2810 auto one_over_a = static_cast<Type>(1) / triAreaTimesTwo(e0, e1);
2811 return Vector<2, Type>(triAreaTimesTwo(p - p0, e1), triAreaTimesTwo(e0, p - p1)) * one_over_a;
2812 }
2813
2814 std::array<Vec3f, 3u> vertices() const
2815 {
2816 return { vertex<0>(), vertex<1>(), vertex<2>() };
2817 }
2818 virtual BV bv() const override;
2819 virtual Type squaredSize() const override;
2820 Ray::IntersectionResult intersect(Ray const & ray, Vector<3, Type> const & p0, Vector<3, Type> const & p1, Vector<3, Type> const & p2);
2821 virtual Ray::IntersectionResult intersect(Ray const & ray_local, Ray const & ray_world, Matrix const & mat) override;
2822 virtual Ray::IntersectionResult intersect(Ray const & ray) override;
2823 virtual Ray::IntersectionResult intersect(Ray const & ray, Matrix const & matrix) override;
2824 virtual void debugTriangle(Vector<4, Type>* _debugTriangle, Matrix const & transform) const override;
2825 virtual Triangle* toTriangle() override;
2826 private:
2827 Vec3u _indices;
2828 Vertex* _vertices;
2829 };
2830}
2831
2832#endif
2833#ifndef VERTEX_H
2834#define VERTEX_H
2835
2836#include <math/RTMath.h>
2837
2838namespace RT
2839{
2840 struct CompressedNormal
2841 {
2842 int _x : 10;
2843 int _y : 10;
2844 int _z : 10;
2845 int _w : 2;
2846 CompressedNormal() = default;
2847 explicit CompressedNormal(Vec3f const & normal)
2848 {
2849 Vec3i compressed(normal.normalize() * 511.f);
2850 _x = compressed.at<0>();
2851 _y = compressed.at<1>();
2852 _z = compressed.at<2>();
2853 _w = 1;
2854 }
2855 explicit CompressedNormal(Vec3f const & tangent, int const & handedness)
2856 {
2857 Vec3i compressed(tangent.normalize() * 511.f);
2858 _x = compressed.at<0>();
2859 _y = compressed.at<1>();
2860 _z = compressed.at<2>();
2861 _w = handedness;
2862 }
2863 auto uncompress() const
2864 {
2865 return Vec3f(Vec3i(_x, _y, _z)) / 511.f;
2866 }
2867 auto const & w() const
2868 {
2869 return _w;
2870 }
2871 };
2872 class Vertex
2873 {
2874 public:
2875 Vertex() = default;
2876 Vertex(Vec3f const & position) :
2877 _position(position)
2878 {
2879 }
2880 Vertex(Vec3f const & position, CompressedNormal const & normal) :
2881 _position(position),
2882 _normal(normal)
2883 {
2884 }
2885 Vertex(Vec3f const & position, Vec2f const & uv) :
2886 _position(position),
2887 _uv(uv)
2888 {
2889 }
2890 Vertex(Vec3f const & position, CompressedNormal const & normal, Vec2f const & uv) :
2891 _position(position),
2892 _normal(normal),
2893 _uv(uv)
2894 {
2895 }
2896 Vertex(Vec3f const & position, CompressedNormal const & normal, Vec2f const & uv, CompressedNormal const & tangent) :
2897 _position(position),
2898 _normal(normal),
2899 _uv(uv),
2900 _tangent(tangent)
2901 {
2902 }
2903 auto const & position() const
2904 {
2905 return _position;
2906 }
2907 auto normal() const
2908 {
2909 return _normal.uncompress();
2910 }
2911 auto const & uv() const
2912 {
2913 return _uv;
2914 }
2915 auto tangent() const
2916 {
2917 return _tangent.uncompress();
2918 }
2919 auto bitangent() const
2920 {
2921 return cross(normal(), tangent()) * static_cast<float>(_tangent.w());
2922 }
2923 auto setPosition(Vec3f const & position)
2924 {
2925 _position = position;
2926 }
2927 auto setNormal(CompressedNormal const & normal)
2928 {
2929 _normal = normal;
2930 }
2931 auto setNormal(Vec3f const & normal)
2932 {
2933 _normal = CompressedNormal(normal);
2934 }
2935 auto setUV(Vec2f const & uv)
2936 {
2937 _uv = uv;
2938 }
2939 auto setTangent(CompressedNormal const & tangent)
2940 {
2941 _tangent = tangent;
2942 }
2943 auto setTangent(Vec3f const & tangent)
2944 {
2945 _tangent = CompressedNormal(tangent);
2946 }
2947 auto set(Vec3f const & t, int const & handedness, Vec3f const & n)
2948 {
2949 setTangent(CompressedNormal(t, handedness));
2950 setNormal(n);
2951 }
2952 static size_t positionMemOffset()
2953 {
2954 return offsetof(Vertex, _position);
2955 }
2956 static size_t normalMemOffset()
2957 {
2958 return offsetof(Vertex, _normal);
2959 }
2960 static size_t uvMemOffset()
2961 {
2962 return offsetof(Vertex, _uv);
2963 }
2964 static size_t tangentMemOffset()
2965 {
2966 return offsetof(Vertex, _tangent);
2967 }
2968 private:
2969 Vec3f _position;
2970 CompressedNormal _normal = CompressedNormal(0.f);
2971 Vec2f _uv;
2972 CompressedNormal _tangent = CompressedNormal(0.f);
2973 };
2974
2975 class VertexUncompressed
2976 {
2977 public:
2978 auto interpolate(Vec3f const & v, Vec3f& res)
2979 {
2980 res = normalize(v + res);
2981 }
2982 auto addTangent(Vec3f const & t)
2983 {
2984 interpolate(t, _t);
2985 }
2986 auto addBitangent(Vec3f const & b)
2987 {
2988 interpolate(b, _b);
2989 }
2990 auto addNormal(Vec3f const & n)
2991 {
2992 interpolate(n, _n);
2993 }
2994 auto add(Vec3f const & t, Vec3f const & b, Vec3f const & n)
2995 {
2996 addTangent(t);
2997 addBitangent(b);
2998 addNormal(n);
2999 }
3000 auto const & tangent() const
3001 {
3002 return _t;
3003 }
3004 auto const & bitangent() const
3005 {
3006 return _b;
3007 }
3008 auto const & normal() const
3009 {
3010 return _n;
3011 }
3012 auto const & t() const
3013 {
3014 return tangent();
3015 }
3016 auto const & b() const
3017 {
3018 return bitangent();
3019 }
3020 auto const & n() const
3021 {
3022 return normal();
3023 }
3024 private:
3025 Vec3f _t = 0.f;
3026 Vec3f _b = 0.f;
3027 Vec3f _n = 0.f;
3028 };
3029}
3030
3031#endif
3032#ifndef MATHHELPERS_H
3033#define MATHHELPERS_H
3034
3035#include <math/RTMath.h>
3036#define GLM_ENABLE_EXPERIMENTAL
3037#include <glm/gtc/matrix_transform.hpp>
3038#include <array>
3039
3040namespace RT
3041{
3042 template<unsigned Dim, typename T>
3043 class AABB;
3044 class MathHelpers
3045 {
3046 public:
3047 template<typename T>
3048 static auto projectionMatrixPerspective(T const & fov_degrees, T const & aspect_ratio, T const & z_near, T const & z_far)
3049 {
3050 auto const t = tan(radians(fov_degrees) * static_cast<T>(0.5));
3051 auto const sx = static_cast<T>(1) / (aspect_ratio * t);
3052 auto const sy = static_cast<T>(1) / t;
3053 auto const sz = static_cast<T>(1) / (z_far - z_near);
3054 return Matrix<4, 4, T>({ sx, static_cast<T>(0), static_cast<T>(0), static_cast<T>(0),
3055 static_cast<T>(0), sy, static_cast<T>(0), static_cast<T>(0),
3056 static_cast<T>(0), static_cast<T>(0), (z_far + z_near) * sz, static_cast<T>(1),
3057 static_cast<T>(0), static_cast<T>(0), -(static_cast<T>(2) * z_far * z_near) * sz, static_cast<T>(0) });
3058 }
3059 template<unsigned Dim, typename T>
3060 static auto projectionMatrixOrtho(AABB<Dim, T> const & aabb)
3061 {
3062 return scale(static_cast<T>(1) / aabb.halfExtent()) * translate(-aabb.center());
3063 }
3064 template<typename T>
3065 static auto changeOfBasis(Vector<3, T> const & o, Vector<3, T> const & i, Vector<3, T> const & j, Vector<3, T> const & k)
3066 {
3067 return changeOfBasis(i, j, k) * translate(-o);
3068 }
3069 template<typename T>
3070 static auto changeOfBasis(Vector<3, T> const & i, Vector<3, T> const & j, Vector<3, T> const & k)
3071 {
3072 return Matrix<4, 4, T>({ i.appendZero(), j.appendZero(), k.appendZero(), Vector<4, T>::standardBasis<3>() }).transpose();
3073 }
3074 template<typename T>
3075 static auto changeOfBasisInverse(Vector<3, T> const & o, Vector<3, T> const & i, Vector<3, T> const & j, Vector<3, T> const & k)
3076 {
3077 return Matrix<4, 4, T>({ i.appendZero(), j.appendZero(), k.appendZero(), o.toHomogeneous() });
3078 }
3079 template<typename T>
3080 static auto changeOfBasisInverse(Vector<3, T> const & i, Vector<3, T> const & j, Vector<3, T> const & k)
3081 {
3082 return Matrix<3, 3, T>({ i, j, k });
3083 }
3084 template<typename T>
3085 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)))
3086 {
3087 return fract(std::sin(dot(p, seed.xy())) * seed.z());
3088 }
3089 template<typename T>
3090 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)))
3091 {
3092 auto start = floor(p);
3093 auto end = start + static_cast<T>(1);
3094 auto weights = smoothstep(start, end, p);
3095 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());
3096 }
3097 template<typename T>
3098 static auto hash(T const & p)
3099 {
3100 return fract(std::sin(p) * static_cast<T>(14721.28));
3101 }
3102 template<typename T>
3103 static auto valueNoise(T const & p)
3104 {
3105 auto start = std::floor(p);
3106 auto end = start + static_cast<T>(1);
3107 return lerp(hash(start), hash(end), smoothstep(start, end, p));
3108 }
3109 template<typename T>
3110 static auto fract(T const & val)
3111 {
3112 return val - std::floor(val);
3113 }
3114 template<typename T>
3115 static auto elementsPerThread(T const & num_elements, T const & num_threads)
3116 {
3117 return static_cast<T>(std::ceil(static_cast<float>(num_elements) / static_cast<float>(num_threads)));
3118 }
3119 template <typename T, unsigned index>
3120 struct ComputePow
3121 {
3122 static auto call(const T& base)
3123 {
3124 return base * ComputePow<T, index - 1>::call(base);
3125 }
3126 };
3127 template <typename T>
3128 struct ComputePow<T, 0>
3129 {
3130 static auto call(const T& base)
3131 {
3132 return base;
3133 }
3134 };
3135 template <unsigned exponent, typename T>
3136 static auto pow(T const & base)
3137 {
3138 return exponent ? ComputePow<T, exponent - 1>::call(base) : static_cast<T>(1);
3139 }
3140 template<unsigned Dim, typename T>
3141 static auto transformVector(Matrix<Dim + 1, Dim + 1, T> const & mat, Vector<Dim, T> const & vec)
3142 {
3143 return transform<Dim, T, 0>(mat, vec);
3144 }
3145 template<unsigned Dim, typename T>
3146 static auto transformPoint(Matrix<Dim + 1, Dim + 1, T> const & mat, Vector<Dim, T> const & point)
3147 {
3148 return transform<Dim, T, 1>(mat, point);
3149 }
3150 template<unsigned Dim, typename T, unsigned Hom>
3151 static auto transform(Matrix<Dim + 1, Dim + 1, T> const & mat, Vector<Dim, T> const & v)
3152 {
3153 return (mat * Vector<Dim + 1, T>(v, static_cast<T>(Hom))).reduce<>();
3154 }
3155 template<unsigned Dim, typename T>
3156 static auto transformReduce(Matrix<Dim + 1, Dim + 1, T> const & mat, Vector<Dim, T> const & v)
3157 {
3158 return Matrix<Dim, Dim, T>(mat) * v;
3159 }
3160 template<typename T>
3161 static auto solveQuadratic(T const & p_half, T const & q, T& t_min)
3162 {
3163 T d;
3164 if ((d = (p_half * p_half) - q) >= static_cast<T>(0)) {
3165 t_min = -p_half - std::sqrt(d);
3166 return true;
3167 }
3168 return false;
3169 }
3170 };
3171}
3172
3173#endif
3174#ifndef MATVECHELPERS_H
3175#define MATVECHELPERS_H
3176
3177#include <math/RTVector.h>
3178#include <math/RTMatrix.h>
3179#include <math/Meta.h>
3180#include <algorithm>
3181#include <Constants.h>
3182
3183namespace RT
3184{
3185 template<typename T>
3186 static auto dot(T const & a, T const & b)
3187 {
3188 return b.dot(a);
3189 }
3190 template<typename T>
3191 static auto cross(Vector<3, T> const & a, Vector<3, T> const & b)
3192 {
3193 return Vector<3, T>(a.y() * b.z() - a.z() * b.y(),
3194 a.z() * b.x() - a.x() * b.z(),
3195 a.x() * b.y() - a.y() * b.x());
3196 }
3197 template<typename T>
3198 static auto cross(Vector<2, T> const & a, Vector<2, T> const & b)
3199 {
3200 return a.x() * b.y() - b.x() * a.y();
3201 }
3202 template<typename T>
3203 static auto triAreaTimesTwo(Vector<3, T> const & e0, Vector<3, T> const & e1)
3204 {
3205 return cross(e0, e1).length();
3206 }
3207 template<typename T>
3208 static auto triAreaTimesTwo(Vector<2, T> const & e0, Vector<2, T> const & e1)
3209 {
3210 return cross(e0, e1);
3211 }
3212 template<typename T, typename Type>
3213 auto toScreen(Vector<3, T> const & vec, Matrix<4, 4, T> const & vp, Vector<2, Type> const & win_size)
3214 {
3215 return (vp * vec).homogeneousDivide().NDCToUV().UVToScreen(win_size);
3216 }
3217 template<typename S, typename T>
3218 auto interpolateBary(Vector<2, S> const & uv, T const & p0, T const & p1, T const & p2)
3219 {
3220 return (static_cast<S>(1) - uv.at<0>() - uv.at<1>()) * p0 + uv.at<0>() * p1 + uv.at<1>() * p2;
3221 }
3222 template<typename T>
3223 static auto reflect(T const & d, T const & n)
3224 {
3225 return d.reflect(n);
3226 }
3227 template<typename T>
3228 static auto radians(T const & degrees)
3229 {
3230 return degrees * Constants::piOverOneHundredEighty<T>();
3231 }
3232 template<typename T>
3233 static auto degrees(T const & radians)
3234 {
3235 return radians * Constants::oneHundredEightyOverPi<T>();
3236 }
3237 template<typename T>
3238 static auto& minimize(T const & other, T& out)
3239 {
3240 out = std::min(out, other);
3241 return out;
3242 }
3243 template<typename T>
3244 static auto& maximize(T const & other, T& out)
3245 {
3246 out = std::max(out, other);
3247 return out;
3248 }
3249 template<typename T>
3250 static auto minimum(T const & a, T const & b)
3251 {
3252 return a.minimum(b);
3253 }
3254 template<typename T>
3255 static auto maximum(T const & a, T const & b)
3256 {
3257 return a.maximum(b);
3258 }
3259 template<typename T>
3260 static auto round(T const & a)
3261 {
3262 return a.round();
3263 }
3264 template<typename T>
3265 static auto floor(T const & a)
3266 {
3267 return a.floor();
3268 }
3269 template<typename T>
3270 static auto ceil(T const & a)
3271 {
3272 return a.ceil();
3273 }
3274 template<typename T>
3275 static auto abs(T const & a)
3276 {
3277 return a.abs();
3278 }
3279 template<typename T>
3280 static auto minReduce(T const & a)
3281 {
3282 return a.minReduce();
3283 }
3284 template<typename T>
3285 static auto maxReduce(T const & a)
3286 {
3287 return a.maxReduce();
3288 }
3289 template<unsigned Dim, typename T>
3290 static auto clamp(Vector<Dim, T> const & a, Vector<Dim, T> const & min, Vector<Dim, T> const & max)
3291 {
3292 return minimum(max, maximum(min, a));
3293 }
3294 template<typename T>
3295 static auto clamp(T const & a, T const & min, T const & max)
3296 {
3297 return std::min(max, std::max(min, a));
3298 }
3299 template<typename T>
3300 static auto distance(T const & a, T const & b)
3301 {
3302 return (a - b).length();
3303 }
3304 template<typename T>
3305 static auto squaredDistance(T const & a, T const & b)
3306 {
3307 return (a - b).squaredLength();
3308 }
3309 template<typename T>
3310 static auto normalize(T const & a)
3311 {
3312 return a / a.length();
3313 }
3314 template<typename T, typename Pred1 = std::plus<T>, typename Pred2 = std::minus<T>, typename Pred3 = std::multiplies<T>>
3315 static auto genLerp(T const & a, T const & b, T const & alpha)
3316 {
3317 return Pred1()(a, Pred3()(Pred2()(b, a), alpha));
3318 }
3319 template<typename T>
3320 static auto lerp(T const & a, T const & b, T const & alpha)
3321 {
3322 return genLerp(a, b, alpha);
3323 }
3324 template<typename T>
3325 static auto lerpLogScale(T const & a, T const & b, T const & alpha)
3326 {
3327 return genLerp<T, std::multiplies<T>, std::divides<T>, Pow<T>>(a, b, alpha);
3328 }
3329 template<typename T>
3330 static auto smoothstep(T const & edge0, T const & edge1, T const & x)
3331 {
3332 auto t = clamp((x - edge0) / (edge1 - edge0), T(0), T(1));
3333 return t * t * (static_cast<T>(3) - static_cast<T>(2) * t);
3334 }
3335 template<unsigned Dim, typename T>
3336 static auto identity()
3337 {
3338 return Matrix<Dim, Dim, T>::identity();
3339 }
3340 template<unsigned Rows, unsigned Cols, typename T>
3341 static auto transpose(Matrix<Rows, Cols, T> const & m)
3342 {
3343 return m.transpose();
3344 }
3345 template<unsigned Dim, typename T>
3346 static auto translate(Vector<Dim, T> const & t)
3347 {
3348 return Matrix<Dim + 1, Dim + 1, T>::translate(t);
3349 }
3350 template<unsigned Dim, typename T>
3351 static auto scale(Vector<Dim, T> const & s)
3352 {
3353 return Matrix<Dim + 1, Dim + 1, T>::scale(s);
3354 }
3355 template<typename T>
3356 static auto determinant(Matrix<2, 2, T> const & a)
3357 {
3358 return subDet<0, 0, 1, 1, 1, 0, 0, 1>(a);
3359 }
3360 template<typename T>
3361 static auto determinant(Matrix<3, 3, T> const a)
3362 {
3363 return determinantUpper3x3(a);
3364 }
3365 template<unsigned Dim, typename T>
3366 static auto determinantUpper3x3(Matrix<Dim, Dim, T> const & a)
3367 {
3368 return determinantUpper3x3(a, subDet0_3x3(a), subDet1_3x3(a), subDet2_3x3(a));
3369 }
3370 template<unsigned Dim, typename T>
3371 static auto determinantUpper3x3(Matrix<Dim, Dim, T> const & a, T const & s0, T const & s1, T const & s2)
3372 {
3373 return
3374 a.at<0, 0>() * s0 -
3375 a.at<1, 0>() * s1 +
3376 a.at<2, 0>() * s2;
3377 }
3378 template<typename T>
3379 static auto determinant(Matrix<4, 4, T> const & a)
3380 {
3381 return determinant(a, subDet0(a), subDet1(a), subDet2(a), subDet3(a), subDet4(a), subDet5(a));
3382 }
3383 template<typename T>
3384 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)
3385 {
3386 return
3387 a.at<0, 0>() * (a.at<1, 1>() * s0 - a.at<2, 1>() * s1 + a.at<3, 1>() * s2) -
3388 a.at<1, 0>() * (a.at<0, 1>() * s0 - a.at<2, 1>() * s3 + a.at<3, 1>() * s5) +
3389 a.at<2, 0>() * (a.at<0, 1>() * s1 - a.at<1, 1>() * s3 + a.at<3, 1>() * s4) -
3390 a.at<3, 0>() * (a.at<0, 1>() * s2 - a.at<1, 1>() * s5 + a.at<2, 1>() * s4);
3391 }
3392 template<typename T>
3393 static auto validDeterminant(T const & det)
3394 {
3395 return det <= -std::numeric_limits<T>::epsilon() || det >= std::numeric_limits<T>::epsilon();
3396 }
3397 template<unsigned Dim, typename T>
3398 static auto validDeterminant(Matrix<Dim, Dim, T> const & m)
3399 {
3400 return validDeterminant(determinant(m));
3401 }
3402 template<unsigned i0, unsigned i1, unsigned i2, unsigned i3, unsigned i4, unsigned i5, unsigned i6, unsigned i7, unsigned Dim, typename T>
3403 static auto subDet(Matrix<Dim, Dim, T> const & a)
3404 {
3405 return a.at<i0, i1>() * a.at<i2, i3>() - a.at<i4, i5>() * a.at<i6, i7>();
3406 }
3407 template<unsigned Dim, typename T>
3408 static auto subDet0_3x3(Matrix<Dim, Dim, T> const & a)
3409 {
3410 return subDet<1, 1, 2, 2, 2, 1, 1, 2>(a);
3411 }
3412 template<unsigned Dim, typename T>
3413 static auto subDet1_3x3(Matrix<Dim, Dim, T> const & a)
3414 {
3415 return subDet<2, 1, 0, 2, 0, 1, 2, 2>(a);
3416 }
3417 template<unsigned Dim, typename T>
3418 static auto subDet2_3x3(Matrix<Dim, Dim, T> const & a)
3419 {
3420 return subDet<0, 1, 1, 2, 1, 1, 0, 2>(a);
3421 }
3422 template<typename T>
3423 static auto subDet0(Matrix<4, 4, T> const & a)
3424 {
3425 return subDet<2, 2, 3, 3, 3, 2, 2, 3>(a);
3426 }
3427 template<typename T>
3428 static auto subDet1(Matrix<4, 4, T> const & a)
3429 {
3430 return subDet<1, 2, 3, 3, 3, 2, 1, 3>(a);
3431 }
3432 template<typename T>
3433 static auto subDet2(Matrix<4, 4, T> const & a)
3434 {
3435 return subDet<1, 2, 2, 3, 2, 2, 1, 3>(a);
3436 }
3437 template<typename T>
3438 static auto subDet3(Matrix<4, 4, T> const & a)
3439 {
3440 return subDet<0, 2, 3, 3, 3, 2, 0, 3>(a);
3441 }
3442 template<typename T>
3443 static auto subDet4(Matrix<4, 4, T> const & a)
3444 {
3445 return subDet<0, 2, 1, 3, 1, 2, 0, 3>(a);
3446 }
3447 template<typename T>
3448 static auto subDet5(Matrix<4, 4, T> const & a)
3449 {
3450 return subDet<0, 2, 2, 3, 2, 2, 0, 3>(a);
3451 }
3452 template<typename T>
3453 static auto subDet6(Matrix<4, 4, T> const & a)
3454 {
3455 return subDet<2, 1, 3, 3, 3, 1, 2, 3>(a);
3456 }
3457 template<typename T>
3458 static auto subDet7(Matrix<4, 4, T> const & a)
3459 {
3460 return subDet<1, 1, 3, 3, 3, 1, 1, 3>(a);
3461 }
3462 template<typename T>
3463 static auto subDet8(Matrix<4, 4, T> const & a)
3464 {
3465 return subDet<1, 1, 2, 3, 2, 1, 1, 3>(a);
3466 }
3467 template<typename T>
3468 static auto subDet9(Matrix<4, 4, T> const & a)
3469 {
3470 return subDet<0, 1, 1, 3, 1, 1, 0, 3>(a);
3471 }
3472 template<typename T>
3473 static auto subDet10(Matrix<4, 4, T> const & a)
3474 {
3475 return subDet<2, 1, 3, 2, 3, 1, 2, 2>(a);
3476 }
3477 template<typename T>
3478 static auto subDet11(Matrix<4, 4, T> const & a)
3479 {
3480 return subDet<1, 1, 3, 2, 3, 1, 1, 2>(a);
3481 }
3482 template<typename T>
3483 static auto subDet12(Matrix<4, 4, T> const & a)
3484 {
3485 return subDet<1, 1, 2, 2, 2, 1, 1, 2>(a);
3486 }
3487 template<typename T>
3488 static auto subDet13(Matrix<4, 4, T> const & a)
3489 {
3490 return subDet<0, 1, 3, 2, 3, 1, 0, 2>(a);
3491 }
3492 template<typename T>
3493 static auto subDet14(Matrix<4, 4, T> const & a)
3494 {
3495 return subDet<0, 1, 2, 2, 2, 1, 0, 2>(a);
3496 }
3497 template<typename T>
3498 static auto subDet15(Matrix<4, 4, T> const & a)
3499 {
3500 return subDet<0, 1, 1, 2, 1, 1, 0, 2>(a);
3501 }
3502 template<typename T>
3503 static auto subDet16(Matrix<4, 4, T> const & a)
3504 {
3505 return subDet<0, 1, 3, 3, 3, 1, 0, 3>(a);
3506 }
3507 template<typename T>
3508 static auto subDet17(Matrix<4, 4, T> const & a)
3509 {
3510 return subDet<0, 1, 2, 3, 2, 1, 0, 3>(a);
3511 }
3512 template<typename T>
3513 static auto adjugate(Matrix<3, 3, T> const & a, T const & s0, T const & s1, T const & s2)
3514 {
3515 return Matrix<3, 3, T>({ s0,
3516 s1,
3517 s2,
3518 subDet<2, 0, 1, 2, 1, 0, 2, 2>(a),
3519 subDet<0, 0, 2, 2, 2, 0, 0, 2>(a),
3520 subDet<1, 0, 0, 2, 0, 0, 1, 2>(a),
3521 subDet<1, 0, 2, 1, 2, 0, 1, 1>(a),
3522 subDet<2, 0, 0, 1, 0, 0, 2, 1>(a),
3523 subDet<0, 0, 1, 1, 1, 0, 0, 1>(a) });
3524 }
3525 template<typename T>
3526 static auto adjugate(Matrix<3, 3, T> const & a)
3527 {
3528 return adjugate(a, subDet0_3x3(a), subDet1_3x3(a), subDet2_3x3(a));
3529 }
3530 template<typename T>
3531 static auto adjugate(Matrix<4, 4, T> const & a)
3532 {
3533 return adjugate(a, subDet0(a), subDet1(a), subDet2(a), subDet3(a), subDet4(a), subDet5(a),
3534 subDet6(a), subDet7(a), subDet8(a), subDet9(a), subDet10(a), subDet11(a), subDet12(a),
3535 subDet13(a), subDet14(a), subDet15(a), subDet16(a), subDet17(a));
3536 }
3537 template<typename T>
3538 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,
3539 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)
3540 {
3541 return Matrix<4, 4, T>({
3542 a.at<1, 1>() * s0 - a.at<2, 1>() * s1 + a.at<3, 1>() * s2,
3543 -a.at<0, 1>() * s0 + a.at<2, 1>() * s3 - a.at<3, 1>() * s5,
3544 a.at<0, 1>() * s1 - a.at<1, 1>() * s3 + a.at<3, 1>() * s4,
3545 -a.at<0, 1>() * s2 + a.at<1, 1>() * s5 - a.at<2, 1>() * s4,
3546 -a.at<1, 0>() * s0 + a.at<2, 0>() * s1 - a.at<3, 0>() * s2,
3547 a.at<0, 0>() * s0 - a.at<2, 0>() * s3 + a.at<3, 0>() * s5,
3548 -a.at<0, 0>() * s1 + a.at<1, 0>() * s3 - a.at<3, 0>() * s4,
3549 a.at<0, 0>() * s2 - a.at<1, 0>() * s5 + a.at<2, 0>() * s4,
3550 a.at<1, 0>() * s6 - a.at<2, 0>() * s7 + a.at<3, 0>() * s8,
3551 -a.at<0, 0>() * s6 + a.at<2, 0>() * s16 - a.at<3, 0>() * s17,
3552 a.at<0, 0>() * s7 - a.at<1, 0>() * s16 + a.at<3, 0>() * s9,
3553 -a.at<0, 0>() * s8 + a.at<1, 0>() * s17 - a.at<2, 0>() * s9,
3554 -a.at<1, 0>() * s10 + a.at<2, 0>() * s11 - a.at<3, 0>() * s12,
3555 a.at<0, 0>() * s10 - a.at<2, 0>() * s13 + a.at<3, 0>() * s14,
3556 -a.at<0, 0>() * s11 + a.at<1, 0>() * s13 - a.at<3, 0>() * s15,
3557 a.at<0, 0>() * s12 - a.at<1, 0>() * s14 + a.at<2, 0 >() * s15 });
3558 }
3559 template<typename T>
3560 static auto adjugate(Matrix<2, 2, T> const & a)
3561 {
3562 return Matrix<2, 2, T>({
3563 a.at<1, 1>(), -a.at<0, 1>(),
3564 -a.at<1, 0>(), a.at<0, 0>() });
3565 }
3566 template<typename T>
3567 static auto inverse(Matrix<3, 3, T> const & a)
3568 {
3569 return inverseUpper3x3(a);
3570 }
3571 template<unsigned Dim, typename T>
3572 static auto inverseUpper3x3(Matrix<Dim, Dim, T> const & a)
3573 {
3574 auto s0 = subDet0_3x3(a);
3575 auto s1 = subDet1_3x3(a);
3576 auto s2 = subDet2_3x3(a);
3577 auto one_over_det = static_cast<T>(1) / determinantUpper3x3(a, s0, s1, s2);
3578 return Matrix<3, 3, T>({
3579 s0 * one_over_det,
3580 s1 * one_over_det,
3581 s2 * one_over_det,
3582 subDet<2, 0, 1, 2, 1, 0, 2, 2>(a) * one_over_det,
3583 subDet<0, 0, 2, 2, 2, 0, 0, 2>(a) * one_over_det,
3584 subDet<1, 0, 0, 2, 0, 0, 1, 2>(a) * one_over_det,
3585 subDet<1, 0, 2, 1, 2, 0, 1, 1>(a) * one_over_det,
3586 subDet<2, 0, 0, 1, 0, 0, 2, 1>(a) * one_over_det,
3587 subDet<0, 0, 1, 1, 1, 0, 0, 1>(a) * one_over_det });
3588 }
3589 template<typename T>
3590 static auto inverse(Matrix<4, 4, T> const & a)
3591 {
3592 auto s0 = subDet0(a);
3593 auto s1 = subDet1(a);
3594 auto s2 = subDet2(a);
3595 auto s3 = subDet3(a);
3596 auto s4 = subDet4(a);
3597 auto s5 = subDet5(a);
3598 auto one_over_det = static_cast<T>(1) / determinant(a, s0, s1, s2, s3, s4, s5);
3599 auto s6 = subDet6(a);
3600 auto s7 = subDet7(a);
3601 auto s8 = subDet8(a);
3602 auto s9 = subDet9(a);
3603 auto s10 = subDet10(a);
3604 auto s11 = subDet11(a);
3605 auto s12 = subDet12(a);
3606 auto s13 = subDet13(a);
3607 auto s14 = subDet14(a);
3608 auto s15 = subDet15(a);
3609 auto s16 = subDet16(a);
3610 auto s17 = subDet17(a);
3611 return Matrix<4, 4, T>({
3612 ( a.at<1, 1>() * s0 - a.at<2, 1>() * s1 + a.at<3, 1>() * s2) * one_over_det,
3613 (-a.at<0, 1>() * s0 + a.at<2, 1>() * s3 - a.at<3, 1>() * s5) * one_over_det,
3614 ( a.at<0, 1>() * s1 - a.at<1, 1>() * s3 + a.at<3, 1>() * s4) * one_over_det,
3615 (-a.at<0, 1>() * s2 + a.at<1, 1>() * s5 - a.at<2, 1>() * s4) * one_over_det,
3616 (-a.at<1, 0>() * s0 + a.at<2, 0>() * s1 - a.at<3, 0>() * s2) * one_over_det,
3617 ( a.at<0, 0>() * s0 - a.at<2, 0>() * s3 + a.at<3, 0>() * s5) * one_over_det,
3618 (-a.at<0, 0>() * s1 + a.at<1, 0>() * s3 - a.at<3, 0>() * s4) * one_over_det,
3619 ( a.at<0, 0>() * s2 - a.at<1, 0>() * s5 + a.at<2, 0>() * s4) * one_over_det,
3620 ( a.at<1, 0>() * s6 - a.at<2, 0>() * s7 + a.at<3, 0>() * s8) * one_over_det,
3621 (-a.at<0, 0>() * s6 + a.at<2, 0>() * s16 - a.at<3, 0>() * s17) * one_over_det,
3622 ( a.at<0, 0>() * s7 - a.at<1, 0>() * s16 + a.at<3, 0>() * s9) * one_over_det,
3623 (-a.at<0, 0>() * s8 + a.at<1, 0>() * s17 - a.at<2, 0>() * s9) * one_over_det,
3624 (-a.at<1, 0>() * s10 + a.at<2, 0>() * s11 - a.at<3, 0>() * s12) * one_over_det,
3625 ( a.at<0, 0>() * s10 - a.at<2, 0>() * s13 + a.at<3, 0>() * s14) * one_over_det,
3626 (-a.at<0, 0>() * s11 + a.at<1, 0>() * s13 - a.at<3, 0>() * s15) * one_over_det,
3627 ( a.at<0, 0>() * s12 - a.at<1, 0>() * s14 + a.at<2, 0 >() * s15) * one_over_det });
3628 }
3629 template<unsigned Dim, typename T>
3630 static auto inverse(Matrix<Dim, Dim, T> const & m, T const & det)
3631 {
3632 return adjugate(m) * (static_cast<T>(1) / det);
3633 }
3634 template<unsigned Dim, typename T>
3635 static auto inverse(Matrix<Dim, Dim, T> const & m)
3636 {
3637 return inverse(m, determinant(m));
3638 }
3639 template<typename T>
3640 static auto rotation3Dx(T const & rad)
3641 {
3642 return Matrix<3, 3, T>({
3643 static_cast<T>(1), static_cast<T>(0), static_cast<T>(0),
3644 static_cast<T>(0), cos(rad), sin(rad),
3645 static_cast<T>(0), -sin(rad), cos(rad) });
3646 }
3647 template<typename T>
3648 static auto rotation3Dy(T const & rad)
3649 {
3650 return Matrix<3, 3, T>({
3651 cos(rad), static_cast<T>(0), -sin(rad),
3652 static_cast<T>(0), static_cast<T>(1), static_cast<T>(0),
3653 sin(rad), static_cast<T>(0), cos(rad) });
3654 }
3655 template<typename T>
3656 static auto rotation3Dz(T const & rad)
3657 {
3658 return Matrix<3, 3, T>({
3659 cos(rad), sin(rad), static_cast<T>(0),
3660 -sin(rad), cos(rad), static_cast<T>(0),
3661 static_cast<T>(0), static_cast<T>(0), static_cast<T>(1) });
3662 }
3663 template<typename T>
3664 static auto rotation3DxHom(T const & rad)
3665 {
3666 return Matrix<4, 4, T>({
3667 static_cast<T>(1), static_cast<T>(0), static_cast<T>(0), static_cast<T>(0),
3668 static_cast<T>(0), cos(rad), sin(rad), static_cast<T>(0),
3669 static_cast<T>(0), -sin(rad), cos(rad), static_cast<T>(0),
3670 static_cast<T>(0), static_cast<T>(0), static_cast<T>(0), static_cast<T>(1) });
3671 }
3672 template<typename T>
3673 static auto rotation3DyHom(T const & rad)
3674 {
3675 return Matrix<4, 4, T>({
3676 cos(rad), static_cast<T>(0), -sin(rad), static_cast<T>(0),
3677 static_cast<T>(0), static_cast<T>(1), static_cast<T>(0), static_cast<T>(0),
3678 sin(rad), static_cast<T>(0), cos(rad), static_cast<T>(0),
3679 static_cast<T>(0), static_cast<T>(0), static_cast<T>(0), static_cast<T>(1) });
3680 }
3681 template<typename T>
3682 static auto rotation3DzHom(T const & rad)
3683 {
3684 return Matrix<4, 4, T>({
3685 cos(rad), sin(rad), static_cast<T>(0), static_cast<T>(0),
3686 -sin(rad), cos(rad), static_cast<T>(0), static_cast<T>(0),
3687 static_cast<T>(0), static_cast<T>(0), static_cast<T>(1), static_cast<T>(0),
3688 static_cast<T>(0), static_cast<T>(0), static_cast<T>(0), static_cast<T>(1) });
3689 }
3690}
3691
3692#endif
3693#ifndef META_H
3694#define META_H
3695
3696#include <math/RTVector.h>
3697#include <math/RTMatrix.h>
3698
3699namespace RT
3700{
3701 template<typename T> struct Min : std::binary_function<T, T, T>
3702 {
3703 T operator() (T const & a, T const & b)
3704 {
3705 return std::min(a, b);
3706 }
3707 };
3708 template<typename T> struct Max : std::binary_function<T, T, T>
3709 {
3710 T operator() (T const & a, T const & b)
3711 {
3712 return std::max(a, b);
3713 }
3714 };
3715 template<typename T> struct Round : std::unary_function<T, T>
3716 {
3717 T operator() (T const & a)
3718 {
3719 return std::round(a);
3720 }
3721 };
3722 template<typename T> struct Floor : std::unary_function<T, T>
3723 {
3724 T operator() (T const & a)
3725 {
3726 return std::floor(a);
3727 }
3728 };
3729 template<typename T> struct Ceil : std::unary_function<T, T>
3730 {
3731 T operator() (T const & a)
3732 {
3733 return std::ceil(a);
3734 }
3735 };
3736 template<typename T> struct Abs : std::unary_function<T, T>
3737 {
3738 T operator() (T const & a)
3739 {
3740 return std::abs(a);
3741 }
3742 };
3743 template<typename T> struct Pow : std::binary_function<T, T, T>
3744 {
3745 T operator()(T const & base, T const & exponent)
3746 {
3747 return std::pow(base, exponent);
3748 }
3749 };
3750}
3751
3752#endif
3753#ifndef RTMATH_H
3754#define RTMATH_H
3755
3756#include <math/MatVecHelpers.h>
3757#include <math/RTMatrix.h>
3758
3759#endif
3760#ifndef RTMATRIX_H
3761#define RTMATRIX_H
3762
3763#include <glm/glm.hpp>
3764#include <iostream>
3765
3766namespace RT
3767{
3768 template<unsigned Rows, unsigned Cols, typename T>
3769 class Matrix
3770 {
3771 public:
3772 static unsigned const constexpr cols() { return Cols; }
3773 static unsigned const constexpr rows() { return Rows; }
3774 static unsigned const constexpr maxCol() { return cols() - 1u; }
3775 static unsigned const constexpr maxRow() { return rows() - 1u; }
3776 static unsigned const constexpr elements() { return cols() * rows(); }
3777 static unsigned const constexpr maxIdx() { return elements() - 1u; }
3778 Matrix() = default;
3779 Matrix(Matrix const & other) = default;
3780 Matrix& operator=(Matrix const & other) = default;
3781 Matrix(const Vector<Rows, T>(&cols)[cols()])
3782 {
3783 construct(cols);
3784 }
3785 Matrix(const T(&vals)[elements()])
3786 {
3787 construct(vals);
3788 }
3789 Matrix(T const * const ptr)
3790 {
3791 Algorithm::Copy<T, maxIdx()>::call(ptr, _cols);
3792 }
3793 static auto scale(Vector<Cols - 1u, T> const & s)
3794 {
3795 Matrix res;
3796 res.computeScale(s.toHomogeneous());
3797 return res;
3798 }
3799 static auto translate(Vector<Cols - 1u, T> const & t)
3800 {
3801 Matrix res;
3802 res.computeIdentity<maxIdx() - rows()>();
3803 res.col<maxCol()>() = t.toHomogeneous();
3804 return res;
3805 }
3806 static auto identity()
3807 {
3808 Matrix res;
3809 res.computeIdentity();
3810 return res;
3811 }
3812 auto transpose() const
3813 {
3814 Matrix<Cols, Rows, T> res;
3815 res.computeTranspose(*this);
3816 return res;
3817 }
3818 template<unsigned i>
3819 auto fillTranspose(Matrix<Cols, Rows, T> const & other)
3820 {
3821 at<i>() = other.at<rowIdx<i>(), colIdx<i>()>();
3822 }
3823 template<unsigned i = maxIdx()>
3824 auto computeTranspose(Matrix<Cols, Rows, T> const & other)
3825 {
3826 fillTranspose<i>(other);
3827 computeTranspose<i - 1>(other);
3828 }
3829 template<>
3830 auto computeTranspose<0>(Matrix<Cols, Rows, T> const & other)
3831 {
3832 fillTranspose<0>(other);
3833 }
3834 template<unsigned OtherRows, unsigned OtherCols>
3835 Matrix(Matrix<OtherRows, OtherCols, T> const & other)
3836 {
3837 static_assert(OtherRows >= Rows && OtherCols >= Cols, "Matrix dimensions must be smaller");
3838 ComputeFillCol<OtherRows, OtherCols>::call(other, *this);
3839 }
3840 template<unsigned OtherRows, unsigned OtherCols, unsigned col = Cols - 1u>
3841 struct ComputeFillCol
3842 {
3843 static auto call(Matrix<OtherRows, OtherCols, T> const & other, Matrix& res)
3844 {
3845 ComputeFillRow<OtherRows, OtherCols, col>::call(other, res);
3846 ComputeFillCol<OtherRows, OtherCols, col - 1u>::call(other, res);
3847 }
3848 };
3849 template<unsigned OtherRows, unsigned OtherCols>
3850 struct ComputeFillCol<OtherRows, OtherCols, 0>
3851 {
3852 static auto call(Matrix<OtherRows, OtherCols, T> const & other, Matrix& res)
3853 {
3854 ComputeFillRow<OtherRows, OtherCols, 0>::call(other, res);
3855 }
3856 };
3857 template<unsigned OtherRows, unsigned OtherCols, unsigned const col, unsigned row = Rows - 1u>
3858 struct ComputeFillRow
3859 {
3860 static auto call(Matrix<OtherRows, OtherCols, T> const & other, Matrix& res)
3861 {
3862 res.col<col>().at<row>() = other.col<col>().at<row>();
3863 ComputeFillRow<OtherRows, OtherCols, col, row - 1u>::call(other, res);
3864 }
3865 };
3866 template<unsigned OtherRows, unsigned OtherCols, unsigned const col>
3867 struct ComputeFillRow<OtherRows, OtherCols, col, 0>
3868 {
3869 static auto call(Matrix<OtherRows, OtherCols, T> const & other, Matrix& res)
3870 {
3871 res.col<col>().at<0>() = other.col<col>().at<0>();
3872 }
3873 };
3874 auto& operator [] (unsigned const & col)
3875 {
3876 return *(_cols + col);
3877 }
3878 auto const & operator [] (unsigned const & col) const
3879 {
3880 return *(_cols + col);
3881 }
3882 template<unsigned row>
3883 auto row() const
3884 {
3885 Vector<Cols, T> res;
3886 ComputeRow<row>::call(*this, res);
3887 return res;
3888 }
3889 auto row(unsigned const & row) const
3890 {
3891 Vector<Cols, T> res;
3892 ComputeRowDyn<>::call(*this, row, res);
3893 return res;
3894 }
3895 template<unsigned col = Cols - 1u>
3896 struct ComputeRowDyn
3897 {
3898 static auto call(Matrix const & m, unsigned const & row, Vector<Cols, T>& res)
3899 {
3900 res.at<col>() = m.col<col>()[row];
3901 ComputeRowDyn<col - 1u>::call(m, row, res);
3902 }
3903 };
3904 template<>
3905 struct ComputeRowDyn<0>
3906 {
3907 static auto call(Matrix const & m, unsigned const & row, Vector<Cols, T>& res)
3908 {
3909 res.at<0>() = m.col<0>()[row];
3910 }
3911 };
3912 template<unsigned row, unsigned col = Cols - 1u>
3913 struct ComputeRow
3914 {
3915 static auto call(Matrix const & m, Vector<Cols, T>& res)
3916 {
3917 res.at<col>() = m.col<col>().at<row>();
3918 ComputeRow<row, col - 1>::call(m, res);
3919 }
3920 };
3921 template<unsigned row>
3922 struct ComputeRow<row, 0>
3923 {
3924 static auto call(Matrix const & m, Vector<Cols, T>& res)
3925 {
3926 res.at<0>() = m.col<0>().at<row>();
3927 }
3928 };
3929 template<unsigned col>
3930 auto & col()
3931 {
3932 static_assert(col < Cols, "Invalid index");
3933 return *(_cols + col);
3934 }
3935 template<unsigned col>
3936 auto const & col() const
3937 {
3938 static_assert(col < Cols, "Invalid index");
3939 return *(_cols + col);
3940 }
3941 T const * ptr() const
3942 {
3943 return _cols->ptr();
3944 }
3945 template<unsigned col_, unsigned row_>
3946 auto const & at() const
3947 {
3948 return col<col_>().at<row_>();
3949 }
3950 template<unsigned col_, unsigned row_>
3951 auto & at()
3952 {
3953 return col<col_>().at<row_>();
3954 }
3955 template<unsigned i>
3956 auto const & at() const
3957 {
3958 return at<colIdx<i>(), rowIdx<i>()>();
3959 }
3960 template<unsigned i>
3961 auto & at()
3962 {
3963 return at<colIdx<i>(), rowIdx<i>()>();
3964 }
3965 template<unsigned i>
3966 static auto const constexpr colIdx()
3967 {
3968 return i / Rows;
3969 }
3970 template<unsigned i>
3971 static auto const constexpr rowIdx()
3972 {
3973 return i % Rows;
3974 }
3975 template<unsigned row, unsigned col>
3976 static auto const constexpr idx()
3977 {
3978 return row + col * Rows;
3979 }
3980 template<unsigned i>
3981 static auto isDiagonalElement()
3982 {
3983 return colIdx<i>() == rowIdx<i>();
3984 }
3985 template<unsigned i>
3986 auto fillScale(Vector<Cols, T> const & s)
3987 {
3988 at<i>() = isDiagonalElement<i>() ? s.at<rowIdx<i>()>() : static_cast<T>(0);
3989 }
3990 template<unsigned i = maxIdx()>
3991 auto computeScale(Vector<Cols, T> const & s)
3992 {
3993 fillScale<i>(s);
3994 computeScale<i - 1u>(s);
3995 }
3996 template<>
3997 auto computeScale<0>(Vector<Cols, T> const & s)
3998 {
3999 fillScale<0>(s);
4000 }
4001 template<unsigned i>
4002 auto fillIdentity()
4003 {
4004 at<i>() = static_cast<T>(isDiagonalElement<i>() ? 1 : 0);
4005 }
4006 template<unsigned i = maxIdx()>
4007 auto computeIdentity()
4008 {
4009 fillIdentity<i>();
4010 computeIdentity<i - 1u>();
4011 }
4012 template<>
4013 auto computeIdentity<0>()
4014 {
4015 fillIdentity<0>();
4016 }
4017 template<unsigned Cols2>
4018 auto operator * (Matrix<Cols, Cols2, T> const & other) const
4019 {
4020 Matrix<Rows, Cols2, T> res;
4021 ComputeMatMultiply<Cols2>::call(*this, other, res);
4022 return res;
4023 }
4024 private:
4025 template<unsigned row, unsigned col>
4026 auto dotMatrixMultiply(Vector<Cols, T> const & v) const
4027 {
4028 return at<col, row>() * v.at<col>();
4029 }
4030 template<unsigned row, unsigned col = maxCol()>
4031 struct ComputeDotMatrixMultiply
4032 {
4033 static auto call(Matrix const & m, Vector<Cols, T> const & v)
4034 {
4035 return m.dotMatrixMultiply<row, col>(v) + ComputeDotMatrixMultiply<row, col - 1>::call(m, v);
4036 }
4037 };
4038 template<unsigned row>
4039 struct ComputeDotMatrixMultiply<row, 0>
4040 {
4041 static auto call(Matrix const & m, Vector<Cols, T> const & v)
4042 {
4043 return m.dotMatrixMultiply<row, 0>(v);
4044 }
4045 };
4046 template<unsigned Cols2, unsigned i>
4047 auto dotMatrixMultiply(Matrix<Cols, Cols2, T> const & b, Matrix<Rows, Cols2, T>& res) const
4048 {
4049 res.at<i>() = ComputeDotMatrixMultiply<res.rowIdx<i>()>::call(*this, b.col<res.colIdx<i>()>());
4050 }
4051 template<unsigned Cols2, unsigned i = Rows * Cols2 - 1u>
4052 struct ComputeMatMultiply
4053 {
4054 static auto call(Matrix const & a, Matrix<Cols, Cols2, T> const & b, Matrix<Rows, Cols2, T>& res)
4055 {
4056 a.dotMatrixMultiply<Cols2, i>(b, res);
4057 ComputeMatMultiply<Cols2, i - 1>::call(a, b, res);
4058 }
4059 };
4060 template<unsigned Cols2>
4061 struct ComputeMatMultiply<Cols2, 0>
4062 {
4063 static auto call(Matrix const & a, Matrix<Cols, Cols2, T> const & b, Matrix<Rows, Cols2, T>& res)
4064 {
4065 a.dotMatrixMultiply<Cols2, 0>(b, res);
4066 }
4067 };
4068 public:
4069 auto operator*(Vector<Cols, T> const & v) const
4070 {
4071 Vector<Rows, T> res;
4072 computeVecMultiply(v, res);
4073 return res;
4074 }
4075 auto operator*(Vector<Cols - 1, T> const & v) const
4076 {
4077 return *this * v.toHomogeneous();
4078 }
4079 private:
4080 template<unsigned row>
4081 auto vecMultiply(Vector<Cols, T> const & v, Vector<Rows, T>& res) const
4082 {
4083 res.at<row>() = ComputeDotMatrixMultiply<row>::call(*this, v);
4084 }
4085 template<unsigned row = maxRow()>
4086 auto computeVecMultiply(Vector<Cols, T> const & v, Vector<Rows, T>& res) const
4087 {
4088 vecMultiply<row>(v, res);
4089 computeVecMultiply<row - 1>(v, res);
4090 }
4091 template<>
4092 auto computeVecMultiply<0>(Vector<Cols, T> const & v, Vector<Rows, T>& res) const
4093 {
4094 vecMultiply<0>(v, res);
4095 }
4096 template<unsigned col_>
4097 auto fillConstruct(const Vector<Rows, T>(&cols)[Cols])
4098 {
4099 col<col_>() = *(cols + col_);
4100 }
4101 template<unsigned col = maxCol()>
4102 auto construct(const Vector<Rows, T>(&cols)[Cols])
4103 {
4104 fillConstruct<col>(cols);
4105 construct<col - 1>(cols);
4106 }
4107 template<>
4108 auto construct<0>(const Vector<Rows, T>(&cols)[Cols])
4109 {
4110 fillConstruct<0>(cols);
4111 }
4112 template<unsigned i>
4113 auto fillConstruct(const T(&vals)[elements()])
4114 {
4115 at<i>() = *(vals + i);
4116 }
4117 template<unsigned i = maxIdx()>
4118 auto construct(const T(&vals)[elements()])
4119 {
4120 fillConstruct<i>(vals);
4121 construct<i - 1>(vals);
4122 }
4123 template<>
4124 auto construct<0>(const T(&vals)[elements()])
4125 {
4126 fillConstruct<0>(vals);
4127 }
4128 public:
4129 auto operator*(T const & s) const
4130 {
4131 Matrix res;
4132 res.computeScalarMult(*this, s);
4133 return res;
4134 }
4135 template<unsigned i>
4136 auto scalarMult(Matrix const & m, T const & s)
4137 {
4138 at<i>() = m.at<i>() * s;
4139 }
4140 template<unsigned i = maxIdx()>
4141 auto computeScalarMult(Matrix const & m, T const & s)
4142 {
4143 scalarMult<i>(m, s);
4144 computeScalarMult<i - 1>(m, s);
4145 }
4146 template<>
4147 auto computeScalarMult<0>(Matrix const & m, T const & s)
4148 {
4149 scalarMult<0>(m, s);
4150 }
4151 /**
4152 * Conversion from/to glm
4153 */
4154 public:
4155 explicit Matrix(glm::mat<Cols, Rows, T> const & m)
4156 {
4157 Algorithm::Copy<T, Rows * Cols - 1u>::call(&m[0][0], _cols->begin());
4158 }
4159 operator glm::mat<Cols, Rows, T>() const
4160 {
4161 glm::mat<Cols, Rows, T> res;
4162 Algorithm::Copy<T, Rows * Cols - 1u>::call(_cols->begin(), &res[0][0]);
4163 return res;
4164 }
4165 /**
4166 * Debug output
4167 */
4168 friend auto& operator << (std::ostream& os, Matrix const & m)
4169 {
4170 os << "[";
4171 ComputeDebugRow<>::call(m, os);
4172 os << "]";
4173 return os;
4174 }
4175 template<unsigned row = Rows - 1u>
4176 struct ComputeDebugRow
4177 {
4178 static void call(Matrix const & m, std::ostream& os)
4179 {
4180 ComputeDebugCol<row>::call(m, os);
4181 os << std::endl;
4182 ComputeDebugRow<row - 1u>::call(m, os);
4183 }
4184 };
4185 template<>
4186 struct ComputeDebugRow<0>
4187 {
4188 static void call(Matrix const & m, std::ostream& os)
4189 {
4190 ComputeDebugCol<0>::call(m, os);
4191 }
4192 };
4193 template<unsigned row, unsigned col = Cols - 1u>
4194 struct ComputeDebugCol
4195 {
4196 static void call(Matrix const & m, std::ostream& os)
4197 {
4198 os << m.col<Cols - col - 1u>().at<Rows - row - 1u>() << " ";
4199 ComputeDebugCol<row, col - 1u>::call(m, os);
4200 }
4201 };
4202 template<unsigned row>
4203 struct ComputeDebugCol<row, 0>
4204 {
4205 static void call(Matrix const & m, std::ostream& os)
4206 {
4207 os << m.col<Cols - 1u>().at<Rows - row - 1u>();
4208 }
4209 };
4210 private:
4211 Vector<Rows, T> _cols[Cols];
4212 };
4213
4214 using Mat2f = Matrix<2, 2, float>;
4215 using Mat3f = Matrix<3, 3, float>;
4216 using Mat4f = Matrix<4, 4, float>;
4217
4218 using Mat2u = Matrix<2, 2, unsigned>;
4219 using Mat3u = Matrix<3, 3, unsigned>;
4220 using Mat4u = Matrix<4, 4, unsigned>;
4221
4222 using Mat2i = Matrix<2, 2, int>;
4223 using Mat3i = Matrix<3, 3, int>;
4224 using Mat4i = Matrix<4, 4, int>;
4225}
4226
4227#endif
4228#ifndef RTVECTOR_H
4229#define RTVECTOR_H
4230
4231#include <glm/glm.hpp>
4232#include <ostream>
4233#include <Algorithm.h>
4234
4235namespace RT
4236{
4237 template<unsigned Dim, typename T>
4238 class Vector
4239 {
4240 public:
4241 Vector() = default;
4242 Vector(T const & scalar)
4243 {
4244 computeScalar(scalar);
4245 }
4246 template<typename TOther>
4247 Vector(TOther const & scalar) :
4248 Vector(static_cast<T>(scalar))
4249 {
4250 }
4251 template<typename ...Args>
4252 Vector(Args... args) : _data{ args... }
4253 {
4254 }
4255 Vector(Vector const & other) = default;
4256 template<typename TOther>
4257 Vector(Vector<Dim, TOther> const & other)
4258 {
4259 Convert<TOther>::call(other, *this);
4260 }
4261 Vector(Vector<Dim - 1, T> const & other, T const & scalar)
4262 {
4263 Algorithm::Copy<T, Dim - 2u>::call(other.begin(), _data);
4264 back() = scalar;
4265 }
4266 template<unsigned axis>
4267 static auto standardBasis()
4268 {
4269 Vector res;
4270 ComputeStandardBasis<axis>::call(res);
4271 return res;
4272 }
4273 template<unsigned Dim1>
4274 Vector(Vector<Dim1, T> const & v1, Vector<Dim - Dim1, T> const & v2)
4275 {
4276 Algorithm::Copy<T, Dim1 - 1>::call(v1.begin(), _data);
4277 Algorithm::Copy<T, Dim - Dim1 - 1>::call(v2.begin(), _data + Dim1);
4278 }
4279 auto & operator [] (unsigned const & i)
4280 {
4281 return *(_data + i);
4282 }
4283 auto const & operator [] (unsigned const & i) const
4284 {
4285 return *(_data + i);
4286 }
4287 auto const * ptr() const
4288 {
4289 return _data;
4290 }
4291 auto xyz() const
4292 {
4293 return Vector<3, T>(x(), y(), z());
4294 }
4295 auto xz() const
4296 {
4297 return Vector<2, T>(x(), z());
4298 }
4299 auto xy() const
4300 {
4301 return Vector<2, T>(x(), y());
4302 }
4303 auto yz() const
4304 {
4305 return Vector<2, T>(y(), z());
4306 }
4307 auto const & x() const
4308 {
4309 return at<0>();
4310 }
4311 auto const & y() const
4312 {
4313 return at<1>();
4314 }
4315 auto const & z() const
4316 {
4317 return at<2>();
4318 }
4319 auto const & w() const
4320 {
4321 return at<3>();
4322 }
4323 auto const & r() const
4324 {
4325 return x();
4326 }
4327 auto const & g() const
4328 {
4329 return y();
4330 }
4331 auto const & b() const
4332 {
4333 return z();
4334 }
4335 auto const & a() const
4336 {
4337 return w();
4338 }
4339 auto const & u() const
4340 {
4341 return x();
4342 }
4343 auto const & v() const
4344 {
4345 return y();
4346 }
4347 template<unsigned i>
4348 auto const & at() const
4349 {
4350 static_assert(i < Dim, "Invalid i");
4351 return *(_data + i);
4352 }
4353 template<unsigned i>
4354 auto& at()
4355 {
4356 static_assert(i < Dim, "Invalid i");
4357 return *(_data + i);
4358 }
4359 auto append(T const & scalar) const
4360 {
4361 return Vector<Dim + 1, T>(*this, scalar);
4362 }
4363 template<unsigned Dim2>
4364 auto append(Vector<Dim2, T> const & other)
4365 {
4366 return Vector<Dim + Dim2, T>(*this, other);
4367 }
4368 auto appendZero() const
4369 {
4370 return append(static_cast<T>(0));
4371 }
4372 auto appendOne() const
4373 {
4374 return append(static_cast<T>(1));
4375 }
4376 auto appendMinusOne() const
4377 {
4378 return append(static_cast<T>(-1));
4379 }
4380 auto* begin()
4381 {
4382 return _data;
4383 }
4384 auto* end()
4385 {
4386 return _data + Dim;
4387 }
4388 auto const* begin() const
4389 {
4390 return _data;
4391 }
4392 auto const* end() const
4393 {
4394 return begin() + Dim;
4395 }
4396 auto const & front() const
4397 {
4398 return *begin();
4399 }
4400 auto const & back() const
4401 {
4402 return *(end() - 1);
4403 }
4404 auto & front()
4405 {
4406 return *begin();
4407 }
4408 auto & back()
4409 {
4410 return *(end() - 1);
4411 }
4412 auto toHomogeneous() const
4413 {
4414 return appendOne();
4415 }
4416 auto homogeneousDivide() const
4417 {
4418 return *this / back();
4419 }
4420 auto toCartesian() const
4421 {
4422 return homogeneousDivide().reduce<>();
4423 }
4424 auto NDCToUV() const
4425 {
4426 return *this * static_cast<T>(0.5) + static_cast<T>(0.5);
4427 }
4428 auto UVToNDC() const
4429 {
4430 return *this * static_cast<T>(2) - static_cast<T>(1);
4431 }
4432 auto UVToScreen(Vector<2, T> const & screen_size) const
4433 {
4434 return Vector<2, T>(u(), static_cast<T>(1) - v()) * screen_size;
4435 }
4436 auto validU() const
4437 {
4438 return u() >= static_cast<T>(0);
4439 }
4440 auto validV() const
4441 {
4442 return v() >= static_cast<T>(0);
4443 }
4444 auto validW() const
4445 {
4446 return u() + v() <= static_cast<T>(1);
4447 }
4448 auto validUV() const
4449 {
4450 return validU() && validV();
4451 }
4452 auto validUVW() const
4453 {
4454 return validU() && validV() && validW();
4455 }
4456 auto validVW() const
4457 {
4458 return validV() && validW();
4459 }
4460 auto aspectRatio() const
4461 {
4462 return x() / y();
4463 }
4464 auto operator + (Vector const & other) const
4465 {
4466 Vector res;
4467 Compute<std::plus<T>>::call(*this, other, res);
4468 return res;
4469 }
4470 auto operator - (Vector const & other) const
4471 {
4472 Vector res;
4473 Compute<std::minus<T>>::call(*this, other, res);
4474 return res;
4475 }
4476 auto operator * (Vector const & other) const
4477 {
4478 Vector res;
4479 Compute<std::multiplies<T>>::call(*this, other, res);
4480 return res;
4481 }
4482 auto operator / (Vector const & other) const
4483 {
4484 Vector res;
4485 Compute<std::divides<T>>::call(*this, other, res);
4486 return res;
4487 }
4488 auto& operator += (Vector const & other)
4489 {
4490 Compute<std::plus<T>>::call(*this, other, *this);
4491 return *this;
4492 }
4493 auto& operator -= (Vector const & other)
4494 {
4495 Compute<std::minus<T>>::call(*this, other, *this);
4496 return *this;
4497 }
4498 auto& operator *= (Vector const & other)
4499 {
4500 Compute<std::multiplies<T>>::call(*this, other, *this);
4501 return *this;
4502 }
4503 auto& operator /= (Vector const & other)
4504 {
4505 Compute<std::divides<T>>::call(*this, other, *this);
4506 return *this;
4507 }
4508 auto operator - () const
4509 {
4510 Vector res;
4511 ComputePred<std::negate<T>>::call(*this, res);
4512 return res;
4513 }
4514 auto minimum(Vector const & other) const
4515 {
4516 Vector res;
4517 Compute<Min<T>>::call(*this, other, res);
4518 return res;
4519 }
4520 auto maximum(Vector const & other) const
4521 {
4522 Vector res;
4523 Compute<Max<T>>::call(*this, other, res);
4524 return res;
4525 }
4526 auto round() const
4527 {
4528 Vector res;
4529 ComputePred<Round<T>>::call(*this, res);
4530 return res;
4531 }
4532 auto floor() const
4533 {
4534 Vector res;
4535 ComputePred<Floor<T>>::call(*this, res);
4536 return res;
4537 }
4538 auto ceil() const
4539 {
4540 Vector res;
4541 ComputePred<Ceil<T>>::call(*this, res);
4542 return res;
4543 }
4544 auto abs() const
4545 {
4546 Vector res;
4547 ComputePred<Abs<T>>::call(*this, res);
4548 return res;
4549 }
4550 auto minReduce() const
4551 {
4552 return ComputePredReduce<Min<T>>::call(*this);
4553 }
4554 auto maxReduce() const
4555 {
4556 return ComputePredReduce<Max<T>>::call(*this);
4557 }
4558 auto operator == (Vector const & other) const
4559 {
4560 return ComputeReduce<std::equal_to<T>, std::logical_and<T>>::call(*this, other);
4561 }
4562 auto operator != (Vector const & other) const
4563 {
4564 return ComputeReduce<std::not_equal_to<T>, std::logical_or<T>>::call(*this, other);
4565 }
4566 auto operator < (Vector const & other) const
4567 {
4568 return ComputeReduce<std::less<T>, std::logical_and<T>>::call(*this, other);
4569 }
4570 auto operator > (Vector const & other) const
4571 {
4572 return ComputeReduce<std::greater<T>, std::logical_and<T>>::call(*this, other);
4573 }
4574 auto operator <= (Vector const & other) const
4575 {
4576 return ComputeReduce<std::less_equal<T>, std::logical_and<T>>::call(*this, other);
4577 }
4578 auto operator >= (Vector const & other) const
4579 {
4580 return ComputeReduce<std::greater_equal<T>, std::logical_and<T>>::call(*this, other);
4581 }
4582 auto& minimize(Vector const & other)
4583 {
4584 Compute<Min<T>>::call(*this, other, *this);
4585 return *this;
4586 }
4587 auto& maximize(Vector const & other)
4588 {
4589 Compute<Max<T>>::call(*this, other, *this);
4590 return *this;
4591 }
4592 auto dot(Vector const & other) const
4593 {
4594 return ComputeReduce<std::multiplies<T>, std::plus<T>>::call(*this, other);
4595 }
4596 auto scalarTriple(Vector const & b, Vector const & c) const
4597 {
4598 return dot(cross(b, c));
4599 }
4600 auto isRightHanded(Vector const & b, Vector const & c) const
4601 {
4602 return scalarTriple(b, c) > static_cast<T>(0);
4603 }
4604 auto isLeftHanded(Vector const & b, Vector const & c) const
4605 {
4606 return !isRightHanded(b, c);
4607 }
4608 auto handedness(Vector const & b, Vector const & c) const
4609 {
4610 return isRightHanded(b, c) ? 1 : -1;
4611 }
4612 auto orthogonalize(Vector const & b) const
4613 {
4614 return *this - b * dot(b);
4615 }
4616 auto reflect(Vector const & n) const
4617 {
4618 return *this - static_cast<T>(2) * dot(n) * n;
4619 }
4620 auto length() const
4621 {
4622 return std::sqrt(squaredLength());
4623 }
4624 auto normalize() const
4625 {
4626 return RT::normalize(*this);
4627 }
4628 auto squaredLength() const
4629 {
4630 return dot(*this);
4631 }
4632 auto volume() const
4633 {
4634 return ComputePredReduce<std::multiplies<T>>::call(*this);
4635 }
4636 auto shortestAxis() const
4637 {
4638 auto best = Dim - 1;
4639 ComputeBestAxis<std::less<T>>::call(*this, best);
4640 return best;
4641 }
4642 auto longestAxis() const
4643 {
4644 auto best = Dim - 1;
4645 ComputeBestAxis<std::greater<T>>::call(*this, best);
4646 return best;
4647 }
4648 Vector(glm::vec<Dim, T> const & vec)
4649 {
4650 Algorithm::Copy<T, Dim - 1>::call(&vec[0], _data);
4651 }
4652 operator glm::vec<Dim, T>() const
4653 {
4654 glm::vec<Dim, T> vec;
4655 Algorithm::Copy<T, Dim - 1>::call(_data, &vec[0]);
4656 return vec;
4657 }
4658 template<unsigned N = Dim - 1>
4659 auto reduce() const
4660 {
4661 static_assert(N < Dim, "N must be smaller to reduce vector dimension.");
4662 Vector<N, T> ret;
4663 Algorithm::Copy<T, N - 1>::call(_data, ret.begin());
4664 return ret;
4665 }
4666 friend auto& operator << (std::ostream& os, Vector const & vec)
4667 {
4668 os << "[";
4669 ComputeDebug<>::call(vec, os);
4670 os << "]";
4671 return os;
4672 }
4673 template<unsigned i = 0>
4674 struct ComputeDebug
4675 {
4676 static void call(Vector const & vec, std::ostream& os)
4677 {
4678 os << vec.at<i>() << " ";
4679 ComputeDebug<i + 1>::call(vec, os);
4680 }
4681 };
4682 template<>
4683 struct ComputeDebug<Dim - 1>
4684 {
4685 static void call(Vector const & vec, std::ostream& os)
4686 {
4687 os << vec.back();
4688 }
4689 };
4690 private:
4691 T _data[Dim];
4692
4693 template<unsigned axis, unsigned i>
4694 auto fillStandardBasis()
4695 {
4696 at<i>() = static_cast<T>(i == axis ? 1 : 0);
4697 }
4698 template<unsigned axis, unsigned i = Dim - 1u>
4699 struct ComputeStandardBasis
4700 {
4701 static auto call(Vector& res)
4702 {
4703 res.fillStandardBasis<axis, i>();
4704 ComputeStandardBasis<axis, i - 1>::call(res);
4705 }
4706 };
4707 template<unsigned axis>
4708 struct ComputeStandardBasis<axis, 0>
4709 {
4710 static auto call(Vector& res)
4711 {
4712 res.fillStandardBasis<axis, 0>();
4713 }
4714 };
4715 template<typename Pred, unsigned i>
4716 auto fill(Vector const & a, Vector const & b)
4717 {
4718 at<i>() = Pred()(a.at<i>(), b.at<i>());
4719 }
4720 template<typename Pred, unsigned i = Dim - 1>
4721 struct Compute
4722 {
4723 static auto call(Vector const & a, Vector const & b, Vector& res)
4724 {
4725 res.fill<Pred, i>(a, b);
4726 Compute<Pred, i - 1>::call(a, b, res);
4727 }
4728 };
4729 template<typename Pred>
4730 struct Compute<Pred, 0>
4731 {
4732 static auto call(Vector const & a, Vector const & b, Vector& res)
4733 {
4734 res.fill<Pred, 0>(a, b);
4735 }
4736 };
4737 template<typename Pred, unsigned i>
4738 auto fill(Vector const & v)
4739 {
4740 at<i>() = Pred()(v.at<i>());
4741 }
4742 template<typename Pred, unsigned i = Dim - 1>
4743 struct ComputePred
4744 {
4745 static auto call(Vector const & v, Vector& res)
4746 {
4747 res.fill<Pred, i>(v);
4748 ComputePred<Pred, i - 1>::call(v, res);
4749 }
4750 };
4751 template<typename Pred>
4752 struct ComputePred<Pred, 0>
4753 {
4754 static auto call(Vector const & v, Vector& res)
4755 {
4756 res.fill<Pred, 0>(v);
4757 }
4758 };
4759 template<typename Pred, unsigned i = Dim - 1>
4760 struct ComputePredReduce
4761 {
4762 static auto call(Vector const & v)
4763 {
4764 return Pred()(v.at<i>(), ComputePredReduce<Pred, i - 1>::call(v));
4765 }
4766 };
4767 template<typename Pred>
4768 struct ComputePredReduce<Pred, 0>
4769 {
4770 static auto call(Vector const & v)
4771 {
4772 return v.at<0>();
4773 }
4774 };
4775 template<typename BinaryOp, typename ReduceOp, unsigned i = Dim - 1>
4776 struct ComputeReduce
4777 {
4778 static auto call(Vector const & a, Vector const & b)
4779 {
4780 return ReduceOp()(BinaryOp()(a.at<i>(), b.at<i>()), ComputeReduce<BinaryOp, ReduceOp, i - 1>::call(a, b));
4781 }
4782 };
4783 template<typename BinaryOp, typename ReduceOp>
4784 struct ComputeReduce<BinaryOp, ReduceOp, 0>
4785 {
4786 static auto call(Vector const & a, Vector const & b)
4787 {
4788 return BinaryOp()(a.at<0>(), b.at<0>());
4789 }
4790 };
4791 template<unsigned i>
4792 auto fillScalar(T const & scalar)
4793 {
4794 at<i>() = scalar;
4795 }
4796 template<unsigned i = Dim - 1>
4797 auto computeScalar(T const & scalar)
4798 {
4799 fillScalar<i>(scalar);
4800 computeScalar<i - 1>(scalar);
4801 }
4802 template<>
4803 auto computeScalar<0>(T const & scalar)
4804 {
4805 fillScalar<0>(scalar);
4806 }
4807 template<typename TOther, unsigned i>
4808 auto fillConvert(Vector<Dim, TOther> const & other)
4809 {
4810 at<i>() = static_cast<T>(other.at<i>());
4811 }
4812 template<typename TOther, unsigned i = Dim - 1>
4813 struct Convert
4814 {
4815 static auto call(Vector<Dim, TOther> const & other, Vector& res)
4816 {
4817 res.fillConvert<TOther, i>(other);
4818 Convert<TOther, i - 1>::call(other, res);
4819 }
4820 };
4821 template<typename TOther>
4822 struct Convert<TOther, 0>
4823 {
4824 static auto call(Vector<Dim, TOther> const & other, Vector& res)
4825 {
4826 res.fillConvert<TOther, 0>(other);
4827 }
4828 };
4829 template<typename Pred, unsigned i>
4830 auto bestAxis(unsigned& best) const
4831 {
4832 if (Pred()(at<i>(), *(_data + best))) {
4833 best = i;
4834 }
4835 }
4836 template<typename Pred, unsigned i = Dim - 2u>
4837 struct ComputeBestAxis
4838 {
4839 static auto call(Vector const & v, unsigned& best)
4840 {
4841 v.bestAxis<Pred, i>(best);
4842 ComputeBestAxis<Pred, i - 1>::call(v, best);
4843 }
4844 };
4845 template<typename Pred>
4846 struct ComputeBestAxis<Pred, 0>
4847 {
4848 static auto call(Vector const & v, unsigned& best)
4849 {
4850 v.bestAxis<Pred, 0>(best);
4851 }
4852 };
4853 };
4854
4855 template<unsigned Dim, typename T>
4856 auto operator + (T const & s, Vector<Dim, T> const & v)
4857 {
4858 return Vector<Dim, T>(s) + v;
4859 }
4860 template<unsigned Dim, typename T>
4861 auto operator - (T const & s, Vector<Dim, T> const & v)
4862 {
4863 return Vector<Dim, T>(s) - v;
4864 }
4865 template<unsigned Dim, typename T>
4866 auto operator * (T const & s, Vector<Dim, T> const & v)
4867 {
4868 return Vector<Dim, T>(s) * v;
4869 }
4870 template<unsigned Dim, typename T>
4871 auto operator / (T const & s, Vector<Dim, T> const & v)
4872 {
4873 return Vector<Dim, T>(s) / v;
4874 }
4875
4876 using Vec2f = Vector<2, float>;
4877 using Vec3f = Vector<3, float>;
4878 using Vec4f = Vector<4, float>;
4879
4880 using Vec2u = Vector<2, unsigned>;
4881 using Vec3u = Vector<3, unsigned>;
4882 using Vec4u = Vector<4, unsigned>;
4883
4884 using Vec2i = Vector<2, int>;
4885 using Vec3i = Vector<3, int>;
4886 using Vec4i = Vector<4, int>;
4887
4888 using Point2f = Vec2f;
4889 using Point3f = Vec3f;
4890 using Point4f = Vec4f;
4891
4892 using Point2u = Vec2u;
4893 using Point3u = Vec3u;
4894 using Point4u = Vec4u;
4895
4896 using Point2i = Vec2i;
4897 using Point3i = Vec3i;
4898 using Point4i = Vec4i;
4899}
4900
4901#endif
4902#ifndef OPENGLAPI_H
4903#define OPENGLAPI_H
4904
4905#include <GL/glew.h>
4906#include <opengl/OpenGLUtils.h>
4907#include <math/RTMath.h>
4908#include <memory>
4909#include <vector>
4910#include <functional>
4911#include <opengl/GLTexture.h>
4912#include <opengl/GLVertexArray.h>
4913#include <opengl/GLShaderSource.h>
4914#include <StackTrivial.h>
4915#include <opengl/GLMaterialSetup.h>
4916#include <opengl/GLShaderSetup.h>
4917#include <opengl/GLSLShaderGenerator.h>
4918#include <opengl/GLShaderProgram.h>
4919#include <opengl/GLFramebuffer.h>
4920#include <opengl/GLSampler.h>
4921#include <opengl/GLBuffer.h>
4922#include <cstdint>
4923#include <opengl/GLShaderInterface.h>
4924#include <opengl/GLMaterialSetup.h>
4925#include <boost/pool/object_pool.hpp>
4926#include <AABB.h>
4927#include <deque>
4928#include <Plane.h>
4929#include <Sphere.h>
4930#include <RenderContext.h>
4931
4932namespace RT
4933{
4934 class Mesh;
4935 class Material;
4936 class GLSLShaderGenerator;
4937 struct GlobalShaderParams;
4938 class GLSampler;
4939 class GraphicsSettings;
4940
4941 class OpenGLAPI : public RenderContext
4942 {
4943 public:
4944 OpenGLAPI(Vec4f const & clear_color);
4945 OpenGLAPI(OpenGLAPI const & other) = delete;
4946 OpenGLAPI& operator=(OpenGLAPI const & other) = delete;
4947 OpenGLAPI(OpenGLAPI&& other) = default;
4948 OpenGLAPI& operator=(OpenGLAPI&& other) = default;
4949 ~OpenGLAPI();
4950 virtual void setViewport(Vec2u const & size) const override;
4951 auto clearRendertarget(bool color, bool depth, bool stencil) const
4952 {
4953 GLbitfield flag = 0;
4954 if (color) {
4955 flag |= GL_COLOR_BUFFER_BIT;
4956 }
4957 if (depth) {
4958 flag |= GL_DEPTH_BUFFER_BIT;
4959 }
4960 if (stencil) {
4961 flag |= GL_STENCIL_BUFFER_BIT;
4962 }
4963 GL_CHECK(glClear(flag));
4964 }
4965 virtual void clearRendertarget(bool const & color, bool const & depth, bool const & stencil) const override
4966 {
4967 GLbitfield flag = 0;
4968 if (color) {
4969 flag |= GL_COLOR_BUFFER_BIT;
4970 }
4971 if (depth) {
4972 flag |= GL_DEPTH_BUFFER_BIT;
4973 }
4974 if (stencil) {
4975 flag |= GL_STENCIL_BUFFER_BIT;
4976 }
4977 GL_CHECK(glClear(flag));
4978 }
4979 static const size_t _maxRendertargets = 8;
4980 virtual void setDepthTestEnabled(bool const & enabled) const override { GL_CHECK(enabled ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST)); }
4981 virtual void setFaceCullingEnabled(bool const & enabled) const { GL_CHECK(enabled ? glEnable(GL_CULL_FACE) : glDisable(GL_CULL_FACE)); }
4982 virtual void setDepthClampEnabled(bool const & enabled) const { GL_CHECK(enabled ? glEnable(GL_DEPTH_CLAMP) : glDisable(GL_DEPTH_CLAMP)); }
4983 virtual void setDepthWriteEnabled(bool const & enabled) const { GL_CHECK(glDepthMask(enabled)); }
4984 virtual void setDepthFunc(DepthFunc const & f) const override
4985 {
4986 GLenum func;
4987 if (f == DepthFunc::NEVER) {
4988 func = GL_NEVER;
4989 }
4990 else if (f == DepthFunc::LESS) {
4991 func = GL_LESS;
4992 }
4993 else if (f == DepthFunc::EQUAL) {
4994 func = GL_EQUAL;
4995 }
4996 else if (f == DepthFunc::LEQUAL) {
4997 func = GL_LEQUAL;
4998 }
4999 else if (f == DepthFunc::GREATER) {
5000 func = GL_GREATER;
5001 }
5002 else if (f == DepthFunc::NOTEQUAL) {
5003 func = GL_NOTEQUAL;
5004 }
5005 else if (f == DepthFunc::GEQUAL) {
5006 func = GL_GEQUAL;
5007 }
5008 else if (f == DepthFunc::ALWAYS) {
5009 func = GL_ALWAYS;
5010 }
5011 GL_CHECK(glDepthFunc(func));
5012 }
5013 virtual void setCullMode(CullMode const & m) const override
5014 {
5015 GL_CHECK(glCullFace(m == CullMode::BACK ? GL_BACK : GL_FRONT));
5016 }
5017 using ShaderGenerator = GLSLShaderGenerator;
5018 virtual std::shared_ptr<Texture> createRenderToTexture(Vec2u const & size, Texture::TexFilter const & tf) const override
5019 {
5020 auto tex = std::make_shared<GLTexture>(GL_TEXTURE_2D);
5021 tex->bind();
5022 tex->setTexMinFilter(tf);
5023 tex->setTexMagFilter<GLTexture::TexFilter::LINEAR>();
5024 tex->param(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
5025 tex->param(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
5026 tex->image2D(0, GL_RGBA16F, size, 0, GL_RGBA, GL_FLOAT, nullptr);
5027 return tex;
5028 }
5029 virtual Rendertarget* createRendertarget() const override
5030 {
5031 return new GLFramebuffer();
5032 }
5033 virtual Rendertarget* createRendertarget(std::vector<std::shared_ptr<Texture>> const & color_attachments, std::shared_ptr<Texture> const & depth_attachment) const override
5034 {
5035 return new GLFramebuffer(color_attachments, depth_attachment);
5036 }
5037 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
5038 {
5039 return new GLFramebuffer(color_attachments, depth_attachment, depth_layer);
5040 }
5041 class GLMeshData : public GPUMeshData
5042 {
5043 public:
5044 explicit GLMeshData(Mesh& mesh);
5045 GLMeshData(GLMeshData const & other) = delete;
5046 GLMeshData& operator=(GLMeshData const & other) = delete;
5047 GLMeshData(GLMeshData&& other) noexcept = default;
5048 GLMeshData& operator=(GLMeshData&& other) noexcept = default;
5049 virtual int const & count() const override { return _count; }
5050 auto type() const { return _type; }
5051 auto const & vao() const { return _vao; }
5052 virtual void draw() const override;
5053 virtual Mesh& mesh() override { return _mesh; }
5054 private:
5055 GLVertexArray _vao;
5056 GLBuffer _vbo;
5057 GLBuffer _ibo;
5058 GLsizei _count;
5059 GLenum _type;
5060 Mesh& _mesh;
5061 };
5062 // Texture unit bindings
5063 static constexpr const int diffuseTexUnit = 0;
5064 static constexpr const int alphaTexUnit = 1;
5065 static constexpr const int normalTexUnit = 2;
5066 static constexpr const int heightTexUnit = 3;
5067 static constexpr const int miscTexUnit0 = 4;
5068 static constexpr const int miscTexUnit1 = 5;
5069 static constexpr const int miscTexUnit2 = 6;
5070 static constexpr const int miscTexUnit3 = 7;
5071 static constexpr const int miscTexUnit4 = 8;
5072 static constexpr const int miscTexUnit5 = 9;
5073 virtual void beginFrame() const;
5074 virtual void bindShader(Shader const * shader) override;
5075 virtual void bindShadowmap(const Texture& shadowmap) const override;
5076 virtual void renderMesh(const GPUMeshData& gmd) const override;
5077 virtual void renderMesh(const GPUMeshData& gmd, const Mat4f& model_matrix) const override;
5078 virtual void renderMesh(const GPUMeshData& gmd, const Mat4f& model_matrix, const Mat3f& model_matrix_inverse) const override;
5079 virtual void render2DBillboard(const Vec2f& pos_ndc, const Vec2f& scale, const Texture& texture, const Vec3f& color, float depth_ndc) override;
5080 virtual void renderDebugTriangle(const Vec4f* first, const Mat4f& mvp, const Vec3f& color) override;
5081 virtual void renderDebugFrustum(const Mat4f& vp_debug_frustum, const Mat4f& mvp) override;
5082 virtual void bindBackbuffer(unsigned const & id) const override;
5083 virtual void ssr(const Texture& lighting_buffer, const Texture& view_space_normals, const Texture& depth_buffer,
5084 const Mat4f& projection_matrix, const Vec4f& blend_weight, Texture& lighting_buffer_copy) override;
5085 virtual void separableBlur(Texture const & in, std::array<std::shared_ptr<Rendertarget>, 2> const & out) override;
5086 virtual void renderGodRays(const Texture& depth_buffer, const Texture& lighting_buffer, const Vec2f& light_pos_uv) override;
5087 virtual void renderBrightPass(const Texture& lighting_buffer) override;
5088 virtual void additiveBlend(const Texture& texture);
5089 virtual void endFrame() const;
5090 virtual void setAnisotropy(unsigned anisotropy);
5091 virtual void enablePolygonOffset(float factor, float units) const;
5092 virtual void disablePolygonOffset() const;
5093 virtual void renderSkydome(const Mat4f& view_projection_matrix, const GPUMeshData& gs);
5094 virtual Texture* createTexture(std::string const & path) const;
5095 virtual void deleteTexture(Texture const * texture) const;
5096 // virtual Shader* createShader(GLShaderSource& vs, GLShaderSource& fs, GLShaderSource& gs = GLShaderSource());
5097 // virtual void deleteShader(Shader* shader);
5098 virtual std::shared_ptr<Texture> createDepthbuffer(Vec2u const & size);
5099 virtual std::shared_ptr<Texture> createShadowmap(GraphicsSettings const & settings);
5100 virtual void setupCompositing(Texture const & lighting_buffer) const override;
5101 // virtual void setupFog(Vec2f const & fog_start_end) const override;
5102 virtual void setupDepthOfField(const GlobalShaderParams & params, Texture const & dof_buffer, Texture const & depth_buffer, Vec3f const & near_center_far) const override;
5103 virtual void setupGodRays(const Vec3f& god_ray_intensity, Texture const & god_ray_buffer) const override;
5104 virtual void setupBloom(Texture const & bloom_buffer) const override;
5105 virtual void setupAutoExposure(const Texture& lighting_buffer) const override;
5106 virtual void resizeShadowmap(Texture& shadow_map, GraphicsSettings const & settings) override;
5107 virtual void createBlurShader(const GraphicsSettings& gs) override;
5108 virtual void createCompositeShader(const GraphicsSettings& gs) override;
5109 virtual void createScreenSpaceReflectionsShader(const GraphicsSettings& gs) override;
5110 virtual void createGodRayShader(const GraphicsSettings& gs) override;
5111 virtual void createBrightnessShader(const GraphicsSettings& gs) override;
5112 virtual MaterialDesc* createMaterialDesc(std::shared_ptr<Material> const & material, GraphicsSettings const & settings,
5113 PtrCache<std::string, Texture>* texture_cache,
5114 PtrCache<std::shared_ptr<Shader>, ShaderDesc>* shader_desc_cache,
5115 PtrCache<std::string, Shader>* shader_cache) const override;
5116 virtual GPUMeshData* createMeshData(Mesh& mesh) const override;
5117 ShaderGenerator const & shaderGenerator() const;
5118 auto activateTexture(Texture const & texture, char const * key, GLint const & tex_unit) const
5119 {
5120 GL_CHECK(glActiveTexture(GL_TEXTURE0 + tex_unit));
5121 texture.bind();
5122 setScalar(_activeShader->uniformLocation(key), tex_unit);
5123 }
5124 virtual Shader const & compositeShader() const override;
5125 virtual Shader const & compositeShaderWithGodRays() const override;
5126 auto renderQuad() const
5127 {
5128 GL_CHECK(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
5129 }
5130 virtual void composite() const override;
5131 private:
5132 struct GlewInit
5133 {
5134 GlewInit();
5135 };
5136 void checkFramebufferStatus();
5137 GlewInit _glewInit;
5138 GLShaderProgram _compositeShader;
5139 GLShaderProgram _compositeShaderWithGodRays;
5140 GLShaderProgram _skydomeShader;
5141 GLShaderProgram _ssrShader;
5142 GLShaderProgram _blurShader;
5143 GLShaderProgram _brightnessShader;
5144 GLShaderProgram _boxShader;
5145 GLShaderProgram _copyShader;
5146 GLShaderProgram _triangleDebugShader;
5147 GLShaderProgram _trianglesDebugShader;
5148 GLShaderProgram _springParticleDebugShader;
5149 GLShaderProgram _springDebugShader;
5150 GLShaderProgram _2DBillboardShader;
5151 ShaderGenerator _shaderGenerator;
5152 GLSampler _samplerAnisotropic;
5153 GLint _glVersionMajor, _glVersionMinor;
5154 GLShaderProgram _debugFrustumShader;
5155 GLShaderProgram _godRayShader;
5156 GLShaderProgram _particleShader;
5157 unsigned _anisotropy = 1u;
5158 GLShaderProgram createMiscShader(GLShaderSource& vs, GLShaderSource& fs, GLShaderSource& gs = GLShaderSource()) const;
5159 //boost::object_pool<GLTexture> _texturePool;
5160 // boost::object_pool<GLShaderProgram> _shaderPool;
5161 static void setupVertexFormat();
5162 template<typename T>
5163 static GLenum fillIndexBuffer(T const * verts_begin, T const * verts_end, unsigned const * inds_begin, unsigned const * inds_end, GLBuffer& index_buffer)
5164 {
5165 if (static_cast<size_t>(verts_end - verts_begin - 1u) <= static_cast<size_t>(std::numeric_limits<unsigned short>::max())) {
5166 StackTrivial<unsigned short> indices;
5167 indices.reserve(inds_end - inds_begin);
5168 while (inds_begin != inds_end) {
5169 indices.push_back_unchecked(static_cast<unsigned short>(*inds_begin++));
5170 }
5171 index_buffer.setData(indices.begin(), indices.size());
5172 return GL_UNSIGNED_SHORT;
5173 }
5174 else {
5175 index_buffer.setData(inds_begin, inds_end - inds_begin);
5176 return GL_UNSIGNED_INT;
5177 }
5178 }
5179 };
5180}
5181
5182#endif
5183#ifndef PHYSICSCAMERACONTROLLER_H
5184#define PHYSICSCAMERACONTROLLER_H
5185
5186#include <memory>
5187#include <math/RTMath.h>
5188#include <FixedTimestepSystem.h>
5189#include <Primitive.h>
5190
5191namespace RT
5192{
5193 class Camera;
5194 class BVTree;
5195
5196 class PhysicsCameraController : public FixedTimestepSystem
5197 {
5198 private:
5199 using Type = Primitive::Type;
5200 using Vector = Vector<3, Type>;
5201 public:
5202 PhysicsCameraController(Camera* const & camera, BVTree*& BVTree);
5203 virtual ~PhysicsCameraController() = default;
5204 virtual void updateSystem() override;
5205 virtual unsigned getID() override;
5206 virtual const char* getName() override;
5207 void setAcceleration(Vector const & dir, Type const & amount);
5208 void setAngularAcceleration(Vector const & aa);
5209 Camera * const & getCamera() const;
5210 void setCamera(Camera * const & camera);
5211 void setDamping(Type const & damping);
5212 Vector const & gravity() const;
5213 void setGravity(Vector const & gravity);
5214 bool const & collisions() const;
5215 void setCollisions(bool const & collisions);
5216 private:
5217 Camera* _c;
5218 Vector _acceleration = static_cast<Type>(0);
5219 Vector _velocity = static_cast<Type>(0);
5220 Type _damp = DAMP_DEFAULT;
5221 Vector _angularAcceleration = static_cast<Type>(0);
5222 Vector _angularVelocity = static_cast<Type>(0);
5223 Vector _gravity = static_cast<Type>(0);
5224 BVTree*& _BVTree;
5225 bool _collisions = true;
5226 static constexpr const Type DAMP_DEFAULT = static_cast<Type>(0.95);
5227 static constexpr const Type DAMP_INTERIOR = static_cast<Type>(0.7);
5228 };
5229}
5230
5231#endif
5232#ifndef MESHRENDERABLES_H
5233#define MESHRENDERABLES_H
5234
5235#include <memory>
5236#include <functional>
5237#include <Primitive.h>
5238#include <Transform.h>
5239
5240#define DYNAMIC_INVERSE 1
5241
5242namespace RT
5243{
5244 class Renderer;
5245 class RenderList;
5246 class CullingParams;
5247 class Transform;
5248 class RenderContext;
5249 class ShaderDesc;
5250 class MaterialDesc;
5251 class GPUMeshData;
5252 class Material;
5253
5254 class LodRenderable
5255 {
5256 public:
5257 LodRenderable() = default;
5258 virtual ~LodRenderable() = default;
5259 virtual void selectLod(CullingParams const & cp) = 0;
5260 };
5261 class GPURenderable
5262 {
5263 public:
5264 GPURenderable() = default;
5265 virtual ~GPURenderable() = default;
5266 virtual void cullGPU(const RenderContext& api) = 0;
5267 };
5268
5269 class IMeshRenderable : public Primitive
5270 {
5271 public:
5272 IMeshRenderable() = default;
5273 virtual ~IMeshRenderable() = default;
5274
5275 std::shared_ptr<ShaderDesc> const * shaderDesc() const;
5276 std::shared_ptr<ShaderDesc> const * shaderDescDepth() const;
5277 MaterialDesc* materialDesc() const;
5278
5279 virtual void renderDepth(RenderContext const & rc) const = 0;
5280 virtual void render(RenderContext const & api) const = 0;
5281 virtual GPUMeshData* gpuMeshData() const = 0;
5282 virtual void setModelMatrix(Mat4f const & m);
5283 virtual void add(RenderList& renderlist) override;
5284 virtual void addUnchecked(RenderList& renderlist) override;
5285 virtual void addIfContributes(const CullingParams& cp, RenderList& renderlist) override;
5286 virtual void addIfContributesUnchecked(const CullingParams& cp, RenderList& renderlist) override;
5287 virtual void addIfContributesAndVisible(const CullingParams& cp, RenderList& renderlist) override;
5288 virtual unsigned numMeshes() const override;
5289 protected:
5290 std::shared_ptr<ShaderDesc> const * _shaderDesc;
5291 std::shared_ptr<ShaderDesc> const * _shaderDescDepth;
5292 std::shared_ptr<MaterialDesc> _materialDesc;
5293 void createBV(const Mesh& mesh, const Transform& transform, Sphere3f& result);
5294 void createBV(Mesh const & mesh, Transform const & transform, AABB3f& result);
5295 bool contributes(CullingParams const & cp) const;
5296 bool intersectFrustum(CullingParams const & cp) const;
5297 };
5298 class SkydomeRenderable
5299 {
5300 public:
5301 SkydomeRenderable(Renderer& renderer, const std::shared_ptr<Mesh>& mesh);
5302 std::shared_ptr<GPUMeshData> const & storage() const;
5303 private:
5304 std::shared_ptr<GPUMeshData> _gmd;
5305 };
5306 class StaticMeshRenderable : public IMeshRenderable
5307 {
5308 public:
5309 StaticMeshRenderable(Renderer& renderer, std::shared_ptr<Mesh> const & mesh,
5310 std::shared_ptr<Material> const & material, Transform const & transform);
5311 virtual ~StaticMeshRenderable() = default;
5312 virtual void render(RenderContext const & rc) const override;
5313 virtual void renderDepth(RenderContext const & rc) const override;
5314 virtual unsigned numTriangles() const override;
5315 virtual BVTree * nestedBVTree() override;
5316 virtual std::shared_ptr<BVTree> transformedBVTree(boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const override;
5317 virtual GPUMeshData* gpuMeshData() const override;
5318 virtual Mat4f const * modelMatrix() const override;
5319 virtual void setModelMatrix(Mat4f const & m);
5320 virtual BV bv() const override;
5321 virtual BV bvLocal() const override;
5322 virtual Type squaredSize() const override;
5323 virtual Ray::IntersectionResult intersect(Ray const & ray) override;
5324 virtual Ray::IntersectionResult intersect(Ray const & ray, Matrix const & matrix) override;
5325 virtual size_t sizeInBytes() const override;
5326 protected:
5327 std::shared_ptr<GPUMeshData> _gmd;
5328 Mat4f _modelMatrix;
5329#if !DYNAMIC_INVERSE
5330 Mat3f _modelMatrixInverse;
5331#endif
5332 };
5333
5334 class StaticMeshRenderableTransform : public StaticMeshRenderable
5335 {
5336 public:
5337 StaticMeshRenderableTransform(Renderer& renderer, std::shared_ptr<Mesh> const & mesh,
5338 std::shared_ptr<Material> const & material, Transform const & transform);
5339 void setTransform(Transform const & t);
5340 virtual Transform const * transform() const override;
5341 private:
5342 Transform _transform;
5343 };
5344
5345 class StaticMeshRenderableShared : public IMeshRenderable
5346 {
5347 public:
5348 StaticMeshRenderableShared(Renderer& renderer, const std::shared_ptr<Mesh>& mesh,
5349 const std::shared_ptr<Material>& material, const std::shared_ptr<Mat4f>& model_matrix);
5350 virtual ~StaticMeshRenderableShared() = default;
5351 virtual void render(RenderContext const & rc) const override;
5352 virtual void renderDepth(RenderContext const & rc) const override;
5353 virtual unsigned numTriangles() const override;
5354 virtual GPUMeshData* gpuMeshData() const override;
5355 virtual Mat4f const * modelMatrix() const override;
5356 virtual BVTree * nestedBVTree() override;
5357 virtual std::shared_ptr<BVTree> transformedBVTree(boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const override;
5358 virtual BV bv() const override;
5359 virtual Type squaredSize() const override;
5360 virtual Ray::IntersectionResult intersect(Ray const & ray) override;
5361 virtual Ray::IntersectionResult intersect(Ray const & ray, Matrix const & matrix) override;
5362 virtual size_t sizeInBytes() const override;
5363 protected:
5364 std::shared_ptr<GPUMeshData> _gmd;
5365 std::shared_ptr<Mat4f> _modelMatrix;
5366 };
5367 class StaticMeshRenderableLod : public IMeshRenderable, public LodRenderable
5368 {
5369 public:
5370 StaticMeshRenderableLod(Renderer& renderer, std::vector<std::shared_ptr<Mesh>> const & meshes,
5371 std::shared_ptr<Material> const & material, Transform const & transform);
5372 virtual ~StaticMeshRenderableLod() = default;
5373 virtual void render(RenderContext const & rc) const override;
5374 virtual void renderDepth(RenderContext const & rc) const override;
5375 virtual unsigned numTriangles() const override;
5376 virtual void add(RenderList& renderlist) override;
5377 virtual void addUnchecked(RenderList& renderlist) override;
5378 virtual void selectLod(const CullingParams& cp) override;
5379 virtual GPUMeshData* gpuMeshData() const override;
5380 virtual Mat4f const * modelMatrix() const override;
5381 virtual BV bv() const override;
5382 virtual BVTree * nestedBVTree() override;
5383 virtual std::shared_ptr<BVTree> transformedBVTree(boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const override;
5384 virtual Type squaredSize() const override;
5385 virtual Ray::IntersectionResult intersect(Ray const & ray) override;
5386 virtual Ray::IntersectionResult intersect(Ray const & ray, Matrix const & matrix) override;
5387 virtual size_t sizeInBytes() const override;
5388 protected:
5389 std::vector<std::shared_ptr<GPUMeshData>> _gmd;
5390 Mat4f _modelMatrix;
5391#if !DYNAMIC_INVERSE
5392 Mat3f _modelMatrixInverse;
5393#endif
5394 unsigned _lod = 0;
5395 };
5396
5397 class MeshRenderablePool
5398 {
5399 public:
5400 MeshRenderablePool() = default;
5401 StaticMeshRenderable* createStaticMeshRenderable(Renderer& renderer, std::shared_ptr<Mesh> const & mesh,
5402 std::shared_ptr<Material> const & material, Transform const & transform)
5403 {
5404 return new(_poolSmr.malloc()) StaticMeshRenderable(renderer, mesh, material, transform);
5405 }
5406 StaticMeshRenderableShared* createStaticMeshRenderableShared(Renderer& renderer, std::shared_ptr<Mesh> const & mesh,
5407 std::shared_ptr<Material> const & material, std::shared_ptr<Mat4f> const & model_matrix)
5408 {
5409 return new(_poolSmrShared.malloc()) StaticMeshRenderableShared(renderer, mesh, material, model_matrix);
5410 }
5411 StaticMeshRenderableLod* createStaticMeshRenderableLod(Renderer& renderer, std::vector<std::shared_ptr<Mesh>> const & meshes,
5412 std::shared_ptr<Material> const & material, Transform const & transform)
5413 {
5414 return new(_poolSmrLod.malloc()) StaticMeshRenderableLod(renderer, meshes, material, transform);
5415 }
5416 StaticMeshRenderableTransform* createStaticMeshRenderableTransform(Renderer& renderer, std::shared_ptr<Mesh> const & mesh,
5417 std::shared_ptr<Material> const & material, Transform const & transform)
5418 {
5419 return new(_poolSmrTransform.malloc()) StaticMeshRenderableTransform(renderer, mesh, material, transform);
5420 }
5421 private:
5422 boost::object_pool<StaticMeshRenderable> _poolSmr;
5423 boost::object_pool<StaticMeshRenderableShared> _poolSmrShared;
5424 boost::object_pool<StaticMeshRenderableLod> _poolSmrLod;
5425 boost::object_pool<StaticMeshRenderableTransform> _poolSmrTransform;
5426 };
5427}
5428
5429#endif // !MESHRENDERABLES_H
5430#ifndef RENDERER_H
5431#define RENDERER_H
5432
5433#include <math/MathHelpers.h>
5434#include <System.h>
5435#include <math/RTMath.h>
5436#include <glm/gtx/quaternion.hpp>
5437#include <map>
5438#include <Model.h>
5439#include <memory>
5440#include <Camera.h>
5441#include <Light.h>
5442#include <iostream>
5443#include <Settings.h>
5444#include <functional>
5445#include <GraphicsSettings.h>
5446#include <Timing.h>
5447#include <StackTrivial.h>
5448#include <Flags.h>
5449#include <renderer/MeshRenderables.h>
5450#include <set>
5451#include <GameTimer.h>
5452#include <GlobalShaderParams.h>
5453#include <future>
5454#include <BVTree.h>
5455#include <RenderList.h>
5456#include <PtrCache.h>
5457#include <boost/pool/object_pool.hpp>
5458#include <deque>
5459#include <StringHelper.h>
5460#include <Ray.h>
5461#include <renderer/Rendertargets.h>
5462#include <RenderContext.h>
5463#include <BVTreeLeafNode.h>
5464#include <BVTreeInternalNode.h>
5465#include <FrustumVertices.h>
5466
5467#define RENDERER_STATS 1
5468
5469namespace RT
5470{
5471 class Renderer : public System, public GraphicsSettings::Listener
5472 {
5473 public:
5474 using BV = typename Primitive::BV;
5475 using BVTree = BVTree;
5476 using Type = typename Primitive::Type;
5477 using Vec2 = Vector<2, Type>;
5478 using Vec3 = Vector<3, Type>;
5479 using Vec4 = Vector<4, Type>;
5480 using Matrix = typename Primitive::Matrix;
5481 using Ray = typename Primitive::Ray;
5482 using MeshRenderable = IMeshRenderable;
5483 using MeshRenderablePtr = MeshRenderable * ;
5484 using MaterialDescCache = PtrCache<std::shared_ptr<Material>, MaterialDesc>;
5485 using MeshCache = PtrCache<std::shared_ptr<Mesh>, GPUMeshData>;
5486#if RENDERER_STATS
5487 struct CullingStats
5488 {
5489 unsigned _BVTreeTraversalMicroSeconds;
5490 unsigned _fineCullingMicroSeconds;
5491 };
5492 struct RendererStats
5493 {
5494 unsigned _renderedTriangles;
5495 unsigned _renderedTrianglesShadow;
5496 unsigned _renderedMeshes;
5497 unsigned _renderedMeshesShadow;
5498 unsigned _sceneRenderingCPUMicroSeconds;
5499 unsigned _shadowMapRenderCPUMicroSeconds;
5500 unsigned _sceneMeshGroupingMicroSeconds;
5501 unsigned _shadowMapGroupingMicroSeconds;
5502 unsigned _rendererIdleTimeMicroSeconds;
5503 CullingStats _cullStats;
5504 CullingStats _cullStatsSM;
5505 };
5506
5507 auto const & stats() const { return _stats; }
5508#endif
5509 Renderer(GraphicsSettings * gs, RenderContext& rc) : _rc(rc), _gs(gs)
5510 {
5511 _mainRendertarget = std::unique_ptr<Rendertarget>(rc.createRendertarget());
5512 onResize(_viewPortSize);
5513 _blurredCircleTexture = _rc.createTexture("assets/circle.png");
5514 _blurredCircleTexture2 = _rc.createTexture("assets/circle2.png");
5515 }
5516 virtual ~Renderer()
5517 {
5518 delete _BVTreeStatic;
5519 _rc.deleteTexture(_blurredCircleTexture);
5520 _rc.deleteTexture(_blurredCircleTexture2);
5521 std::cout << "~Renderer()" << std::endl;
5522 _skydomeRenderable = nullptr;
5523 if (_shaderCache.size() || _shaderDescCache.size() || _materialDescCache.size() || _textureCache.size() || _meshCache.size()) {
5524 std::cout << "Error: Potential space leak detected!" << std::endl;
5525 std::cout << "Num shader descriptions:" << _shaderDescCache.size() << std::endl;
5526 std::cout << "Num material descriptions:" << _materialDescCache.size() << std::endl;
5527 std::cout << "Num shaders:" << _shaderCache.size() << std::endl;
5528 std::cout << "Num textures:" << _textureCache.size() << std::endl;
5529 std::cout << "Num meshes:" << _meshCache.size() << std::endl;
5530 abort();
5531 }
5532 }
5533 virtual unsigned getID() override
5534 {
5535 return 2;
5536 }
5537 virtual const char* getName() override
5538 {
5539 return "Renderer";
5540 }
5541 virtual void normalMappingChanged(GraphicsSettings const * gs) override
5542 {
5543 }
5544 virtual void depthOfFieldChanged(GraphicsSettings const * gs) override
5545 {
5546 for (unsigned i = 0; i < _rt._dofBuffer.size(); i++) {
5547 _rt._dofBuffer[i] = nullptr;
5548 _dofRendertargets[i] = nullptr;
5549 }
5550 if (gs->depthOfField()) {
5551 for (unsigned i = 0; i < _rt._dofBuffer.size(); i++) {
5552 _rt._dofBuffer[i] = _rc.createRenderToTexture(_viewPortSize * gs->depthOfFieldScaleFactor(), Texture::TexFilter::LINEAR);
5553 std::vector<std::shared_ptr<Texture>> color_attachments = { _rt._dofBuffer[i] };
5554 _dofRendertargets[i] = std::shared_ptr<Rendertarget>(_rc.createRendertarget(color_attachments, nullptr));
5555 }
5556 _rc.createBlurShader(*gs);
5557 }
5558 compositingChanged(gs);
5559 }
5560 virtual void bloomChanged(GraphicsSettings const * gs) override
5561 {
5562 _bloomRendertargets.clear();
5563 _rt._bloomTextures.clear();
5564 if (_gs->bloom()) {
5565 _rt._bloomTextures.resize(_gs->bloomSteps());
5566 _bloomRendertargets.resize(_gs->bloomSteps());
5567 for (unsigned i = 0; i < _gs->bloomSteps(); i++) {
5568 for (unsigned j = 0; j < 2; j++) {
5569 _rt._bloomTextures[i][j] = _rc.createRenderToTexture(_viewPortSize * (std::pow(gs->bloomScaleFactor(), static_cast<float>(i + 1))), Texture::TexFilter::LINEAR);
5570 std::vector<std::shared_ptr<Texture>> color_attachments = { _rt._bloomTextures[i][j] };
5571 _bloomRendertargets[i][j] = std::shared_ptr<Rendertarget>(_rc.createRendertarget(color_attachments, nullptr));
5572 }
5573 }
5574 _rc.createBrightnessShader(*gs);
5575 }
5576 compositingChanged(gs);
5577 }
5578 virtual void screenSpaceReflectionsChanged(GraphicsSettings const * gs) override
5579 {
5580 std::vector<std::shared_ptr<Texture>> color_attachments = { _rt._lightingBuffer };
5581 if (gs->screenSpaceReflections()) {
5582 _rc.createScreenSpaceReflectionsShader(*gs);
5583 _rt._lightingBufferCopy = std::shared_ptr<Texture>(_rt._lightingBuffer->copy());
5584 _rt._viewSpaceNormals = _rc.createRenderToTexture(_viewPortSize, Texture::TexFilter::NEAREST);
5585 color_attachments.push_back(_rt._viewSpaceNormals);
5586 std::vector<std::shared_ptr<Texture>> color_attachments_ssr = { _rt._lightingBuffer };
5587 _ssrRendertarget = std::unique_ptr<Rendertarget>(_rc.createRendertarget(color_attachments_ssr, nullptr));
5588 }
5589 else {
5590 _rt._lightingBufferCopy = nullptr;
5591 _rt._viewSpaceNormals = nullptr;
5592 _ssrRendertarget = nullptr;
5593 }
5594 _mainRendertarget = std::unique_ptr<Rendertarget>(_rc.createRendertarget(color_attachments, _rt._depthBuffer));
5595 }
5596 virtual void shadowsChanged(GraphicsSettings const * gs) override
5597 {
5598 _shadowMapping = gs->shadows() || gs->shadowsPCF() || gs->softShadows();
5599 _rt._shadowMap = _shadowMapping ? _rc.createShadowmap(*_gs) : nullptr;
5600 _shadowRendertargets.clear();
5601 if (_rt._shadowMap) {
5602 for (int i = 0; i < static_cast<int>(_gs->numFrustumSplits()); i++) {
5603 _shadowRendertargets.push_back(std::unique_ptr<Rendertarget>(_rc.createRendertarget({}, _rt._shadowMap, i)));
5604 }
5605 }
5606 }
5607 virtual void shadowMapSizeChanged(GraphicsSettings const * gs) override
5608 {
5609 if (_rt._shadowMap) {
5610 _rc.resizeShadowmap(*_rt._shadowMap, *_gs);
5611 }
5612 }
5613 virtual void compositingChanged(GraphicsSettings const * gs) override
5614 {
5615 if (gs->postProcessingEnabled()) {
5616 _rc.createCompositeShader(*_gs);
5617 }
5618 }
5619 virtual void gammaChanged(GraphicsSettings const * gs) override
5620 {
5621 compositingChanged(gs);
5622 }
5623 virtual void anisotropyChanged(GraphicsSettings const * gs) override
5624 {
5625 _rc.setAnisotropy(gs->getAnisotropy());
5626 }
5627 virtual void godRaysChanged(GraphicsSettings const * gs) override
5628 {
5629 if (gs->godRays()) {
5630 _rt._godRayBuffer = _rc.createRenderToTexture(_viewPortSize * gs->godRayScale(), Texture::TexFilter::LINEAR);
5631 std::vector<std::shared_ptr<Texture>> color_attachments = { _rt._godRayBuffer };
5632 _godRayRendertarget = std::unique_ptr<Rendertarget>(_rc.createRendertarget(color_attachments, nullptr));
5633 _rc.createGodRayShader(*gs);
5634 }
5635 else {
5636 _rt._godRayBuffer = nullptr;
5637 _godRayRendertarget = nullptr;
5638 }
5639 compositingChanged(gs);
5640 }
5641 virtual void fogChanged(GraphicsSettings const * gs) override
5642 {
5643 }
5644 auto updateBounds(Primitive* p)
5645 {
5646 _sceneBounds.unify(p->bv());
5647 }
5648 auto updateBounds(std::vector<Primitive*> const & primitives)
5649 {
5650 for (auto const & p : primitives) {
5651 _sceneBounds.unify(p->bv());
5652 }
5653 }
5654 auto setSkydome(std::shared_ptr<SkydomeRenderable> const & sdr)
5655 {
5656 _skydomeRenderable = sdr;
5657 }
5658 auto const & skydome() const
5659 {
5660 return _skydomeRenderable;
5661 }
5662 auto setCamera(std::shared_ptr<Camera> const & camera)
5663 {
5664 _camera = camera;
5665 }
5666 auto setDirectionalLight(std::shared_ptr<DirectionalLight> const & dl)
5667 {
5668 _directionalLight = dl;
5669 }
5670 auto ndcNear(Vec2 const & ndc) const
5671 {
5672 return ndc.appendMinusOne();
5673 }
5674 auto ndcFar(Vec2 const & ndc) const
5675 {
5676 return ndc.appendOne();
5677 }
5678 auto rayFromNdc(Vec2 const & ndc) const
5679 {
5680 auto vp_inverse = _camera->viewMatrixInverse() * inverse(_gsp._projectionMatrix);
5681 auto ray_near_world = (vp_inverse * ndcNear(ndc)).toCartesian();
5682 return Ray(ray_near_world, (vp_inverse * ndcFar(ndc)).toCartesian() - ray_near_world);
5683 }
5684 auto rayFromUV(Vec2 const & uv) const
5685 {
5686 return rayFromNdc(uv.UVToNDC());
5687 }
5688 auto uvFromWindowPos(Vec2 const & window_pos) const
5689 {
5690 return Vec2(window_pos.at<0>() / _viewPortSize.at<0>(),
5691 static_cast<Type>(1) - window_pos.at<1>() / _viewPortSize.at<1>());
5692 }
5693 auto ray(Vec2 const & window_pos) const
5694 {
5695 return rayFromUV(uvFromWindowPos(window_pos));
5696 }
5697 auto const & camParams() const
5698 {
5699 return _camera->params();
5700 }
5701 auto const & viewMatrixOrtho() const
5702 {
5703 return _gsp._viewMatrixOrtho;
5704 }
5705 auto const & viewMatrix() const
5706 {
5707 return _gsp._viewMatrix;
5708 }
5709 virtual bool update() override
5710 {
5711#if RENDERER_STATS
5712 _stats = {};
5713#endif
5714 _multiThreadedCulling = _gs->multithreadedCulling() && _shadowMapping;
5715 _renderListScene = _multiThreadedCulling ? &_renderListAsync : &_renderList;
5716 _rc.beginFrame();
5717 _gsp._camPosworld = &_camera->pos();
5718 _gsp._viewMatrix = _camera->viewMatrix();
5719 _gsp._projectionMatrix = MathHelpers::projectionMatrixPerspective<Type>(_camera->params()._fovDegrees, _viewPortSize.aspectRatio(), _camera->params()._near, _camera->params()._far);
5720 _gsp._viewMatrixOrtho = _camera->viewMatrixOrtho();
5721 _vpScene = _gsp._projectionMatrix * _gsp._viewMatrix;
5722 _rc.setDepthTestEnabled(true);
5723 _rc.setFaceCullingEnabled(true);
5724 _rc.setCullMode(RenderContext::CullMode::FRONT);
5725 _rc.setDepthFunc(RenderContext::DepthFunc::LEQUAL);
5726 _rc.setDepthWriteEnabled(true);
5727 _gsp._lightDirWorld = &_directionalLight->direction();
5728 _gsp._lightIntensity = &_directionalLight->intensity();
5729 _gsp._time = _gameTimer->timeSeconds();
5730 _gsp._exposure = _gs->exposure();
5731 _gsp._gamma = _gs->gamma();
5732 _gsp._fogStartEnd = &_gs->fogStartEnd();
5733 _gsp._fogColor = &_gs->fogColor();
5734 std::future<void> async;
5735 auto cull_vp = _gsp._projectionMatrix * (*_cullCamera)->viewMatrix();
5736 if (_multiThreadedCulling) {
5737 async = std::async(std::launch::async, [this, cull_vp]() {
5738 _stats._cullStats = cullMeshes(cull_vp, **_cullCamera, *_renderListScene, _fullyVisibleMeshesAsync);
5739 });
5740 }
5741 if (_shadowMapping) {
5742 renderShadowMap();
5743 }
5744 if (_multiThreadedCulling) {
5745 {
5746#if RENDERER_STATS
5747 Timing timing;
5748#endif
5749 async.get();
5750#if RENDERER_STATS
5751 _stats._rendererIdleTimeMicroSeconds = timing.duration<std::chrono::microseconds>();
5752#endif
5753 }
5754 selectLod(*_renderListScene, **_cullCamera, cull_vp);
5755 }
5756 else {
5757 _stats._cullStats = cullMeshes(cull_vp, **_cullCamera, *_renderListScene, _fullyVisibleMeshes);
5758 selectLod(*_renderListScene, **_cullCamera, cull_vp);
5759 }
5760 _rc.setViewport(_viewPortSize);
5761 _gsp._VP = &_vpScene;
5762 _mainRendertarget ? _mainRendertarget->bind() : _rc.bindBackbuffer(_defaultRenderTarget);
5763 _rc.clearRendertarget(_skydomeRenderable == nullptr, !_gs->depthPrepassEnabled(), false);
5764 if (_rt._shadowMap) {
5765 _rc.bindShadowmap(*_rt._shadowMap);
5766 }
5767 renderScene();
5768 _rc.setCullMode(RenderContext::CullMode::BACK);
5769 if (_skydomeRenderable) {
5770 auto skydome_vp = _gsp._projectionMatrix * _camera->viewMatrixOrtho();
5771 _rc.renderSkydome(skydome_vp, *_skydomeRenderable->storage());
5772 }
5773 if (_debugTriangle) {
5774 _rc.setCullMode(RenderContext::CullMode::FRONT);
5775 _rc.renderDebugTriangle(_debugTriangle, _vpScene, Vector<3, Type>(static_cast<Type>(0), static_cast<Type>(1), static_cast<Type>(1)));
5776 _rc.setCullMode(RenderContext::CullMode::BACK);
5777 }
5778 if (_gs->autoExposure()) {
5779 _rt._lightingBuffer->generateMipmap();
5780 }
5781 auto light_pos_ndc = (_vpScene * Vector<4, Type>(*_gsp._camPosworld + *_gsp._lightDirWorld * -_camera->params()._far, static_cast<Type>(1))).toCartesian().reduce<>();
5782 _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));
5783 _rc.setDepthTestEnabled(false);
5784 if (_debugCamera) {
5785 _rc.renderDebugFrustum(_gsp._projectionMatrix * _debugCamera->viewMatrix(), _vpScene);
5786 }
5787 if (_ssrRendertarget) {
5788 _rt._depthBuffer->setTexMinFilter(Texture::TexFilter::LINEAR_MIPMAP_LINEAR);
5789 _rt._lightingBuffer->copyAssign(_rt._lightingBufferCopy.get());
5790 _rt._lightingBufferCopy->setTexMinFilter(Texture::TexFilter::LINEAR);
5791 _ssrRendertarget->bind();
5792 _rc.ssr(*_rt._lightingBuffer, *_rt._viewSpaceNormals, *_rt._depthBuffer, _gsp._projectionMatrix, Vector<4, Type>(_gs->SSRBlendWeight()), *_rt._lightingBufferCopy);
5793 _rt._depthBuffer->setTexMinFilter(Texture::TexFilter::NEAREST);
5794 }
5795 if (_gs->depthOfField()) {
5796 _rc.setViewport(_viewPortSize * _gs->depthOfFieldScaleFactor());
5797 _rt._lightingBuffer->setTexMinFilter(Texture::TexFilter::LINEAR);
5798 _rc.separableBlur(*_rt._lightingBuffer, _dofRendertargets);
5799 _rt._lightingBuffer->setTexMinFilter(Texture::TexFilter::NEAREST);
5800 _rc.setViewport(_viewPortSize);
5801 }
5802 if (_gs->bloom()) {
5803 _rc.setViewport(_viewPortSize * _gs->bloomScaleFactor());
5804 _bloomRendertargets[0][0]->bind();
5805 _rt._lightingBuffer->setTexMinFilter(Texture::TexFilter::LINEAR);
5806 _rc.renderBrightPass(*_rt._lightingBuffer);
5807 _rc.separableBlur(*_rt._bloomTextures[0][0], _bloomRendertargets[0]);
5808 for (unsigned i = 1; i < _gs->bloomSteps(); i++) {
5809 _rc.setViewport(_viewPortSize * std::powf(_gs->bloomScaleFactor(), static_cast<float>(i + 1)));
5810 _rc.separableBlur(*_rt._bloomTextures[i - 1][0], _bloomRendertargets[i]);
5811 }
5812 for (int i = static_cast<int>(_gs->bloomSteps()) - 2; i >= 0; i--) {
5813 _rc.setViewport(_viewPortSize * std::powf(_gs->bloomScaleFactor(), static_cast<float>(i + 1)));
5814 _bloomRendertargets[i][0]->bind();
5815 _rc.additiveBlend(*_rt._bloomTextures[i + 1][0]);
5816 }
5817 _rc.setViewport(_viewPortSize);
5818 }
5819 Vector<3, Type> god_ray_intensity(0);
5820 if (_gs->godRays() && light_pos_ndc >= static_cast<Type>(-1) && light_pos_ndc <= static_cast<Type>(1)) {
5821 auto light_pos_uv = light_pos_ndc.NDCToUV();
5822 _rc.setViewport(_viewPortSize * _gs->godRayScale());
5823 _rt._lightingBuffer->setTexMinFilter(Texture::TexFilter::LINEAR);
5824 _rt._depthBuffer->setTexMinFilter(Texture::TexFilter::LINEAR);
5825 _godRayRendertarget->bind();
5826 _rc.renderGodRays(*_rt._depthBuffer, *_rt._lightingBuffer, light_pos_uv);
5827 _rt._depthBuffer->setTexMinFilter(Texture::TexFilter::NEAREST);
5828 _rc.setViewport(_viewPortSize);
5829 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()));
5830 }
5831 _rc.bindBackbuffer(_defaultRenderTarget);
5832 _gs->autoExposure() ? _rt._lightingBuffer->setTexMinFilter(Texture::TexFilter::LINEAR_MIPMAP_LINEAR) : _rt._lightingBuffer->setTexMinFilter(Texture::TexFilter::NEAREST);
5833 bool render_god_rays = _godRayRendertarget && god_ray_intensity > static_cast<Type>(0);
5834 render_god_rays ? _rc.bindShader(&_rc.compositeShaderWithGodRays()) : _rc.bindShader(&_rc.compositeShader());
5835 _rc.setupCompositing(*_rt._lightingBuffer);
5836 if (_gs->depthOfField()) {
5837 _rc.setupDepthOfField(_gsp, *_rt._dofBuffer[0], *_rt._depthBuffer, _gs->dofNearCenterFar());
5838 }
5839 if (render_god_rays) {
5840 _rc.setupGodRays(god_ray_intensity, *_rt._godRayBuffer);
5841 }
5842 if (_gs->bloom()) {
5843 _rc.setupBloom(*_rt._bloomTextures[0][0]);
5844 }
5845 if (_gs->autoExposure()) {
5846 _rc.setupAutoExposure(*_rt._lightingBuffer);
5847 }
5848 _rc.composite();
5849 if (_gs->renderCrossHair()) {
5850 _rc.render2DBillboard(_mousePosNDC, Vector<2, Type>(0.025) * Vector<2, Type>(static_cast<Type>(1), aspectRatio()), *_blurredCircleTexture2,
5851 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));
5852 }
5853 _rc.endFrame();
5854 return true;
5855 }
5856 void onResize(Vec2u const & window_size)
5857 {
5858 _viewPortSize = window_size;
5859 _rt._lightingBuffer = _gs->autoExposure() ? _rc.createRenderToTexture(_viewPortSize, Texture::TexFilter::LINEAR_MIPMAP_LINEAR) : _rc.createRenderToTexture(_viewPortSize, Texture::TexFilter::NEAREST);
5860 _rt._depthBuffer = _rc.createDepthbuffer(_viewPortSize);
5861 godRaysChanged(_gs);
5862 depthOfFieldChanged(_gs);
5863 bloomChanged(_gs);
5864 screenSpaceReflectionsChanged(_gs);
5865 }
5866 Type aspectRatio() const
5867 {
5868 return _viewPortSize.aspectRatio();
5869 }
5870 auto setDefaultRendertarget(unsigned const & rt) { _defaultRenderTarget = rt; }
5871 auto* renderContext() { return &_rc; }
5872 auto const & viewProjectionMatrix() const
5873 {
5874 return _vpScene;
5875 }
5876 auto findNearestPrimitive(Ray const & ray)
5877 {
5878 return findNearestPrimitive(ray, *_BVTreeStatic);
5879 }
5880 IntersectRayResult<Type, Matrix> findNearestPrimitive(Ray const & ray, BVTree& BVTree)
5881 {
5882 IntersectRayResult<Type, Matrix> res(camParams()._far);
5883 if (_recursiveRayTrace) {
5884 BVTree.findNearestNested(ray, res, [&ray, &res](Primitive* mr) {
5885 mr->nestedBVTree()->findNearestPrecise(Ray(ray, inverse(*mr->modelMatrix())), ray, mr->modelMatrix(), res);
5886 });
5887 }
5888 else {
5889 StackTrivial<BVTreeNode::NodePtr> stack;
5890 stack.reserve(16u);
5891 StackTrivial<BVTreeNode::NodePtr> s;
5892 s.reserve(16u);
5893 BVTree.findNearestNested(ray, res, stack, [&ray, &res, &s](Primitive* mr) {
5894 mr->nestedBVTree()->findNearestPrecise(Ray(ray, inverse(*mr->modelMatrix())), ray, mr->modelMatrix(), res, s);
5895 });
5896 }
5897 return res;
5898 }
5899 auto findNearestPrimitive(Ray const & ray, BVTree& BVTree, Primitive*& parent)
5900 {
5901 IntersectRayResult<Type, Matrix> res(camParams()._far);
5902 BVTree.findNearestNested(ray, res, [&ray, &res, &parent](Primitive* mr) {
5903 mr->nestedBVTree()->findNearestPrecise(Ray(ray, inverse(*mr->modelMatrix())), ray, mr->modelMatrix(), mr, res, parent);
5904 });
5905 return res;
5906 }
5907 BVTree*& staticBVTree()
5908 {
5909 return _BVTreeStatic;
5910 }
5911 BV const & sceneBounds() const
5912 {
5913 return _sceneBounds;
5914 }
5915 auto createMaterialDesc(std::shared_ptr<Material> const & material)
5916 {
5917 auto ret = _materialDescCache.getOrCreate(material, [this, material]() {
5918 return _rc.createMaterialDesc(material, *_gs, &_textureCache, &_shaderDescCache, &_shaderCache);
5919 }, [this](MaterialDesc* material_desc) {
5920 delete material_desc;
5921 });
5922 if (!std::get<1>(ret)) { // Only add to listeners if it was not in the cache
5923 _gs->addListener(std::get<0>(ret));
5924 }
5925 return std::get<0>(ret);
5926 }
5927 auto addMesh(std::shared_ptr<Mesh> const & mesh)
5928 {
5929 return std::get<0>(_meshCache.getOrCreate(mesh, [this, mesh]() {
5930 return _rc.createMeshData(*mesh);
5931 }, [this](GPUMeshData* gmd) {
5932 delete gmd;
5933 }));
5934 }
5935 auto setDebugCamera(std::shared_ptr<Camera> const & camera)
5936 {
5937 _debugCamera = camera;
5938 _cullCamera = _debugCamera ? &_debugCamera : &_camera;
5939 }
5940 auto const & debugCamera() const
5941 {
5942 return _debugCamera;
5943 }
5944 auto buildBVTree(Primitive** const begin, Primitive** const end)
5945 {
5946 std::cout << "Mesh renderables:" << StringHelper::formatNumber(static_cast<unsigned>(end - begin)) << std::endl;
5947 if (!(end - begin)) {
5948 throw std::exception("No meshes were added to the renderer.");
5949 }
5950 if (!_camera) {
5951 throw std::exception("No camera was added to the renderer.");
5952 }
5953 if (!_directionalLight) {
5954 throw std::exception("No directional light was added to the renderer.");
5955 }
5956 Timing timing;
5957 _BVTreeStatic = new BVTree(begin, end);
5958 std::cout << "BVTree construction took " << timing.duration<std::chrono::milliseconds>() << " milliseconds." << std::endl;
5959 std::cout << "BVTree takes " << _BVTreeStatic->sizeInMegaBytes() << " MB memory" << std::endl;
5960 std::cout << "Scene bounds:" << _BVTreeStatic->bv() << std::endl;
5961 unsigned internal_nodes, leaf_nodes;
5962 _BVTreeStatic->countNodes(internal_nodes, leaf_nodes);
5963 std::cout << "BVTree internal nodes:" << StringHelper::formatNumber(internal_nodes) << std::endl;
5964 std::cout << "BVTree leaf nodes:" << StringHelper::formatNumber(leaf_nodes) << std::endl;
5965 unsigned triangles = 0;
5966 for (auto ptr = begin; ptr != end;) {
5967 triangles += (*ptr++)->numTriangles();
5968 }
5969 std::cout << "Triangles:" << StringHelper::formatNumber(triangles) << std::endl;
5970 size_t size_in_bytes = 0;
5971 for (auto ptr = begin; ptr != end;) {
5972 size_in_bytes += (*ptr++)->sizeInBytes();
5973 }
5974 std::cout << "Renderables take " << static_cast<float>(size_in_bytes) / 1024.f / 1024.f << " MB memory" << std::endl;
5975
5976 std::cout << "BVTree internal node takes " << sizeof(BVTreeInternalNode) << " bytes memory" << std::endl;
5977 std::cout << "BVTree leaf node takes " << sizeof(BVTreeLeafNode) << " bytes memory" << std::endl;
5978 }
5979 auto const & viewPortSize() const
5980 {
5981 return _viewPortSize;
5982 }
5983 auto setDebugTriangle(Vector<4, Type> const * triangle)
5984 {
5985 _debugTriangle = triangle;
5986 }
5987 auto setMousePos(Vector<2, Type> const & window_pos)
5988 {
5989 auto uv = window_pos / _viewPortSize;
5990 uv.at<1>() = static_cast<Type>(1) - uv.at<1>();
5991 _mousePosNDC = uv.UVToNDC();
5992 }
5993 auto toggleRecursiveRayTrace()
5994 {
5995 _recursiveRayTrace = !_recursiveRayTrace;
5996 }
5997 private:
5998 RenderContext& _rc;
5999 std::vector<CsmSplit> _splits;
6000 GlobalShaderParams _gsp;
6001 Vector<2, Type> _viewPortSize = Vector<2, Type>( static_cast<Type>(640), static_cast<Type>(480));
6002 std::shared_ptr<Camera> _camera;
6003 std::shared_ptr<DirectionalLight> _directionalLight;
6004 std::shared_ptr<Camera> _debugCamera;
6005 std::shared_ptr<Camera>* _cullCamera = &_camera;
6006 GraphicsSettings * const _gs;
6007 std::array<std::shared_ptr<Rendertarget>, 2> _dofRendertargets;
6008 std::vector<std::array<std::shared_ptr<Rendertarget>, 2u>> _bloomRendertargets;
6009 std::unique_ptr<Rendertarget> _godRayRendertarget;
6010 std::unique_ptr<Rendertarget> _mainRendertarget;
6011 std::unique_ptr<Rendertarget> _ssrRendertarget;
6012 std::vector<std::shared_ptr<Rendertarget>> _shadowRendertargets;
6013 Rendertargets _rt;
6014 StackTrivial<Matrix> _vpLightVolume;
6015 unsigned _defaultRenderTarget = 0;
6016 Matrix _vpScene;
6017 bool _shadowMapping;
6018 bool _multiThreadedCulling;
6019 BV _sceneBounds;
6020 Vec2f _mousePosNDC;
6021 Texture* _blurredCircleTexture;
6022 Texture* _blurredCircleTexture2;
6023#if RENDERER_STATS
6024 RendererStats _stats;
6025#endif
6026 std::vector<MeshRenderablePtr> _meshRenderables;
6027 StackTrivial<Primitive*> _fullyVisibleMeshes;
6028 StackTrivial<Primitive*> _fullyVisibleMeshesAsync;
6029 RenderList _renderList;
6030 RenderList _renderListAsync;
6031 RenderList* _renderListScene;
6032 std::map<ShaderDesc const *, std::map<MaterialDesc const *, StackTrivial<MeshRenderable const*>>> _displayList;
6033 BVTree* _BVTreeStatic;
6034 PtrCache<std::string, Texture> _textureCache;
6035 PtrCache<std::string, Shader> _shaderCache;
6036 PtrCache<std::shared_ptr<Shader>, ShaderDesc> _shaderDescCache;
6037 MaterialDescCache _materialDescCache;
6038 MeshCache _meshCache;
6039 boost::object_pool<GPUMeshData> _meshPool;
6040 boost::object_pool<MaterialDesc> _materialDescPool;
6041 boost::object_pool<ShaderDesc> _shaderDescPool;
6042 std::shared_ptr<SkydomeRenderable> _skydomeRenderable;
6043 Vector<4, Type> const * _debugTriangle = nullptr;
6044 bool _recursiveRayTrace = true;
6045 void renderScene()
6046 {
6047#if RENDERER_STATS
6048 Timing timing;
6049#endif
6050 groupMeshes(_renderListScene->visibleMeshes());
6051#if RENDERER_STATS
6052 _stats._sceneMeshGroupingMicroSeconds = timing.duration<std::chrono::microseconds>();
6053 timing.start();
6054#endif
6055 auto stats = renderMeshes();
6056#if RENDERER_STATS
6057 _stats._renderedMeshes = stats._renderedMeshes;
6058 _stats._renderedTriangles = stats._renderedTriangles;
6059 _stats._sceneRenderingCPUMicroSeconds = timing.duration<std::chrono::microseconds>();
6060#endif
6061 }
6062 void renderShadowMap()
6063 {
6064 _gsp._worldToLight.clear();
6065 _gsp._worldToLight.grow(_gs->numFrustumSplits());
6066 _splits.resize(_gs->numFrustumSplits());
6067 for (auto & s : _splits) {
6068 s.renderlist().clear();
6069 }
6070 _directionalLight->csmSplits<Type>(aspectRatio(), (*_cullCamera)->params()._near, (*_cullCamera)->params()._far, (*_cullCamera)->params()._fovDegrees, ((*_cullCamera)->viewMatrixInverse()),
6071 static_cast<Type>(_gs->shadowMapSize()), _gsp._smFrustumSplits, _gs->numFrustumSplits(), _gs->frustumSplitLogAlpha(), _splits.data(), _gsp._worldToLight.begin());
6072 _rc.setDepthClampEnabled(true);
6073 _rc.enablePolygonOffset(_gs->shadowPolygonOffsetFactor(), _gs->shadowPolygonOffsetUnits());
6074 _rc.setViewport(Vec2u(_gs->shadowMapSize()));
6075 auto const * world_to_light = _gsp._worldToLight.begin();
6076 auto const * shadow_render_target = _shadowRendertargets.data();
6077 auto cp = (*_cullCamera)->cullingParams(frustumPlanes(Mat4f()), frustumVertices(Mat4f()));
6078 auto on_intersect_frustum = [&cp](Primitive* ptr, RenderList& rl) {
6079 ptr->addIfContributesAndVisible(cp, rl);
6080 };
6081 auto on_became_fully_visible = [&cp](Primitive* ptr, RenderList& rl) {
6082 ptr->addIfContributes(cp, rl);
6083 };
6084 auto on_render = [](Primitive* ptr, RenderList& rl) {
6085 ptr->add(rl);
6086 };
6087#if RENDERER_STATS
6088 Timing t;
6089#endif
6090 CsmTree ct(_splits.data(), _splits.data() + _splits.size(), _directionalLight->viewMatrix());
6091 ct.descendVisible(*_BVTreeStatic, cp, { on_intersect_frustum, on_became_fully_visible, on_render });
6092#if RENDERER_STATS
6093 _stats._cullStatsSM._BVTreeTraversalMicroSeconds += t.duration<std::chrono::microseconds>();
6094#endif
6095 for (auto& s : _splits) {
6096 {
6097 selectLod(s.renderlist(), **_cullCamera, s.vp());
6098 }
6099#if RENDERER_STATS
6100 Timing timing;
6101#endif
6102 groupMeshes<true>(s.renderlist().visibleMeshes());
6103#if RENDERER_STATS
6104 _stats._shadowMapGroupingMicroSeconds += timing.duration<std::chrono::microseconds>();
6105 timing.start();
6106#endif
6107 (*shadow_render_target++)->bind();
6108 _rc.clearRendertarget(false, true, false);
6109 _gsp._VP = world_to_light++;
6110 auto const stats = renderMeshes<true>();
6111#if RENDERER_STATS
6112 _stats._shadowMapRenderCPUMicroSeconds += timing.duration<std::chrono::microseconds>();
6113 _stats._renderedMeshesShadow += stats._renderedMeshes;
6114 _stats._renderedTrianglesShadow += stats._renderedTriangles;
6115#endif
6116 }
6117 _rc.disablePolygonOffset();
6118 // _gsp._smFrustumSplits = &_gs->frustumSplits();
6119 _rc.setDepthClampEnabled(false);
6120 _gsp._viewMatrixThirdRow = (*_cullCamera)->viewMatrix().row<2>();
6121 }
6122 FrustumPlanes<3u, Type> frustumPlanes(Matrix const & vp)
6123 {
6124 return FrustumPlanes<3u, Type>(vp);
6125 }
6126 FrustumVertices<3u, Type> frustumVertices(Matrix const & vp)
6127 {
6128 return FrustumVertices<3u, Type>(inverse(vp));
6129 }
6130 CullingStats cullMeshes(Matrix const & vp, Camera camera,
6131 RenderList& renderlist, StackTrivial<Primitive*>& fully_visible_meshes)
6132 {
6133 renderlist.clear();
6134 fully_visible_meshes.clear();
6135 auto cp = camera.cullingParams(frustumPlanes(vp), frustumVertices(vp));
6136 CullingStats stats;
6137 {
6138#if RENDERER_STATS
6139 Timing timing;
6140#endif
6141 auto on_intersect_frustum = [&cp, &renderlist](Primitive* ptr) {
6142 ptr->addIfContributesAndVisible(cp, renderlist);
6143 };
6144 auto on_became_fully_visible = [&cp, &fully_visible_meshes](Primitive* ptr) {
6145 fully_visible_meshes.push_back(ptr);
6146 };
6147 auto on_render = [&renderlist](Primitive* ptr) {
6148 ptr->add(renderlist);
6149 };
6150 _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);
6151#if RENDERER_STATS
6152 stats._BVTreeTraversalMicroSeconds = timing.duration<std::chrono::microseconds>();
6153#endif
6154 }
6155#if RENDERER_STATS
6156 Timing timing;
6157#endif
6158 auto num_threads = std::thread::hardware_concurrency();
6159 auto num_meshes = static_cast<unsigned>(fully_visible_meshes.size());
6160 auto elements_per_thread = MathHelpers::elementsPerThread(num_meshes, num_threads);
6161 if (_gs->multithreadedDetailCulling() && elements_per_thread >= 256u) {
6162 std::vector<std::future<RenderList>> futures;
6163 futures.reserve(num_threads);
6164 auto* begin = fully_visible_meshes.begin();
6165 for (unsigned i = 0; i < num_threads; i++) {
6166 auto* end = std::min(begin + elements_per_thread, fully_visible_meshes.end());
6167 futures.push_back(std::async(std::launch::async, [begin, end, &cp]() {
6168 RenderList renderlist;
6169 renderlist.reserve(end - begin);
6170 for (auto* ptr = begin; ptr != end;) {
6171 (*ptr++)->addIfContributesUnchecked(cp, renderlist);
6172 }
6173 return renderlist;
6174 }));
6175 begin += elements_per_thread;
6176 }
6177 for (auto& f : futures) {
6178 renderlist.append(f.get());
6179 }
6180 }
6181 else {
6182 for (auto* ptr = fully_visible_meshes.begin(); ptr != fully_visible_meshes.end();) {
6183 (*ptr++)->addIfContributes(cp, renderlist);
6184 }
6185 }
6186#if RENDERER_STATS
6187 stats._fineCullingMicroSeconds = timing.duration<std::chrono::microseconds>();
6188#endif
6189 return stats;
6190 }
6191 void selectLod(RenderList const & renderlist, Camera const & camera, Mat4f const & vp)
6192 {
6193 if (renderlist.cpuLodList().size()) {
6194 auto cp = camera.cullingParams(frustumPlanes(vp), frustumVertices(vp));
6195 for (const auto& m : renderlist.cpuLodList()) {
6196 m->selectLod(cp);
6197 }
6198 }
6199 }
6200 template<bool depth = false>
6201 void groupMeshes(MeshRenderable const * const * begin, MeshRenderable const * const * const end)
6202 {
6203 while (begin != end) {
6204 _displayList[depth ? (*begin)->shaderDescDepth()->get() : (*begin)->shaderDesc()->get()][(*begin)->materialDesc()].push_back(*begin);
6205 ++begin;
6206 }
6207 }
6208 template<bool depth = false>
6209 void groupMeshes(typename RenderList::Stack const & meshes)
6210 {
6211 groupMeshes<depth>(meshes.begin(), meshes.end());
6212 }
6213 struct MeshRenderStats
6214 {
6215 unsigned _renderedTriangles;
6216 unsigned _renderedMeshes;
6217 };
6218 template<bool depth = false>
6219 auto renderMeshes()
6220 {
6221 MeshRenderStats stats = {};
6222 for (auto const & shader : _displayList) {
6223 shader.first->setup(_gsp, _rc);
6224 for (auto const & material : shader.second) {
6225 depth ? material.first->setupDepth(*_rc.activeShader()) : material.first->setup(*_rc.activeShader());
6226 for (auto const & mr : material.second) {
6227 depth ? mr->renderDepth(_rc) : mr->render(_rc);
6228#if RENDERER_STATS
6229 stats._renderedTriangles += mr->numTriangles();
6230 stats._renderedMeshes += mr->numMeshes();
6231#endif
6232 }
6233 }
6234 }
6235 _displayList.clear();
6236 return stats;
6237 }
6238 };
6239}
6240
6241#endif
6242#include <physics/PhysicsCameraController.h>
6243#include <GameTimer.h>
6244#include <Camera.h>
6245#include <iostream>
6246#include <BVTree.h>
6247#include <Triangle.h>
6248#include <set>
6249
6250namespace RT
6251{
6252 PhysicsCameraController::PhysicsCameraController(Camera* const & camera, BVTree*& BVTree) :
6253 _c(camera),
6254 _BVTree(BVTree)
6255 {
6256 }
6257 void PhysicsCameraController::updateSystem()
6258 {
6259 setDamping(DAMP_DEFAULT);
6260 _velocity += ((_acceleration + _gravity) * _dt);
6261 _velocity *= _damp;
6262 if (_collisions) {
6263 auto const v_constant = _velocity * _dt;
6264 auto v_inv = Vector(static_cast<Type>(1)) / v_constant;
6265 auto min_t_min = std::numeric_limits<Type>::max();
6266 Primitive const * nearest = nullptr;
6267 _BVTree->intersectNested(_c->collisionShape(), v_constant, v_inv, min_t_min, [this, &min_t_min, &nearest, &v_constant, &v_inv](Primitive const * imr) {
6268 boost::object_pool<Triangle> tri_pool;
6269 StackTrivial<Vertex> vertices;
6270 imr->transformedBVTree(tri_pool, vertices)->intersectPrimitives(_c->collisionShape(), v_constant, v_inv, min_t_min, nearest);
6271 setDamping(DAMP_INTERIOR);
6272 });
6273 if (nearest) {
6274 _c->setPosition(_c->pos() + v_constant * min_t_min);
6275 }
6276 else {
6277 _c->setPosition(_c->pos() + v_constant);
6278 }
6279 }
6280 else {
6281 _c->setPosition(_c->pos() + _velocity * _dt);
6282 }
6283 _angularVelocity += _angularAcceleration * _dt;
6284 _c->setEulerRadians(_c->eulerRadians() - _angularVelocity * _dt);
6285 _angularVelocity *= DAMP_DEFAULT;
6286 }
6287 unsigned PhysicsCameraController::getID()
6288 {
6289 return 0;
6290 }
6291 const char * PhysicsCameraController::getName()
6292 {
6293 return "PhysicsCameraController";
6294 }
6295 void PhysicsCameraController::setAcceleration(Vector const & dir, Type const & amount)
6296 {
6297 _acceleration = dir.length() > static_cast<Type>(0) ? normalize(dir) * amount : static_cast<Type>(0);
6298 }
6299 void PhysicsCameraController::setAngularAcceleration(Vector const & aa)
6300 {
6301 _angularAcceleration = aa;
6302 }
6303 Camera* const & PhysicsCameraController::getCamera() const
6304 {
6305 return _c;
6306 }
6307 void PhysicsCameraController::setCamera(Camera* const & camera)
6308 {
6309 _c = camera;
6310 }
6311 void PhysicsCameraController::setDamping(Type const & damping)
6312 {
6313 _damp = damping;
6314 }
6315 PhysicsCameraController::Vector const & PhysicsCameraController::gravity() const
6316 {
6317 return _gravity;
6318 }
6319 void PhysicsCameraController::setGravity(Vector const & gravity)
6320 {
6321 _gravity = gravity;
6322 }
6323 bool const & PhysicsCameraController::collisions() const
6324 {
6325 return _collisions;
6326 }
6327 void PhysicsCameraController::setCollisions(bool const & collisions)
6328 {
6329 _collisions = collisions;
6330 }
6331}
6332#include <bv_treeNodePool.h>
6333#include <StackTrivial.h>
6334#include <bv_treeInternalNode.h>
6335#include <bv_treeLeafNode.h>
6336
6337namespace RT
6338{
6339 bv_treeNodePool::bv_treeNodePool(size_t num_primitives)
6340 {
6341 auto const height = static_cast<size_t>(std::floor(log2(static_cast<double>(num_primitives))));
6342 auto const num_nodes = static_cast<size_t>(std::pow(2.0, static_cast<double>(height) + 1.0) - 1.0);
6343 auto num_internal_nodes = num_nodes - num_primitives;
6344 maximize<size_t>(32u, num_primitives);
6345 maximize<size_t>(32u, num_internal_nodes);
6346 _internalNodePool.set_next_size(num_internal_nodes);
6347 _leafNodePool.set_next_size(num_primitives);
6348 }
6349 bv_treeNode* bv_treeNodePool::createInternalNode(bv_treeNode::PrimitiveInfo* const begin, bv_treeNode::PrimitiveInfo* const end)
6350 {
6351 return new (_internalNodePool.malloc()) bv_treeInternalNode(begin, end, *this);
6352 }
6353 bv_treeNode* bv_treeNodePool::createLeafNode(Primitive* p)
6354 {
6355 return new (_leafNodePool.malloc()) bv_treeLeafNode(p);
6356 }
6357 bv_treeNode* bv_treeNodePool::createNode(bv_treeNode::PrimitiveInfo* const begin, bv_treeNode::PrimitiveInfo* const end)
6358 {
6359 return Algorithm::continueSplit(begin, end) ? createInternalNode(begin, end) : createLeafNode(begin->primitive());
6360 }
6361 bv_treeNode* bv_treeNodePool::createNode(StackTrivial<bv_treeNode::PrimitiveInfo>& infos)
6362 {
6363 return createNode(infos.begin(), infos.end());
6364 }
6365 void bv_treeNodePool::destroy(bv_treeLeafNode* node)
6366 {
6367 _leafNodePool.destroy(node);
6368 }
6369 void bv_treeNodePool::destroy(bv_treeInternalNode* node)
6370 {
6371 _internalNodePool.destroy(node);
6372 }
6373}
6374#include <BVTreeInternalNode.h>
6375#include <CullingParams.h>
6376#include <BVTreeNodePool.h>
6377#include <StackTrivial.h>
6378#include <BVTreeLeafNode.h>
6379#include <CsmInternalNode.h>
6380#include <CsmLeafNode.h>
6381
6382namespace RT
6383{
6384 void BVTreeInternalNode::init(PrimitiveInfo const * begin, PrimitiveInfo const * const end)
6385 {
6386 while (begin != end) {
6387 insert(*begin++);
6388 }
6389 }
6390 bool BVTreeInternalNode::contributes(CullingParams const & cp) const
6391 {
6392 return _bv.contributes(cp.pEye(), cp.alpha(), _maxSquaredSize);
6393 }
6394 bool BVTreeInternalNode::fullyContributes(CullingParams const & cp) const
6395 {
6396 return _bv.fullyContributes(cp.pEye(), cp.alpha(), _minSquaredSize);
6397 }
6398 IntersectResult BVTreeInternalNode::intersectFrustum(CullingParams const & cp) const
6399 {
6400 return IntersectionTests::intersectFrustum(_bv, cp.frustumPlanes(), cp.frustumVertices());
6401 }
6402 IntersectResult BVTreeInternalNode::intersectFrustum(CullingParams const & cp, IntersectedPlanes const & in, IntersectedPlanes& out) const
6403 {
6404 return IntersectionTests::intersectFrustum(_bv, cp.frustumPlanes(), cp.frustumVertices(), in, out);
6405 }
6406 ContribResult BVTreeInternalNode::computeContribution(CullingParams const & cp) const
6407 {
6408 return _bv.computeContribution(cp.pEye(), cp.alpha(), _minSquaredSize, _maxSquaredSize);
6409 }
6410 BVTreeInternalNode::BVTreeInternalNode(PrimitiveInfo* const begin, PrimitiveInfo* const end, BVTreeNodePool& np)
6411 : BVTreeNode(),
6412 _bv(begin->bv()),
6413 _minSquaredSize(begin->squaredSize()),
6414 _maxSquaredSize(begin->squaredSize())
6415 {
6416 init(begin + 1u, end);
6417 auto const axis = _bv.longestAxis();
6418 auto const bv_center = _bv.center(axis);
6419 auto* const mid = Algorithm::partitionForceSplit(begin, end, [&axis, &bv_center](PrimitiveInfo const & p) {
6420 return p.bv().center(axis) < bv_center;
6421 });
6422 _left = np.createNode(begin, mid);
6423 _right = np.createNode(mid, end);
6424 }
6425 void BVTreeInternalNode::recurseVisible(CullingParams const & cp, Callback const & cb) const
6426 {
6427 _left->cullVisiblePrimitives(cp, cb);
6428 _right->cullVisiblePrimitives(cp, cb);
6429 }
6430 void BVTreeInternalNode::recurseVisible(CullingParams const & cp, IntersectedPlanes const & ip, Callback const & cb) const
6431 {
6432 _left->cullVisiblePrimitives(cp, ip, cb);
6433 _right->cullVisiblePrimitives(cp, ip, cb);
6434 }
6435 void BVTreeInternalNode::recurseContributing(CullingParams const & cp, Callback const & cb) const
6436 {
6437 _left->cullContributingPrimitives(cp, cb);
6438 _right->cullContributingPrimitives(cp, cb);
6439 }
6440 void BVTreeInternalNode::recurseAll(Callback::CbFunc const & on_render) const
6441 {
6442 _left->cullAllPrimitives(on_render);
6443 _right->cullAllPrimitives(on_render);
6444 }
6445 void BVTreeInternalNode::cullVisiblePrimitives(CullingParams const & cp, Callback const & cb) const
6446 {
6447 if (contributes(cp)) {
6448 if (auto const result = intersectFrustum(cp)) {
6449 result.intersecting() ? recurseVisible(cp, cb) : recurseContributing(cp, cb);
6450 }
6451 }
6452 }
6453 void BVTreeInternalNode::cullVisiblePrimitives(CullingParams const & cp, IntersectedPlanes const & in, Callback const & cb) const
6454 {
6455 if (contributes(cp)) {
6456 IntersectedPlanes out;
6457 if (auto const result = intersectFrustum(cp, in, out)) {
6458 result.intersecting() ? recurseVisible(cp, out, cb) : recurseContributing(cp, cb);
6459 }
6460 }
6461 }
6462 void BVTreeInternalNode::cullContributingPrimitives(CullingParams const & cp, Callback const & cb) const
6463 {
6464 if (auto const result = computeContribution(cp)) {
6465 result.intersecting() ? recurseContributing(cp, cb) : recurseAll(cb.onRender());
6466 }
6467 }
6468 void BVTreeInternalNode::cullAllPrimitives(Callback::CbFunc const & on_render) const
6469 {
6470 recurseAll(on_render);
6471 }
6472 size_t BVTreeInternalNode::sizeInBytes() const
6473 {
6474 return sizeof *this + _left->sizeInBytes() + _right->sizeInBytes();
6475 }
6476 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
6477 {
6478 Type t_min;
6479 if (_bv.intersects(bv, v, v_inv, t_min) && t_min < min_t_min) {
6480 _left->intersectNested(bv, v, v_inv, min_t_min, intersect_nested);
6481 _right->intersectNested(bv, v, v_inv, min_t_min, intersect_nested);
6482 }
6483 }
6484 void BVTreeInternalNode::intersectPrimitives(BV const & bv, Vector const & v, Vector const & v_inv, Type& min_t_min, Primitive const *& nearest) const
6485 {
6486 Type t_min;
6487 if (_bv.intersects(bv, v, v_inv, t_min) && t_min < min_t_min) {
6488 _left->intersectPrimitives(bv, v, v_inv, min_t_min, nearest);
6489 _right->intersectPrimitives(bv, v, v_inv, min_t_min, nearest);
6490 }
6491 }
6492 void BVTreeInternalNode::countNodes(unsigned& internal_nodes, unsigned& leaf_nodes) const
6493 {
6494 _left->countNodes(++internal_nodes, leaf_nodes);
6495 _right->countNodes(internal_nodes, leaf_nodes);
6496 }
6497
6498 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
6499 {
6500 _left->findNearest(ray_local, ray_world, transform, nearest, nearest_t, nearest_transform);
6501 _right->findNearest(ray_local, ray_world, transform, nearest, nearest_t, nearest_transform);
6502 }
6503 void BVTreeInternalNode::recurseNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res)
6504 {
6505 _left->findNearestPrecise(ray_local, ray_world, transform, res);
6506 _right->findNearestPrecise(ray_local, ray_world, transform, res);
6507 }
6508
6509 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
6510 {
6511 if (IntersectionTests::continueSearch(_bv, ray_local, ray_world, *transform, nearest_t)) {
6512 recurseNearest(ray_local, ray_world, transform, nearest, nearest_t, nearest_transform);
6513 }
6514 }
6515 void BVTreeInternalNode::findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res)
6516 {
6517 if (IntersectionTests::continueSearch(_bv, ray_local, ray_world, *transform, res)) {
6518 recurseNearestPrecise(ray_local, ray_world, transform, res);
6519 }
6520 }
6521 void BVTreeInternalNode::findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive* parent, IntersectRayResult& res, Primitive*& parent_res)
6522 {
6523 if (IntersectionTests::continueSearch(_bv, ray_local, ray_world, *transform, res)) {
6524 _left->findNearestPrecise(ray_local, ray_world, transform, parent, res, parent_res);
6525 _right->findNearestPrecise(ray_local, ray_world, transform, parent, res, parent_res);
6526 }
6527 }
6528 void BVTreeInternalNode::findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res, StackTrivial<NodePtr>& stack)
6529 {
6530 if (IntersectionTests::continueSearch(_bv, ray_local, ray_world, *transform, res)) {
6531 stack.push_back(_right);
6532 stack.push_back(_left);
6533 }
6534 }
6535 void BVTreeInternalNode::findNearestNested(Ray const & ray, IntersectRayResult& res, std::function<void(Primitive*)> const & find_nested)
6536 {
6537 if (IntersectionTests::continueSearch(_bv, ray, res)) {
6538 NodePtr nodes[2] = { _left, _right };
6539 if (_right->dist(ray) < _left->dist(ray)) {
6540 Algorithm::swap(*nodes, *(nodes + 1u));
6541 }
6542 (*nodes)->findNearestNested(ray, res, find_nested);
6543 (*(nodes + 1u))->findNearestNested(ray, res, find_nested);
6544 }
6545 }
6546 void BVTreeInternalNode::findNearestNested(Ray const & ray, IntersectRayResult& res, std::function<void(Primitive*)> const & find_nested, StackTrivial<NodePtr>& stack)
6547 {
6548 if (IntersectionTests::continueSearch(_bv, ray, res)) {
6549 stack.push_back(_right);
6550 stack.push_back(_left);
6551 if (_right->dist(ray) < _left->dist(ray)) {
6552 Algorithm::swap(stack.back(), *(&stack.back() - 1u));
6553 }
6554 }
6555 }
6556 bool BVTreeInternalNode::largerThan(BVTreeInternalNode const & other) const
6557 {
6558 return _bv.largerThan(other._bv);
6559 }
6560 void BVTreeInternalNode::recurseQueryRange(BV const & bv, Callback::CbFunc const & cb) const
6561 {
6562 _left->queryRange(bv, cb);
6563 _right->queryRange(bv, cb);
6564 }
6565 void BVTreeInternalNode::recurseQueryRange(BV const & bv, CullingParams const & cp, Callback::CbFunc const & cb) const
6566 {
6567 _left->queryRange(bv, cp, cb);
6568 _right->queryRange(bv, cp, cb);
6569 }
6570 void BVTreeInternalNode::recurseQueryContributing(CullingParams const & cp, Callback::CbFunc const & cb) const
6571 {
6572 _left->queryContributing(cp, cb);
6573 _right->queryContributing(cp, cb);
6574 }
6575 void BVTreeInternalNode::recurseQueryAll(Callback::CbFunc const & cb) const
6576 {
6577 _left->queryAll(cb);
6578 _right->queryAll(cb);
6579 }
6580 void BVTreeInternalNode::queryRange(BV const & bv, Callback::CbFunc const & cb) const
6581 {
6582 if (bv.contains(_bv)) {
6583 recurseQueryAll(cb);
6584 }
6585 else if (bv.intersects(_bv)) {
6586 recurseQueryRange(bv, cb);
6587 }
6588 }
6589 void BVTreeInternalNode::queryRange(BV const & bv, CullingParams const & cp, Callback::CbFunc const & cb) const
6590 {
6591 if (contributes(cp)) {
6592 if (bv.contains(_bv)) {
6593 recurseQueryContributing(cp, cb);
6594 }
6595 else if (bv.intersects(_bv)) {
6596 recurseQueryRange(bv, cp, cb);
6597 }
6598 }
6599 }
6600 void BVTreeInternalNode::queryContributing(CullingParams const & cp, Callback::CbFunc const & cb) const
6601 {
6602 if (auto const result = computeContribution(cp)) {
6603 result.intersecting() ? recurseQueryContributing(cp, cb) : recurseQueryAll(cb);
6604 }
6605 }
6606 void BVTreeInternalNode::queryAll(Callback::CbFunc const & cb) const
6607 {
6608 recurseQueryAll(cb);
6609 }
6610 BVTreeInternalNode::BV BVTreeInternalNode::getBV() const
6611 {
6612 return _bv;
6613 }
6614 BVTreeInternalNode::Type BVTreeInternalNode::minSquaredDist(Vector const & point) const
6615 {
6616 return _bv.minSquaredDist(point);
6617 }
6618 BVTreeInternalNode::Type BVTreeInternalNode::dist(Ray const & ray) const
6619 {
6620 return minSquaredDist(ray.origin());
6621 }
6622 void BVTreeInternalNode::destroy(BVTreeNodePool& pool)
6623 {
6624 pool.destroy(this);
6625 }
6626 BVTreeInternalNode::Type BVTreeInternalNode::cost(BV const & bv) const
6627 {
6628 return _bv.cost(bv);
6629 }
6630 void BVTreeInternalNode::insert(PrimitiveInfo const & info, NodePtr& this_ptr, BVTreeNodePool& node_pool)
6631 {
6632 insert(info);
6633 auto& child = childToDescend(info.bv());
6634 child->insert(info, child, node_pool);
6635 }
6636 bool BVTreeInternalNode::remove(PrimitiveInfo const & info, NodePtr& this_ptr, BVTreeNodePool& node_pool, bool& deleted)
6637 {
6638 bool dirty = false;
6639 if (_bv.intersects(info.bv())) {
6640 bool deleted_left = false;
6641 dirty = dirty || _left->remove(info, _left, node_pool, deleted_left);
6642 bool deleted_right = false;
6643 dirty = dirty || _right->remove(info, _right, node_pool, deleted_right);
6644 if (deleted_left) {
6645 rebuild(this_ptr, _right, node_pool);
6646 }
6647 else if (deleted_right) {
6648 rebuild(this_ptr, _left, node_pool);
6649 }
6650 }
6651 if (dirty) {
6652 markAsDirty();
6653 }
6654 return dirty;
6655 }
6656 bool BVTreeInternalNode::removeIfDoesNotFit(PrimitiveInfo const & info, BV const & bv_old, BVTreeNode const * parent, BVTreeNode const * root, NodePtr& this_ptr, BVTreeNodePool& node_pool, bool& deleted)
6657 {
6658 bool dirty = false;
6659 if (_bv.intersects(bv_old)) {
6660 bool deleted_left = false;
6661 dirty = dirty || _left->removeIfDoesNotFit(info, bv_old, this, root, _left, node_pool, deleted_left);
6662 bool deleted_right = false;
6663 dirty = dirty || _right->removeIfDoesNotFit(info, bv_old, this, root, _right, node_pool, deleted_right);
6664 if (deleted_left) {
6665 rebuild(this_ptr, _right, node_pool);
6666 }
6667 else if (deleted_right) {
6668 rebuild(this_ptr, _left, node_pool);
6669 }
6670 }
6671 if (dirty) {
6672 markAsDirty();
6673 }
6674 return dirty;
6675 }
6676 void BVTreeInternalNode::destroyTree(StackTrivial<PrimitiveInfo>& primitives, BVTreeNodePool& node_pool)
6677 {
6678 _left->destroyTree(primitives, node_pool);
6679 _right->destroyTree(primitives, node_pool);
6680 destroy(node_pool);
6681 }
6682 BVTreeInternalNode::DirtyInfo BVTreeInternalNode::recalculateDirty()
6683 {
6684 if (isDirty()) {
6685 collectFromChildren(_left->recalculateDirty());
6686 collectFromChildren(_right->recalculateDirty());
6687 }
6688 return { _bv, _minSquaredSize, _maxSquaredSize };
6689 }
6690 size_t BVTreeInternalNode::minHeight(size_t const & height) const
6691 {
6692 return std::min(_left->minHeight(height + 1u), _right->minHeight(height + 1u));
6693 }
6694 size_t BVTreeInternalNode::maxHeight(size_t const & height) const
6695 {
6696 return std::max(_left->maxHeight(height + 1u), _right->maxHeight(height + 1u));
6697 }
6698 void BVTreeInternalNode::averageHeight(float const & height, float const & inv_num_leafs, float& avg_height) const
6699 {
6700 _left->averageHeight(height + 1.f, inv_num_leafs, avg_height);
6701 _right->averageHeight(height + 1.f, inv_num_leafs, avg_height);
6702 }
6703 void BVTreeInternalNode::insert(BVTreeInternalNode::PrimitiveInfo const & pi)
6704 {
6705 _bv.unify(pi.bv());
6706 minimize(pi.squaredSize(), _minSquaredSize);
6707 maximize(pi.squaredSize(), _maxSquaredSize);
6708 }
6709 BVTreeInternalNode::NodePtr& BVTreeInternalNode::childToDescend(BV const & bv)
6710 {
6711 return _left->cost(bv) < _right->cost(bv) ? _left : _right;
6712 }
6713 void BVTreeInternalNode::markAsDirty()
6714 {
6715 _bv = BV();
6716 _minSquaredSize = std::numeric_limits<Type>::max();
6717 _maxSquaredSize = std::numeric_limits<Type>::lowest();
6718 }
6719 bool BVTreeInternalNode::isDirty() const
6720 {
6721 return _maxSquaredSize == std::numeric_limits<Type>::lowest();
6722 }
6723 void BVTreeInternalNode::rebuild(NodePtr& this_ptr, NodePtr child, BVTreeNodePool& node_pool)
6724 {
6725 StackTrivial<PrimitiveInfo> infos;
6726 child->destroyTree(infos, node_pool);
6727 this_ptr = node_pool.createNode(infos);
6728 destroy(node_pool);
6729 }
6730 void BVTreeInternalNode::collectFromChildren(DirtyInfo const & di)
6731 {
6732 _bv.unify(di.bv());
6733 minimize(di.minSquaredSize(), _minSquaredSize);
6734 maximize(di.maxSquaredSize(), _maxSquaredSize);
6735 }
6736 void BVTreeInternalNode::descendVisible(Descendable & other, CullingParams const & cp, Callback2 const & cb)
6737 {
6738 other.descendVisible(*this, cp, cb);
6739 }
6740 void BVTreeInternalNode::descendVisible(CsmInternalNode & other, CullingParams const & cp, Callback2 const & cb)
6741 {
6742 if (contributes(cp)) {
6743 if (auto const result = IntersectionTests::intersectFrustumIgnoreNear(_bv, other.frustumPlanes())) {
6744 if (result.intersecting()) {
6745 _bv.largerThan(other.bvLight()) ? recurseVisible(other, cp, cb) : other.recurseVisible(*this, cp, cb);
6746 }
6747 else {
6748 _bv.largerThan(other.bvLight()) ? recurseContributing(other, cp, cb) : other.recurseContributing(*this, cp, cb);
6749 }
6750 }
6751 }
6752 }
6753 void BVTreeInternalNode::descendVisible(CsmLeafNode & other, CullingParams const & cp, Callback2 const & cb)
6754 {
6755 if (contributes(cp)) {
6756 if (auto const result = IntersectionTests::intersectFrustumIgnoreNear(_bv, other.split().frustumPlanes())) {
6757 result.intersecting() ? recurseVisible(other, cp, cb) : recurseContributing(other, cp, cb);
6758 }
6759 }
6760 }
6761 void BVTreeInternalNode::descendContributing(Descendable & other, CullingParams const & cp, Callback2 const & cb)
6762 {
6763 other.descendContributing(*this, cp, cb);
6764 }
6765 void BVTreeInternalNode::descendContributing(CsmInternalNode & other, CullingParams const & cp, Callback2 const & cb)
6766 {
6767 if (auto const result = computeContribution(cp)) {
6768 if (result.intersecting()) {
6769 _bv.largerThan(other.bvLight()) ? recurseContributing(other, cp, cb) : other.recurseContributing(*this, cp, cb);
6770 }
6771 else {
6772 descendAll(other, cb.onRender());
6773 }
6774 }
6775 }
6776 void BVTreeInternalNode::descendContributing(CsmLeafNode & other, CullingParams const & cp, Callback2 const & cb)
6777 {
6778 if (auto const result = computeContribution(cp)) {
6779 result.intersecting() ? recurseContributing(other, cp, cb) : descendAll(other, cb.onRender());
6780 }
6781 }
6782 void BVTreeInternalNode::descendAll(Descendable & other, Callback2::CbFunc const & on_render)
6783 {
6784 other.descendAll(*this, on_render);
6785 }
6786 void BVTreeInternalNode::descendAll(CsmInternalNode & other, Callback2::CbFunc const & on_render)
6787 {
6788 recurseAll(other, on_render);
6789 }
6790 void BVTreeInternalNode::descendAll(CsmLeafNode & other, Callback2::CbFunc const & on_render)
6791 {
6792 recurseAll(other, on_render);
6793 }
6794 void BVTreeInternalNode::recurseVisible(Descendable & other, CullingParams const & cp, Callback2 const & cb)
6795 {
6796 _left->descendVisible(other, cp, cb);
6797 _right->descendVisible(other, cp, cb);
6798 }
6799 void BVTreeInternalNode::recurseContributing(Descendable & other, CullingParams const & cp, Callback2 const & cb)
6800 {
6801 _left->descendContributing(other, cp, cb);
6802 _right->descendContributing(other, cp, cb);
6803 }
6804 void BVTreeInternalNode::recurseAll(Descendable & other, Callback2::CbFunc const & on_render)
6805 {
6806 _left->descendAll(other, on_render);
6807 _right->descendAll(other, on_render);
6808 }
6809}
6810#include <BVTreeLeafNode.h>
6811#include <BVTreeInternalNode.h>
6812#include <BVTreeNodePool.h>
6813#include <StackTrivial.h>
6814#include <CullingParams.h>
6815#include <CsmInternalNode.h>
6816#include <CsmLeafNode.h>
6817
6818namespace RT
6819{
6820 BVTreeLeafNode::BVTreeLeafNode(Primitive* const & primitive)
6821 : BVTreeNode(),
6822 _primitive(primitive)
6823 {
6824 }
6825 void BVTreeLeafNode::cullVisiblePrimitives(CullingParams const & cp, Callback const & cb) const
6826 {
6827 cb.onIntersectFrustum()(_primitive);
6828 }
6829 void BVTreeLeafNode::cullVisiblePrimitives(CullingParams const & cp, IntersectedPlanes const & in, Callback const & cb) const
6830 {
6831 cb.onIntersectFrustum()(_primitive);
6832 }
6833 void BVTreeLeafNode::cullContributingPrimitives(CullingParams const & cp, Callback const & cb) const
6834 {
6835 cb.onBecameFullyVisible()(_primitive);
6836 }
6837 void BVTreeLeafNode::cullAllPrimitives(Callback::CbFunc const & on_render) const
6838 {
6839 on_render(_primitive);
6840 }
6841 size_t BVTreeLeafNode::sizeInBytes() const
6842 {
6843 return sizeof *this;
6844 }
6845 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
6846 {
6847 Type t_min;
6848 if (getBV().intersects(bv, v, v_inv, t_min) && t_min < min_t_min) {
6849 intersect_nested(_primitive);
6850 }
6851 }
6852 void BVTreeLeafNode::intersectPrimitives(BV const & bv, Vector const & v, Vector const & v_inv, Type& min_t_min, Primitive const *& nearest) const
6853 {
6854 Type t_min;
6855 if (getBV().intersects(bv, v, v_inv, t_min) && t_min < min_t_min) {
6856 min_t_min = t_min;
6857 nearest = _primitive;
6858 }
6859 }
6860 void BVTreeLeafNode::countNodes(unsigned& internal_nodes, unsigned& leaf_nodes) const
6861 {
6862 ++leaf_nodes;
6863 }
6864 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
6865 {
6866 Type t_min;
6867 if (getBV().intersect(ray_local, t_min)) {
6868 auto const t_world = distance(ray_world.origin(), MathHelpers::transformPoint(*transform, ray_local.pos(t_min)));
6869 if (t_world < nearest_t) {
6870 nearest = _primitive;
6871 nearest_t = t_world;
6872 nearest_transform = transform;
6873 }
6874 }
6875 }
6876 void BVTreeLeafNode::findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res)
6877 {
6878 if (IntersectionTests::continueSearch(getBV(), ray_local, ray_world, *transform, res)) {
6879 if (auto const result = _primitive->intersect(ray_local, ray_world, *transform)) {
6880 if (result.t() < res.minTMin()) {
6881 res.update(result, transform, _primitive);
6882 }
6883 }
6884 }
6885 }
6886 void BVTreeLeafNode::findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, Primitive* parent, IntersectRayResult& res, Primitive*& parent_res)
6887 {
6888 if (IntersectionTests::continueSearch(getBV(), ray_local, ray_world, *transform, res)) {
6889 if (auto const result = _primitive->intersect(ray_local, ray_world, *transform)) {
6890 if (result.t() < res.minTMin()) {
6891 res.update(result, transform, _primitive);
6892 parent_res = parent;
6893 }
6894 }
6895 }
6896 }
6897 void BVTreeLeafNode::findNearestPrecise(Ray const & ray_local, Ray const & ray_world, Matrix const * transform, IntersectRayResult& res, StackTrivial<NodePtr>& stack)
6898 {
6899 findNearestPrecise(ray_local, ray_world, transform, res);
6900 }
6901 void BVTreeLeafNode::findNearestNested(Ray const & ray, IntersectRayResult& res, std::function<void(Primitive*)> const & find_nested)
6902 {
6903 find_nested(_primitive);
6904 }
6905 void BVTreeLeafNode::findNearestNested(Ray const & ray, IntersectRayResult& res, std::function<void(Primitive*)> const & find_nested, StackTrivial<NodePtr>& stack)
6906 {
6907 findNearestNested(ray, res, find_nested);
6908 }
6909 void BVTreeLeafNode::queryRange(BV const & bv, Callback::CbFunc const & cb) const
6910 {
6911 if (bv.intersects(getBV())) {
6912 cb(_primitive);
6913 }
6914 }
6915 void BVTreeLeafNode::queryRange(BV const & bv, CullingParams const & cp, Callback::CbFunc const & cb) const
6916 {
6917 if (contributes(cp) && bv.intersects(getBV())) {
6918 cb(_primitive);
6919 }
6920 }
6921 void BVTreeLeafNode::queryContributing(CullingParams const & cp, Callback::CbFunc const & cb) const
6922 {
6923 if (contributes(cp)) {
6924 cb(_primitive);
6925 }
6926 }
6927 void BVTreeLeafNode::queryAll(Callback::CbFunc const & cb) const
6928 {
6929 cb(_primitive);
6930 }
6931 BVTreeLeafNode::BV BVTreeLeafNode::getBV() const
6932 {
6933 return _primitive->bv();
6934 }
6935 BVTreeLeafNode::Type BVTreeLeafNode::minSquaredDist(Vector const & point) const
6936 {
6937 return getBV().minSquaredDist(point);
6938 }
6939 BVTreeLeafNode::Type BVTreeLeafNode::dist(Ray const & ray) const
6940 {
6941 return minSquaredDist(ray.origin());
6942 }
6943 void BVTreeLeafNode::destroy(BVTreeNodePool& pool)
6944 {
6945 pool.destroy(this);
6946 }
6947 BVTreeLeafNode::Type BVTreeLeafNode::cost(BV const & bv) const
6948 {
6949 return getBV().cost(bv);
6950 }
6951 void BVTreeLeafNode::insert(PrimitiveInfo const & info, NodePtr& this_ptr, BVTreeNodePool& node_pool)
6952 {
6953 PrimitiveInfo infos[2] = { info, _primitive };
6954 this_ptr = node_pool.createNode(infos, infos + 2);
6955 destroy(node_pool);
6956 }
6957 bool BVTreeLeafNode::remove(PrimitiveInfo const & info, NodePtr& this_ptr, BVTreeNodePool& node_pool, bool& deleted)
6958 {
6959 deleted = info.primitive() == _primitive;
6960 if (deleted) {
6961 destroy(node_pool);
6962 }
6963 return deleted;
6964 }
6965 bool BVTreeLeafNode::removeIfDoesNotFit(PrimitiveInfo const & info, BV const & bv_old, BVTreeNode const * parent, BVTreeNode const * root, NodePtr& this_ptr, BVTreeNodePool& node_pool, bool& deleted)
6966 {
6967 deleted = this != root && info.primitive() == _primitive && !parent->getBV().contains(info.bv());
6968 if (deleted) {
6969 destroy(node_pool);
6970 }
6971 return deleted;
6972 }
6973 void BVTreeLeafNode::destroyTree(StackTrivial<PrimitiveInfo>& primitives, BVTreeNodePool& node_pool)
6974 {
6975 primitives.push_back(_primitive);
6976 destroy(node_pool);
6977 }
6978 BVTreeLeafNode::DirtyInfo BVTreeLeafNode::recalculateDirty()
6979 {
6980 return { _primitive->bv(), _primitive->squaredSize(), _primitive->squaredSize() };
6981 }
6982 size_t BVTreeLeafNode::minHeight(size_t const & height) const
6983 {
6984 return height;
6985 }
6986 size_t BVTreeLeafNode::maxHeight(size_t const & height) const
6987 {
6988 return height;
6989 }
6990 void BVTreeLeafNode::averageHeight(float const & height, float const & inv_num_leafs, float& avg_height) const
6991 {
6992 avg_height += height * inv_num_leafs;
6993 }
6994 void BVTreeLeafNode::descendVisible(Descendable & other, CullingParams const & cp, Callback2 const & cb)
6995 {
6996 other.descendVisible(*this, cp, cb);
6997 }
6998 void BVTreeLeafNode::descendVisible(CsmInternalNode & other, CullingParams const & cp, Callback2 const & cb)
6999 {
7000 if (contributes(cp)) {
7001 if (auto const result = IntersectionTests::intersectFrustumIgnoreNear(getBV(), other.frustumPlanes())) {
7002 result.intersecting() ? other.recurseVisible(*this, cp, cb) : other.recurseContributing(*this, cp, cb);
7003 }
7004 }
7005 }
7006 void BVTreeLeafNode::descendVisible(CsmLeafNode & other, CullingParams const & cp, Callback2 const & cb)
7007 {
7008 cb.onIntersectFrustum()(_primitive, other.split().renderlist());
7009 }
7010 void BVTreeLeafNode::descendContributing(Descendable & other, CullingParams const & cp, Callback2 const & cb)
7011 {
7012 other.descendContributing(*this, cp, cb);
7013 }
7014 void BVTreeLeafNode::descendContributing(CsmInternalNode & other, CullingParams const & cp, Callback2 const & cb)
7015 {
7016 if (contributes(cp)) {
7017 other.recurseContributing(*this, cp, cb);
7018 }
7019 }
7020 void BVTreeLeafNode::descendContributing(CsmLeafNode & other, CullingParams const & cp, Callback2 const & cb)
7021 {
7022 cb.onBecameFullyVisible()(_primitive, other.split().renderlist());
7023 }
7024 void BVTreeLeafNode::descendAll(Descendable & other, Callback2::CbFunc const & on_render)
7025 {
7026 other.descendAll(*this, on_render);
7027 }
7028 void BVTreeLeafNode::descendAll(CsmInternalNode & other, Callback2::CbFunc const & on_render)
7029 {
7030 other.recurseAll(*this, on_render);
7031 }
7032 void BVTreeLeafNode::descendAll(CsmLeafNode & other, Callback2::CbFunc const & on_render)
7033 {
7034 on_render(_primitive, other.split().renderlist());
7035 }
7036 bool BVTreeLeafNode::contributes(CullingParams const & cp) const
7037 {
7038 return getBV().contributes(cp.pEye(), cp.alpha());
7039 }
7040 IntersectResult BVTreeLeafNode::intersectFrustum(CullingParams const & cp) const
7041 {
7042 return IntersectionTests::intersectFrustum(getBV(), cp.frustumPlanes(), cp.frustumVertices());
7043 }
7044}
7045#include <BVTreeNodePool.h>
7046#include <StackTrivial.h>
7047#include <BVTreeInternalNode.h>
7048#include <BVTreeLeafNode.h>
7049
7050namespace RT
7051{
7052 BVTreeNodePool::BVTreeNodePool(size_t num_primitives)
7053 {
7054 auto const height = static_cast<size_t>(std::floor(log2(static_cast<double>(num_primitives))));
7055 auto const num_nodes = static_cast<size_t>(std::pow(2.0, static_cast<double>(height) + 1.0) - 1.0);
7056 auto num_internal_nodes = num_nodes - num_primitives;
7057 maximize<size_t>(32u, num_primitives);
7058 maximize<size_t>(32u, num_internal_nodes);
7059 _internalNodePool.set_next_size(num_internal_nodes);
7060 _leafNodePool.set_next_size(num_primitives);
7061 }
7062 BVTreeNode* BVTreeNodePool::createInternalNode(BVTreeNode::PrimitiveInfo* const begin, BVTreeNode::PrimitiveInfo* const end)
7063 {
7064 return new (_internalNodePool.malloc()) BVTreeInternalNode(begin, end, *this);
7065 }
7066 BVTreeNode* BVTreeNodePool::createLeafNode(Primitive* p)
7067 {
7068 return new (_leafNodePool.malloc()) BVTreeLeafNode(p);
7069 }
7070 BVTreeNode* BVTreeNodePool::createNode(BVTreeNode::PrimitiveInfo* const begin, BVTreeNode::PrimitiveInfo* const end)
7071 {
7072 return Algorithm::continueSplit(begin, end) ? createInternalNode(begin, end) : createLeafNode(begin->primitive());
7073 }
7074 BVTreeNode* BVTreeNodePool::createNode(StackTrivial<BVTreeNode::PrimitiveInfo>& infos)
7075 {
7076 return createNode(infos.begin(), infos.end());
7077 }
7078 void BVTreeNodePool::destroy(BVTreeLeafNode* node)
7079 {
7080 _leafNodePool.destroy(node);
7081 }
7082 void BVTreeNodePool::destroy(BVTreeInternalNode* node)
7083 {
7084 _internalNodePool.destroy(node);
7085 }
7086}
7087#include <CsmInternalNode.h>
7088#include <CsmNodePool.h>
7089#include <CsmSplit.h>
7090#include <CsmNode.h>
7091#include <BVTreeInternalNode.h>
7092#include <BVTreeLeafNode.h>
7093#include <CsmTree.h>
7094
7095namespace RT
7096{
7097 CsmInternalNode::CsmInternalNode(CsmSplit * const begin, CsmSplit * const end, CsmTree & np, Matrix<4, 4, Type> const & view_matrix_light) :
7098 _bvLight(begin->bvLight())
7099 {
7100 for (auto const * ptr = begin + 1; ptr != end; ) {
7101 _bvLight.unify((ptr++)->bvLight());
7102 }
7103 _fp = FrustumPlanes<3, Type>(MathHelpers::projectionMatrixOrtho(_bvLight) * view_matrix_light);
7104 auto axis = _bvLight.longestAxis();
7105 auto center = _bvLight.center(axis);
7106 auto* const mid = Algorithm::partitionForceSplit(begin, end, [&axis, ¢er](CsmSplit const & split) {
7107 return split.bvLight().center(axis) < center;
7108 });
7109 _left = np.createNode(begin, mid, view_matrix_light);
7110 _right = np.createNode(mid, end, view_matrix_light);
7111 }
7112 CsmInternalNode::~CsmInternalNode()
7113 {
7114 delete _left;
7115 delete _right;
7116 }
7117 FrustumPlanes<3, CsmInternalNode::Type> const & CsmInternalNode::frustumPlanes() const
7118 {
7119 return _fp;
7120 }
7121 void CsmInternalNode::recurseVisible(Descendable & other, CullingParams const & cp, Callback2 const & cb)
7122 {
7123 _left->descendVisible(other, cp, cb);
7124 _right->descendVisible(other, cp, cb);
7125 }
7126 void CsmInternalNode::recurseContributing(Descendable & other, CullingParams const & cp, Callback2 const & cb)
7127 {
7128 _left->descendContributing(other, cp, cb);
7129 _right->descendContributing(other, cp, cb);
7130 }
7131 void CsmInternalNode::recurseAll(Descendable & other, Callback2::CbFunc const & on_render)
7132 {
7133 _left->descendAll(other, on_render);
7134 _right->descendAll(other, on_render);
7135 }
7136 CsmInternalNode::BV const & CsmInternalNode::bvLight() const
7137 {
7138 return _bvLight;
7139 }
7140 void CsmInternalNode::descendVisible(Descendable & other, CullingParams const & cp, Callback2 const & cb)
7141 {
7142 other.descendVisible(*this, cp, cb);
7143 }
7144 void CsmInternalNode::descendVisible(BVTreeInternalNode & other, CullingParams const & cp, Callback2 const & cb)
7145 {
7146 other.descendVisible(*this, cp, cb);
7147 }
7148 void CsmInternalNode::descendVisible(BVTreeLeafNode & other, CullingParams const & cp, Callback2 const & cb)
7149 {
7150 other.descendVisible(*this, cp, cb);
7151 }
7152 void CsmInternalNode::descendContributing(Descendable & other, CullingParams const & cp, Callback2 const & cb)
7153 {
7154 other.descendContributing(*this, cp, cb);
7155 }
7156 void CsmInternalNode::descendContributing(BVTreeInternalNode & other, CullingParams const & cp, Callback2 const & cb)
7157 {
7158 other.descendContributing(*this, cp, cb);
7159 }
7160 void CsmInternalNode::descendContributing(BVTreeLeafNode & other, CullingParams const & cp, Callback2 const & cb)
7161 {
7162 other.descendContributing(*this, cp, cb);
7163 }
7164 void CsmInternalNode::descendAll(Descendable & other, Callback2::CbFunc const & on_render)
7165 {
7166 other.descendAll(*this, on_render);
7167 }
7168 void CsmInternalNode::descendAll(BVTreeInternalNode & other, Callback2::CbFunc const & on_render)
7169 {
7170 other.descendAll(*this, on_render);
7171 }
7172 void CsmInternalNode::descendAll(BVTreeLeafNode & other, Callback2::CbFunc const & on_render)
7173 {
7174 other.descendAll(*this, on_render);
7175 }
7176}
7177#include <CsmLeafNode.h>
7178#include <BVTreeInternalNode.h>
7179#include <BVTreeLeafNode.h>
7180
7181namespace RT
7182{
7183 CsmLeafNode::CsmLeafNode(CsmSplit * split) :
7184 _split(split)
7185 {
7186 }
7187 void CsmLeafNode::descendVisible(Descendable & other, CullingParams const & cp, Callback2 const & cb)
7188 {
7189 other.descendVisible(*this, cp, cb);
7190 }
7191 void CsmLeafNode::descendVisible(BVTreeInternalNode & other, CullingParams const & cp, Callback2 const & cb)
7192 {
7193 other.descendVisible(*this, cp, cb);
7194 }
7195 void CsmLeafNode::descendVisible(BVTreeLeafNode & other, CullingParams const & cp, Callback2 const & cb)
7196 {
7197 other.descendVisible(*this, cp, cb);
7198 }
7199 void CsmLeafNode::descendContributing(Descendable & other, CullingParams const & cp, Callback2 const & cb)
7200 {
7201 other.descendContributing(*this, cp, cb);
7202 }
7203 void CsmLeafNode::descendContributing(BVTreeInternalNode & other, CullingParams const & cp, Callback2 const & cb)
7204 {
7205 other.descendContributing(*this, cp, cb);
7206 }
7207 void CsmLeafNode::descendContributing(BVTreeLeafNode & other, CullingParams const & cp, Callback2 const & cb)
7208 {
7209 other.descendContributing(*this, cp, cb);
7210 }
7211 void CsmLeafNode::descendAll(Descendable & other, Callback2::CbFunc const & on_render)
7212 {
7213 other.descendAll(*this, on_render);
7214 }
7215 void CsmLeafNode::descendAll(BVTreeInternalNode & other, Callback2::CbFunc const & on_render)
7216 {
7217 other.descendAll(*this, on_render);
7218 }
7219 void CsmLeafNode::descendAll(BVTreeLeafNode & other, Callback2::CbFunc const & on_render)
7220 {
7221 other.descendAll(*this, on_render);
7222 }
7223 CsmSplit& CsmLeafNode::split()
7224 {
7225 return *_split;
7226 }
7227}
7228#include <CsmNodePool.h>
7229
7230namespace RT
7231{
7232 CsmNode * CsmNodePool::createNode(CsmSplit * begin, CsmSplit * end, Matrix<4, 4, Type> const & view_matrix_light)
7233 {
7234 return Algorithm::continueSplit(begin, end) ? createInternalNode(begin, end, view_matrix_light) : createLeafNode(begin);
7235 }
7236 CsmNode * CsmNodePool::createInternalNode(CsmSplit * begin, CsmSplit * end, Matrix<4, 4, Type> const & view_matrix_light)
7237 {
7238 return nullptr;
7239 //return new (_internalNodePool.malloc()) CsmInternalNode(begin, end, *this, view_matrix_light);
7240 }
7241 CsmNode * CsmNodePool::createLeafNode(CsmSplit * s)
7242 {
7243 return new (_leafNodePool.malloc()) CsmLeafNode(s);
7244 }
7245}
7246#include <CsmSplit.h>
7247
7248namespace RT
7249{
7250 CsmSplit::CsmSplit(BV const & bv_light, Matrix<4, 4, Type> const & view_matrix_light, Matrix<4, 4, Type>* vp) :
7251 _bvLight(bv_light),
7252 _vp(vp)
7253 {
7254 init(view_matrix_light);
7255 }
7256 CsmSplit::BV const & CsmSplit::bvLight() const
7257 {
7258 return _bvLight;
7259 }
7260 Matrix<4, 4, CsmSplit::Type> const & CsmSplit::vp() const
7261 {
7262 return *_vp;
7263 }
7264 FrustumPlanes<3, CsmSplit::Type> const & CsmSplit::frustumPlanes() const
7265 {
7266 return _fp;
7267 }
7268 RenderList & CsmSplit::renderlist()
7269 {
7270 return _rl;
7271 }
7272 void CsmSplit::set(BV const & bv_light, Matrix<4, 4, Type> const & view_matrix_light, Matrix<4, 4, Type>* vp)
7273 {
7274 _bvLight = bv_light;
7275 _vp = vp;
7276 init(view_matrix_light);
7277 }
7278 void CsmSplit::init(Matrix<4, 4, Type> const & view_matrix_light)
7279 {
7280 *_vp = MathHelpers::projectionMatrixOrtho(_bvLight) * view_matrix_light;
7281 _fp = FrustumPlanes<3, Type>(*_vp);
7282 }
7283}
7284#include <CsmTree.h>
7285#include <BVTree.h>
7286#include <CsmInternalNode.h>
7287#include <CsmLeafNode.h>
7288
7289namespace RT
7290{
7291 CsmTree::CsmTree(CsmSplit * begin, CsmSplit * end, Matrix<4, 4, Type> const & view_matrix_light)
7292 {
7293 _root = createNode(begin, end, view_matrix_light);
7294 }
7295 CsmTree::~CsmTree()
7296 {
7297 delete _root;
7298 }
7299 CsmNode * CsmTree::root()
7300 {
7301 return _root;
7302 }
7303 void CsmTree::descendVisible(BVTree& bvt, CullingParams const & cp, Callback2 const & cb)
7304 {
7305 _root->descendVisible(*bvt.root(), cp, cb);
7306 }
7307 CsmNode * CsmTree::createNode(CsmSplit * begin, CsmSplit * end, Matrix<4, 4, Type> const & view_matrix_light)
7308 {
7309 return Algorithm::continueSplit(begin, end) ? createInternalNode(begin, end, view_matrix_light) : createLeafNode(begin);
7310 }
7311 CsmNode * CsmTree::createInternalNode(CsmSplit * begin, CsmSplit * end, Matrix<4, 4, Type> const & view_matrix_light)
7312 {
7313 return new CsmInternalNode(begin, end, *this, view_matrix_light);
7314 }
7315 CsmNode * CsmTree::createLeafNode(CsmSplit * cs)
7316 {
7317 return new CsmLeafNode(cs);
7318 }
7319}
7320#include <FixedTimestepSystem.h>
7321#include <GameTimer.h>
7322#include <iostream>
7323
7324namespace RT
7325{
7326 bool FixedTimestepSystem::update()
7327 {
7328 _acc += _gameTimer->deltaTimeSeconds();
7329 bool did_update = false;
7330 while (_acc >= _dt) {
7331 updateSystem();
7332 _acc -= _dt;
7333 did_update = true;
7334 }
7335 return did_update;
7336 }
7337}
7338#include <GameTimer.h>
7339
7340namespace RT
7341{
7342 GameTimer::GameTimer() :
7343 _baseTime(timeNow()),
7344 _prevTime(_baseTime)
7345 {
7346 }
7347 void GameTimer::tick()
7348 {
7349 _currTime = timeNow();
7350 _deltaTime = _currTime - _prevTime;
7351 _prevTime = _currTime;
7352 }
7353 void GameTimer::stop()
7354 {
7355 if (!stopped()) {
7356 _stopTime = timeNow();
7357 _stopped = true;
7358 }
7359 }
7360 void GameTimer::start()
7361 {
7362 _currTime = timeNow();
7363 if (stopped()) {
7364 _pausedTime += _currTime - _stopTime;
7365 _prevTime = _currTime;
7366 _stopped = false;
7367 }
7368 }
7369 float GameTimer::timeSeconds() const
7370 {
7371 return toSeconds(((stopped() ? _stopTime : _currTime) - _baseTime - _pausedTime).count());
7372 }
7373 float GameTimer::deltaTimeSeconds() const
7374 {
7375 return stopped() ? 0.f : toSeconds(_deltaTime.count());
7376 }
7377 float GameTimer::totalTimeSeconds() const
7378 {
7379 return toSeconds((_currTime - _baseTime).count());
7380 }
7381 bool GameTimer::stopped() const
7382 {
7383 return _stopped;
7384 }
7385}
7386#define GLM_ENABLE_EXPERIMENTAL
7387#include "Mesh.h"
7388#include <fstream>
7389#include <sstream>
7390#include <iostream>
7391#include <glm/gtx/string_cast.hpp>
7392#include <AABB.h>
7393#include <math/RTMath.h>
7394#include <BVTree.h>
7395
7396namespace RT
7397{
7398 Mesh::Mesh(StackTrivial<Vertex>&& vertices, StackTrivial<unsigned int>&& indices, std::shared_ptr<Material> const * materials, unsigned int const & material_index) :
7399 _vertices(std::move(vertices)),
7400 _indices(std::move(indices)),
7401 _material(*(materials + material_index)),
7402 _materialIndex(material_index)
7403 {
7404 init();
7405 }
7406 Mesh::~Mesh()
7407 {
7408 delete _bvTree;
7409 }
7410 StackTrivial<Vertex> const & Mesh::vertices() const
7411 {
7412 return _vertices;
7413 }
7414 StackTrivial<unsigned int> const & Mesh::indices() const
7415 {
7416 return _indices;
7417 }
7418 void Mesh::setVertices(StackTrivial<Vertex>&& vertices)
7419 {
7420 _vertices = std::move(vertices);
7421 init();
7422 }
7423 void Mesh::setIndices(StackTrivial<unsigned>&& indices)
7424 {
7425 _indices = std::move(indices);
7426 init();
7427 }
7428 unsigned const & Mesh::materialIndex() const
7429 {
7430 return _materialIndex;
7431 }
7432 AABB3f const & Mesh::aabb() const
7433 {
7434 return _aabb;
7435 }
7436 Sphere3f const & Mesh::sphere() const
7437 {
7438 return _sphere;
7439 }
7440 void Mesh::setMaterialIndex(unsigned const & material_index)
7441 {
7442 _materialIndex = material_index;
7443 }
7444 void Mesh::setMaterial(std::shared_ptr<Material> const & material)
7445 {
7446 _material = material;
7447 }
7448 std::shared_ptr<Material> const & Mesh::material() const
7449 {
7450 return _material;
7451 }
7452 BVTree * Mesh::bvTree()
7453 {
7454 return _bvTree;
7455 }
7456
7457 void Mesh::triangles(Vertex * vertices, boost::object_pool<Triangle>& tri_pool, StackTrivial<Primitive*>& triangles) const
7458 {
7459 triangles.reserveToFit(_indices.size() / 3u);
7460 auto const * begin = _indices.begin();
7461 auto const * end = _indices.end();
7462 while (begin != end) {
7463 triangles.push_back_unchecked(new (tri_pool.malloc()) Triangle(Vec3u(*begin, *(begin + 1), *(begin + 2)), vertices));
7464 begin += 3;
7465 }
7466 }
7467
7468 std::shared_ptr<BVTree> Mesh::transformedBVTree(Matrix<4, 4, Type> const & transform,
7469 Matrix<3, 3, Type> const & m_inv_transpose, boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const
7470 {
7471 vertices.clear();
7472 vertices.reserve(_vertices.size());
7473 for (auto const * ptr = _vertices.begin(); ptr != _vertices.end();) {
7474 vertices.push_back_unchecked(Vertex(MathHelpers::transformPoint(transform, ptr->position()), CompressedNormal(m_inv_transpose * ptr->normal()), ptr->uv(),
7475 CompressedNormal(m_inv_transpose * ptr->tangent())));
7476 ++ptr;
7477 }
7478 StackTrivial<Primitive*> tris;
7479 triangles(vertices.begin(), tri_pool, tris);
7480 return std::make_shared<BVTree>(tris.begin(), tris.end());
7481 }
7482
7483 void Mesh::computeTangentSpace()
7484 {
7485 auto * begin = new VertexUncompressed[_vertices.size()]();
7486 for (auto const * i = _indices.begin(); i != _indices.end(); i += 3) {
7487 auto& v0 = _vertices[*i];
7488 auto& v1 = _vertices[*(i + 1)];
7489 auto& v2 = _vertices[*(i + 2)];
7490 auto const & uv0 = v0.uv();
7491 auto const & uv1 = v1.uv();
7492 auto const & uv2 = v2.uv();
7493 auto const s1 = uv1.u() - uv0.u();
7494 auto const t1 = uv1.v() - uv0.v();
7495 auto const s2 = uv2.u() - uv0.u();
7496 auto const t2 = uv2.v() - uv0.v();
7497 auto const e1 = v1.position() - v0.position();
7498 auto const e2 = v2.position() - v0.position();
7499 auto const one_over_det = static_cast<Type>(1) / (s1 * t2 - t1 * s2);
7500 auto t = one_over_det * (e1 * t2 - e2 * t1);
7501 auto b = one_over_det * (e2 * s1 - e1 * s2);
7502 auto n = cross(e1, e2);
7503 begin[*i].add(t, b, n);
7504 begin[*(i + 1)].add(t, b, n);
7505 begin[*(i + 2)].add(t, b, n);
7506 }
7507 auto const * end = begin + _vertices.size();
7508 auto * v = _vertices.begin();
7509 for (; begin != end; ++begin) {
7510 (v++)->set(begin->t().orthogonalize(begin->n()), begin->t().handedness(begin->b(), begin->n()), begin->n());
7511 }
7512 delete[](begin - _vertices.size());
7513 }
7514
7515 void Mesh::init()
7516 {
7517 computeTangentSpace();
7518 _aabb = AABB3f(*this);
7519 _sphere = Sphere3f(*this);
7520 StackTrivial<Primitive*> tris;
7521 triangles(_vertices.begin(), _trianglePool, tris);
7522 _bvTree = new BVTree(tris.begin(), tris.end());
7523 }
7524}
7525#include <renderer/MeshRenderables.h>
7526#include <RenderList.h>
7527#include <Mesh.h>
7528#include <renderer/Renderer.h>
7529
7530namespace RT
7531{
7532 std::shared_ptr<ShaderDesc> const * IMeshRenderable::shaderDesc() const { return _shaderDesc; }
7533 std::shared_ptr<ShaderDesc> const * IMeshRenderable::shaderDescDepth() const { return _shaderDescDepth; }
7534 MaterialDesc * IMeshRenderable::materialDesc() const { return _materialDesc.get(); }
7535 void IMeshRenderable::setModelMatrix(Mat4f const & m)
7536 {
7537 }
7538 void IMeshRenderable::add(RenderList& renderlist)
7539 {
7540 renderlist.addVisibleMesh(this);
7541 }
7542 void IMeshRenderable::addUnchecked(RenderList& renderlist)
7543 {
7544 renderlist.addVisibleMeshUnchecked(this);
7545 }
7546 void IMeshRenderable::addIfContributes(const CullingParams& cp, RenderList& renderlist)
7547 {
7548 if (contributes(cp)) {
7549 add(renderlist);
7550 }
7551 }
7552 void IMeshRenderable::addIfContributesUnchecked(const CullingParams& cp, RenderList& renderlist)
7553 {
7554 if (contributes(cp)) {
7555 addUnchecked(renderlist);
7556 }
7557 }
7558 void IMeshRenderable::addIfContributesAndVisible(const CullingParams& cp, RenderList& renderlist)
7559 {
7560 if (contributes(cp) && intersectFrustum(cp)) {
7561 add(renderlist);
7562 }
7563 }
7564 unsigned IMeshRenderable::numMeshes() const
7565 {
7566 return 1;
7567 }
7568 void IMeshRenderable::createBV(const Mesh& mesh, const Transform& transform, Sphere3f& result)
7569 {
7570 //result = Sphere3f(mesh, transform);
7571 }
7572 void IMeshRenderable::createBV(Mesh const & mesh, Transform const & transform, AABB3f& result)
7573 {
7574 result = AABB3f(mesh.aabb(), transform.matrix());
7575 }
7576 bool IMeshRenderable::contributes(CullingParams const & cp) const
7577 {
7578 return bv().contributes(cp.pEye(), cp.alpha());
7579 }
7580 bool IMeshRenderable::intersectFrustum(CullingParams const & cp) const
7581 {
7582 return !IntersectionTests::outsideFrustum(bv(), cp.frustumPlanes(), cp.frustumVertices());
7583 }
7584 SkydomeRenderable::SkydomeRenderable(Renderer& renderer, const std::shared_ptr<Mesh>& mesh) :
7585 _gmd(renderer.addMesh(mesh))
7586 {
7587 }
7588 const std::shared_ptr<GPUMeshData>& SkydomeRenderable::storage() const
7589 {
7590 return _gmd;
7591 }
7592 StaticMeshRenderable::StaticMeshRenderable(Renderer& renderer, std::shared_ptr<Mesh> const & mesh,
7593 std::shared_ptr<Material> const & material, Transform const & transform) :
7594 _gmd(renderer.addMesh(mesh)),
7595 _modelMatrix(transform.matrix())
7596#if !DYNAMIC_INVERSE
7597 , _modelMatrixInverse(transform.getModelMatrixInverse())
7598#endif
7599 {
7600 _materialDesc = renderer.createMaterialDesc(material);
7601 _shaderDesc = _materialDesc->shaderDesc(MaterialDesc::ShaderKey::DEFAULT);
7602 _shaderDescDepth = _materialDesc->shaderDesc(MaterialDesc::ShaderKey::DEPTH);
7603 }
7604 void StaticMeshRenderable::render(RenderContext const & rc) const
7605 {
7606 rc.renderMesh(*_gmd, _modelMatrix,
7607#if DYNAMIC_INVERSE
7608 inverseUpper3x3(_modelMatrix)
7609#else
7610 _modelMatrixInverse
7611#endif
7612 );
7613 }
7614 void StaticMeshRenderable::renderDepth(RenderContext const & rc) const
7615 {
7616 rc.renderMesh(*_gmd, _modelMatrix);
7617 }
7618 unsigned StaticMeshRenderable::numTriangles() const
7619 {
7620 return _gmd->count() / 3;
7621 }
7622 BVTree * StaticMeshRenderable::nestedBVTree()
7623 {
7624 return _gmd->mesh().bvTree();
7625 }
7626 std::shared_ptr<BVTree> StaticMeshRenderable::transformedBVTree(boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const
7627 {
7628 return _gmd->mesh().transformedBVTree(_modelMatrix, transpose(inverseUpper3x3(_modelMatrix)), tri_pool, vertices);
7629 }
7630 GPUMeshData* StaticMeshRenderable::gpuMeshData() const
7631 {
7632 return _gmd.get();
7633 }
7634 Mat4f const * StaticMeshRenderable::modelMatrix() const
7635 {
7636 return &_modelMatrix;
7637 }
7638 void StaticMeshRenderable::setModelMatrix(Mat4f const & m)
7639 {
7640 _modelMatrix = m;
7641 }
7642 Primitive::BV StaticMeshRenderable::bv() const
7643 {
7644 return BV(_gmd->mesh().aabb(), _modelMatrix);
7645 }
7646 Primitive::BV StaticMeshRenderable::bvLocal() const
7647 {
7648 return _gmd->mesh().aabb();
7649 }
7650 Primitive::Type StaticMeshRenderable::squaredSize() const
7651 {
7652 return bv().squaredSize();
7653 }
7654 Primitive::Ray::IntersectionResult StaticMeshRenderable::intersect(Ray const & ray)
7655 {
7656 return Primitive::Ray::IntersectionResult();
7657 }
7658 Primitive::Ray::IntersectionResult StaticMeshRenderable::intersect(Ray const & ray, Matrix const & matrix)
7659 {
7660 return Ray::IntersectionResult();
7661 }
7662 size_t StaticMeshRenderable::sizeInBytes() const
7663 {
7664 return sizeof *this;
7665 }
7666 StaticMeshRenderableTransform::StaticMeshRenderableTransform(Renderer& renderer, std::shared_ptr<Mesh> const & mesh,
7667 std::shared_ptr<Material> const & material, Transform const & transform) :
7668 StaticMeshRenderable(renderer, mesh, material, transform),
7669 _transform(transform)
7670 {
7671 }
7672 void StaticMeshRenderableTransform::setTransform(Transform const & t)
7673 {
7674 _transform = t;
7675 _modelMatrix = _transform.matrix();
7676 }
7677
7678 Transform const * StaticMeshRenderableTransform::transform() const
7679 {
7680 return &_transform;
7681 }
7682
7683 StaticMeshRenderableShared::StaticMeshRenderableShared(Renderer& renderer, const std::shared_ptr<Mesh>& mesh,
7684 const std::shared_ptr<Material>& material, const std::shared_ptr<Mat4f>& model_matrix) :
7685 _gmd(renderer.addMesh(mesh)),
7686 _modelMatrix(model_matrix)
7687 {
7688 _materialDesc = renderer.createMaterialDesc(material);
7689 _shaderDesc = _materialDesc->shaderDesc(MaterialDesc::ShaderKey::DEFAULT);
7690 _shaderDescDepth = _materialDesc->shaderDesc(MaterialDesc::ShaderKey::DEPTH);
7691 }
7692 void StaticMeshRenderableShared::render(RenderContext const & rc) const
7693 {
7694 rc.renderMesh(*_gmd, *_modelMatrix, inverseUpper3x3(*_modelMatrix));
7695 }
7696 void StaticMeshRenderableShared::renderDepth(RenderContext const & rc) const
7697 {
7698 rc.renderMesh(*_gmd, *_modelMatrix);
7699 }
7700 unsigned StaticMeshRenderableShared::numTriangles() const
7701 {
7702 return _gmd->count() / 3;
7703 }
7704 GPUMeshData* StaticMeshRenderableShared::gpuMeshData() const
7705 {
7706 return _gmd.get();
7707 }
7708 Mat4f const * StaticMeshRenderableShared::modelMatrix() const
7709 {
7710 return _modelMatrix.get();
7711 }
7712 BVTree * StaticMeshRenderableShared::nestedBVTree()
7713 {
7714 return _gmd->mesh().bvTree();
7715 }
7716 std::shared_ptr<BVTree> StaticMeshRenderableShared::transformedBVTree(boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const
7717 {
7718 return _gmd->mesh().transformedBVTree(*_modelMatrix, transpose(inverseUpper3x3(*_modelMatrix)), tri_pool, vertices);
7719 }
7720 Primitive::BV StaticMeshRenderableShared::bv() const
7721 {
7722 return BV(_gmd->mesh().aabb(), *_modelMatrix);
7723 }
7724 Primitive::Type StaticMeshRenderableShared::squaredSize() const
7725 {
7726 return bv().squaredSize();
7727 }
7728 Primitive::Ray::IntersectionResult StaticMeshRenderableShared::intersect(Ray const & ray)
7729 {
7730 return Ray::IntersectionResult();
7731 }
7732 Primitive::Ray::IntersectionResult StaticMeshRenderableShared::intersect(Ray const & ray, Matrix const & matrix)
7733 {
7734 return Ray::IntersectionResult();
7735 }
7736 size_t StaticMeshRenderableShared::sizeInBytes() const
7737 {
7738 return sizeof *this;
7739 }
7740 StaticMeshRenderableLod::StaticMeshRenderableLod(Renderer& renderer, std::vector<std::shared_ptr<Mesh>> const & meshes,
7741 std::shared_ptr<Material> const & material, Transform const & transform) :
7742 _modelMatrix(transform.matrix())
7743#if !DYNAMIC_INVERSE
7744 , _modelMatrixInverse(transform.getModelMatrixInverse())
7745#endif
7746 {
7747 _materialDesc = renderer.createMaterialDesc(material);
7748 _shaderDesc = _materialDesc->shaderDesc(MaterialDesc::ShaderKey::DEFAULT);
7749 _shaderDescDepth = _materialDesc->shaderDesc(MaterialDesc::ShaderKey::DEPTH);
7750 _gmd.reserve(meshes.size());
7751 for (const auto& m : meshes) {
7752 _gmd.push_back(renderer.addMesh(m));
7753 }
7754 }
7755 void StaticMeshRenderableLod::render(RenderContext const & rc) const
7756 {
7757 rc.renderMesh(*_gmd[_lod], _modelMatrix,
7758#if DYNAMIC_INVERSE
7759 inverseUpper3x3(_modelMatrix)
7760#else
7761 _modelMatrixInverse
7762#endif
7763 );
7764 }
7765 void StaticMeshRenderableLod::renderDepth(RenderContext const & rc) const
7766 {
7767 rc.renderMesh(*_gmd[_lod], _modelMatrix);
7768 }
7769 unsigned StaticMeshRenderableLod::numTriangles() const
7770 {
7771 return _gmd[_lod]->count() / 3u;
7772 }
7773 void StaticMeshRenderableLod::add(RenderList& renderlist)
7774 {
7775 renderlist.addVisibleMesh(this);
7776 renderlist.addToCPULodList(this);
7777 }
7778 void StaticMeshRenderableLod::addUnchecked(RenderList& renderlist)
7779 {
7780 renderlist.addVisibleMeshUnchecked(this);
7781 renderlist.addToCPULodListUnchecked(this);
7782 }
7783 void StaticMeshRenderableLod::selectLod(CullingParams const & cp)
7784 {
7785 using Type = typename BV::Type;
7786 auto b = bv();
7787 auto ratio = b.squaredSize() / b.minSquaredDist(cp.pEye());
7788 auto alpha = static_cast<Type>(1) - std::min((ratio - cp.alpha()) / cp.lodRange(), static_cast<Type>(1));
7789 _lod = static_cast<unsigned>(std::round(alpha * (_gmd.size() - 1u)));
7790 }
7791 GPUMeshData* StaticMeshRenderableLod::gpuMeshData() const
7792 {
7793 return _gmd.front().get();
7794 }
7795 Mat4f const * StaticMeshRenderableLod::modelMatrix() const
7796 {
7797 return &_modelMatrix;
7798 }
7799 Primitive::BV StaticMeshRenderableLod::bv() const
7800 {
7801 BV bv = _gmd[0]->mesh().aabb();
7802 for (unsigned i = 1; i < _gmd.size(); i++) {
7803 bv.unify(_gmd[i]->mesh().aabb());
7804 }
7805 return BV(bv, _modelMatrix);
7806 }
7807 BVTree * StaticMeshRenderableLod::nestedBVTree()
7808 {
7809 return _gmd[0]->mesh().bvTree();
7810 }
7811 std::shared_ptr<BVTree> StaticMeshRenderableLod::transformedBVTree(boost::object_pool<Triangle>& tri_pool, StackTrivial<Vertex>& vertices) const
7812 {
7813 return _gmd[0]->mesh().transformedBVTree(_modelMatrix, transpose(inverseUpper3x3(_modelMatrix)), tri_pool, vertices);
7814 }
7815 Primitive::Type StaticMeshRenderableLod::squaredSize() const
7816 {
7817 return bv().squaredSize();
7818 }
7819 Primitive::Ray::IntersectionResult StaticMeshRenderableLod::intersect(Ray const & ray)
7820 {
7821 return Ray::IntersectionResult();
7822 }
7823 Primitive::Ray::IntersectionResult StaticMeshRenderableLod::intersect(Ray const & ray, Matrix const & matrix)
7824 {
7825 return Ray::IntersectionResult();
7826 }
7827 size_t StaticMeshRenderableLod::sizeInBytes() const
7828 {
7829 return sizeof *this;
7830 }
7831}
7832#include <Transform.h>
7833#define GLM_ENABLE_EXPERIMENTAL
7834#include <glm/gtc/matrix_transform.hpp>
7835#include <glm/gtx/transform.hpp>
7836
7837namespace RT
7838{
7839 Transform::Transform(Vec3f const & translation, Vec3f const & scale, Vec3f const & degrees) :
7840 _translation(translation),
7841 _scale(scale),
7842 _degrees(degrees)
7843 {
7844 }
7845 Mat4f Transform::matrix() const
7846 {
7847 return RT::translate(_translation) *
7848 rotation3DxHom(radians(_degrees.at<0>())) *
7849 rotation3DzHom(radians(_degrees.at<2>())) *
7850 rotation3DyHom(radians(_degrees.at<1>())) *
7851 RT::scale(_scale);
7852 }
7853 Mat3f Transform::inverseMatrix() const
7854 {
7855 return inverse(Mat3f(matrix()));
7856 }
7857 void Transform::setTranslation(Vec3f const & translation)
7858 {
7859 _translation = translation;
7860 }
7861 void Transform::setScale(Vec3f const & scale)
7862 {
7863 _scale = _scale;
7864 }
7865 void Transform::setDegrees(Vec3f const & degrees)
7866 {
7867 _degrees = degrees;
7868 }
7869 Vec3f const & Transform::translation() const
7870 {
7871 return _translation;
7872 }
7873 Vec3f const & Transform::scale() const
7874 {
7875 return _scale;
7876 }
7877 Vec3f const & Transform::degrees() const
7878 {
7879 return _degrees;
7880 }
7881}
7882#include <Triangle.h>
7883#include <Camera.h>
7884#include <physics/Particle.h>
7885
7886namespace RT
7887{
7888 Triangle::BV Triangle::bv() const
7889 {
7890 return BV::fromVertices<3>(vertices().data());
7891 }
7892 Triangle::Type Triangle::squaredSize() const
7893 {
7894 return bv().squaredSize();
7895 }
7896 Triangle::Ray::IntersectionResult Triangle::intersect(Ray const & ray, Vec3 const & p0, Vec3 const & p1, Vec3 const & p2)
7897 {
7898 Ray::IntersectionResult res;
7899 auto e1 = p1 - p0;
7900 auto e2 = p2 - p0;
7901 auto d = ray.dir();
7902 auto a = -d.z() * e2.y() + d.y() * e2.z();
7903 auto b = -d.z() * e1.y() + d.y() * e1.z();
7904 auto c = e1.y() * e2.z() - e2.y() * e1.z();
7905 auto det = e1.x() * a - e2.x() * b - d.x() * c;
7906 if (validDeterminant(det)) {
7907 auto one_over_det = static_cast<Type>(1) / det;
7908 auto q = ray.origin() - p0;
7909 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())));
7910 if (res.uv().validU()) {
7911 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())));
7912 if (res.uv().validVW()) {
7913 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())));
7914 return res;
7915 }
7916 }
7917 }
7918 return res;
7919 }
7920 Triangle::Ray::IntersectionResult Triangle::intersect(Ray const & ray_local, Ray const & ray_world, Matrix const & mat)
7921 {
7922 if (auto res = intersect(ray_local)) {
7923 res.setT(distance(ray_world.origin(), MathHelpers::transformPoint(mat, ray_local.pos(res.t()))));
7924 return res;
7925 }
7926 return Triangle::Ray::IntersectionResult();
7927 }
7928 Triangle::Ray::IntersectionResult Triangle::intersect(Ray const & ray)
7929 {
7930 return intersect(ray, vertex<0>(), vertex<1>(), vertex<2>());
7931 }
7932 Triangle::Ray::IntersectionResult Triangle::intersect(Ray const & ray, Matrix const & mat)
7933 {
7934 return intersect(ray, MathHelpers::transformPoint(mat, vertex<0>()), MathHelpers::transformPoint(mat, vertex<1>()), MathHelpers::transformPoint(mat, vertex<2>()));
7935 }
7936 void Triangle::debugTriangle(Vector<4, Type> * _debugTriangle, Matrix const & transform) const
7937 {
7938 *_debugTriangle++ = transform * vertex<0>().toHomogeneous();
7939 *_debugTriangle++ = transform * vertex<1>().toHomogeneous();
7940 *_debugTriangle = transform * vertex<2>().toHomogeneous();
7941 }
7942 Triangle * Triangle::toTriangle()
7943 {
7944 return this;
7945 }
7946}
7947#include <opengl/OpenGLAPI.h>
7948#include <iostream>
7949#include <opengl/GLVertexArray.h>
7950#include <opengl/GLBuffer.h>
7951#include <Model.h>
7952#include <Vertex.h>
7953#include <Mesh.h>
7954#include <Timing.h>
7955#include <SOIL/SOIL.h>
7956#include <Material.h>
7957#include <Settings.h>
7958#include <GraphicsSettings.h>
7959#include <opengl/GLMaterialSetup.h>
7960#include <fstream>
7961#include <Flags.h>
7962#include <GLShaderDesc.h>
7963#include <GlobalShaderParams.h>
7964#include <math/MathHelpers.h>
7965#include <Ray.h>
7966#include <GLMaterialDesc.h>
7967#include <NDCCube.h>
7968
7969namespace RT
7970{
7971 OpenGLAPI::OpenGLAPI(Vec4f const & clear_color) :
7972 _boxShader(createMiscShader(GLShaderSource("assets/opengl/vs_box.glsl", GL_VERTEX_SHADER),
7973 GLShaderSource("assets/opengl/fs_box.glsl", GL_FRAGMENT_SHADER), GLShaderSource("assets/opengl/gs_box.glsl", GL_GEOMETRY_SHADER))),
7974 _debugFrustumShader(createMiscShader(GLShaderSource("assets/opengl/vs_debug_frustum.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_debug_frustum.glsl", GL_FRAGMENT_SHADER))),
7975 _skydomeShader(createMiscShader(GLShaderSource("assets/opengl/vs_skybox.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_skydome_new.glsl", GL_FRAGMENT_SHADER))),
7976 _trianglesDebugShader(createMiscShader(GLShaderSource("assets/opengl/vs_triangles_debug.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_triangle.glsl", GL_FRAGMENT_SHADER))),
7977 _triangleDebugShader(createMiscShader(GLShaderSource("assets/opengl/vs_triangle_debug.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_triangle.glsl", GL_FRAGMENT_SHADER))),
7978 _particleShader(createMiscShader(GLShaderSource("assets/opengl/vs_particles.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_particles.glsl", GL_FRAGMENT_SHADER))),
7979 _copyShader(createMiscShader(GLShaderSource("assets/opengl/vs_screen.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_copy.glsl", GL_FRAGMENT_SHADER))),
7980 _springParticleDebugShader(createMiscShader(GLShaderSource("assets/opengl/vs_debug_spring_particle.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_debug_spring_particle.glsl", GL_FRAGMENT_SHADER))),
7981 _springDebugShader(createMiscShader(GLShaderSource("assets/opengl/vs_debug_spring.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_debug_spring_particle.glsl", GL_FRAGMENT_SHADER))),
7982 _2DBillboardShader(createMiscShader(GLShaderSource("assets/opengl/vs_2d_billboard.glsl", GL_VERTEX_SHADER), GLShaderSource("assets/opengl/fs_2d_billboard.glsl", GL_FRAGMENT_SHADER)))
7983 {
7984 GL_CHECK(glGetIntegerv(GL_MAJOR_VERSION, &_glVersionMajor));
7985 GL_CHECK(glGetIntegerv(GL_MINOR_VERSION, &_glVersionMinor));
7986 std::cout << ", GL Version: " << _glVersionMajor << "." << _glVersionMinor << std::endl;
7987
7988 GL_CHECK(glClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]));
7989 }
7990 OpenGLAPI::~OpenGLAPI()
7991 {
7992 }
7993 /*ZNearMapping OpenGLAPI::getZNearMapping() const
7994 {
7995 return ZNearMapping::MINUS_ONE;
7996 }*/
7997 void OpenGLAPI::setViewport(Vec2u const & size) const
7998 {
7999 GL_CHECK(glViewport(0, 0, size.at<0>(), size.at<1>()));
8000 }
8001 void OpenGLAPI::beginFrame() const
8002 {
8003 for (unsigned i = 0; _anisotropy > 1 && i <= static_cast<unsigned>(heightTexUnit); i++) {
8004 _samplerAnisotropic.bind(i);
8005 }
8006 }
8007 void OpenGLAPI::bindShader(Shader const * shader)
8008 {
8009 _activeShader = shader;
8010 _activeShader->bind();
8011 }
8012 void OpenGLAPI::bindShadowmap(const Texture & shadowmap) const
8013 {
8014 GL_CHECK(glActiveTexture(GL_TEXTURE0 + miscTexUnit0));
8015 shadowmap.bind();
8016 }
8017 void OpenGLAPI::renderMesh(GPUMeshData const & gmd) const
8018 {
8019 gmd.draw();
8020 }
8021 void OpenGLAPI::renderMesh(const GPUMeshData& gmd, const Mat4f & model_matrix) const
8022 {
8023 setMatrix(_activeShader->uniformLocation(GLSLShaderGenerator::modelMatrix), model_matrix);
8024 renderMesh(gmd);
8025 }
8026 void OpenGLAPI::renderMesh(const GPUMeshData& gmd, const Mat4f& model_matrix, const Mat3f& model_matrix_inverse) const
8027 {
8028 setMatrixTranspose(_activeShader->uniformLocation(GLSLShaderGenerator::modelMatrixTransposeInverse), model_matrix_inverse);
8029 renderMesh(gmd, model_matrix);
8030 }
8031 void OpenGLAPI::render2DBillboard(const Vec2f & pos_ndc, const Vec2f & scale, const Texture& texture, const Vec3f& color, float depth_ndc)
8032 {
8033 GL_CHECK(glEnable(GL_BLEND));
8034 GL_CHECK(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
8035 bindShader(&_2DBillboardShader);
8036 setVector(_activeShader->uniformLocation("pos_ndc"), pos_ndc);
8037 setVector(_activeShader->uniformLocation("scale"), scale);
8038 setVector(_activeShader->uniformLocation("color"), color);
8039 setScalar(_activeShader->uniformLocation("depth_ndc"), depth_ndc);
8040 activateTexture(texture, "ts", miscTexUnit0);
8041 renderQuad();
8042 GL_CHECK(glDisable(GL_BLEND));
8043 }
8044 void OpenGLAPI::renderDebugTriangle(const Vec4f * triangle, const Mat4f & mvp, const Vec3f & color)
8045 {
8046 GL_CHECK(glPolygonMode(GL_FRONT_AND_BACK, GL_LINE));
8047 bindShader(&_triangleDebugShader);
8048 setVector(_activeShader->uniformLocation("color"), color);
8049 setMatrix(_activeShader->uniformLocation("MVP"), mvp);
8050 setVectorArray(_activeShader->uniformLocation("position"), *triangle, 3);
8051 GL_CHECK(glDrawArrays(GL_TRIANGLES, 0, 3));
8052 GL_CHECK(glPolygonMode(GL_FRONT_AND_BACK, GL_FILL));
8053 }
8054 void OpenGLAPI::renderDebugFrustum(const Mat4f & vp_debug_frustum, const Mat4f & vp)
8055 {
8056 GL_CHECK(glLineWidth(4.f));
8057 bindShader(&_debugFrustumShader);
8058 auto mat = vp * inverse(vp_debug_frustum);
8059 auto cube_ndc = NDCCube<3, float>();
8060 setMatrix(_activeShader->uniformLocation("t"), mat);
8061 GLVertexArray vao;
8062 vao.bind();
8063 GLBuffer vbo(GL_ARRAY_BUFFER);
8064 vbo.setData(cube_ndc.verts(), cube_ndc.numVerts());
8065 GLBuffer ibo(GL_ELEMENT_ARRAY_BUFFER);
8066 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 };
8067 ibo.setData(indices.data(), indices.size());
8068 GL_CHECK(glEnableVertexAttribArray(0));
8069 GL_CHECK(glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(Vec3f), 0));
8070 GL_CHECK(glDrawElements(GL_LINES, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_SHORT, nullptr));
8071 GL_CHECK(glLineWidth(1.f));
8072 }
8073 void OpenGLAPI::bindBackbuffer(unsigned const & id) const
8074 {
8075 GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, id));
8076 }
8077 void OpenGLAPI::ssr(const Texture & lighting_buffer, const Texture& view_space_normals, const Texture& depth_buffer,
8078 const Mat4f& projection_matrix, const Vec4f& blend_weight, Texture& lighting_buffer_copy)
8079 {
8080 depth_buffer.generateMipmap();
8081 GL_CHECK(glEnable(GL_BLEND));
8082 GL_CHECK(glBlendColor(blend_weight.at<0>(), blend_weight.at<1>(), blend_weight.at<2>(), blend_weight.at<3>()));
8083 GL_CHECK(glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR));
8084 bindShader(&_ssrShader);
8085 activateTexture(view_space_normals, GLSLShaderGenerator::viewSpaceNormalsSampler, miscTexUnit0);
8086 activateTexture(lighting_buffer_copy, GLSLShaderGenerator::lightingSampler, miscTexUnit1);
8087 activateTexture(depth_buffer, GLSLShaderGenerator::depthSampler, miscTexUnit2);
8088 setMatrix(_ssrShader.uniformLocation(GLSLShaderGenerator::projectionMatrix), projection_matrix);
8089 auto p_inverse = inverse(projection_matrix);
8090 setMatrix(_ssrShader.uniformLocation(GLSLShaderGenerator::projectionMatrixInverse), p_inverse);
8091 setVector(_ssrShader.uniformLocation(GLSLShaderGenerator::projectionMatrixInverseThirdRow), p_inverse.row<2>());
8092 setVector(_ssrShader.uniformLocation(GLSLShaderGenerator::projectionMatrixInverseFourthRow), p_inverse.row<3>());
8093 renderQuad();
8094 GL_CHECK(glDisable(GL_BLEND));
8095 }
8096 void OpenGLAPI::separableBlur(Texture const & in, std::array<std::shared_ptr<Rendertarget>, 2> const & out)
8097 {
8098 bindShader(&_blurShader);
8099 auto const & dim = out[0]->colorAttachment(0).dim();
8100 for (unsigned i = 0; i < 2; i++) {
8101 out[!i]->bind();
8102 setVector(_activeShader->uniformLocation(GLSLShaderGenerator::texelSize), Vec2f(1.f / dim.at<0>() * i, 1.f / dim.at<1>() * !i));
8103 activateTexture(i ? out[1]->colorAttachment(0) : in, GLSLShaderGenerator::toBlurSampler, miscTexUnit1);
8104 renderQuad();
8105 }
8106 }
8107 void OpenGLAPI::renderGodRays(Texture const & depth_buffer, Texture const & lighting_buffer, const Vec2f & light_pos_uv)
8108 {
8109 bindShader(&_godRayShader);
8110 activateTexture(depth_buffer, GLSLShaderGenerator::depthSampler, miscTexUnit0);
8111 activateTexture(lighting_buffer, GLSLShaderGenerator::lightingSampler, miscTexUnit1);
8112 setVector(_activeShader->uniformLocation(GLSLShaderGenerator::lightPosUV), light_pos_uv);
8113 renderQuad();
8114 }
8115 void OpenGLAPI::renderBrightPass(const Texture & lighting_buffer)
8116 {
8117 bindShader(&_brightnessShader);
8118 activateTexture(lighting_buffer, GLSLShaderGenerator::lightingSampler, miscTexUnit0);
8119 renderQuad();
8120 }
8121 void OpenGLAPI::additiveBlend(const Texture & texture)
8122 {
8123 GL_CHECK(glEnable(GL_BLEND));
8124 GL_CHECK(glBlendFunc(GL_ONE, GL_ONE));
8125 bindShader(&_copyShader);
8126 activateTexture(texture, GLSLShaderGenerator::lightingSampler, miscTexUnit0);
8127 renderQuad();
8128 GL_CHECK(glDisable(GL_BLEND));
8129 }
8130 void OpenGLAPI::endFrame() const
8131 {
8132 for (unsigned i = 0; i <= static_cast<unsigned>(heightTexUnit); i++) {
8133 _samplerAnisotropic.unbind(i);
8134 }
8135 }
8136 void OpenGLAPI::setAnisotropy(unsigned anisotropy)
8137 {
8138 if (_glVersionMajor >= 4 && _glVersionMinor >= 6) {
8139 float max_ani;
8140 GL_CHECK(glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &max_ani));
8141 _anisotropy = glm::clamp(anisotropy, 1u, static_cast<unsigned>(max_ani));
8142 _samplerAnisotropic.param(GL_TEXTURE_MAX_ANISOTROPY, static_cast<float>(_anisotropy));
8143 }
8144 }
8145 void OpenGLAPI::enablePolygonOffset(float factor, float units) const
8146 {
8147 GL_CHECK(glEnable(GL_POLYGON_OFFSET_FILL));
8148 GL_CHECK(glPolygonOffset(factor, units));
8149 }
8150 void OpenGLAPI::disablePolygonOffset() const
8151 {
8152 GL_CHECK(glDisable(GL_POLYGON_OFFSET_FILL));
8153 }
8154 void OpenGLAPI::renderSkydome(Mat4f const & view_projection_matrix, const GPUMeshData& gs)
8155 {
8156 bindShader(&_skydomeShader);
8157 setMatrix(_activeShader->uniformLocation(GLSLShaderGenerator::viewProjectionMatrix), view_projection_matrix);
8158 renderMesh(gs);
8159 }
8160 Texture* OpenGLAPI::createTexture(std::string const & path) const
8161 {
8162 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)) {
8163 // return new (_texturePool.malloc()) GLTexture(tex, GL_TEXTURE_2D);
8164 return new GLTexture(tex, GL_TEXTURE_2D);
8165 }
8166 throw std::exception((std::string("Could not create texture ") + path).c_str());
8167 }
8168 void OpenGLAPI::deleteTexture(Texture const * texture) const
8169 {
8170 // _texturePool.destroy(texture);
8171 delete texture;
8172 }
8173 /*Shader* OpenGLAPI::createShader(GLShaderSource& vs, GLShaderSource& fs, GLShaderSource& gs)
8174 {
8175 //auto ret = new(_shaderPool.malloc()) Shader();
8176 auto ret = new GLShaderProgram();
8177 ret->add(vs);
8178 if (gs._key != "") { ret->add(gs); }
8179 ret->add(fs);
8180 ret->link();
8181 return ret;
8182 }*/
8183 /* void OpenGLAPI::deleteShader(Shader * shader)
8184 {
8185 //_shaderPool.destroy(shader);
8186 delete shader;
8187 }*/
8188
8189 std::shared_ptr<Texture> OpenGLAPI::createDepthbuffer(const Vec2u & size)
8190 {
8191 auto tex = std::make_shared<GLTexture>(GL_TEXTURE_2D);
8192 tex->bind();
8193 tex->param(GL_TEXTURE_MIN_FILTER, GL_NEAREST);
8194 tex->param(GL_TEXTURE_MAG_FILTER, GL_NEAREST);
8195 tex->param(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
8196 tex->param(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
8197 tex->image2D(0, GL_DEPTH_COMPONENT24, size, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
8198 return tex;
8199 }
8200 std::shared_ptr<Texture> OpenGLAPI::createShadowmap(const GraphicsSettings& settings)
8201 {
8202 auto tex = std::make_shared<GLTexture>(GL_TEXTURE_2D_ARRAY);
8203 tex->bind();
8204 GLint filter = settings.shadowsPCF() ? GL_LINEAR : GL_NEAREST;
8205 tex->param(GL_TEXTURE_MIN_FILTER, filter);
8206 tex->param(GL_TEXTURE_MAG_FILTER, filter);
8207 tex->param(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
8208 tex->param(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
8209 tex->param(GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
8210 tex->param(GL_TEXTURE_BORDER_COLOR, Vec4f(std::numeric_limits<float>::max()).ptr());
8211 if (settings.shadowsPCF()) {
8212 tex->param(GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
8213 tex->param(GL_TEXTURE_COMPARE_FUNC, GL_GREATER);
8214 }
8215 resizeShadowmap(*tex, settings);
8216 return tex;
8217 }
8218 void OpenGLAPI::setupCompositing(Texture const & lighting_buffer) const
8219 {
8220 activateTexture(lighting_buffer, GLSLShaderGenerator::lightingSampler, miscTexUnit1);
8221 }
8222 //void OpenGLAPI::setupFog(Vec2f const & fog_start_end) const
8223 // {
8224 // setVector(_activeShader->uniformLocation(GLSLShaderGenerator::fogStartEnd), fog_start_end);
8225 //}
8226 void OpenGLAPI::setupDepthOfField(GlobalShaderParams const & params, Texture const & dof_buffer, Texture const & depth_buffer, Vec3f const & near_center_far) const
8227 {
8228 activateTexture(dof_buffer, GLSLShaderGenerator::dofSampler, miscTexUnit2);
8229 activateTexture(depth_buffer, GLSLShaderGenerator::depthSampler, miscTexUnit3);
8230 auto p_inverse = inverse(params._projectionMatrix);
8231 setVector(_activeShader->uniformLocation(GLSLShaderGenerator::projectionMatrixInverseThirdRow), p_inverse.row<2>());
8232 setVector(_activeShader->uniformLocation(GLSLShaderGenerator::projectionMatrixInverseFourthRow), p_inverse.row<3>());
8233 setVector(_activeShader->uniformLocation(GLSLShaderGenerator::dofNearCenterFar), near_center_far);
8234 }
8235 void OpenGLAPI::setupGodRays(const Vec3f& god_ray_intensity, Texture const & god_ray_buffer) const
8236 {
8237 activateTexture(god_ray_buffer, GLSLShaderGenerator::godRaySampler, miscTexUnit4);
8238 setVector(_activeShader->uniformLocation(GLSLShaderGenerator::godRayIntensity), god_ray_intensity);
8239 }
8240 void OpenGLAPI::setupBloom(Texture const & bloom_buffer) const
8241 {
8242 activateTexture(bloom_buffer, GLSLShaderGenerator::bloomSampler, miscTexUnit5);
8243 }
8244 void OpenGLAPI::setupAutoExposure(const Texture & lighting_buffer) const
8245 {
8246 setScalar(_activeShader->uniformLocation(GLSLShaderGenerator::maxMipLevel), lighting_buffer.maxMipLevel());
8247 }
8248 void OpenGLAPI::resizeShadowmap(Texture& shadow_map, GraphicsSettings const & settings)
8249 {
8250 shadow_map.image3D(0, GL_DEPTH_COMPONENT24, Vec3u(Vec2u(settings.shadowMapSize()), static_cast<unsigned>(settings.numFrustumSplits())), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
8251 }
8252 void OpenGLAPI::createBlurShader(const GraphicsSettings & gs)
8253 {
8254 GLShaderSource vs, fs;
8255 _shaderGenerator.createBlurShaderSource(gs, vs, fs);
8256 _blurShader = createMiscShader(vs, fs);
8257 }
8258 void OpenGLAPI::createCompositeShader(const GraphicsSettings & gs)
8259 {
8260 GLShaderSource vs, fs;
8261 _shaderGenerator.createCompositeShaderSource(gs, vs, fs, false);
8262 _compositeShader = createMiscShader(vs, fs);
8263 _shaderGenerator.createCompositeShaderSource(gs, vs, fs, gs.godRays());
8264 _compositeShaderWithGodRays = createMiscShader(vs, fs);
8265 }
8266 void OpenGLAPI::createScreenSpaceReflectionsShader(const GraphicsSettings & gs)
8267 {
8268 GLShaderSource vs, fs;
8269 _shaderGenerator.createSSRShaderSource(gs, vs, fs);
8270 _ssrShader = createMiscShader(vs, fs);
8271 }
8272 void OpenGLAPI::createGodRayShader(const GraphicsSettings & gs)
8273 {
8274 GLShaderSource vs, fs;
8275 _shaderGenerator.createGodRayShaderSource(gs, vs, fs);
8276 _godRayShader = createMiscShader(vs, fs);
8277 }
8278 void OpenGLAPI::createBrightnessShader(const GraphicsSettings & gs)
8279 {
8280 GLShaderSource vs, fs;
8281 _shaderGenerator.createBrightnessShaderSource(gs, vs, fs);
8282 _brightnessShader = createMiscShader(vs, fs);
8283 }
8284 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
8285 {
8286 return new GLMaterialDesc(material, settings, texture_cache, shader_desc_cache, shader_cache, *this);
8287 }
8288 GPUMeshData * OpenGLAPI::createMeshData(Mesh & mesh) const
8289 {
8290 return new GLMeshData(mesh);
8291 }
8292 OpenGLAPI::ShaderGenerator const & OpenGLAPI::shaderGenerator() const
8293 {
8294 return _shaderGenerator;
8295 }
8296 //Shader const *& OpenGLAPI::activeShader()
8297 // {
8298 // return _activeShader;
8299 //}
8300 Shader const & OpenGLAPI::compositeShader() const
8301 {
8302 return _compositeShader;
8303 }
8304 Shader const & OpenGLAPI::compositeShaderWithGodRays() const
8305 {
8306 return _compositeShaderWithGodRays;
8307 }
8308 void OpenGLAPI::composite() const
8309 {
8310 renderQuad();
8311 }
8312 void OpenGLAPI::checkFramebufferStatus()
8313 {
8314 if (GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
8315 std::cout << "Framebuffer imcomplete" << std::endl;
8316 }
8317 }
8318 GLShaderProgram OpenGLAPI::createMiscShader(GLShaderSource & vs, GLShaderSource & fs, GLShaderSource& gs) const
8319 {
8320 GLShaderProgram shader;
8321 shader.add(vs);
8322 if (gs._key != "") {
8323 shader.add(gs);
8324 }
8325 shader.add(fs);
8326 shader.link();
8327 return shader;
8328 }
8329 template<unsigned index>
8330 struct EnableVertexAttribArrays
8331 {
8332 static auto call()
8333 {
8334 GL_CHECK(glEnableVertexAttribArray(index));
8335 EnableVertexAttribArrays<index - 1u>::call();
8336 }
8337 };
8338 template<>
8339 struct EnableVertexAttribArrays<0>
8340 {
8341 static auto call()
8342 {
8343 GL_CHECK(glEnableVertexAttribArray(0));
8344 }
8345 };
8346 void OpenGLAPI::setupVertexFormat()
8347 {
8348 EnableVertexAttribArrays<3>::call();
8349 GL_CHECK(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(Vertex::positionMemOffset())));
8350 GL_CHECK(glVertexAttribPointer(1, 4, GL_INT_2_10_10_10_REV, GL_TRUE, sizeof(Vertex), reinterpret_cast<void*>(Vertex::normalMemOffset())));
8351 GL_CHECK(glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(Vertex::uvMemOffset())));
8352 GL_CHECK(glVertexAttribPointer(3, 4, GL_INT_2_10_10_10_REV, GL_TRUE, sizeof(Vertex), reinterpret_cast<void*>(Vertex::tangentMemOffset())));
8353 GL_CHECK(glBindVertexArray(0));
8354 }
8355 OpenGLAPI::GlewInit::GlewInit()
8356 {
8357 glewExperimental = true;
8358 auto result = glewInit();
8359 if (result == GLEW_OK) {
8360 std::cout << "OpenGLAPI::OpenGLAPI(): Initialized GLEW";
8361 }
8362 else {
8363 std::cout << "OpenGLAPI::OpenGLAPI() Failed to initialized GLEW: " << glewGetErrorString(result) << std::endl;
8364 }
8365 }
8366 OpenGLAPI::GLMeshData::GLMeshData(Mesh& mesh) :
8367 _vbo(GL_ARRAY_BUFFER),
8368 _ibo(GL_ELEMENT_ARRAY_BUFFER),
8369 _mesh(mesh)
8370 {
8371 auto const & mesh_verts = mesh.vertices();
8372 auto const & mesh_inds = mesh.indices();
8373 _count = static_cast<GLsizei>(mesh_inds.size());
8374 _vao.bind();
8375 _vbo.setData(mesh_verts.begin(), mesh_verts.size());
8376 _type = fillIndexBuffer(mesh_verts.begin(), mesh_verts.end(), mesh_inds.begin(), mesh_inds.end(), _ibo);
8377 setupVertexFormat();
8378 }
8379 void OpenGLAPI::GLMeshData::draw() const
8380 {
8381 _vao.bind();
8382 GL_CHECK(glDrawElements(GL_TRIANGLES, count(), type(), nullptr));
8383 }
8384}
8385#include <opengl/GLSLShaderGenerator.h>
8386#include <GraphicsSettings.h>
8387#include <Flags.h>
8388#include <iostream>
8389
8390namespace RT
8391{
8392 GLSLShaderGenerator::GLSLShaderGenerator() :
8393 _compositeVertexSource(std::string(vertexFileComposite), GL_VERTEX_SHADER)
8394 {
8395 _windParamString = "uniform float " + std::string(time) + "; \n\
8396uniform vec3 " + std::string(bbMin) + "; // AABB min xz\n\
8397uniform vec3 " + std::string(bbMax) + "; // AABB max xz\n" + std::string(noiseCodeGLSL());
8398
8399 _springParticleDataStr = "layout (std430, binding = " + str(bufferBindingSpringSkinnedInitPos) + ") readonly buffer init_pos_buffer \n\
8400{ \n\
8401 vec4 init_pos[]; \n\
8402};\n\
8403layout(std430, binding = " + str(bufferBindingSpringSkinnedPos) + ") readonly buffer pos_buffer \n\
8404{ \n\
8405 vec4 pos[]; \n\
8406};\n";
8407 }
8408 GLShaderSource GLSLShaderGenerator::createMeshVertexShaderSource(unsigned const & flags, GraphicsSettings const & gs)const
8409 {
8410 std::string key = "vs";
8411 if (flags & MeshRenderFlag::MR_SPRING_SKINNED) {
8412 key += "_spring_skinned";
8413 }
8414 key += ".glsl";
8415 GLShaderSource src;
8416 src._key = key;
8417 src._source = createMeshVertexSource(flags, gs);
8418 src._type = GL_VERTEX_SHADER;
8419 return src;
8420 }
8421 GLShaderSource GLSLShaderGenerator::createMeshFragmentShaderSource(unsigned const & flags, GraphicsSettings const & gs)const
8422 {
8423 std::string key = "fs";
8424 if (flags & MeshRenderFlag::MR_DIFFUSE_MAP) {
8425 key += "_albedo";
8426 }
8427 if (flags & MeshRenderFlag::MR_NORMAL_MAP) {
8428 key += "_normal";
8429 if (flags & MeshRenderFlag::MR_HEIGHT_MAP) {
8430 key += "_parallax";
8431 }
8432 }
8433 if (flags & MeshRenderFlag::MR_ALPHA_MAP) {
8434 key += "_alpha";
8435 }
8436 if (flags & MeshRenderFlag::MR_REFLECTIVE) {
8437 key += "_reflective";
8438 }
8439 if (gs.screenSpaceReflections()) {
8440 key += "_ssr";
8441 }
8442 if (gs.shadows() || gs.shadowsPCF()) {
8443 key += "_shadows";
8444 }
8445 if (gs.shadowsPCF()) {
8446 key += "_pcf";
8447 }
8448 if (gs.softShadows()) {
8449 key += "_soft_shadows";
8450 }
8451 if (gs.gammaEnabled()) {
8452 key += "_gamma";
8453 }
8454 if (gs.fog()) {
8455 key += "_fog";
8456 }
8457 key += ".glsl";
8458 GLShaderSource src;
8459 src._key = key;
8460 src._source = createMeshFragmentSource(flags, gs);
8461 src._type = GL_FRAGMENT_SHADER;
8462 return src;
8463 }
8464 GLShaderSource GLSLShaderGenerator::createMeshVertexShaderDepthSource(unsigned const & flags, GraphicsSettings const & gs)const
8465 {
8466 std::string key = "vs_depth";
8467 if (flags & MeshRenderFlag::MR_SPRING_SKINNED) {
8468 key += "_spring_skinned";
8469 }
8470 key += ".glsl";
8471 GLShaderSource src;
8472 src._key = key;
8473 src._source = createMeshVertexDepthSource(flags, gs);
8474 src._type = GL_VERTEX_SHADER;
8475 return src;
8476 }
8477 GLShaderSource GLSLShaderGenerator::createMeshFragmentShaderDepthSource(unsigned const & flags, GraphicsSettings const & gs)const
8478 {
8479 std::string key = "fs_depth";
8480 if (flags & MeshRenderFlag::MR_ALPHA_MAP) {
8481 key += "_alpha";
8482 }
8483 key += ".glsl";
8484 GLShaderSource src;
8485 src._key = key;
8486 src._source = createMeshFragmentDepthSource(flags, gs);
8487 src._type = GL_FRAGMENT_SHADER;
8488 return src;
8489 }
8490 void GLSLShaderGenerator::createCompositeShaderSource(GraphicsSettings const & gs, GLShaderSource& vertex_src, GLShaderSource& fragment_src, bool god_rays)const
8491 {
8492 vertex_src = _compositeVertexSource;
8493 std::string key = "fs_composite";
8494 if (gs.depthOfField()) {
8495 key += "_dof";
8496 }
8497 if (gs.exposureEnabled()) {
8498 key += "_exposure";
8499 }
8500 if (gs.gammaEnabled()) {
8501 key += "_gamma";
8502 }
8503 if (god_rays) {
8504 key += "_god_rays";
8505 }
8506 if (gs.bloom()) {
8507 key += "_bloom";
8508 }
8509 key += ".glsl";
8510 fragment_src._key = key;
8511 fragment_src._source = createCompositeShaderSource(gs, god_rays);
8512 fragment_src._type = GL_FRAGMENT_SHADER;
8513 }
8514 void GLSLShaderGenerator::createBlurShaderSource(GraphicsSettings const & gs, GLShaderSource & vertex_src, GLShaderSource & fragment_src)const
8515 {
8516 vertex_src = _compositeVertexSource;
8517 fragment_src._source = "#version 330 \n\
8518layout(location = 0) out vec3 fragmentColor;\n\
8519in vec2 uv;\n\
8520uniform sampler2D " + std::string(toBlurSampler) + ";\n\
8521uniform vec2 " + std::string(texelSize) + ";\n";
8522 fragment_src._source += blurSource(gs.blurWeights(gs.blurRadius(), gs.blurSigma()));
8523 fragment_src._source += "void main()\n\
8524{\n\
8525 fragmentColor = vec3(0.f);\n\
8526 for (int i = -" + str(gs.blurRadius()) + "; i <= " + str(gs.blurRadius()) + "; i++){\n\
8527 fragmentColor += texture(" + std::string(toBlurSampler) + ", uv + i * " + std::string(texelSize) + ").rgb * blur_weights[i + " + str(gs.blurRadius()) + "];\n\
8528 }\n\
8529}\n";
8530 fragment_src._key = "fs_blur";
8531 fragment_src._type = GL_FRAGMENT_SHADER;
8532 }
8533 void GLSLShaderGenerator::createSSRShaderSource(const GraphicsSettings & gs, GLShaderSource & vertex_src, GLShaderSource & fragment_src)const
8534 {
8535 vertex_src = _compositeVertexSource;
8536 fragment_src._source = "#version 330 \n\
8537layout(location = 0) out vec3 fragmentColor;\n\
8538in vec2 uv;\n\
8539uniform sampler2D " + std::string(lightingSampler) + ";\n\
8540uniform sampler2D " + std::string(viewSpaceNormalsSampler) + ";\n\
8541uniform sampler2D " + std::string(depthSampler) + ";\n\
8542uniform mat4 " + std::string(projectionMatrixInverse) + "; // Inverse projection matrix\n\
8543uniform mat4 " + std::string(projectionMatrix) + "; // Projection matrix\n\
8544uniform vec4 " + std::string(projectionMatrixInverseThirdRow) + "; // Third row of inverse projection matrix\n\
8545uniform vec4 " + std::string(projectionMatrixInverseFourthRow) + "; // Fourth row of inverse projection matrix\n"
8546+ std::string(commonHelpers()) + "void main()\n\
8547{\n\
8548 vec3 normal_view = textureLod(" + std::string(viewSpaceNormalsSampler) + ", uv, 0.f).xyz;\n\
8549 if (normal_view != vec3(0.f)) {\n\
8550 vec4 pos_view_h = " + std::string(projectionMatrixInverse) + " * vec4(uv_to_ndc(vec3(uv, texture(" + std::string(depthSampler) + ", uv).r)), 1.f);\n\
8551 vec3 pos_view = pos_view_h.xyz / pos_view_h.w;\n\
8552 vec3 ray = reflect_(normalize(pos_view), normal_view) * max(-pos_view.z * " + str(gs.SSRRayLenScale()) + "f, " + str(gs.SSRMinRayLen()) + ");\n\
8553 vec3 delta = ray / " + str(gs.SSRSteps()) + "f;\n\
8554 vec3 ray_pos_view = pos_view + delta;\n\
8555 for (float i = 0.f; i < " + str(gs.SSRSteps()) + "f; i++, ray_pos_view += delta) {\n\
8556 vec4 ray_pos_h = " + std::string(projectionMatrix) + " * vec4(ray_pos_view, 1.f);\n\
8557 vec2 ray_pos_ndc = ray_pos_h.xy / ray_pos_h.w;\n\
8558 vec2 uv = ndc_to_uv(ray_pos_ndc);\n\
8559 vec4 comp_ndc = vec4(uv_to_ndc(vec3(uv, texture(" + std::string(depthSampler) + ", uv).r)), 1.f);\n\
8560 float comp_depth = dot(comp_ndc, " + std::string(projectionMatrixInverseThirdRow) + ") / dot(comp_ndc, " + std::string(projectionMatrixInverseFourthRow) + ");\n\
8561 if (ray_pos_view.z > comp_depth) { \n\
8562 float sign;\n\
8563 for (uint i = 0u; i < " + str(gs.SSRBinarySteps()) + "u; i++, delta *= 0.5f, ray_pos_view += delta * sign) { \n\
8564 ray_pos_h = " + std::string(projectionMatrix) + " * vec4(ray_pos_view, 1.f);\n\
8565 ray_pos_ndc = ray_pos_h.xy / ray_pos_h.w;\n\
8566 uv = ndc_to_uv(ray_pos_ndc);\n\
8567 vec4 comp_ndc = vec4(uv_to_ndc(vec3(uv, texture(" + std::string(depthSampler) + ", uv).r)), 1.f);\n\
8568 float comp_depth = dot(comp_ndc, " + std::string(projectionMatrixInverseThirdRow) + ") / dot(comp_ndc, " + std::string(projectionMatrixInverseFourthRow) + ");\n\
8569 sign = ray_pos_view.z > comp_depth ? -1.f : 1.f;\n\
8570 }\n\
8571 fragmentColor = textureLod(" + std::string(lightingSampler) + ", uv, 0.f).rgb;\n\
8572 return;\n\
8573 }\n\
8574 }\n\
8575 }\n\
8576 fragmentColor = textureLod(" + std::string(lightingSampler) + ", uv, 0.f).rgb;\n\
8577}\n";
8578 fragment_src._key = "fs_ssr";
8579 fragment_src._type = GL_FRAGMENT_SHADER;
8580 }
8581 void GLSLShaderGenerator::createGodRayShaderSource(const GraphicsSettings& gs, GLShaderSource & vertex_src, GLShaderSource & fragment_src) const
8582 {
8583 vertex_src = _compositeVertexSource;
8584 fragment_src._source = "#version 330\n\
8585layout(location = 0) out vec3 fragmentColor;\n\
8586uniform sampler2D " + std::string(lightingSampler) + ";\n\
8587uniform sampler2D " + std::string(depthSampler) + ";\n\
8588uniform vec2 " + std::string(lightPosUV) + ";\n\
8589in vec2 uv;\n\
8590void main()\n\
8591{\n\
8592 fragmentColor = vec3(0.f);\n\
8593 vec2 delta = (" + std::string(lightPosUV) + " - uv) / " + str(gs.godRaySteps()) + ";\n\
8594 vec2 tex_coord = uv;\n\
8595 float decay = 1.f;\n\
8596 for (float i = 0.f; i < " + str(gs.godRaySteps()) + "; i++, tex_coord += delta, decay *= " + str(gs.godRayDecay()) + ") { \n\
8597 fragmentColor += decay * texture(" + std::string(lightingSampler) + ", tex_coord).rgb * float(texture(" + std::string(depthSampler) + ", tex_coord).r == 1.f);\n\
8598 }\n\
8599 fragmentColor /= " + str(gs.godRaySteps()) + ";\n\
8600}\n";
8601 fragment_src._key = "fs_god_ray";
8602 fragment_src._type = GL_FRAGMENT_SHADER;
8603 }
8604 void GLSLShaderGenerator::createBrightnessShaderSource(const GraphicsSettings & gs, GLShaderSource & vertex_src, GLShaderSource & fragment_src) const
8605 {
8606 vertex_src = _compositeVertexSource;
8607 fragment_src._source = "#version 330\n\
8608layout (location = 0) out vec3 fragmentColor;\n\
8609uniform sampler2D " + std::string(lightingSampler) + ";\n\
8610in vec2 uv;\n\
8611void main() \n\
8612{\n\
8613 vec3 col = texture(" + std::string(lightingSampler) + ", uv).rgb; \n\
8614 fragmentColor = col * smoothstep(0.85f, 1.f, dot(col, vec3(0.2126f, 0.7152f, 0.0722f)));\n\
8615}";
8616 fragment_src._type = GL_FRAGMENT_SHADER;
8617 }
8618 std::string GLSLShaderGenerator::createMeshVertexSource(unsigned const & flags, GraphicsSettings const & gs) const
8619 {
8620 std::string version = (flags & MR_SPRING_SKINNED) ? "450" : "330";
8621 std::string shader_src;
8622 shader_src += "#version " + version + "\n\
8623layout(location = 0) in vec3 position;\n\
8624layout(location = 1) in vec3 normal;\n\
8625layout(location = 2) in vec2 uv;\n\
8626layout(location = 3) in vec4 tangent;\n\
8627layout (location = 4) in uvec4 p_indices;\n\
8628layout(location = 5) in vec4 weights;\n\
8629// Shader constants\n\
8630uniform mat4 VP; \n\
8631// Model constants\n\
8632uniform mat4 " + std::string(modelMatrix) + ";\n\
8633out vec3 pos_world;\n\
8634out vec3 normal_local;\n\
8635out vec2 uv_out;\n\
8636out vec4 tangent_local;\n";
8637 if (flags & MeshRenderFlag::MR_SPRING_SKINNED) {
8638 shader_src += _springParticleDataStr;
8639 }
8640 if (gs.depthPrepassEnabled()) {
8641 shader_src += "invariant gl_Position; \n";
8642 }
8643 shader_src += "void main()\n\
8644{\n";
8645 if (flags & MeshRenderFlag::MR_SPRING_SKINNED) {
8646 shader_src += " vec3 offs = vec3(0.f);\n\
8647 for (uint i = 0; i < 4; i++) { \n\
8648 offs += (pos[p_indices[i]].xyz - init_pos[p_indices[i]].xyz) * weights[i]; \n\
8649 }\n";
8650 shader_src += " pos_world = (" + std::string(modelMatrix) + " * vec4(position + offs, 1.f)).xyz;\n";
8651 }
8652 else {
8653 shader_src += " pos_world = (" + std::string(modelMatrix) + " * vec4(position, 1.f)).xyz;\n";
8654 }
8655 shader_src += " gl_Position = VP * vec4(pos_world, 1.f);\n\
8656 normal_local = normal;\n\
8657 uv_out = uv;\n\
8658 tangent_local = tangent;\n";
8659 shader_src += "}\n";
8660 return shader_src;
8661 }
8662 std::string GLSLShaderGenerator::createMeshVertexDepthSource(unsigned const & flags, GraphicsSettings const & gs) const
8663 {
8664 std::string version = (flags & MR_SPRING_SKINNED) ? "450" : "330";
8665 std::string shader_src = "#version " + version + "\n\
8666layout(location = 0) in vec3 position;\n\
8667layout(location = 2) in vec2 uv;\n\
8668layout(location = 5) in uvec4 p_indices; \n\
8669layout(location = 6) in vec4 weights; \n";
8670 if (gs.depthPrepassEnabled()) {
8671 shader_src += "invariant gl_Position; \n";
8672 }
8673 shader_src += "uniform mat4 " + std::string(modelMatrix) + ";\n";
8674 shader_src += "uniform mat4 " + std::string(viewProjectionMatrix) + "; \n";
8675 shader_src += _windParamString;
8676 shader_src += "out vec2 uv_out;\n";
8677 if (flags & MR_SPRING_SKINNED) {
8678 shader_src += _springParticleDataStr;
8679 }
8680 shader_src += "void main()\n\
8681{\n";
8682 if (flags & MR_SPRING_SKINNED) {
8683 shader_src += " vec3 offs = vec3(0.f);\n\
8684 for (uint i = 0; i < 4; i++) { \n\
8685 offs += (pos[p_indices[i]].xyz - init_pos[p_indices[i]].xyz) * weights[i]; \n\
8686 }\n";
8687 shader_src += " vec4 pos_world = " + std::string(modelMatrix) + " * vec4(position + offs, 1.f);\n";
8688 }
8689 else {
8690 shader_src += " vec4 pos_world = " + std::string(modelMatrix) + " * vec4(position, 1.f);\n";
8691 }
8692 shader_src += " gl_Position = " + std::string(viewProjectionMatrix) + " * pos_world;\n";
8693 shader_src += " uv_out = uv;\n\
8694}\n";
8695 return shader_src;
8696 }
8697 std::string GLSLShaderGenerator::createMeshFragmentSource(unsigned const & flags, GraphicsSettings const & gs) const
8698 {
8699 std::string version = "330";
8700 bool tangent_space = (flags & MR_NORMAL_MAP) || (flags & MR_HEIGHT_MAP);
8701 std::string shader_src = "#version " + version + " \n\
8702layout(location = 0) out vec3 fragmentColor;\n";
8703 unsigned rt_index = 1;
8704 if (gs.screenSpaceReflections()) {
8705 shader_src += "layout(location = " + str(rt_index) + ") out vec3 viewSpaceNormal; \n";
8706 rt_index++;
8707 }
8708 shader_src += "in vec3 pos_world;\n\
8709in vec2 uv_out;\n\
8710uniform vec3 " + std::string(diffuseColor) + ";\n\
8711uniform sampler2D " + std::string(diffuseSampler) + ";\n\
8712uniform sampler2D " + std::string(alphaSampler) + ";\n\
8713uniform sampler2D " + std::string(normalSampler) + ";\n\
8714uniform sampler2D " + std::string(heightSampler) + ";\n\
8715uniform float " + std::string(parallaxHeightScale) + "; // Parallax ray scale\n\
8716uniform float " + std::string(shadowMapBias) + "; // Shadow map bias\n\
8717uniform float " + std::string(parallaxMinSteps) + "; // Parallax min steps\n\
8718uniform float " + std::string(parallaxMaxSteps) + "; // Parallax max steps\n\
8719uniform float " + std::string(parallaxBinarySearchSteps) + "; // Parallax binary search steps\n\
8720uniform vec3 " + std::string(lightDirWorld) + "; // light direction world space\n\
8721uniform vec3 " + std::string(cameraPositionWorld) + "; // camera position world space\n\
8722uniform vec3 " + std::string(lightIntensity) + "; // light intensity\n\
8723uniform mat4 " + std::string(worldToLightMatrices) + " [" + str(gs.numFrustumSplits()) + "]; // world space to light space\n\
8724uniform float " + std::string(frustumSplits) + " [" + str(gs.numFrustumSplits()) + "]; // frustum_splits\n\
8725uniform int " + std::string(numfrustumSplits) + "; // num frustum splits\n";
8726 shader_src += (gs.shadowsPCF() ? "uniform sampler2DArrayShadow " : "uniform sampler2DArray ") + std::string(shadowSampler) + ";\n";
8727 shader_src += "// Material constants\n\
8728uniform float " + std::string(ambientConstant) + ";\n\
8729uniform float " + std::string(diffuseConstant) + ";\n\
8730uniform float " + std::string(specularConstant) + ";\n\
8731uniform float " + std::string(specularExponent) + ";\n\
8732uniform float " + std::string(gamma) + ";\n\
8733uniform mat3 " + std::string(modelMatrixTransposeInverse) + ";\n\
8734uniform mat3 " + std::string(viewMatrixOrtho) + ";\n\
8735uniform vec4 " + std::string(viewMatrixThirdRow) + ";\n\
8736uniform vec2 " + std::string(fogStartEnd) + ";\n\
8737uniform vec3 " + std::string(fogColor) + ";\n\
8738in vec3 normal_local;\n\
8739in vec4 tangent_local;\n";
8740 shader_src += blurSource(gs.blurWeights2D(gs.shadowBlurRadius(), gs.shadowBlurSigma()));
8741 shader_src += "void main()\n\
8742{\n\
8743 vec2 uv = uv_out;\n";
8744 if (tangent_space) {
8745 shader_src += " vec3 bitangent_local = tangent_local.w * cross(normal_local, tangent_local.xyz);\n";
8746 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";
8747 }
8748 shader_src += " vec3 e =" + std::string(tangent_space ? " world_to_tangent *" : "") + " normalize(" + std::string(cameraPositionWorld) + " - pos_world); \n";
8749 if ((flags & MR_NORMAL_MAP) && (flags & MR_HEIGHT_MAP)) {
8750 if (!gs.reliefMapping()) {
8751 shader_src += " uv -= e.xy / e.z * (1.f - textureLod(" + std::string(heightSampler) + ", uv, 0.f).r) * " + std::string(parallaxHeightScale) + "; \n";
8752 }
8753 else {
8754 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\
8755 vec2 ray = e.xy * " + std::string(parallaxHeightScale) + ";\n\
8756 vec2 delta = ray / steps;\n\
8757 float layer_delta = 1.f / steps;\n\
8758 float layer_depth = 1.f - layer_delta;\n\
8759 uv -= delta;\n\
8760 for (float i = 0.f; i < steps; i++, uv -= delta, layer_depth -= layer_delta) {\n\
8761 if(textureLod(" + std::string(heightSampler) + ", uv, 0.f).r > layer_depth){\n\
8762 delta *= 0.5f;\n\
8763 layer_delta *= 0.5f;\n\
8764 uv += delta;\n\
8765 layer_depth += layer_delta;\n\
8766 for (float i = 0.f, sign; i < " + std::string(parallaxBinarySearchSteps) + "; i++, uv += delta * sign, layer_depth += layer_delta * sign){\n\
8767 sign = (textureLod(" + std::string(heightSampler) + ", uv, 0.f).r > layer_depth) ? 1.f : -1.f;\n\
8768 delta *= 0.5f;\n\
8769 layer_delta *= 0.5f;\n\
8770 }\n\
8771 break;\n\
8772 }\n\
8773 }\n";
8774 }
8775 }
8776 if (flags & MeshRenderFlag::MR_ALPHA_MAP) {
8777 shader_src += " if (texture(" + std::string(alphaSampler) + ", uv).r < 0.5f) {\n\
8778 discard;\n\
8779 return;\n\
8780 }\n";
8781 }
8782 shader_src += " vec3 l = " + std::string((tangent_space ? "world_to_tangent *" : "")) + std::string(lightDirWorld) + ";\n";
8783 if (flags & MeshRenderFlag::MR_NORMAL_MAP) {
8784 shader_src += " vec3 n = normalize((texture(" + std::string(normalSampler) + ", uv).xyz * 2.f - 1.f));\n";
8785 }
8786 else {
8787 shader_src += " vec3 n = normalize(" + std::string(modelMatrixTransposeInverse) + " * normal_local);\n";
8788 }
8789 shader_src += " float diffuse = max(dot(l, n), 0.f);\n\
8790 float specular = pow(max(dot(normalize(e + l), n), 0.f), " + std::string(specularExponent) + ");\n";
8791
8792 if (flags & MeshRenderFlag::MR_DIFFUSE_MAP) {
8793 shader_src += " vec3 albedo = texture(" + std::string(diffuseSampler) + ", uv).rgb;\n";
8794 }
8795 else {
8796 shader_src += " vec3 albedo = " + std::string(diffuseColor) + ";\n";
8797 }
8798 if (gs.gammaEnabled()) {
8799 shader_src += " albedo = pow(albedo, vec3(" + std::string(gamma) + "));\n";
8800 }
8801 if (gs.shadows() || gs.fog()) {
8802 shader_src += " float depth_view = dot(" + std::string(viewMatrixThirdRow) + ", vec4(pos_world, 1.f));\n";
8803 }
8804 if (gs.shadows() || gs.shadowsPCF()) {
8805 shader_src += " int index = " + std::string(numfrustumSplits) + "-1;\n\
8806 for (int i = " + std::string(numfrustumSplits) + "-2; i >= 0; i--) {\n\
8807 index -= int(depth_view < " + std::string(frustumSplits) + "[i]);\n\
8808 }\n";
8809 shader_src += " vec4 shadow_coord = " + std::string(worldToLightMatrices) + "[index] * vec4(pos_world, 1.f);\n\
8810 shadow_coord.xyz /= shadow_coord.w;\n\
8811 shadow_coord = shadow_coord * 0.5f + 0.5f;\n";
8812 if (!gs.shadowsPCF()) {
8813 shader_src += " if (all(greaterThanEqual(shadow_coord.xyz, vec3(0.f))) && all(lessThanEqual(shadow_coord.xyz, vec3(1.f)))) {\n ";
8814 }
8815 if (gs.softShadows()) {
8816 auto rad = str(gs.shadowBlurRadius());
8817 shader_src += " float light_factor = 1.f;\n\
8818 vec2 offs = 1.f / textureSize(" + std::string(shadowSampler) + ", 0).xy;\n\
8819 for (int u = -" + rad + "; u <= " + rad + "; u++) {\n\
8820 for(int v = -" + rad + "; v <= " + rad + "; v++) {\n\
8821 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\
8822 }\n\
8823}\n";
8824 }
8825 else {
8826 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";
8827 }
8828 shader_src += " specular *= light_factor;\n\
8829 diffuse *= light_factor;\n";
8830 if (!gs.shadowsPCF()) {
8831 shader_src += " }\n";
8832 }
8833 }
8834 shader_src += " fragmentColor = " + std::string(lightIntensity) + " * albedo * (" + std::string(ambientConstant) + " + " + std::string(diffuseConstant) + " * diffuse + " + std::string(specularConstant) + " * specular);\n";
8835 if (gs.fog()) {
8836 shader_src += " fragmentColor = mix(fragmentColor, " + std::string(fogColor) + ", smoothstep(" + std::string(fogStartEnd) + ".x, " + std::string(fogStartEnd) + ".y, depth_view)); \n";
8837 }
8838 if (gs.screenSpaceReflections()) {
8839 if (flags & MR_REFLECTIVE) {
8840 shader_src += " mat3 mv_inverse = " + std::string(viewMatrixOrtho) + " * " + std::string(modelMatrixTransposeInverse) + ";\n";
8841 if (tangent_space) {
8842 shader_src += " mat3 tangent_to_view = mat3(normalize(mv_inverse * tangent_local.xyz), normalize(mv_inverse * bitangent_local), normalize(mv_inverse * normal_local));\n\
8843 viewSpaceNormal = normalize(tangent_to_view * n);\n";
8844 }
8845 else {
8846 shader_src += " viewSpaceNormal = normalize(mv_inverse * normal_local);\n";
8847 }
8848 }
8849 else {
8850 shader_src += " viewSpaceNormal = vec3(0.f);\n";
8851 }
8852 }
8853 shader_src += "}\n";
8854 return shader_src;
8855 }
8856 std::string GLSLShaderGenerator::createMeshFragmentDepthSource(unsigned const & flags, GraphicsSettings const & gs) const
8857 {
8858 std::string shader_src = "#version 330\n\
8859in vec2 uv_out;\n";
8860 if (flags & MR_ALPHA_MAP) {
8861 shader_src += "uniform sampler2D " + std::string(alphaSampler) + ";\n";
8862 }
8863 shader_src += "void main()\n\
8864{\n";
8865 if (flags & MR_ALPHA_MAP) {
8866 shader_src += " if (texture(" + std::string(alphaSampler) + ", uv_out).r < 0.5f){\n\
8867 discard;\n\
8868 }\n";
8869 }
8870 shader_src += "}";
8871 return shader_src;
8872 }
8873 std::string GLSLShaderGenerator::createCompositeShaderSource(GraphicsSettings const & gs, bool const & god_rays) const
8874 {
8875 std::string shader_src = "#version 330\n\
8876layout(location = 0) out vec3 fragmentColor;\n\
8877uniform sampler2D " + std::string(lightingSampler) + ";\n\
8878uniform sampler2D " + std::string(depthSampler) + ";\n\
8879uniform sampler2D " + std::string(dofSampler) + ";\n\
8880uniform sampler2D " + std::string(godRaySampler) + ";\n\
8881uniform sampler2D " + std::string(bloomSampler) + ";\n\
8882uniform vec4 " + std::string(projectionMatrixInverseThirdRow) + ";\n\
8883uniform vec4 " + std::string(projectionMatrixInverseFourthRow) + ";\n\
8884uniform vec3 " + godRayIntensity + ";\n\
8885uniform float " + std::string(maxMipLevel) + ";\n\
8886uniform vec3 " + std::string(dofNearCenterFar) + ";\n\
8887in vec2 uv;\n\
8888void main()\n\
8889{\n\
8890 fragmentColor = textureLod(" + std::string(lightingSampler) + ", uv, 0.f).rgb;\n";
8891 if (gs.depthOfField()) {
8892 shader_src += " vec4 pos_ndc = vec4(vec3(uv, texture(" + std::string(depthSampler) + ", uv).r) * 2.f - 1.f, 1.f);\n\
8893 float depth_view = dot(" + std::string(projectionMatrixInverseThirdRow) + ", pos_ndc) / dot(" + std::string(projectionMatrixInverseFourthRow) + ", pos_ndc);\n\
8894 vec3 blur_color = texture(" + std::string(dofSampler) + ", uv).rgb;\n\
8895 fragmentColor = (depth_view >= " + std::string(dofNearCenterFar) + ".y) ? \n\
8896 mix(fragmentColor, blur_color, smoothstep(" + std::string(dofNearCenterFar) + ".y, " + std::string(dofNearCenterFar) + ".z, depth_view)) : \n\
8897 mix(blur_color, fragmentColor, smoothstep(" + std::string(dofNearCenterFar) + ".x, " + std::string(dofNearCenterFar) + ".y, depth_view));\n";
8898 }
8899 if (gs.autoExposure()) {
8900 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";
8901 }
8902 if (god_rays) {
8903 shader_src += " fragmentColor += texture(" + std::string(godRaySampler) + ", uv).rgb * " + godRayIntensity + ";\n";
8904 }
8905 if (gs.bloom()) {
8906 shader_src += " fragmentColor += texture(" + std::string(bloomSampler) + ", uv).rgb" + (gs.autoExposure() ? " * (1.f - smoothstep(0.f, " + str(gs.refBrightness()) + ", scene_brightness))" : "") + ";\n";
8907 }
8908 if (gs.exposureEnabled()) {
8909 shader_src += " fragmentColor *= " + str(gs.exposure()) + (gs.autoExposure() ? " * clamp(0.25f / scene_brightness, 0.5f, 3.f)" : "") + ";\n";
8910 }
8911 shader_src += " fragmentColor /= 1.f + fragmentColor;\n";
8912 if (gs.gammaEnabled()) {
8913 shader_src += " fragmentColor = pow(fragmentColor, vec3(" + str(1.f / gs.gamma()) + "));\n";
8914 }
8915 return shader_src + "}\n";
8916 }
8917 std::string GLSLShaderGenerator::blurSource(StackTrivial<float> const & weights) const
8918 {
8919 std::string res = " const float blur_weights[" + str(weights.size()) + "] = float[](";
8920 for (auto* ptr = weights.begin(); ptr != weights.end(); ptr++) {
8921 res += str(*ptr);
8922 res += ptr == weights.end() - 1u ? ");\n" : ",";
8923 }
8924 return res;
8925 }
8926}