1 | // Copyright (C) 2016 Paul Lemire |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "frustumcullingjob_p.h" |
5 | #include <Qt3DRender/private/job_common_p.h> |
6 | #include <Qt3DRender/private/managers_p.h> |
7 | #include <Qt3DRender/private/entity_p.h> |
8 | #include <Qt3DRender/private/sphere_p.h> |
9 | #include <Qt3DRender/private/managers_p.h> |
10 | #include <Qt3DRender/private/nodemanagers_p.h> |
11 | |
12 | QT_BEGIN_NAMESPACE |
13 | |
14 | namespace Qt3DRender { |
15 | |
16 | namespace Render { |
17 | |
18 | namespace { |
19 | int instanceCounter = 0; |
20 | } // anonymous |
21 | |
22 | FrustumCullingJob::FrustumCullingJob() |
23 | : Qt3DCore::QAspectJob() |
24 | , m_root(nullptr) |
25 | , m_manager(nullptr) |
26 | , m_active(false) |
27 | { |
28 | SET_JOB_RUN_STAT_TYPE(this, JobTypes::FrustumCulling, instanceCounter++) |
29 | } |
30 | |
31 | FrustumCullingJob::~FrustumCullingJob() |
32 | { |
33 | --instanceCounter; |
34 | } |
35 | |
36 | void FrustumCullingJob::run() |
37 | { |
38 | // Early return if not activated |
39 | if (!m_active) |
40 | return; |
41 | |
42 | m_visibleEntities.clear(); |
43 | |
44 | const Plane planes[6] = { |
45 | Plane(m_viewProjection.row(index: 3) + m_viewProjection.row(index: 0)), // Left |
46 | Plane(m_viewProjection.row(index: 3) - m_viewProjection.row(index: 0)), // Right |
47 | Plane(m_viewProjection.row(index: 3) + m_viewProjection.row(index: 1)), // Top |
48 | Plane(m_viewProjection.row(index: 3) - m_viewProjection.row(index: 1)), // Bottom |
49 | Plane(m_viewProjection.row(index: 3) + m_viewProjection.row(index: 2)), // Front |
50 | Plane(m_viewProjection.row(index: 3) - m_viewProjection.row(index: 2)), // Back |
51 | }; |
52 | |
53 | cullScene(e: m_root, planes); |
54 | |
55 | // sort needed for set_intersection in RenderViewBuilder |
56 | std::sort(first: m_visibleEntities.begin(), last: m_visibleEntities.end()); |
57 | } |
58 | |
59 | void FrustumCullingJob::cullScene(Entity *e, const Plane *planes) |
60 | { |
61 | e->traverse(operation: [planes, this](Entity *e) { |
62 | const Sphere *s = e->worldBoundingVolumeWithChildren(); |
63 | |
64 | // Unrolled loop |
65 | if (Vector3D::dotProduct(a: s->center(), b: planes[0].normal) + planes[0].d < -s->radius()) |
66 | return; |
67 | if (Vector3D::dotProduct(a: s->center(), b: planes[1].normal) + planes[1].d < -s->radius()) |
68 | return; |
69 | if (Vector3D::dotProduct(a: s->center(), b: planes[2].normal) + planes[2].d < -s->radius()) |
70 | return; |
71 | if (Vector3D::dotProduct(a: s->center(), b: planes[3].normal) + planes[3].d < -s->radius()) |
72 | return; |
73 | if (Vector3D::dotProduct(a: s->center(), b: planes[4].normal) + planes[4].d < -s->radius()) |
74 | return; |
75 | if (Vector3D::dotProduct(a: s->center(), b: planes[5].normal) + planes[5].d < -s->radius()) |
76 | return; |
77 | |
78 | m_visibleEntities.push_back(x: e); |
79 | }); |
80 | } |
81 | |
82 | bool FrustumCullingJob::isRequired() |
83 | { |
84 | return m_active; |
85 | } |
86 | |
87 | } // Render |
88 | |
89 | } // Qt3DRender |
90 | |
91 | QT_END_NAMESPACE |
92 | |