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