summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/resonance-audio/resonance_audio/geometrical_acoustics/proxy_room_estimator.h
blob: 63aa589983392dffc8ced12ac1d3e840d96405df (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
Copyright 2018 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS-IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef RESONANCE_AUDIO_GEOMETRICAL_ACOUSTICS_PROXY_ROOM_ESTIMATOR_H_
#define RESONANCE_AUDIO_GEOMETRICAL_ACOUSTICS_PROXY_ROOM_ESTIMATOR_H_

#include <array>
#include <utility>
#include <vector>

#include "Eigen/Core"
#include "api/resonance_audio_api.h"
#include "base/constants_and_types.h"
#include "base/misc_math.h"
#include "geometrical_acoustics/path.h"
#include "platforms/common/room_properties.h"

namespace vraudio {

// A class that estimates a "proxy room" from traced sound propagation paths.
// A proxy room is used to model dynamic early reflections as if they are
// reflected from a box-shaped room, even though the real scene geometry is
// arbitrarily complex. This is to complement the pre-computed late reverb
// effects, and it takes the same input (i.e., the ray tracing results) as the
// reverb pre-computation. The proxy room is estimated from the first order
// ray paths (i.e., those from the source to the first hit points), and the
// estimation has two stages:
//   1. Fitting the geometry (currently only as an axis-aligned cube).
//   2. Fitting the surface materials on the six walls.
class ProxyRoomEstimator {
 public:
  ProxyRoomEstimator() = default;

  // ProxyRoomEstimator is neither copyable nor movable.
  ProxyRoomEstimator(const ProxyRoomEstimator&) = delete;
  ProxyRoomEstimator& operator=(const ProxyRoomEstimator&) = delete;

  // Collects hit point data from traced ray paths, batch-by-batch.
  //
  // @param paths_batch A batch of ray paths.
  void CollectHitPointData(const std::vector<Path>& paths_batch);

  // Estimates a cube-shaped proxy room from collected hit points. Hit points
  // are sorted according to their traveled distance. In order to make the
  // estimation more robust, we discard "outlier" hit points, i.e., those whose
  // traveled distances are too large or too small.
  //
  // @param outlier_portion What portion of the hit points are considered as
  //     outliers. For example, a value of 0.1 means that the hit points whose
  //     distances are in the top 10% and bottom 10% are considered as outliers
  //     and discarded. The value must be in the range of [0, 0.5].
  // @param room_properties Room properties of the estimated axis-aligned cube-
  //     shaped room, each wall having an estimated surface material.
  // @return True if the estimation is successful.
  bool EstimateCubicProxyRoom(float outlier_portion,
                              RoomProperties* room_properties);

 private:
  class CoefficientsVector : public Eigen::Matrix<float, kNumReverbOctaveBands,
                                                  1, Eigen::DontAlign> {
   public:
    // Inherits all constructors with 1-or-more arguments. Necessary because
    // MSVC12 doesn't support inheriting constructors.
    template <typename Arg1, typename... Args>
    CoefficientsVector(const Arg1& arg1, Args&&... args)
        : Matrix(arg1, std::forward<Args>(args)...) {}

    // Constructs a zero vector.
    CoefficientsVector() { setZero(); }
  };

  // A struct to contain data necessary for estimating a proxy room.
  struct HitPointData {
    // Origin of the ray that creates this hit point.
    WorldPosition origin;

    // Direction of the ray that creates this hit point.
    WorldPosition direction;

    // Ray parameter t corresponding to the hit point. If the ray escaped the
    // scene and did not hit anything, then |t_far| takes the value of
    // |AcousticRay::kInfinity|. Escaped rays are still useful in estimating
    // surface materials, because they can be considered completely absorbed
    // and should increase the effective absorption coefficients.
    float t_far;

    // Absorption coefficients of the surface of the hit point across the
    // frequency bands.
    std::array<float, kNumReverbOctaveBands> absorption_coefficients;
  };

  // Collects one hit point from one traced ray path.
  //
  // @param path Traced ray path.
  // @return Collected hit point.
  HitPointData CollectHitPointDataFromPath(const Path& path);

  // Estimates the geometry of the cube.
  //
  // @param outlier_portion Portion of all hit points to be discarded. See
  //     EstimateCube() above.
  // @param position Output center position of the estimated cube.
  // @param dimensions Output dimensions of the estimated cube.
  // @return True if the estimation is successful.
  bool EstimateCubeGeometry(float outlier_portion, float* position,
                            float* dimensions, float* rotation);

  // Groups hit points by which walls they lie on in an assumed axis-aligned
  // room.
  //
  // @param room_position Center position of the assumed axis-aligned room.
  // @param room_dimensions Dimensions of the assumed axis-aligned room.
  // @return An array of six elements, each being a vector of hit points
  //     on one of the six walls.
  std::array<std::vector<HitPointData>, kNumRoomSurfaces> GroupHitPointsByWalls(
      const WorldPosition& room_position, const WorldPosition& room_dimensions);

  // Compute the hit point positions and distances (measured along the normal
  // direction of the walls that they hit) from hit points on walls.
  //
  // @param hit_points_on_walls Hit points on walls.
  // @return A vector of {hit point position, distance} pairs.
  std::vector<std::pair<WorldPosition, float>>
  ComputeDistancesAndPositionsFromHitPoints(
      const std::array<std::vector<HitPointData>, kNumRoomSurfaces>&
          hit_points_on_walls);

  // Estimates the surface materials on the six walls of the proxy room.
  //
  // @param room_position Center position of the estimated proxy room.
  // @param room_dimensions Dimensions of the estimated proxy room.
  // @param material_names Names of the estimated surface materials.
  void EstimateSurfaceMaterials(const WorldPosition& room_position,
                                const WorldPosition& room_dimensions,
                                MaterialName* material_names);

  // Collected hit points.
  std::vector<HitPointData> hit_points_;
};

}  // namespace vraudio

#endif  // RESONANCE_AUDIO_GEOMETRICAL_ACOUSTICS_PROXY_ROOM_ESTIMATOR_H_