diff --git a/ogre2/src/Ogre2GpuRays.cc b/ogre2/src/Ogre2GpuRays.cc index d63a0531c..c68bead3c 100644 --- a/ogre2/src/Ogre2GpuRays.cc +++ b/ogre2/src/Ogre2GpuRays.cc @@ -172,6 +172,9 @@ class ignition::rendering::Ogre2GpuRaysPrivate /// \brief Listener for setting particle noise value based on particle /// emitter region public: std::unique_ptr particleNoiseListener[6]; + + /// \brief Min allowed angle in radians; + public: const math::Angle kMinAllowedAngle = 1e-4; }; using namespace ignition; @@ -455,6 +458,7 @@ void Ogre2GpuRays::ConfigureCamera() { // horizontal gpu rays setup auto hfovAngle = this->AngleMax() - this->AngleMin(); + hfovAngle = std::max(this->dataPtr->kMinAllowedAngle, hfovAngle); this->SetHFOV(hfovAngle); // vertical laser setup @@ -462,7 +466,8 @@ void Ogre2GpuRays::ConfigureCamera() if (this->VerticalRangeCount() > 1) { - vfovAngle = (this->VerticalAngleMax() - this->VerticalAngleMin()).Radian(); + vfovAngle = std::max(this->dataPtr->kMinAllowedAngle.Radian(), + (this->VerticalAngleMax() - this->VerticalAngleMin()).Radian()); } else { @@ -547,11 +552,16 @@ void Ogre2GpuRays::CreateSampleTexture() double max = this->AngleMax().Radian(); double vmin = this->VerticalAngleMin().Radian(); double vmax = this->VerticalAngleMax().Radian(); - double hStep = (max-min) / static_cast(this->dataPtr->w2nd-1); + + double hAngle = std::max(this->dataPtr->kMinAllowedAngle.Radian(), max - min); + double vAngle = std::max(this->dataPtr->kMinAllowedAngle.Radian(), + vmax - vmin); + + double hStep = hAngle / static_cast(this->dataPtr->w2nd-1); double vStep = 1.0; // non-planar case if (this->dataPtr->h2nd > 1) - vStep = (vmax-vmin) / static_cast(this->dataPtr->h2nd-1); + vStep = vAngle / static_cast(this->dataPtr->h2nd-1); // create an RGB texture (cubeUVTex) to pack info that tells the shaders how // to sample from the cubemap textures. diff --git a/test/integration/gpu_rays.cc b/test/integration/gpu_rays.cc index 0db85ec79..44eb54ed3 100644 --- a/test/integration/gpu_rays.cc +++ b/test/integration/gpu_rays.cc @@ -64,6 +64,9 @@ class GpuRaysTest: public testing::Test, // Test detection of particles public: void RaysParticles(const std::string &_renderEngine); + + // Test single ray box intersection + public: void SingleRay(const std::string &_renderEngine); }; ///////////////////////////////////////////////// @@ -150,7 +153,7 @@ void GpuRaysTest::Configure(const std::string &_renderEngine) void GpuRaysTest::RaysUnitBox(const std::string &_renderEngine) { #ifdef __APPLE__ - std::cerr << "Skipping test for apple, see issue #35." << std::endl; + ignerr << "Skipping test for apple, see issue #35." << std::endl; return; #endif @@ -335,7 +338,7 @@ void GpuRaysTest::RaysUnitBox(const std::string &_renderEngine) void GpuRaysTest::LaserVertical(const std::string &_renderEngine) { #ifdef __APPLE__ - std::cerr << "Skipping test for apple, see issue #35." << std::endl; + ignerr << "Skipping test for apple, see issue #35." << std::endl; return; #endif @@ -468,7 +471,7 @@ void GpuRaysTest::LaserVertical(const std::string &_renderEngine) void GpuRaysTest::RaysParticles(const std::string &_renderEngine) { #ifdef __APPLE__ - std::cerr << "Skipping test for apple, see issue #35." << std::endl; + ignerr << "Skipping test for apple, see issue #35." << std::endl; return; #endif @@ -677,6 +680,104 @@ void GpuRaysTest::RaysParticles(const std::string &_renderEngine) engine->DestroyScene(scene); rendering::unloadEngine(engine->Name()); } + +///////////////////////////////////////////////// +/// \brief Test single ray box intersection +void GpuRaysTest::SingleRay(const std::string &_renderEngine) +{ +#ifdef __APPLE__ + ignerr << "Skipping test for apple, see issue #35." << std::endl; + return; +#endif + + if (_renderEngine == "optix") + { + igndbg << "GpuRays not supported yet in rendering engine: " + << _renderEngine << std::endl; + return; + } + + // Test GPU single ray box intersection. + // Place GPU above box looking downwards + // ray should intersect with center of box + + const double hMinAngle = 0.0; + const double hMaxAngle = 0.0; + const double minRange = 0.05; + const double maxRange = 40.0; + const int hRayCount = 1; + const int vRayCount = 1; + + // create and populate scene + RenderEngine *engine = rendering::engine(_renderEngine); + if (!engine) + { + igndbg << "Engine '" << _renderEngine + << "' is not supported" << std::endl; + return; + } + + ScenePtr scene = engine->CreateScene("scene"); + ASSERT_TRUE(scene != nullptr); + + VisualPtr root = scene->RootVisual(); + + // Create first ray caster + ignition::math::Pose3d testPose(ignition::math::Vector3d(0, 0, 7), + ignition::math::Quaterniond(0, IGN_PI/2.0, 0)); + + GpuRaysPtr gpuRays = scene->CreateGpuRays("gpu_rays"); + gpuRays->SetWorldPosition(testPose.Pos()); + gpuRays->SetWorldRotation(testPose.Rot()); + gpuRays->SetNearClipPlane(minRange); + gpuRays->SetFarClipPlane(maxRange); + gpuRays->SetAngleMin(hMinAngle); + gpuRays->SetAngleMax(hMaxAngle); + gpuRays->SetRayCount(hRayCount); + + gpuRays->SetVerticalRayCount(vRayCount); + root->AddChild(gpuRays); + + // box in the center + ignition::math::Pose3d box01Pose(ignition::math::Vector3d(0, 0, 4.5), + ignition::math::Quaterniond::Identity); + VisualPtr visualBox1 = scene->CreateVisual("UnitBox1"); + visualBox1->AddGeometry(scene->CreateBox()); + visualBox1->SetWorldPosition(box01Pose.Pos()); + visualBox1->SetWorldRotation(box01Pose.Rot()); + root->AddChild(visualBox1); + + // Verify rays caster range readings + // listen to new gpu rays frames + unsigned int channels = gpuRays->Channels(); + float *scan = new float[hRayCount * vRayCount * channels]; + common::ConnectionPtr c = + gpuRays->ConnectNewGpuRaysFrame( + std::bind(&::OnNewGpuRaysFrame, scan, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, + std::placeholders::_4, std::placeholders::_5)); + + gpuRays->Update(); + + int mid = 0; + double unitBoxSize = 1.0; + double expectedRangeAtMidPointBox = testPose.Pos().Z() - + (abs(box01Pose.Pos().Z()) + unitBoxSize/2); + + // rays caster 1 should see box01 and box02 + EXPECT_NEAR(scan[mid], expectedRangeAtMidPointBox, LASER_TOL); + + c.reset(); + + delete [] scan; + + scan = nullptr; + + // Clean up + engine->DestroyScene(scene); + rendering::unloadEngine(engine->Name()); +} + ///////////////////////////////////////////////// TEST_P(GpuRaysTest, Configure) { @@ -701,6 +802,13 @@ TEST_P(GpuRaysTest, RaysParticles) RaysParticles(GetParam()); } +///////////////////////////////////////////////// +TEST_P(GpuRaysTest, SingleRay) +{ + SingleRay(GetParam()); +} + + INSTANTIATE_TEST_CASE_P(GpuRays, GpuRaysTest, RENDER_ENGINE_VALUES, ignition::rendering::PrintToStringParam());