Skip to content

Commit ba63511

Browse files
committed
Perf: Reduce std::fmax usage in RayIntersection
1 parent 33d25a6 commit ba63511

File tree

1 file changed

+59
-25
lines changed

1 file changed

+59
-25
lines changed

octree.h

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,27 @@ namespace OrthoTree
176176
struct IsStdOptional<std::optional<U>> : std::true_type
177177
{};
178178

179+
template<size_t... Is, class F>
180+
constexpr void static_for_impl(std::index_sequence<Is...>, F&& f) noexcept
181+
{
182+
(f(static_cast<uint32_t>(std::integral_constant<size_t, Is>{})), ...);
183+
}
184+
185+
template<size_t N, class F>
186+
constexpr void static_for(F&& f) noexcept
187+
{
188+
if constexpr (N < 16)
189+
{
190+
static_for_impl(std::make_index_sequence<N>{}, std::forward<F>(f));
191+
}
192+
else
193+
{
194+
constexpr uint32_t uintN = static_cast<uint32_t>(N);
195+
for (uint32_t i = 0; i < uintN; ++i)
196+
f(i);
197+
}
198+
}
199+
179200
template<typename T>
180201
inline constexpr bool IsStdOptionalV = IsStdOptional<T>::value;
181202

@@ -1882,11 +1903,10 @@ namespace OrthoTree
18821903
constexpr std::optional<BoxPickResult> Hit(const Vector& center, const Vector& halfSize) const noexcept
18831904
{
18841905
Vector minDifference, maxDifference;
1885-
for (dim_t dimensionID = 0; dimensionID < DIMENSION_NO; ++dimensionID)
1886-
minDifference[dimensionID] = center[dimensionID] - halfSize[dimensionID] - m_origin[dimensionID];
1887-
1888-
for (dim_t dimensionID = 0; dimensionID < DIMENSION_NO; ++dimensionID)
1889-
maxDifference[dimensionID] = center[dimensionID] + halfSize[dimensionID] - m_origin[dimensionID];
1906+
detail::static_for<DIMENSION_NO>(
1907+
[&](dim_t dimensionID) noexcept { minDifference[dimensionID] = center[dimensionID] - halfSize[dimensionID] - m_origin[dimensionID]; });
1908+
detail::static_for<DIMENSION_NO>(
1909+
[&](dim_t dimensionID) noexcept { maxDifference[dimensionID] = center[dimensionID] + halfSize[dimensionID] - m_origin[dimensionID]; });
18901910

18911911
return HitTest<isConeToleranceConsidered>(minDifference, maxDifference);
18921912
}
@@ -1895,11 +1915,10 @@ namespace OrthoTree
18951915
constexpr std::optional<BoxPickResult> Hit(const TBox& box) const noexcept
18961916
{
18971917
Vector minDifference, maxDifference;
1898-
for (dim_t dimensionID = 0; dimensionID < DIMENSION_NO; ++dimensionID)
1899-
minDifference[dimensionID] = AD::GetBoxMinC(box, dimensionID) - m_origin[dimensionID];
1900-
1901-
for (dim_t dimensionID = 0; dimensionID < DIMENSION_NO; ++dimensionID)
1902-
maxDifference[dimensionID] = AD::GetBoxMaxC(box, dimensionID) - m_origin[dimensionID];
1918+
detail::static_for<DIMENSION_NO>(
1919+
[&](dim_t dimensionID) noexcept { minDifference[dimensionID] = AD::GetBoxMinC(box, dimensionID) - m_origin[dimensionID]; });
1920+
detail::static_for<DIMENSION_NO>(
1921+
[&](dim_t dimensionID) noexcept { maxDifference[dimensionID] = AD::GetBoxMaxC(box, dimensionID) - m_origin[dimensionID]; });
19031922

19041923
return HitTest<isConeToleranceConsidered>(minDifference, maxDifference);
19051924
}
@@ -1908,37 +1927,52 @@ namespace OrthoTree
19081927
constexpr BoxRayHitTester() = default;
19091928

