JPL Spatial
Sound spatialization and propagation library
Loading...
Searching...
No Matches
DirectPathService.h
Go to the documentation of this file.
1//
2// ██╗██████╗ ██╗ ██╗██████╗ ███████╗
3// ██║██╔══██╗ ██║ ██║██╔══██╗██╔════╝ ** JPLSpatial **
4// ██║██████╔╝ ██║ ██║██████╔╝███████╗
5// ██ ██║██╔═══╝ ██║ ██║██╔══██╗╚════██║ https://github.com/Jaytheway/JPLSpatial
6// ╚█████╔╝██║ ███████╗██║██████╔╝███████║
7// ╚════╝ ╚═╝ ╚══════╝╚═╝╚═════╝ ╚══════╝
8//
9// Copyright 2024 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"
31
32#include <algorithm>
33#include <cmath>
34#include <memory>
35#include <iterator>
36#include <vector>
37#include <memory_resource>
38
39namespace JPL
40{
41 //==========================================================================
42 template<CVec3 Vec3Type>
44 {
45 float Distance; //< Distance from source to listener
46 float DirectionDot; //< Dot product between source direction relative to listener and listener's forward vector
47 float InvDirectionDot; //< Dot product listener direction relative to source and source's forward vector
48
49 JPL::Position<Vec3Type> Position; //< Direction and orientation relative to listener
50 };
51
53 {
54 float InnerAngle; //< width of the inner sector in radians
55 float OuterAngle; //< width of the outer sector in radians, should be > InnerAngle
56 };
57
58 using AttenuationCurveRef = std::shared_ptr<AttenuationFunction>;
59
60 // TODO: we might want Curve ID to be able to retrieve volume and other attenuations quickly
66
72
75
81
82 //==========================================================================
84 {
85 public:
86 // Alias to override allocator for the internal FlatMap we use
87 template<class Key, class T>
89
90 public:
91 DirectPathService() = default;
92
95
96 // High level API to:
97 // - get distance-based volume attenuation and air absorption values
98
100
104
109
119 template<CVec3 Vec3Type>
122 template<CVec3 Vec3Type>
123 static JPL_INLINE float ProcessAngleAttenuation(const Vec3Type& position,
126
128
130
131 // TODO: mabye we could batch process multiple distances/sources per curve, if they are sharing curves?
132 /*
133 Essentially it is a tradeoff between:
134 - efficient evaluation - which is better if we have a lot of curves per source
135 - efficient cache look-up - which is better if we access values a lot and share curves between sources
136 */
137
147
157
158
169
178
179 private:
180 static JPL_INLINE float ProcessAngleAttenuationImpl(float azimutCos, const AttenuationCone& cone);
181
182 private:
183 using CurveAttenuationCacheArray = std::pmr::vector<CurveAttenuationCache>;
184
185 // TODO: can we store cache for more efficient access?
188 };
189} // namespace JPL
190
191//==============================================================================
192//
193// Code beyond this point is implementation detail...
194//
195//==============================================================================
196namespace JPL
197{
199 {
200 const auto handle = DirectEffectHandle::New();
201 mAttenuationCache.emplace(handle,
202 initParameters.BaseCurve
203 ? CurveAttenuationCacheArray({ {.Curve = initParameters.BaseCurve, .AttenuationValue = 1.0f } }, GetDefaultMemoryResource())
204 : CurveAttenuationCacheArray(GetDefaultMemoryResource()));
205
206 mDirectionAttenuationCache.emplace(handle,
207 ConeAttenuationCache{ .Cone = initParameters.AttenuationCone, .AttenuationValue = 1.0f });
208
209 return handle;
210 }
211
213 {
214 return mAttenuationCache.erase(source) + mDirectionAttenuationCache.erase(source);
215 }
216
218 {
219 if (!source.IsValid() || !attenuationFunction)
220 return nullptr;
221
222 //std::shared_ptr<AttenuationFunction> curve = make_pmr_shared(attenuationFunction);
223 auto& cache = mAttenuationCache[source];
224 return cache.emplace_back(attenuationFunction, 1.0f).Curve;
225 //return curve;
226 }
227
229 {
230 auto it = mAttenuationCache.find(source);
231 if (it == mAttenuationCache.end())
232 return 1.0f;
233
234 auto cache = std::ranges::find(it->second, curve, [](const CurveAttenuationCache& cache) { return cache.Curve; });
235 if (cache != std::ranges::end(it->second))
236 return cache->AttenuationValue;
237
238 return 1.0f;
239 }
240
242 {
243 auto it = mDirectionAttenuationCache.find(source);
244 if (it == mDirectionAttenuationCache.end())
245 return 1.0f;
246
247 return it->second.AttenuationValue;
248 }
249
254
256 {
257 auto it = mAttenuationCache.find(source);
258 if (it == mAttenuationCache.end())
259 return false;
260
261 for (CurveAttenuationCache& cache : it->second)
262 cache.AttenuationValue = cache.Curve->Evaluate(distance);
263
264 return true;
265 }
266
268 {
269 auto it = mDirectionAttenuationCache.find(source);
270 if (it == mDirectionAttenuationCache.end())
271 return false;
272
273 JPL_ASSERT(directionDot >= -1.0f && directionDot <= 1.0f);
274
275 it->second.AttenuationValue = ProcessAngleAttenuationImpl(directionDot, it->second.Cone);
276
277 return true;
278 }
279
280 template<CVec3 Vec3Type>
282 {
283 static const Vec3Type cForwardAxis(0, 0, -1); // TODO: this is very assuming
284#if 1
285 const Basis<Vec3Type> listenerBasis = listener.Orientation.ToBasisUnsafe();
286 const Vec3Type sourceRelativePosition = source.Location - listener.Location;
287
289 // If source is directly on top, above or below the listener,
290 // nudge it a bit forward
293 {
295 }
296
297 // Get distance and cos of source in listener's frame
298 const float distance = Length(sourcePosInListenerFrame);
300 const float directionDot = DotProduct(dirRelativeToListener, cForwardAxis);
301
302 // Get cos of listener in source's frame
303 const Vec3Type& sourceForward = source.Orientation.Forward;
304 const Vec3Type listenerToSourceDir = listenerBasis.InverseTransform(-dirRelativeToListener);
305 const float invDirectionDot = DotProduct(sourceForward, listenerToSourceDir);
306
307 // Get orientation of source in listener's frame
308 const Basis<Vec3Type> sourceToListenerOrientation = listenerBasis.InverseTransform(source.Orientation.ToBasisUnsafe());
309#else
310 Vec3Type sourcePosInListenerFrame = listener.Orientation.ToQuat().Rotate(source.Location);
311
312 // If source is directly on top, above or below the listener,
313 // nudge it a bit forward
316 {
318 }
319
320 // Get distance and cos of source in listener's frame
321 const float distance = Length(sourcePosInListenerFrame);
323 const float directionDot = DotProduct(dirRelativeToListener, cForwardAxis);
324
325 // Get cos of listener in source's frame
326 const Vec3Type sourceForward = source.Orientation.ToQuat().Rotate(cForwardAxis);
327 const Vec3Type listenerToSourceDir = listener.Orientation.ToQuat().Conjugated().Rotate(-dirRelativeToListener);
328 const float invDirectionDot = DotProduct(sourceForward, listenerToSourceDir);
329
330 // Get orientation of source in listener's frame
332 (listener.Orientation.ToQuat().Conjugated() * source.Orientation.ToQuat()).ToBasis();
333#endif
336 .DirectionDot = directionDot,
337 .InvDirectionDot = invDirectionDot,
338 .Position = {
339 .Location = dirRelativeToListener,
340 .Orientation = {.Up = sourceToListenerOrientation.Y, .Forward = sourceToListenerOrientation.Z}
341 }
342 };
343 }
344
345 JPL_INLINE float DirectPathService::ProcessAngleAttenuationImpl(float azimutCos, const AttenuationCone& cone)
346 {
347 // Compute cosines of half of the cone sectors
348 const float cutoffInner = std::cos(cone.InnerAngle * 0.5f); // TODO: can we cache actual dot isntead of angles?
349 const float cutoffOuter = std::cos(cone.OuterAngle * 0.5f);
350
351 float factor = 0.0f;
352
354 return factor;
355
357 {
358 // Between inner and outer cones
360 }
361 else
362 {
363 // Outside the outer cone
364 factor = 1.0f;
365 }
366
367 return factor;
368 }
369
371 {
372 if (cone.InnerAngle >= JPL_TWO_PI)
373 {
374 // Inner angle is 360 degrees so no need to do any attenuation.
375 return 0.0f;
376 }
377
378 return ProcessAngleAttenuationImpl(std::cos(azimuth), cone);
379 }
380
381 template<CVec3 Vec3Type>
385 {
386 if (cone.InnerAngle >= JPL_TWO_PI)
387 {
388 // Inner angle is 360 degrees so no need to do any attenuation.
389 return 0.0f;
390 }
391
392 // Position and reference must not be the same point
394
395 const Vec3Type referenceForward = referencePoint.Orientation.Forward;
396 const Vec3Type sourceDirection = Normalized(position - referencePoint.Location);
397 const float dot = DotProduct(referenceForward, sourceDirection);
398
399 return ProcessAngleAttenuationImpl(dot, cone);
400 }
401
402} // namespace JPL
#define JPL_ASSERT(inExpression,...)
Main assert macro, usage: JPL_ASSERT(condition, message) or JPL_ASSERT(condition)
Definition ErrorReporting.h:76
Definition DirectPathService.h:84
JPL_INLINE bool ReleaseEffectData(DirectEffectHandle source)
Definition DirectPathService.h:212
JPL_INLINE float GetDistanceAttenuation(DirectEffectHandle source, const AttenuationCurveRef &curve) const
Definition DirectPathService.h:228
DirectPathService(const DirectPathService &)=delete
DirectPathService & operator=(const DirectPathService &)=delete
static JPL_INLINE float ProcessAngleAttenuation(const Vec3Type &position, const Position< Vec3Type > &referencePoint, AttenuationCone cone)
Definition DirectPathService.h:382
static JPL_INLINE DirectPathResult< Vec3Type > ProcessDirectPath(const Position< Vec3Type > &source, const Position< Vec3Type > &listener)
Definition DirectPathService.h:281
JPL_INLINE AttenuationCurveRef AssignAttenuationCurve(DirectEffectHandle source, AttenuationCurveRef attenuationFunction)
Definition DirectPathService.h:217
JPL_INLINE float GetDirectionAttenuation(DirectEffectHandle source) const
Definition DirectPathService.h:241
JPL_INLINE bool EvaluateDirection(DirectEffectHandle source, float directionDot)
Definition DirectPathService.h:267
JPL_INLINE DirectEffectHandle InitializeDirrectEffect(const DirectEffectInitParameters &initParameters)
Definition DirectPathService.h:198
static JPL_INLINE float EvaluateDistance(float distance, const AttenuationCurveRef &attenuationCurve)
Definition DirectPathService.h:250
Definition FlatMap.h:51
JPL_INLINE constexpr bool IsNearlyZero(T value, T errorTolerance=JPL_FLOAT_EPS_V< T >) noexcept
Definition Math.h:146
JPL_INLINE constexpr bool IsNearlyEqual(T a, T b, T tolerance=JPL_FLOAT_EPS_V< T >) noexcept
Definition Math.h:152
Definition AcousticMaterial.h:36
JPL_INLINE auto GetX(const Vec3Type &v) noexcept
Definition Vec3Traits.h:35
std::shared_ptr< AttenuationFunction > AttenuationCurveRef
Definition DirectPathService.h:58
JPL_INLINE auto GetZ(const Vec3Type &v) noexcept
Definition Vec3Traits.h:37
std::pmr::memory_resource * GetDefaultMemoryResource() noexcept
Definition Memory.h:42
JPL_INLINE simd min(const simd &a, const simd &b) noexcept
Element-wise min.
Definition SIMD.h:1813
Definition DirectPathService.h:53
float OuterAngle
Definition DirectPathService.h:55
float InnerAngle
Definition DirectPathService.h:54
Orthonormal basis (column-major)
Definition MinimalBasis.h:35
Definition DirectPathService.h:68
float AttenuationValue
Definition DirectPathService.h:70
AttenuationCone Cone
Definition DirectPathService.h:69
Definition DirectPathService.h:62
float AttenuationValue
Definition DirectPathService.h:64
AttenuationCurveRef Curve
Definition DirectPathService.h:63
Definition DirectPathService.h:77
JPL::AttenuationCone AttenuationCone
Definition DirectPathService.h:79
AttenuationCurveRef BaseCurve
Definition DirectPathService.h:78
Definition DirectPathService.h:44
float DirectionDot
Definition DirectPathService.h:46
float InvDirectionDot
Definition DirectPathService.h:47
float Distance
Definition DirectPathService.h:45
JPL::Position< Vec3Type > Position
Definition DirectPathService.h:49
Definition DirectPathService.h:73
static constexpr IDType New() noexcept
Definition IDType.h:44
Location and orientation in one place.
Definition Position.h:80