Wayverb
exact.h
Go to the documentation of this file.
1 #pragma once
2 
4 
5 #include "core/callback_accumulator.h"
6 #include "core/geo/box.h"
7 #include <iostream>
8 
13 
14 namespace wayverb {
15 namespace raytracer {
16 namespace image_source {
17 
18 // Combined Wave and Ray Based Room Acoustic Simulations of Small Rooms
19 // Marc Aretz, p. 71
20 
21 glm::vec3 image_source_position(const glm::ivec3& order,
22  const glm::vec3& source,
23  const glm::vec3& dim);
24 
25 template <typename T>
26 constexpr T power(T t, size_t p) {
27  return p == 0 ? core::unit_constructor_v<T> : t * power(t, p - 1);
28 }
29 
30 template <typename T>
31 auto attenuation_factor(const glm::ivec3& order,
32  const glm::vec3& image_source,
33  const glm::vec3& receiver,
34  const T& impedance) {
35  const auto diff = image_source - receiver;
36  const auto cos_theta = glm::abs(diff) / glm::length(diff);
37 
38  return power(core::average_wall_impedance_to_pressure_reflectance(
39  impedance, cos_theta.x),
40  abs(order.x)) *
41  power(core::average_wall_impedance_to_pressure_reflectance(
42  impedance, cos_theta.y),
43  abs(order.y)) *
44  power(core::average_wall_impedance_to_pressure_reflectance(
45  impedance, cos_theta.z),
46  abs(order.z));
47 }
48 
49 template <typename T>
50 auto traverse_images(const core::geo::box& box,
51  const glm::vec3& source,
52  const glm::vec3& receiver,
53  double max_distance,
54  const T& impedance) {
55  const auto dim = dimensions(box);
56  const auto shells = glm::ivec3(glm::ceil(glm::vec3(max_distance) / dim));
57 
58  std::cout << "shells: " << shells.x << ", " << shells.y << ", " << shells.z
59  << '\n';
60 
61  using impulse_t = impulse<::detail::components_v<T>>;
62 
63  util::aligned::vector<impulse_t> impulses;
64  impulses.reserve(shells.x * shells.y * shells.z * 8);
65 
66  for (auto i = -shells.x; i != shells.x + 1; ++i) {
67  for (auto j = -shells.y; j != shells.y + 1; ++j) {
68  for (auto k = -shells.z; k != shells.z + 1; ++k) {
69  const auto order = glm::ivec3{i, j, k};
70  const auto pos = box.get_min() +
71  image_source_position(order, source, dim);
72  const auto dist = glm::distance(pos, receiver);
73 
74  if (dist < max_distance) {
75  const auto attenuation =
76  attenuation_factor(order, pos, receiver, impedance);
77 
78  impulses.emplace_back(
79  impulse_t{attenuation,
80  core::to_cl_float3{}(pos),
81  glm::distance(pos, receiver)});
82  }
83  }
84  }
85  }
86 
87  return impulses;
88 }
89 
90 template <typename Surface>
91 auto find_impulses(const core::geo::box& box,
92  const glm::vec3& source,
93  const glm::vec3& receiver,
94  const Surface& surface,
95  double max_distance) {
96  const auto impedance = core::pressure_reflectance_to_average_wall_impedance(
97  core::absorption_to_pressure_reflectance(surface));
98 
99  return traverse_images(box, source, receiver, max_distance, impedance);
100 }
101 
102 } // namespace image_source
103 } // namespace raytracer
104 } // namespace wayverb
Definition: pressure.h:22
Definition: capsule_base.h:9