/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include "WhiteBox_precompiled.h" #include "Util/WhiteBoxTextureUtil.h" #include "WhiteBoxTestFixtures.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace UnitTest { std::random_device rd; std::mt19937 gen(rd()); // rngs for the first and subsequent significant figures of the random numbers std::uniform_real_distribution<> rndFirstSigFig(1.0, 10.0); std::uniform_real_distribution<> rndOtherSigFigs(0.0, 1.0); // generate noise after the specified decimal place with the first significant // figure always being one decimal place after afterDecimalPlace float GenerateNoiseWithSignificantFigures(AZ::u32 afterDecimalPlace) { // number of significant figures of randomness to generate const double numSigFigs = 8; // scaling factor to push the noise back into the desired range const double sigFactor = std::pow(10.0, numSigFigs + afterDecimalPlace); // random value for first guaranteed significant digit const double firstSigFig = azlossy_cast(rndFirstSigFig(gen)) * std::pow(10.0, numSigFigs - 1); // random value for the other significant digits const double otherSigFigs = azlossy_cast(rndOtherSigFigs(gen) * std::pow(10.0, numSigFigs - 1)); // unscaled random value with rndSigFigs significant figures const double fixedLengthRandom = firstSigFig + otherSigFigs; // scaled random value to push the noise into the desired significant digit range const float noise = fixedLengthRandom / sigFactor; return noise; } // generates a vector of Vector3s with noise for in specified range decimal places std::vector GenerateNoiseForSignificantFigureRange(AZ::u32 startDecimalPlace, AZ::u32 endDecimalPlace) { std::vector noise(endDecimalPlace - startDecimalPlace + 1); for (AZ::u32 decimal = startDecimalPlace, i = 0; decimal <= endDecimalPlace; decimal++, i++) { float x = GenerateNoiseWithSignificantFigures(decimal); float y = GenerateNoiseWithSignificantFigures(decimal); float z = GenerateNoiseWithSignificantFigures(decimal); noise[i] = Vector3{x, y, z}; } return noise; } // vector of noise vectors with between 3 and 6 significat figures const std::vector Noise = GenerateNoiseForSignificantFigureRange(3, 6); // noise source permutations to be applied to each test const std::vector Source = { NoiseSource::None, NoiseSource::XComponent, NoiseSource::YComponent, NoiseSource::ZComponent, NoiseSource::XYComponent, NoiseSource::XZComponent, NoiseSource::YZComponent, NoiseSource::XYZComponent}; enum CubeVertex : AZ::u32 { FrontTopLeft, FrontTopRight, BackTopLeft, BackTopRight, FrontBottomLeft, FrontBottomRight, BackBottomLeft, BackBottomRight }; const std::vector UnitCube = { AZ::Vector3(-0.5f, 0.5f, 0.5f), // FrontTopLeft AZ::Vector3(0.5f, 0.5f, 0.5f), // FrontTopRight AZ::Vector3(-0.5f, -0.5f, 0.5f), // BackTopLeft AZ::Vector3(0.5f, -0.5f, 0.5f), // BackTopRight AZ::Vector3(-0.5f, 0.5f, -0.5f), // FrontBottomLeft AZ::Vector3(0.5f, 0.5f, -0.5f), // FrontBottomRight AZ::Vector3(-0.5f, -0.5f, -0.5f), // BackBottomLeft AZ::Vector3(0.5f, -0.5f, -0.5f) // BackBottomRight }; // returns a vector with noise applied to it as determined by the source AZ::Vector3 GenerateNoiseyVector(const AZ::Vector3& in, const Vector3& noise, NoiseSource source) { switch (source) { case NoiseSource::None: return in; case NoiseSource::XComponent: return AZ::Vector3(in.GetX() + noise.x, in.GetY(), in.GetZ()); case NoiseSource::YComponent: return AZ::Vector3(in.GetX(), in.GetY() + noise.y, in.GetZ()); case NoiseSource::ZComponent: return AZ::Vector3(in.GetX(), in.GetY(), in.GetZ() + noise.z); case NoiseSource::XYComponent: return AZ::Vector3(in.GetX() + noise.x, in.GetY() + noise.y, in.GetZ()); case NoiseSource::XZComponent: return AZ::Vector3(in.GetX() + noise.x, in.GetY(), in.GetZ() + noise.z); case NoiseSource::YZComponent: return AZ::Vector3(in.GetX(), in.GetY() + noise.y, in.GetZ() + noise.z); case NoiseSource::XYZComponent: return AZ::Vector3(in.GetX() + noise.x, in.GetY() + noise.y, in.GetZ() + noise.z); default: return in; } } // returns a quaternion with the specified rotation AZ::Quaternion GetQuaternionFromRotation(Rotation rotation) { static const AZ::Quaternion qXAxis = AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisX(), 45); static const AZ::Quaternion qZAxis = AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisZ(), 45); static const AZ::Quaternion qXZAxis = qXAxis + qZAxis; switch (rotation) { case Rotation::Identity: return AZ::Quaternion::CreateIdentity(); case Rotation::XAxis: return qXAxis; case Rotation::ZAxis: return qZAxis; case Rotation::XZAxis: return qXZAxis; default: return AZ::Quaternion::CreateIdentity(); } } TEST_P(WhiteBoxUVTestFixture, FrontFaceCorners) { using WhiteBox::CreatePlanarUVFromVertex; const auto& [noise, source, rotation] = GetParam(); const AZ::Quaternion qRotation = GetQuaternionFromRotation(rotation); const AZ::Vector3 normal = GenerateNoiseyVector(qRotation * AZ::Vector3(0.0f, -1.0f, 0.0f), noise, source); const AZ::Vector2 uv00 = CreatePlanarUVFromVertex(normal, UnitCube[FrontTopLeft]); const AZ::Vector2 uv10 = CreatePlanarUVFromVertex(normal, UnitCube[FrontTopRight]); const AZ::Vector2 uv01 = CreatePlanarUVFromVertex(normal, UnitCube[FrontBottomLeft]); const AZ::Vector2 uv11 = CreatePlanarUVFromVertex(normal, UnitCube[FrontBottomRight]); EXPECT_THAT(uv00, IsClose(AZ::Vector2(1.0f, 0.0f))); EXPECT_THAT(uv10, IsClose(AZ::Vector2(0.0f, 0.0f))); EXPECT_THAT(uv01, IsClose(AZ::Vector2(1.0f, 1.0f))); EXPECT_THAT(uv11, IsClose(AZ::Vector2(0.0f, 1.0f))); } TEST_P(WhiteBoxUVTestFixture, BackFaceCorners) { using WhiteBox::CreatePlanarUVFromVertex; const auto& [noise, source, rotation] = GetParam(); const AZ::Quaternion qRotation = GetQuaternionFromRotation(rotation); const AZ::Vector3 normal = GenerateNoiseyVector(qRotation * AZ::Vector3(0.0f, 1.0f, 0.0f), noise, source); const AZ::Vector2 uv00 = CreatePlanarUVFromVertex(normal, UnitCube[BackTopLeft]); const AZ::Vector2 uv10 = CreatePlanarUVFromVertex(normal, UnitCube[BackTopRight]); const AZ::Vector2 uv01 = CreatePlanarUVFromVertex(normal, UnitCube[BackBottomLeft]); const AZ::Vector2 uv11 = CreatePlanarUVFromVertex(normal, UnitCube[BackBottomRight]); EXPECT_THAT(uv00, IsClose(AZ::Vector2(1.0f, 0.0f))); EXPECT_THAT(uv10, IsClose(AZ::Vector2(0.0f, 0.0f))); EXPECT_THAT(uv01, IsClose(AZ::Vector2(1.0f, 1.0f))); EXPECT_THAT(uv11, IsClose(AZ::Vector2(0.0f, 1.0f))); } TEST_P(WhiteBoxUVTestFixture, LeftFaceCorners) { using WhiteBox::CreatePlanarUVFromVertex; const auto& [noise, source, rotation] = GetParam(); const AZ::Quaternion qRotation = GetQuaternionFromRotation(rotation); const AZ::Vector3 normal = GenerateNoiseyVector(qRotation * AZ::Vector3(-1.0f, 0.0f, 0.0f), noise, source); const AZ::Vector2 uv00 = CreatePlanarUVFromVertex(normal, UnitCube[FrontTopLeft]); const AZ::Vector2 uv10 = CreatePlanarUVFromVertex(normal, UnitCube[BackTopLeft]); const AZ::Vector2 uv01 = CreatePlanarUVFromVertex(normal, UnitCube[FrontBottomLeft]); const AZ::Vector2 uv11 = CreatePlanarUVFromVertex(normal, UnitCube[BackBottomLeft]); EXPECT_THAT(uv00, IsClose(AZ::Vector2(0.0f, 0.0f))); EXPECT_THAT(uv10, IsClose(AZ::Vector2(0.0f, 1.0f))); EXPECT_THAT(uv01, IsClose(AZ::Vector2(1.0f, 0.0f))); EXPECT_THAT(uv11, IsClose(AZ::Vector2(1.0f, 1.0f))); } TEST_P(WhiteBoxUVTestFixture, RightFaceCorners) { using WhiteBox::CreatePlanarUVFromVertex; const auto& [noise, source, rotation] = GetParam(); const AZ::Quaternion qRotation = GetQuaternionFromRotation(rotation); const AZ::Vector3 normal = GenerateNoiseyVector(qRotation * AZ::Vector3(1.0f, 0.0f, 0.0f), noise, source); const AZ::Vector2 uv00 = CreatePlanarUVFromVertex(normal, UnitCube[FrontTopRight]); const AZ::Vector2 uv10 = CreatePlanarUVFromVertex(normal, UnitCube[BackTopRight]); const AZ::Vector2 uv01 = CreatePlanarUVFromVertex(normal, UnitCube[FrontBottomRight]); const AZ::Vector2 uv11 = CreatePlanarUVFromVertex(normal, UnitCube[BackBottomRight]); EXPECT_THAT(uv00, IsClose(AZ::Vector2(0.0f, 0.0f))); EXPECT_THAT(uv10, IsClose(AZ::Vector2(0.0f, 1.0f))); EXPECT_THAT(uv01, IsClose(AZ::Vector2(1.0f, 0.0f))); EXPECT_THAT(uv11, IsClose(AZ::Vector2(1.0f, 1.0f))); } TEST_P(WhiteBoxUVTestFixture, TopFaceCorners) { using WhiteBox::CreatePlanarUVFromVertex; const auto& [noise, source, rotation] = GetParam(); const AZ::Quaternion qRotation = GetQuaternionFromRotation(rotation); const AZ::Vector3 normal = GenerateNoiseyVector(qRotation * AZ::Vector3(0.0f, 0.0f, 1.0f), noise, source); const AZ::Vector2 uv00 = CreatePlanarUVFromVertex(normal, UnitCube[FrontTopLeft]); const AZ::Vector2 uv10 = CreatePlanarUVFromVertex(normal, UnitCube[FrontTopRight]); const AZ::Vector2 uv01 = CreatePlanarUVFromVertex(normal, UnitCube[BackTopLeft]); const AZ::Vector2 uv11 = CreatePlanarUVFromVertex(normal, UnitCube[BackTopRight]); EXPECT_THAT(uv00, IsClose(AZ::Vector2(1.0f, 0.0f))); EXPECT_THAT(uv10, IsClose(AZ::Vector2(0.0f, 0.0f))); EXPECT_THAT(uv01, IsClose(AZ::Vector2(1.0f, 1.0f))); EXPECT_THAT(uv11, IsClose(AZ::Vector2(0.0f, 1.0f))); } TEST_P(WhiteBoxUVTestFixture, BottomFaceCorners) { using WhiteBox::CreatePlanarUVFromVertex; const auto& [noise, source, rotation] = GetParam(); const AZ::Quaternion qRotation = GetQuaternionFromRotation(rotation); const AZ::Vector3 normal = GenerateNoiseyVector(qRotation * AZ::Vector3(0.0f, 0.0f, -1.0f), noise, source); const AZ::Vector2 uv00 = CreatePlanarUVFromVertex(normal, UnitCube[FrontBottomLeft]); const AZ::Vector2 uv10 = CreatePlanarUVFromVertex(normal, UnitCube[FrontBottomRight]); const AZ::Vector2 uv01 = CreatePlanarUVFromVertex(normal, UnitCube[BackBottomLeft]); const AZ::Vector2 uv11 = CreatePlanarUVFromVertex(normal, UnitCube[BackBottomRight]); EXPECT_THAT(uv00, IsClose(AZ::Vector2(1.0f, 0.0f))); EXPECT_THAT(uv10, IsClose(AZ::Vector2(0.0f, 0.0f))); EXPECT_THAT(uv01, IsClose(AZ::Vector2(1.0f, 1.0f))); EXPECT_THAT(uv11, IsClose(AZ::Vector2(0.0f, 1.0f))); } // test with permutations of all noise values and sources with rotations around the x and z axis INSTANTIATE_TEST_CASE_P( , WhiteBoxUVTestFixture, ::testing::Combine( ::testing::ValuesIn(Noise), ::testing::ValuesIn(Source), ::testing::Values(Rotation::Identity, Rotation::XZAxis))); } // namespace UnitTest