/* 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. */ #include "geometrical_acoustics/acoustic_source.h" #include #include #include #include "third_party/googletest/googletest/include/gtest/gtest.h" #include "base/constants_and_types.h" #include "geometrical_acoustics/test_util.h" namespace vraudio { namespace { TEST(AcousticSource, GeneratedRayNonDirectionalDataTest) { std::default_random_engine engine(0); std::uniform_real_distribution distribution(0.0f, 1.0f); const std::array energies{ {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f}}; AcousticSource source({0.1f, 0.2f, 0.3f}, energies, [&engine, &distribution] { return distribution(engine); }); AcousticRay ray = source.GenerateRay(); EXPECT_EQ(ray.type(), AcousticRay::RayType::kSpecular); for (size_t i = 0; i < kNumReverbOctaveBands; ++i) { EXPECT_FLOAT_EQ(ray.energies().at(i), energies.at(i)); } EXPECT_FLOAT_EQ(ray.t_near(), 0.0f); const float expected_origin[3] = {0.1f, 0.2f, 0.3f}; ExpectFloat3Close(ray.origin(), expected_origin); } TEST(AcousticSource, GeneratedRayDirectionDistributionTest) { std::default_random_engine engine(0); std::uniform_real_distribution distribution(0.0f, 1.0f); const std::array energies{ {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}}; AcousticSource source({0.0f, 0.0f, 0.0f}, energies, [&engine, &distribution] { return distribution(engine); }); // Check that the direction vectors on generated rays are all normalized, // i.e., of unit lengths. for (size_t i = 0; i < 1000; ++i) { AcousticRay ray = source.GenerateRay(); const float direction_squared_norm = ray.direction()[0] * ray.direction()[0] + ray.direction()[1] * ray.direction()[1] + ray.direction()[2] * ray.direction()[2]; EXPECT_FLOAT_EQ(direction_squared_norm, 1.0f); } // For a ray whose direction is uniformly distributed over a sphere: // - The PDF of theta is sin(theta), and the CDF is (1 - cos(theta)) / 2. // - The PDF of phi is 1 / 2 pi, and the CDF is 0.5 + phi / 2 pi. ValidateDistribution(100000, 100, [&source]() { AcousticRay ray = source.GenerateRay(); const float cos_theta = ray.direction()[2]; return 0.5f * (1.0f - cos_theta); }); ValidateDistribution(100000, 100, [&source]() { AcousticRay ray = source.GenerateRay(); const float* direction = ray.direction(); const float phi = std::atan2(direction[1], direction[0]); return 0.5f + phi / 2.0f / static_cast(M_PI); }); } // Similar to GeneratedRayDirectionDistributionTest, but tests on the whole // set of rays generated by AcousticSource::GenerateStratifiedRays() that they // are uniformly distributed. TEST(AcousticSource, GeneratedStratifiedRaysDirectionDistributionTest) { std::default_random_engine engine(0); std::uniform_real_distribution distribution(0.0f, 1.0f); const std::array energies{ {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}}; AcousticSource source({0.0f, 0.0f, 0.0f}, energies, [&engine, &distribution] { return distribution(engine); }); // Check that the direction vectors on generated rays are all normalized, // i.e., of unit lengths. const size_t num_rays = 10000; const size_t sqrt_num_rays = 100; std::vector rays = source.GenerateStratifiedRays(num_rays, sqrt_num_rays); for (const AcousticRay& ray : rays) { const float direction_squared_norm = ray.direction()[0] * ray.direction()[0] + ray.direction()[1] * ray.direction()[1] + ray.direction()[2] * ray.direction()[2]; EXPECT_FLOAT_EQ(direction_squared_norm, 1.0f); } // For a ray whose direction is uniformly distributed over a sphere: // - The PDF of theta is sin(theta), and the CDF is (1 - cos(theta)) / 2. // - The PDF of phi is 1 / 2 pi, and the CDF is 0.5 + phi / 2 pi. size_t ray_index = 0; ValidateDistribution(num_rays, 100, [&rays, &ray_index]() { const AcousticRay& ray = rays[ray_index]; ++ray_index; const float cos_theta = ray.direction()[2]; return 0.5f * (1.0f - cos_theta); }); ray_index = 0; ValidateDistribution(num_rays, 100, [&rays, &ray_index]() { const AcousticRay& ray = rays[ray_index]; ++ray_index; const float* direction = ray.direction(); const float phi = std::atan2(direction[1], direction[0]); return 0.5f + phi / kTwoPi; }); } } // namespace } // namespace vraudio