Photon Engine 2.0.0-beta
A physically based renderer.
Loading...
Searching...
No Matches
TBasicTriangle.ipp
Go to the documentation of this file.
1#pragma once
2
4#include "Math/TMatrix2.h"
5
6#include <Common/assertion.h>
7
8#include <cmath>
9#include <type_traits>
10#include <limits>
11
12namespace ph::math
13{
14
15template<typename T>
17 const std::array<TVector3<T>, 3>& attributes,
18 const TVector3<T>& barycentricCoords)
19{
20 return interpolate(
21 attributes[0],
22 attributes[1],
23 attributes[2],
24 barycentricCoords);
25}
26
27template<typename T>
29 const TVector3<T>& attributeA,
30 const TVector3<T>& attributeB,
31 const TVector3<T>& attributeC,
32 const TVector3<T>& barycentricCoords)
33{
35 attributeA, barycentricCoords.x(),
36 attributeB, barycentricCoords.y(),
37 attributeC, barycentricCoords.z());
38}
39
40template<typename T>
42 const std::array<TVector3<T>, 3>& attributes,
43 const std::array<TVector2<T>, 3>& parameterizations,
44 TVector3<T>* const out_dXdU,
45 TVector3<T>* const out_dXdV)
46{
47 PH_ASSERT(out_dXdU);
48 PH_ASSERT(out_dXdV);
49
50 const auto deltaUv01 = parameterizations[1] - parameterizations[0];
51 const auto deltaUv02 = parameterizations[2] - parameterizations[0];
52
53 const TMatrix2<T> A(
54 deltaUv01,
55 deltaUv02);
57 const auto deltaAttr01 = attributes[1] - attributes[0];
58 const auto deltaAttr02 = attributes[2] - attributes[0];
59
60 const std::array<std::array<T, 2>, 3> bs = {
61 deltaAttr01.x(), deltaAttr02.x(),
62 deltaAttr01.y(), deltaAttr02.y(),
63 deltaAttr01.z(), deltaAttr02.z()};
64
65 std::array<std::array<T, 2>, 3> xs;
66 if(A.solve(bs, &xs))
67 {
68 out_dXdU->x() = xs[0][0]; out_dXdV->x() = xs[0][1];
69 out_dXdU->y() = xs[1][0]; out_dXdV->y() = xs[1][1];
70 out_dXdU->z() = xs[2][0]; out_dXdV->z() = xs[2][1];
71
72 return true;
73 }
74 else
75 {
76 return false;
77 }
80template<typename T>
82 TVector3<T> vA,
83 TVector3<T> vB,
84 TVector3<T> vC) :
85
86 m_vA(std::move(vA)),
87 m_vB(std::move(vB)),
88 m_vC(std::move(vC))
89{}
90
91template<typename T>
92inline TBasicTriangle<T>::TBasicTriangle(std::array<TVector3<T>, 3> vertices) :
94 std::move(vertices[0]),
95 std::move(vertices[1]),
96 std::move(vertices[2]))
97{}
98
99template<typename T>
102 const auto [eAB, eAC] = getEdgeVectors();
104 return eAB.cross(eAC).length() * T(0.5);
106
107template<typename T>
109{
110 const auto [eAB, eAC] = getEdgeVectors();
111
112 return eAB.cross(eAC).normalizeLocal();
113}
114
115template<typename T>
117{
118 const auto [eAB, eAC] = getEdgeVectors();
119
120 return !isDegenerate() ? eAB.cross(eAC).safeNormalize(failSafe) : failSafe;
121}
122
123template<typename T>
125{
126 if constexpr(std::is_floating_point_v<T>)
127 {
128 constexpr auto oneThird = static_cast<T>(1) / static_cast<T>(3);
129 return (m_vA + m_vB + m_vC) * oneThird;
130 }
131 else
132 {
133 return (m_vA + m_vB + m_vC) / static_cast<T>(3);
134 }
135}
136
137template<typename T>
139{
140 T minX = m_vA.x(), maxX = m_vA.x(),
141 minY = m_vA.y(), maxY = m_vA.y(),
142 minZ = m_vA.z(), maxZ = m_vA.z();
143
144 if (m_vB.x() > maxX) maxX = m_vB.x();
145 else if(m_vB.x() < minX) minX = m_vB.x();
146 if (m_vB.y() > maxY) maxY = m_vB.y();
147 else if(m_vB.y() < minY) minY = m_vB.y();
148 if (m_vB.z() > maxZ) maxZ = m_vB.z();
149 else if(m_vB.z() < minZ) minZ = m_vB.z();
150
151 if (m_vC.x() > maxX) maxX = m_vC.x();
152 else if(m_vC.x() < minX) minX = m_vC.x();
153 if (m_vC.y() > maxY) maxY = m_vC.y();
154 else if(m_vC.y() < minY) minY = m_vC.y();
155 if (m_vC.z() > maxZ) maxZ = m_vC.z();
156 else if(m_vC.z() < minZ) minZ = m_vC.z();
157
158 constexpr auto TRIANGLE_EPSILON = T(0.0001);
159
160 return math::TAABB3D<T>(
161 math::Vector3R(minX - TRIANGLE_EPSILON, minY - TRIANGLE_EPSILON, minZ - TRIANGLE_EPSILON),
162 math::Vector3R(maxX + TRIANGLE_EPSILON, maxY + TRIANGLE_EPSILON, maxZ + TRIANGLE_EPSILON));
163}
164
165template<typename T>
167{
168 const auto ab = (m_vB - m_vA).length();
169 const auto ac = (m_vC - m_vA).length();
170 const auto bc = (m_vC - m_vB).length();
171
172 const auto termA = ab + ac - bc;
173 const auto termB = ac + bc - ab;
174 const auto termC = ab + bc - ac;
175 if(termA <= static_cast<T>(0) || termB <= static_cast<T>(0) || termC <= static_cast<T>(0) ||
176 isDegenerate())
177 {
178 return std::numeric_limits<T>::infinity();
179 }
180
181 return (ab * ac * bc) / (termA * termB * termC);
182}
183
184template<typename T>
185inline std::pair<TVector3<T>, TVector3<T>> TBasicTriangle<T>::getEdgeVectors() const
186{
187 return {
188 m_vB.sub(m_vA),// edge vector AB
189 m_vC.sub(m_vA) // edge vector AC
190 };
191}
192
193template<typename T>
195{
196 // Reference: Real-Time Collision Detection, Volume 1, P.47 ~ P.48
197 // Computes barycentric coordinates (a, b, c) for a position with
198 // respect to triangle ABC.
199
200 const auto eAP = position.sub(m_vA);
201 const auto [eAB, eAC] = getEdgeVectors();
202
203 const T d00 = eAB.dot(eAB);
204 const T d01 = eAB.dot(eAC);
205 const T d11 = eAC.dot(eAC);
206 const T d20 = eAP.dot(eAB);
207 const T d21 = eAP.dot(eAC);
208
209 // TODO: check numeric stability
210
211 const T denominator = d00 * d11 - d01 * d01;
212 if(denominator == static_cast<T>(0))
213 {
214 return {0, 0, 0};
215 }
216
217 const T rcpDenominator = static_cast<T>(1) / denominator;
218
219 const T b = (d11 * d20 - d01 * d21) * rcpDenominator;
220 const T c = (d00 * d21 - d01 * d20) * rcpDenominator;
221 const T a = static_cast<T>(1) - b - c;
222
223 return {a, b, c};
224}
225
226template<typename T>
228{
230 m_vA, barycentricCoords.x(),
231 m_vB, barycentricCoords.y(),
232 m_vC, barycentricCoords.z());
233}
234
235template<typename T>
236inline TVector3<T> TBasicTriangle<T>::sampleToBarycentricOsada(const std::array<T, 2>& sample) const
237{
238 PH_ASSERT_IN_RANGE_INCLUSIVE(sample[0], T(0), T(1));
239 PH_ASSERT_IN_RANGE_INCLUSIVE(sample[1], T(0), T(1));
240
241 const T A = std::sqrt(sample[0]);
242 const T B = sample[1];
243
244 return {
245 T(1) - A,
246 A * (T(1) - B),
247 B * A
248 };
249}
250
251template<typename T>
252inline TVector3<T> TBasicTriangle<T>::sampleToBarycentricOsada(const std::array<T, 2>& sample, T* const out_pdfA) const
253{
254 PH_ASSERT(out_pdfA);
255
256 *out_pdfA = uniformSurfaceSamplePdfA();
257
258 return sampleToBarycentricOsada(sample);
259}
260
261template<typename T>
263{
264 return static_cast<T>(1) / getArea();
265}
266
267template<typename T>
269{
270 const auto [eAB, eAC] = getEdgeVectors();
271 const T crossFactor = eAB.cross(eAC).lengthSquared();
272
273 // NaN and Inf aware
274 return !(crossFactor > T(0)) || std::isinf(crossFactor);
275}
276
277template<typename T>
279{
280 return m_vA;
281}
282
283template<typename T>
285{
286 return m_vB;
287}
288
289template<typename T>
291{
292 return m_vC;
293}
294
295}// end namespace ph::math
A 3-D Axis-Aligned Bounding Box (AABB).
Definition TAABB3D.h:32
Basic 3-D triangle functionalities.
Definition TBasicTriangle.h:21
TVector3< T > getCentroid() const
Definition TBasicTriangle.ipp:124
T getAspectRatio() const
Calculate aspect ratio of this triangle. For a triangle, its aspect ratio is defined to be the ratio ...
Definition TBasicTriangle.ipp:166
T uniformSurfaceSamplePdfA() const
Definition TBasicTriangle.ipp:262
TVector3< T > getFaceNormal() const
Definition TBasicTriangle.ipp:108
static TVector3< T > interpolate(const std::array< TVector3< T >, 3 > &attributes, const TVector3< T > &barycentricCoords)
Definition TBasicTriangle.ipp:16
static bool calcSurfaceParamDerivatives(const std::array< TVector3< T >, 3 > &attributes, const std::array< TVector2< T >, 3 > &parameterizations, TVector3< T > *out_dXdU, TVector3< T > *out_dXdV)
Definition TBasicTriangle.ipp:41
TVector3< T > getVb() const
Definition TBasicTriangle.ipp:284
bool isDegenerate() const
Definition TBasicTriangle.ipp:268
TVector3< T > sampleToBarycentricOsada(const std::array< T, 2 > &sample) const
Map the 2D sample to a position on the surface of the triangle. A common mapping on triangles which i...
Definition TBasicTriangle.ipp:236
TVector3< T > surfaceToBarycentric(const TVector3< T > &position) const
Definition TBasicTriangle.ipp:194
TVector3< T > safeGetFaceNormal(const TVector3< T > &failSafe={0, 1, 0}) const
Calculate face normal with a fail-safe value. The vertices may form a degenerate triangle (zero cross...
Definition TBasicTriangle.ipp:116
TVector3< T > getVa() const
Definition TBasicTriangle.ipp:278
TVector3< T > getVc() const
Definition TBasicTriangle.ipp:290
TAABB3D< T > getAABB() const
Definition TBasicTriangle.ipp:138
T getArea() const
Definition TBasicTriangle.ipp:100
TVector3< T > barycentricToSurface(const TVector3< T > &barycentricCoords) const
Definition TBasicTriangle.ipp:227
std::pair< TVector3< T >, TVector3< T > > getEdgeVectors() const
Definition TBasicTriangle.ipp:185
TBasicTriangle(TVector3< T > vA, TVector3< T > vB, TVector3< T > vC)
Definition TBasicTriangle.ipp:81
Represents a 2x2 matrix.
Definition TMatrix2.h:16
Represents a 2-D vector.
Definition TVector2.h:19
Represents a 3-D vector.
Definition TVector3.h:17
T & y()
Definition TVector3.ipp:189
T & z()
Definition TVector3.ipp:195
T & x()
Definition TVector3.ipp:183
static TVector3 weightedSum(const TVector3 &vA, T wA, const TVector3 &vB, T wB, const TVector3 &vC, T wC)
Definition TVector3.ipp:19
Derived sub(const Derived &rhs) const
Definition TArithmeticArrayBase.ipp:62
Math functions and utilities.
Definition TransformInfo.h:10
T length(const std::array< T, N > &vec)
Treating input values as a vector and calculates its length.
Definition math.ipp:50
Definition TAABB2D.h:96