1// Copyright (C) 2008-2012 NVIDIA Corporation.
2// Copyright (C) 2019 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4
5#ifndef QSSG_RENDER_CLIPPING_PLANE_H
6#define QSSG_RENDER_CLIPPING_PLANE_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <QtQuick3DUtils/private/qssgplane_p.h>
20#include <QtQuick3DUtils/private/qssgbounds3_p.h>
21#include <QtQuick3DRuntimeRender/private/qtquick3druntimerenderexports_p.h>
22
23QT_BEGIN_NAMESPACE
24
25struct QSSGClipPlane
26{
27 enum BoxEdgeID : quint8
28 {
29 None = 0,
30 xMax = 1,
31 yMax = 1 << 1,
32 zMax = 1 << 2,
33 };
34 using BoxEdgeFlag = std::underlying_type_t<BoxEdgeID>;
35
36 // For an intesection test, we only need two points of the bounding box.
37 // There will be a point nearest to the plane, and a point furthest from the plane.
38 // We can derive these points from the plane normal equation.
39 struct BoxEdge
40 {
41 BoxEdgeFlag lowerEdge;
42 BoxEdgeFlag upperEdge;
43 };
44
45 QVector3D normal;
46 float d;
47 BoxEdge mEdges;
48
49 // For intersection tests, we only need to know if the numerator is greater than, equal to,
50 // or less than zero.
51 [[nodiscard]] constexpr inline float distance(const QVector3D &pt) const { return QVector3D::dotProduct(v1: normal, v2: pt) + d; }
52
53 // Only works if p0 is above the line and p1 is below the plane.
54 inline QVector3D intersectWithLine(const QVector3D &p0, const QVector3D &p1) const
55 {
56 QVector3D dir = p1 - p0;
57 QVector3D pointOnPlane = normal * (-d);
58#ifdef _DEBUG
59 float distanceOfPoint = distance(pointOnPlane);
60 Q_ASSERT(qAbs(distanceOfPoint) < 0.0001f);
61#endif
62 float numerator = QVector3D::dotProduct(v1: pointOnPlane - p0, v2: normal);
63 float denominator = QVector3D::dotProduct(v1: dir, v2: normal);
64
65 Q_ASSERT(qAbs(denominator) > .0001f);
66 float t = (numerator / denominator);
67 QVector3D retval = p0 + dir * t;
68#ifdef _DEBUG
69 float retvalDistance = distance(retval);
70 Q_ASSERT(qAbs(retvalDistance) < .0001f);
71#endif
72 return retval;
73 }
74
75 static inline constexpr QVector3D corner(const QSSGBounds3 &bounds, BoxEdgeFlag edge)
76 {
77 return QVector3D((edge & BoxEdgeID::xMax) ? bounds.maximum[0] : bounds.minimum[0],
78 (edge & BoxEdgeID::yMax) ? bounds.maximum[1] : bounds.minimum[1],
79 (edge & BoxEdgeID::zMax) ? bounds.maximum[2] : bounds.minimum[2]);
80 }
81
82 // dividing the distance numerator
83
84 // I got this code from osg, but it is in graphics gems
85 // as well.
86 /** intersection test between plane and bounding sphere.
87 return 1 if the bs is completely above plane,
88 return 0 if the bs intersects the plane,
89 return -1 if the bs is completely below the plane.*/
90 inline int intersect(const QSSGBounds3 &bounds) const
91 {
92 // if lowest point above plane than all above.
93 if (distance(pt: corner(bounds, edge: mEdges.lowerEdge)) > 0.0f)
94 return 1;
95
96 // if highest point is below plane then all below.
97 if (distance(pt: corner(bounds, edge: mEdges.upperEdge)) < 0.0f)
98 return -1;
99
100 // d_lower<=0.0f && d_upper>=0.0f
101 // therefore must be crossing plane.
102 return 0;
103 }
104
105 [[nodiscard]] constexpr bool intersectSimple(const QSSGBounds3 &bounds) const
106 {
107 return (distance(pt: corner(bounds, edge: mEdges.lowerEdge)) > 0.0f) || !(distance(pt: corner(bounds, edge: mEdges.upperEdge)) < 0.0f);
108 }
109
110 inline void calculateBBoxEdges()
111 {
112 mEdges.upperEdge = (normal[0] >= 0.0f ? BoxEdgeID::xMax : BoxEdgeID::None)
113 | (normal[1] >= 0.0f ? BoxEdgeID::yMax : BoxEdgeID::None)
114 | (normal[2] >= 0.0f ? BoxEdgeID::zMax : BoxEdgeID::None);
115
116 mEdges.lowerEdge = ((~(BoxEdgeFlag(mEdges.upperEdge))) & 7);
117 }
118};
119
120struct Q_QUICK3DRUNTIMERENDER_EXPORT QSSGClippingFrustum
121{
122 QSSGClipPlane mPlanes[6];
123
124 QSSGClippingFrustum() = default;
125
126 QSSGClippingFrustum(const QMatrix4x4 &modelviewprojection, const QSSGClipPlane &nearPlane);
127
128 bool intersectsWith(const QSSGBounds3 &bounds) const
129 {
130 bool ret = true;
131
132 for (quint32 idx = 0; idx < 6 && ret; ++idx)
133 ret = mPlanes[idx].intersectSimple(bounds);
134 return ret;
135 }
136
137 bool intersectsWith(const QVector3D &point, float radius = 0.0f) const
138 {
139 bool ret = true;
140 for (quint32 idx = 0; idx < 6 && ret; ++idx)
141 ret = !(mPlanes[idx].distance(pt: point) < radius);
142 return ret;
143 }
144};
145QT_END_NAMESPACE
146
147#endif
148

source code of qtquick3d/src/runtimerender/qssgrenderclippingfrustum_p.h