RavEngine
Loading...
Searching...
No Matches
sampling.h
1/*
2Copyright 2018 Google Inc. All Rights Reserved.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS-IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17// Collection of sampling functions useful for in stochastic ray tracing.
18
19#ifndef RESONANCE_AUDIO_GEOMETRICAL_ACOUSTICS_SAMPLING_H_
20#define RESONANCE_AUDIO_GEOMETRICAL_ACOUSTICS_SAMPLING_H_
21
22#include <cmath>
23
24#include "Eigen/Dense"
25#include "base/constants_and_types.h"
26#include "base/logging.h"
27
28namespace vraudio {
29
30// Samples a vector uniformly from a unit sphere given two random variables
31// whose values are in [0, 1).
32//
33// @param u The first random variable.
34// @param v The second random variable.
35// @return The sampled vector.
36inline Eigen::Vector3f UniformSampleSphere(float u, float v) {
37 DCHECK(u >= 0.0f && u <= 1.0f);
38 DCHECK(v >= 0.0f && v <= 1.0f);
39 const float cos_theta = 1.0f - 2.0f * v;
40 const float sin_theta = 2.0f * std::sqrt(v * (1.0f - v));
41 const float phi = kTwoPi * u;
42 return Eigen::Vector3f(std::cos(phi) * sin_theta, std::sin(phi) * sin_theta,
43 cos_theta);
44}
45
46// Samples a vector from a unit sphere in a stratified fashion given two
47// random variables whose values are in [0, 1). The collective results from
48// |sample_index| iterating from 0 to |sqrt_num_samples|^2 are uniformly
49// distributed on a sphere.
50//
51// @param u The first random variable.
52// @param v The second random variable.
53// @param sqrt_num_samples The square root of the total number of samples.
54// @param sample_index The index of the currently sampled vector.
55// @return The sampled vector.
56inline Eigen::Vector3f StratifiedSampleSphere(float u, float v,
57 size_t sqrt_num_samples,
58 size_t sample_index) {
59 DCHECK(u >= 0.0f && u <= 1.0f);
60 DCHECK(v >= 0.0f && v <= 1.0f);
61
62 // Make a domain that have |sqrt_num_samples| by |sqrt_num_samples| cells.
63 // First decide which cell that this sample is in, denoted by the coordinates
64 // of the cell's top-left of corner.
65 const float cell_x = static_cast<float>(sample_index / sqrt_num_samples);
66 const float cell_y = static_cast<float>(sample_index % sqrt_num_samples);
67
68 // Then pick a point inside the cell using the two random variables u and v.
69 // Normalize the point to the [0, 1) x [0, 1) domain and send it to
70 // UniformSampleSphere().
71 const float cell_width = 1.0f / static_cast<float>(sqrt_num_samples);
72 return UniformSampleSphere((cell_x + u) * cell_width,
73 (cell_y + v) * cell_width);
74}
75
76// Samples a vector from a unit hemisphere according to the cosine-weighted
77// distribution given two random variables whose values are in [0, 1). The
78// hemisphere lies on a plane whose normal is assumed to be on the +z direction.
79//
80
81static Eigen::Vector3f CosineSampleHemisphere(float u, float v) {
82 DCHECK(u >= 0.0f && u <= 1.0f);
83 DCHECK(v >= 0.0f && v <= 1.0f);
84 const float cos_theta = std::sqrt(1.0f - v);
85 const float sin_theta = std::sqrt(v);
86 const float phi = kTwoPi * u;
87 return Eigen::Vector3f(std::cos(phi) * sin_theta, std::sin(phi) * sin_theta,
88 cos_theta);
89}
90
91// Same as above but the hemisphere lies on a plane whose normal is specified
92// by the user (instead of the +z direction).
93//
94// @param u The first random variable.
95// @param v The second random variable.
96// @param unit_normal The normal of the plane on which the hemisphere resides.
97// @return The sampled vector.
98static Eigen::Vector3f CosineSampleHemisphere(
99 float u, float v, const Eigen::Vector3f& unit_normal) {
100 Eigen::Vector3f local_vector = CosineSampleHemisphere(u, v);
101
102 return Eigen::Quaternionf::FromTwoVectors(Eigen::Vector3f::UnitZ(),
103 unit_normal) *
104 local_vector;
105}
106
107// The probability density function (PDF) that a vector is in a particular
108// direction if the vector is sampled from a cosine-weigted distribution over
109// a unit hemisphere (i.e. it is sampled from the CosineSampleHemisphere()
110// above).
111//
112// @param unit_normal The normal of the plane on which the hemisphere resides.
113// @param unit_direction The direction of the sampled vector.
114// @return Probability density that a sampled vector is in the |unit_direction|.
115static float CosineSampleHemispherePdf(const Eigen::Vector3f& unit_normal,
116 const Eigen::Vector3f& unit_direction) {
117 const float cos_theta = unit_normal.dot(unit_direction);
118
119 // Returns zero probability if the |unit_normal| and |unit_direction| lie on
120 // different sides of the plane, i.e., their inner-product is negative.
121 return cos_theta >= 0.0f ? cos_theta / kPi : 0.0f;
122}
123
124} // namespace vraudio
125
126#endif // RESONANCE_AUDIO_GEOMETRICAL_ACOUSTICS_SAMPLING_H_