JPL Spatial
Sound spatialization and propagation library
Loading...
Searching...
No Matches
SceneInterface.h
Go to the documentation of this file.
1//
2// ██╗██████╗ ██╗ ██╗██████╗ ███████╗
3// ██║██╔══██╗ ██║ ██║██╔══██╗██╔════╝ ** JPLSpatial **
4// ██║██████╔╝ ██║ ██║██████╔╝███████╗
5// ██ ██║██╔═══╝ ██║ ██║██╔══██╗╚════██║ https://github.com/Jaytheway/JPLSpatial
6// ╚█████╔╝██║ ███████╗██║██████╔╝███████║
7// ╚════╝ ╚═╝ ╚══════╝╚═╝╚═════╝ ╚══════╝
8//
9// Copyright 2026 Jaroslav Pevno, JPLSpatial is offered under the terms of the ISC license:
10//
11// Permission to use, copy, modify, and/or distribute this software for any purpose with or
12// without fee is hereby granted, provided that the above copyright notice and this permission
13// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
14// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
16// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
17// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20#pragma once
21
22#include "JPLSpatial/Core.h"
26
27#include <span>
28#include <ranges>
29#include <optional>
30
31namespace JPL
32{
35 {
36 public:
37 static constexpr std::size_t cMaxOrder = 16; // TODO: make sure to use the same value across specular path classes
38
39 template<class SceneType, class Vec3>
40 [[nodiscard]] inline static std::optional<Vec3> ReflectPoint(const SceneType& scene,
41 const Vec3& point,
42 int surfaceId);
43
44 template<class Vec3, class SceneType>
45 static inline bool ValidatePath(const SceneType& scene,
46 std::span<const int> triCache,
47 std::span<const Vec3> imageSources,
48 const Vec3& receiver);
49
50 // Validate visibility of the reflected image source from the reciever
51 template<class Vec3, class SceneType>
52 static inline bool ValidatePath(const SceneType& scene,
54
55 template<class SceneType>
56 static void AccumulateMaterialAbsorption(const SceneType& scene, std::span<const int> surfaces, EnergyBands& outEnergyLoss);
57
58 template<class SceneType, class OnISsReadyCallback>
59 static void ReconstructImageSources(const SceneType& scene, std::span<const int> pathNodes, const OnISsReadyCallback& callback);
60 };
61} // namespace JPL
62
63//==============================================================================
64//
65// Code beyond this point is implementation detail...
66//
67//==============================================================================
68
69namespace JPL
70{
71 template<class SceneType, class Vec3>
72 inline std::optional<Vec3> SceneInterface::ReflectPoint(const SceneType& scene, const Vec3& point, int surfaceId)
73 {
75 if (scene.GetSurfacePlane(surfaceId, planeNormal, planePoint))
76 return Math::GetImageSource(point, planeNormal, planePoint);
77
78 return std::nullopt;
79 }
80
81 template<class Vec3, class SceneType>
82 inline bool SceneInterface::ValidatePath(const SceneType& scene, std::span<const int> triCache, std::span<const Vec3> imageSources, const Vec3& receiver)
83 {
84 using Intersection = typename SceneType::Intersection;
85
86 Vec3 R = receiver;
87
88 // Check that we do intersect the correct surface sequance,
89 // and nothing is obstructing visibility of the image source
90 for (auto i = imageSources.size() - 1; i >= 1; --i)
91 {
92 Intersection hit;
93 if (not scene.Intersect(R, imageSources[i], hit) || hit.SurfaceID != triCache[i])
94 return false;
95
96 // Small offset to avoid self intersection
97 static constexpr float offset = 0.001f;
98
99 R = hit.Position + hit.Normal * offset;
100 }
101
102 // Lastly check visibility between
103 // source and first refleciton point
104 return not scene.IsOccluded(R, imageSources[0]);
105 }
106
107 template<class Vec3, class SceneType>
109 {
110 bool bPathValid = false;
111
112 ReconstructImageSources(scene, path.Nodes, [&](std::span<const Vec3> newImageSources, const Vec3& receiver)
113 {
114 if (path.Nodes.size() - 1 != newImageSources.size())
115 {
116 // Reflection order changed, the path is not valid
117 bPathValid = false;
118 return;
119 }
120
121 Vec3 R = receiver;
122
123 // Check that we do intersect the correct surface sequance,
124 // and nothing is obstructing visibility of the image source
125 for (auto i = newImageSources.size() - 1; i >= 1; --i)
126 {
127 using Intersection = typename SceneType::Intersection;
128
129 Intersection hit;
130 if (not scene.Intersect(R, newImageSources[i], hit) || hit.SurfaceID != path.Nodes[i])
131 {
132 bPathValid = false;
133 return;
134 }
135
136 // Small offset to avoid self intersection
137 static constexpr float offset = 0.001f;
138
139 R = hit.Position + hit.Normal * offset;
140 }
141
142 // Lastly check visibility between
143 // source and first refleciton point
144 bPathValid = not scene.IsOccluded(R, newImageSources[0]);
145 });
146
147 return bPathValid;
148 }
149
150 template<class SceneType>
151 inline void SceneInterface::AccumulateMaterialAbsorption(const SceneType& scene, std::span<const int> surfaces, EnergyBands& outEnergyLoss)
152 {
153 // TODO: this should really be material + ABRDF, or just ABRDF
154 for (int surfaceId : surfaces)
155 {
156 EnergyBands materialAbsorption;
157 if (scene.GetMaterialAbsorption(surfaceId, materialAbsorption))
158 outEnergyLoss += materialAbsorption;
159 }
160 }
161
162 template<class SceneType, class OnISsReadyCallback>
163 inline void SceneInterface::ReconstructImageSources(const SceneType& scene, std::span<const int> pathNodes, const OnISsReadyCallback& callback)
164 {
165 using Vec3 = typename SceneType::Vec3;
166
167 const auto surfaces = pathNodes.subspan(0, pathNodes.size() - 1); // -1 removes receiver
168 const Vec3 source = scene.GetSourcePosition(pathNodes.front());
169 const Vec3 receiver = scene.GetReceiverPosition(pathNodes.back());
170
172 IS.push_back(source);
173
174 JPL_ASSERT(pathNodes.size() <= IS.size());
175
176 for (const int Tjd : surfaces | std::views::drop(1)) // drop the source
177 {
178 auto imageSource = ReflectPoint(scene, IS.back(), Tjd);
179
180 //if (JPL_ENSURE(imageSource.has_value(), "Invalid surface id in specular path."))
181 if (imageSource.has_value())
182 {
183 IS.push_back(*imageSource);
184 }
185 else
186 {
187 // TODO: this technically could happen if the surface has been deleted,
188 // in which case we should just quietly invalidate the path
189 JPL_ASSERT(false); //? temp assert. testing
190 break;
191 }
192 }
193
194 callback(std::span<const Vec3>(IS), receiver);
195 }
196} // namespace JPL
#define JPL_ASSERT(inExpression,...)
Main assert macro, usage: JPL_ASSERT(condition, message) or JPL_ASSERT(condition)
Definition ErrorReporting.h:76
A very experimental scene interface for specular ray tracing.
Definition SceneInterface.h:35
static constexpr std::size_t cMaxOrder
Definition SceneInterface.h:37
static void AccumulateMaterialAbsorption(const SceneType &scene, std::span< const int > surfaces, EnergyBands &outEnergyLoss)
Definition SceneInterface.h:151
static void ReconstructImageSources(const SceneType &scene, std::span< const int > pathNodes, const OnISsReadyCallback &callback)
Definition SceneInterface.h:163
static std::optional< Vec3 > ReflectPoint(const SceneType &scene, const Vec3 &point, int surfaceId)
Definition SceneInterface.h:72
static bool ValidatePath(const SceneType &scene, std::span< const int > triCache, std::span< const Vec3 > imageSources, const Vec3 &receiver)
Definition SceneInterface.h:82
Definition StaticArray.h:35
constexpr JPL_INLINE reference back() noexcept
Definition StaticArray.h:95
constexpr JPL_INLINE void push_back(const T &value)
Definition StaticArray.h:145
constexpr JPL_INLINE size_type size() const
Definition StaticArray.h:77
Definition AcousticMaterial.h:36
JPL_INLINE simd min(const simd &a, const simd &b) noexcept
Element-wise min.
Definition SIMD.h:1813
Definition SpecularPath.h:57
Minimal 4-wide 32-bit float vector implementation for SIMD.
Definition SIMD.h:60
static constexpr std::size_t size() noexcept
Get number of element of the vector.
Definition SIMD.h:97