1// Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
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 "triangleboundingvolume_p.h"
5#include <Qt3DRender/private/qray3d_p.h>
6
7QT_BEGIN_NAMESPACE
8
9namespace Qt3DRender {
10
11namespace Render {
12
13// Note: a, b, c in clockwise order
14// RealTime Collision Detection page 192
15bool intersectsSegmentTriangle(const RayCasting::QRay3D &ray,
16 const Vector3D &a,
17 const Vector3D &b,
18 const Vector3D &c,
19 Vector3D &uvw,
20 float &t)
21{
22 const Vector3D ab = b - a;
23 const Vector3D ac = c - a;
24 const Vector3D qp = (ray.origin() - ray.point(t: ray.distance()));
25
26 const Vector3D n = Vector3D::crossProduct(a: ab, b: ac);
27 const float d = Vector3D::dotProduct(a: qp, b: n);
28
29 if (d <= 0.0f)
30 return false;
31
32 const Vector3D ap = ray.origin() - a;
33 t = Vector3D::dotProduct(a: ap, b: n);
34
35 if (t < 0.0f || t > d)
36 return false;
37
38 const Vector3D e = Vector3D::crossProduct(a: qp, b: ap);
39 uvw.setY(Vector3D::dotProduct(a: ac, b: e));
40
41 if (uvw.y() < 0.0f || uvw.y() > d)
42 return false;
43
44 uvw.setZ(-Vector3D::dotProduct(a: ab, b: e));
45
46 if (uvw.z() < 0.0f || uvw.y() + uvw.z() > d)
47 return false;
48
49 const float ood = 1.0f / d;
50 t *= ood;
51 uvw.setY(uvw.y() * ood);
52 uvw.setZ(uvw.z() * ood);
53 uvw.setX(1.0f - uvw.y() - uvw.z());
54
55 return true;
56}
57
58TriangleBoundingVolume::TriangleBoundingVolume()
59 : QBoundingVolume()
60{
61}
62
63/*
64 The vertices a, b, c are assumed to be in counter clockwise order.
65 */
66TriangleBoundingVolume::TriangleBoundingVolume(Qt3DCore::QNodeId id, const Vector3D &a, const Vector3D &b, const Vector3D &c)
67 : QBoundingVolume()
68 , m_id(id)
69 , m_a(a)
70 , m_b(b)
71 , m_c(c)
72{}
73
74Qt3DCore::QNodeId TriangleBoundingVolume::id() const
75{
76 return m_id;
77}
78
79bool TriangleBoundingVolume::intersects(const RayCasting::QRay3D &ray, Vector3D *q, Vector3D *uvw) const
80{
81 float t = 0.0f;
82 Vector3D uvwr;
83 const bool intersected = intersectsSegmentTriangle(ray, a: m_c, b: m_b, c: m_a, uvw&: uvwr, t);
84
85 if (intersected) {
86 if (q != nullptr)
87 *q = ray.point(t);
88 if (uvw != nullptr)
89 *uvw = uvwr;
90 }
91 return intersected;
92}
93
94TriangleBoundingVolume::Type TriangleBoundingVolume::type() const
95{
96 return RayCasting::QBoundingVolume::Triangle;
97}
98
99Vector3D TriangleBoundingVolume::a() const
100{
101 return m_a;
102}
103
104Vector3D TriangleBoundingVolume::b() const
105{
106 return m_b;
107}
108
109Vector3D TriangleBoundingVolume::c() const
110{
111 return m_c;
112}
113
114void TriangleBoundingVolume::setA(const Vector3D &a)
115{
116 m_a = a;
117}
118
119void TriangleBoundingVolume::setB(const Vector3D &b)
120{
121 m_b = b;
122}
123
124void TriangleBoundingVolume::setC(const Vector3D &c)
125{
126 m_c = c;
127}
128
129TriangleBoundingVolume TriangleBoundingVolume::transformed(const Matrix4x4 &mat) const
130{
131 const Vector3D tA = mat.map(point: m_a);
132 const Vector3D tB = mat.map(point: m_b);
133 const Vector3D tC = mat.map(point: m_c);
134 return TriangleBoundingVolume(id(), tA, tB, tC);
135}
136
137} // namespace Render
138
139} // namespace Qt3DRender
140
141QT_END_NAMESPACE
142

source code of qt3d/src/render/backend/triangleboundingvolume.cpp