JPL Spatial
Sound spatialization and propagation library
Loading...
Searching...
No Matches
DistanceAttenuation.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"
25
26#include <algorithm>
27#include <cmath>
28#include <vector>
29
30namespace JPL
31{
33 {
34 None, // No distance attenuation.
35 Inverse, // Equivalent to OpenAL's AL_INVERSE_DISTANCE_CLAMPED.
36 Linear, // Linear attenuation. Equivalent to OpenAL's AL_LINEAR_DISTANCE_CLAMPED.
37 Exponential, // Exponential attenuation. Equivalent to OpenAL's AL_EXPONENT_DISTANCE_CLAMPED.
38
39 _Count
40 };
41
43 {
44 virtual float Evaluate(float distance) const = 0;
45 virtual ~AttenuationFunction() = default;
46 };
47
48 //==========================================================================
49 // TODO
50 /*struct AttenuationLUT : AttenuationFunction
51 {
52 };*/
53
54 //==========================================================================
56 {
64
65 JPL_INLINE float Evaluate(float distance) const final
66 {
68 auto distanceClamped = [&] { return std::clamp(distance, Parameters.MinDistance, Parameters.MaxDistance); };
69
70 switch (Model)
71 {
73 {
74 auto process = [&]
75 {
78 };
79
80 return isMinMaxValid()
81 ? process()
82 : 1.0f; // To avoid division by zero. Do not attenuate.
83 }
85 {
86 auto process = [&]
87 {
90 };
91
92 return isMinMaxValid()
93 ? process()
94 : 1.0f;
95 }
97 {
98 auto process = [&]
99 {
101 };
102
103 return isMinMaxValid()
104 ? process()
105 : 1.0f;
106 }
108 default:
109 {
110 return 1.0f;
111 }
112 }
113 }
114 };
115
116 // TODO: repurpose this as a generic curve that we may use for stuff like volume envelopes
117 //==========================================================================
122 {
123 struct Point
124 {
125 union
126 {
128 struct
129 {
130 float Distance; //< The distance at which this point is defined
131 float Value; //< The attenuation value at this distance
132 };
133 };
134
137 };
138
140 std::pmr::vector<Point> Points{ GetDefaultMemoryResource() };
141
144 {
145 std::sort(Points.begin(), Points.end(), [](const AttenuationCurve::Point& a, const AttenuationCurve::Point& b)
146 {
147 return a.Distance < b.Distance;
148 });
149 }
150
152 JPL_INLINE float Evaluate(float distance) const final;
153
154 private:
155 JPL_INLINE float EvaluateFunction(const Point& point, float distance, const Point* nextPoint) const;
156 };
157
158//==============================================================================
159//
160// Code beyond this point is implementation detail...
161//
162//==============================================================================
163
165 {
166 if (Points.empty())
167 return 1.0f; // Default attenuation
168
169 // Handle distances before the first point
170 if (distance <= Points.front().Distance)
171 {
172 const auto& point = Points.front();
173 return EvaluateFunction(point, distance, nullptr);
174 }
175
176 // Handle distances beyond the last point
177 if (distance >= Points.back().Distance)
178 {
179 // TODO: we might want to just return point.Value here,
180 // i.e. treat out of bounds as constant
181 const auto& point = Points.back();
182 return EvaluateFunction(point, distance, nullptr);
183 }
184
185 // Binary search to find the point just before the given distance
186 auto it = std::upper_bound(Points.begin(), Points.end(), distance, [](float value, const Point& point)
187 {
188 return value < point.Distance;
189 });
190
191 // Get the current point and the next point
192 const auto& prevPoint = *(it - 1);
193 const Point* nextPoint = (it != Points.end()) ? &(*it) : nullptr;
194
195 // Evaluate the attenuation using the function type of the previous point
196 // TODO: we may want to change this to evaluate function type of the next point
197 return EvaluateFunction(prevPoint, distance, nextPoint);
198 }
199
200 static JPL_INLINE float ComputeAttenuation(Curve::EType curveType, float distance, float distance0, float distance1)
201 {
202 float t = (distance - distance0) / (distance1 - distance0);
203 t = std::clamp(t, 0.0f, 1.0f);
204
205 return EvaluateCurve(curveType, t);
206 }
207
208 JPL_INLINE float AttenuationCurve::EvaluateFunction(const Point& point, float distance, const Point* nextPoint) const
209 {
210 if (!nextPoint || point.FunctionType == Curve::EType::Constant)
211 return point.Value;
212
213 const float amplitude = nextPoint->Value - point.Value;
214 return point.Value + amplitude * ComputeAttenuation(point.FunctionType, distance, point.Distance, nextPoint->Distance);
215 }
216} // namespace JPL
EType
Definition Curves.h:39
Definition AcousticMaterial.h:36
AttenuationModel
Definition DistanceAttenuation.h:33
@ None
Definition DistanceAttenuation.h:34
@ Linear
Definition DistanceAttenuation.h:36
@ Inverse
Definition DistanceAttenuation.h:35
@ _Count
Definition DistanceAttenuation.h:39
@ Exponential
Definition DistanceAttenuation.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
float Rolloff
Definition DistanceAttenuation.h:62
float MaxDistance
Definition DistanceAttenuation.h:61
float MinDistance
Definition DistanceAttenuation.h:60
Definition DistanceAttenuation.h:56
JPL_INLINE float Evaluate(float distance) const final
Definition DistanceAttenuation.h:65
AttenuationModel Model
Definition DistanceAttenuation.h:57
struct JPL::AttenuationBaseModel::DistanceAttenuationParameters Parameters
Definition DistanceAttenuation.h:124
float Distance
Definition DistanceAttenuation.h:130
float Value
Definition DistanceAttenuation.h:131
Curve::Point XY
Definition DistanceAttenuation.h:127
Curve::EType FunctionType
The function type to use from this point onward.
Definition DistanceAttenuation.h:136
Definition DistanceAttenuation.h:122
JPL_INLINE float Evaluate(float distance) const final
Evaluate curve at distance
Definition DistanceAttenuation.h:164
std::pmr::vector< Point > Points
Curve points that should sorted by distance.
Definition DistanceAttenuation.h:140
JPL_INLINE void SortPoints()
Sort curve points by distance. This should be called after changing Points.
Definition DistanceAttenuation.h:143
Definition DistanceAttenuation.h:43
virtual ~AttenuationFunction()=default
virtual float Evaluate(float distance) const =0
Definition Curves.h:33