19101929
template<bool isConeToleranceConsidered = true>
1911-
constexpr std::optional<BoxPickResult> HitTest(const Vector& minDifference, const Vector& maxDifference) const
1930+
constexpr std::optional<BoxPickResult> HitTest(const Vector& minDifference, const Vector& maxDifference) const noexcept
19121931
{
19131932
// plane distances
19141933
std::array<Vector, 2> pd;
1915-
for (dim_t dimensionID = 0; dimensionID < DIMENSION_NO; ++dimensionID)
1916-
pd[0][dimensionID] = minDifference[dimensionID] * m_inverseDirection[dimensionID];
1917-
1918-
for (dim_t dimensionID = 0; dimensionID < DIMENSION_NO; ++dimensionID)
1919-
pd[1][dimensionID] = maxDifference[dimensionID] * m_inverseDirection[dimensionID];
1934+
detail::static_for<DIMENSION_NO>(
1935+
[&](dim_t dimensionID) noexcept { pd[0][dimensionID] = minDifference[dimensionID] * m_inverseDirection[dimensionID]; });
1936+
detail::static_for<DIMENSION_NO>(
1937+
[&](dim_t dimensionID) noexcept { pd[1][dimensionID] = maxDifference[dimensionID] * m_inverseDirection[dimensionID]; });
19201938

1921-
// NaN is eliminated in std::fmax/fmin, and returns the non-NaN.
19221939
std::optional pickResult =
19231940
BoxPickResult{ .enterDistance = -std::numeric_limits<Geometry>::max(), .exitDistance = std::numeric_limits<Geometry>::max() };
19241941

1925-
for (dim_t dimensionID = 0; dimensionID < DIMENSION_NO; ++dimensionID)
1942+
// Find the largest entering distance and the smallest exiting distance. fmax/fmin handles NaN correctly.
1943+
if (m_hasNaNComponent)
19261944
{
1927-
pickResult->enterDistance = std::fmax(pickResult->enterDistance, pd[m_signInfo[dimensionID]][dimensionID]);
1928-
pickResult->exitDistance = std::fmin(pickResult->exitDistance, pd[1 - m_signInfo[dimensionID]][dimensionID]);
1945+
detail::static_for<DIMENSION_NO>([&](dim_t dimensionID) noexcept {
1946+
pickResult->enterDistance = std::fmax(pickResult->enterDistance, pd[m_signInfo[dimensionID]][dimensionID]);
1947+
});
1948+
detail::static_for<DIMENSION_NO>([&](dim_t dimensionID) noexcept {
1949+
pickResult->exitDistance = std::fmin(pickResult->exitDistance, pd[1 - m_signInfo[dimensionID]][dimensionID]);
1950+
});
19291951
}
1952+
else
1953+
{
1954+
detail::static_for<DIMENSION_NO>([&](dim_t dimensionID) noexcept {
1955+
pickResult->enterDistance = std::max(pickResult->enterDistance, pd[m_signInfo[dimensionID]][dimensionID]);
1956+
});
1957+
detail::static_for<DIMENSION_NO>([&](dim_t dimensionID) noexcept {
1958+
pickResult->exitDistance = std::min(pickResult->exitDistance, pd[1 - m_signInfo[dimensionID]][dimensionID]);
1959+
});
1960+
}
1961+
1962+
// enterDistance/exitDistance is not Nan from here
19301963

1964+
// Apply tolerance
19311965
auto exitTolerance = Geometry{};
19321966
if constexpr (isConeToleranceConsidered)
19331967
{
1934-
exitTolerance = std::fmax(Geometry(0), pickResult->exitDistance) * m_toleranceIncrement + m_minTolerance;
1968+
exitTolerance = std::max(Geometry(0), pickResult->exitDistance) * m_toleranceIncrement + m_minTolerance;
19351969

1936-
pickResult->enterDistance -= Geometry(0.5) * (std::fmax(Geometry(0), pickResult->enterDistance) * m_toleranceIncrement + m_minTolerance);
1937-
pickResult->exitDistance += Geometry(0.5) * (std::fmax(Geometry(0), pickResult->exitDistance) * m_toleranceIncrement + m_minTolerance);
1970+
pickResult->enterDistance -= Geometry(0.5) * (std::max(Geometry(0), pickResult->enterDistance) * m_toleranceIncrement + m_minTolerance);
1971+
pickResult->exitDistance += Geometry(0.5) * (std::max(Geometry(0), pickResult->exitDistance) * m_toleranceIncrement + m_minTolerance);
19381972
}
19391973
else
19401974
{ // Numerical inaccuracies could cause false-miss
1941-
exitTolerance = Geometry(0.5) * std::fmax(Geometry(1), pickResult->exitDistance) * std::numeric_limits<Geometry>::epsilon();
1975+
exitTolerance = Geometry(0.5) * std::max(Geometry(1), pickResult->exitDistance) * std::numeric_limits<Geometry>::epsilon();
19421976

19431977
pickResult->enterDistance -= exitTolerance;
19441978
pickResult->exitDistance += exitTolerance;
@@ -1952,7 +1986,7 @@ namespace OrthoTree
19521986
}
19531987

19541988
// Ray origin inside the box case
1955-
pickResult->enterDistance = std::fmax(Geometry(0), pickResult->enterDistance);
1989+
pickResult->enterDistance = std::max(Geometry(0), pickResult->enterDistance);
19561990

19571991
// Handle zero direction components
19581992
if (m_hasNaNComponent)

0 commit comments

Comments
 (0)