9#include <Common/config.h>
10#include <Common/assertion.h>
11#include <Common/primitive_type.h>
20namespace ph {
class EngineInitSettings; }
109 struct IterativeOffsetResult
116 static real fallbackOffsetDist(
const SurfaceHit& X, real distanceFactor);
117 static real maxErrorOffsetDist(
const SurfaceHit& X);
118 static real meanErrorOffsetDist(
const SurfaceHit& X);
121 static IterativeOffsetResult iterativeOffset(
124 std::size_t numIters);
126 static IterativeOffsetResult iterativeMutualOffset(
130 std::size_t numIters);
140 static bool verifyOffset(
145 real rayLength = std::numeric_limits<real>::max());
148 static real s_selfIntersectDelta;
149 static std::size_t s_numIterations;
153#if PH_ENABLE_HIT_EVENT_STATS
155 static void reportStats();
160 std::atomic_uint64_t numEvents;
161 std::atomic_uint64_t numFailedEmpiricalEscapes;
162 std::atomic_uint64_t numFailedInitialEscapes;
163 std::atomic_uint64_t numFailedIterativeEscapes;
164 std::atomic_uint64_t numReintersecs;
166 void markEvent(
const std::uint64_t num = 1)
168 numEvents.fetch_add(num, std::memory_order_relaxed);
171 void markFailedEmpiricalEscape()
173 numFailedEmpiricalEscapes.fetch_add(1, std::memory_order_relaxed);
176 void markFailedInitialEscape()
178 numFailedInitialEscapes.fetch_add(1, std::memory_order_relaxed);
181 void markFailedIterativeEscape()
183 numFailedIterativeEscapes.fetch_add(1, std::memory_order_relaxed);
186 void markReintersect()
188 numReintersecs.fetch_add(1, std::memory_order_relaxed);
192 static HitEventStats s_stats;
216 PH_ASSERT_UNREACHABLE_SECTION();
222#if PH_ENABLE_HIT_EVENT_STATS
230 std::numeric_limits<real>::max(),
236#if PH_ENABLE_HIT_EVENT_STATS
241 m_X.
getPos() + empiricalOffsetVec(m_X, dir),
248 const std::size_t numIters)
const
250#if PH_ENABLE_HIT_EVENT_STATS
254 const IterativeOffsetResult result = iterativeOffset(m_X, dir, numIters);
255 PH_ASSERT_GT(result.maxDistance, 0.0_r);
258 m_X.
getPos() + result.offset,
279 PH_ASSERT_UNREACHABLE_SECTION();
285#if PH_ENABLE_HIT_EVENT_STATS
286 s_stats.markEvent(2);
296 const auto distance = std::sqrt(distance2);
297 const auto rcpDistance = 1.0_r / distance;
313#if PH_ENABLE_HIT_EVENT_STATS
314 s_stats.markEvent(2);
318 const auto originX = m_X.
getPos() + empiricalOffsetVec(m_X, xToX2);
319 const auto originX2 = X2.
getPos() + empiricalOffsetVec(X2, -xToX2);
320 const auto distance = (originX2 - originX).
length();
321 const auto rcpDistance = 1.0_r / distance;
322 if(rcpDistance != 0 && std::isfinite(rcpDistance))
326 (originX2 - originX) * rcpDistance,
339 const std::size_t numIters)
const
341#if PH_ENABLE_HIT_EVENT_STATS
342 s_stats.markEvent(2);
346 const IterativeOffsetResult result = iterativeMutualOffset(m_X, X2, xToX2, numIters);
347 if(result.maxDistance > 0.0_r && std::isfinite(result.maxDistance))
350 m_X.
getPos() + result.offset,
364 return s_selfIntersectDelta;
369 return s_numIterations;
372inline real SurfaceHitRefinery::fallbackOffsetDist(
const SurfaceHit& X,
const real distanceFactor)
378inline real SurfaceHitRefinery::maxErrorOffsetDist(
const SurfaceHit& X)
381 const auto offsetDist = X.
getPos().
length() * maxFactor;
382 if(std::isfinite(offsetDist))
390 constexpr real distanceFactor = 1e-3_r;
391 return fallbackOffsetDist(X, distanceFactor);
395inline real SurfaceHitRefinery::meanErrorOffsetDist(
const SurfaceHit& X)
397 const auto [meanFactor, _] = X.getDetail().getDistanceErrorFactors();
398 const auto offsetDist = X.getPos().length() * meanFactor;
399 if(std::isfinite(offsetDist))
407 constexpr real distanceFactor = 1e-6_r;
408 return fallbackOffsetDist(X, distanceFactor);
414 PH_ASSERT_MSG(dir.isFinite() && !dir.isZero(), dir.toString());
416 const auto N = X.getGeometryNormal();
417 const auto dist = maxErrorOffsetDist(X);
418 const auto offsetVec = N.dot(dir) > 0.0_r ? N * dist : N * -dist;
420#if PH_ENABLE_HIT_EVENT_STATS
421 if(canVerifyOffset(X, dir) && !verifyOffset(X, dir, X.getPos(), offsetVec))
423 s_stats.markFailedEmpiricalEscape();
430inline bool SurfaceHitRefinery::reintersect(
const SurfaceHit& X,
const Ray& ray, HitProbe& probe)
432#if PH_ENABLE_HIT_EVENT_STATS
433 s_stats.markReintersect();
436 return X.reintersect(ray, probe);
441 const auto N = X.getGeometryNormal();
442 const auto topology = X.getDetail().getFaceTopology();
449inline bool SurfaceHitRefinery::verifyOffset(
454 const real rayLength)
456 PH_ASSERT(canVerifyOffset(X, dir));
459 const Ray ray(rayOrigin + rayOffset, dir.normalize(), 0, rayLength, X.getTime());
460 return !X.reintersect(ray, probe);
Options for initializing core engine. These settings are loaded on engine startup and remains constan...
Definition EngineInitSettings.h:20
std::pair< real, real > getDistanceErrorFactors() const
Definition HitDetail.h:185
Lightweight ray intersection testing and reporting object. If an intersection is found,...
Definition HitProbe.h:27
Represents a ray in space.
Definition Ray.h:21
General information about a ray-surface intersection event.
Definition SurfaceHit.h:59
const HitDetail & getDetail() const
Definition SurfaceHit.h:159
math::Vector3R getPos() const
Definition SurfaceHit.h:186
const Time & getTime() const
Definition SurfaceHit.h:181
Algorithms for various hit point adjustments. For surface escaping routines, the generated ray is not...
Definition SurfaceHitRefinery.h:31
std::optional< Ray > tryEscapeEmpirically(const SurfaceHit &X2) const
Mutually escape from X and X2 by some adaptive offset.
Definition SurfaceHitRefinery.h:311
std::optional< Ray > tryEscape(const SurfaceHit &X2) const
Mutually escape from X and X2. The method to use for escaping the surfaces is determined by engine se...
Definition SurfaceHitRefinery.h:265
static std::size_t numIterations()
Number of iterations to perform when escaping in iterative mode.
Definition SurfaceHitRefinery.h:367
Ray escapeIteratively(const math::Vector3R &dir, std::size_t numIters=numIterations()) const
Escape this surface in a specific direction by iteratively re-intersect with the surface....
Definition SurfaceHitRefinery.h:246
Ray escapeManually(const math::Vector3R &dir, real delta=selfIntersectDelta()) const
Escape this surface in a specific direction by a small offset.
Definition SurfaceHitRefinery.h:220
Ray escape(const math::Vector3R &dir) const
Escape this surface in a specific direction. The method to use for escaping the surface is determined...
Definition SurfaceHitRefinery.h:200
SurfaceHitRefinery(const SurfaceHit &X)
Definition SurfaceHitRefinery.h:196
std::optional< Ray > tryEscapeManually(const SurfaceHit &X2, real delta=selfIntersectDelta()) const
Mutually escape from X and X2 by a small offset.
Definition SurfaceHitRefinery.h:283
std::optional< Ray > tryEscapeIteratively(const SurfaceHit &X2, std::size_t numIters=numIterations()) const
Mutually escape from X and X2 by iteratively re-intersect with the surfaces.
Definition SurfaceHitRefinery.h:337
Ray escapeEmpirically(const math::Vector3R &dir) const
Escape this surface in a specific direction by some adaptive offset.
Definition SurfaceHitRefinery.h:234
static real selfIntersectDelta()
A small value for resolving self-intersections.
Definition SurfaceHitRefinery.h:362
static void init(const EngineInitSettings &settings)
Initialize from engine settings.
Definition SurfaceHitRefinery.cpp:43
bool isZero() const
Definition TArithmeticArrayBase.ipp:549
T length() const
Definition TVectorNBase.ipp:38
Derived normalize() const
Normalize the vector. Notice that normalizing a integer typed vector will result in 0-vector most of ...
Definition TVectorNBase.ipp:50
std::string toString() const
Definition TArithmeticArrayBase.ipp:825
bool isFinite() const
Definition TArithmeticArrayBase.ipp:585
T lengthSquared() const
Definition TVectorNBase.ipp:44
Miscellaneous math utilities.
Light transport algorithms.
Definition enums.h:6
T squared(const T value)
Definition math.h:59
T length(const std::array< T, N > &vec)
Treating input values as a vector and calculates its length.
Definition math.ipp:50
TVector3< real > Vector3R
Definition math_fwd.h:52
The root for all renderer implementations.
Definition EEngineProject.h:6
ESurfaceRefineMode
Definition ESurfaceRefineMode.h:11