diff --git a/apps/tutorials/pe/01_ConfinedGas.cpp b/apps/tutorials/pe/01_ConfinedGas.cpp index 5fb805a0a67c94668604d3d3e6447e3d71a0d043..137194ce636f56f9590ae476d9415b7b9849c0c8 100644 --- a/apps/tutorials/pe/01_ConfinedGas.cpp +++ b/apps/tutorials/pe/01_ConfinedGas.cpp @@ -138,7 +138,7 @@ int main( int argc, char ** argv ) if (cfg == NULL) { WALBERLA_ABORT("raytracer needs a working config"); } - Raytracer raytracer(forest, storageID, cfg->getBlock("raytracing")); + Raytracer raytracer(forest, storageID, globalBodyStorage, cfg->getBlock("raytracing")); WALBERLA_LOG_INFO_ON_ROOT("*** INTEGRATOR ***"); //! [Integrator] @@ -165,13 +165,16 @@ int main( int argc, char ** argv ) auto simulationDomain = forest->getDomain(); auto generationDomain = simulationDomain; // simulationDomain.getExtended(-real_c(0.5) * spacing); //! [Planes] - createPlane(*globalBodyStorage, 0, Vec3(1,0,0), simulationDomain.minCorner(), material ); - createPlane(*globalBodyStorage, 0, Vec3(-1,0,0), simulationDomain.maxCorner(), material ); + PlaneID xPosPlane = createPlane(*globalBodyStorage, 0, Vec3(1,0,0), simulationDomain.minCorner(), material ); + PlaneID xNegPlane = createPlane(*globalBodyStorage, 0, Vec3(-1,0,0), simulationDomain.maxCorner(), material ); createPlane(*globalBodyStorage, 0, Vec3(0,1,0), simulationDomain.minCorner(), material ); createPlane(*globalBodyStorage, 0, Vec3(0,-1,0), simulationDomain.maxCorner(), material ); createPlane(*globalBodyStorage, 0, Vec3(0,0,1), simulationDomain.minCorner(), material ); createPlane(*globalBodyStorage, 0, Vec3(0,0,-1), simulationDomain.maxCorner(), material ); //! [Planes] + + raytracer.setBodyInvisible(xNegPlane); + raytracer.setBodyInvisible(xPosPlane); //! [Gas] uint_t numParticles = uint_c(0); diff --git a/apps/tutorials/pe/02_ConfinedGasExtended.cpp b/apps/tutorials/pe/02_ConfinedGasExtended.cpp index a8b5a074d53a92fbeb1008d1413082cf624b555d..416cdd3d1bd6bae61f24a4cba9db6bdcd8e78e85 100644 --- a/apps/tutorials/pe/02_ConfinedGasExtended.cpp +++ b/apps/tutorials/pe/02_ConfinedGasExtended.cpp @@ -149,7 +149,7 @@ int main( int argc, char ** argv ) if (cfg == NULL) { WALBERLA_ABORT("raytracer needs a working config"); } - Raytracer raytracer(forest, storageID, cfg->getBlock("Raytracing")); + Raytracer raytracer(forest, storageID, globalBodyStorage, cfg->getBlock("Raytracing")); WALBERLA_LOG_INFO_ON_ROOT("*** INTEGRATOR ***"); cr::HCSITS cr(globalBodyStorage, forest, storageID, ccdID, fcdID); diff --git a/src/pe/raytracing/Raytracer.cpp b/src/pe/raytracing/Raytracer.cpp index 2a7b36e383781302970bbe7d39980d893b5662c1..c2555920979230526568802724391740771f92da 100644 --- a/src/pe/raytracing/Raytracer.cpp +++ b/src/pe/raytracing/Raytracer.cpp @@ -40,11 +40,11 @@ namespace raytracing { * \param lookAtPoint Point the camera looks at in the global world frame. * \param upVector Vector indicating the upwards direction of the camera. */ -Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID, +Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID, const shared_ptr<BodyStorage> globalBodyStorage, size_t pixelsHorizontal, size_t pixelsVertical, real_t fov_vertical, const Vec3& cameraPosition, const Vec3& lookAtPoint, const Vec3& upVector) - : forest_(forest), storageID_(storageID), + : forest_(forest), storageID_(storageID), globalBodyStorage_(globalBodyStorage), pixelsHorizontal_(pixelsHorizontal), pixelsVertical_(pixelsVertical), fov_vertical_(fov_vertical), cameraPosition_(cameraPosition), lookAtPoint_(lookAtPoint), upVector_(upVector), @@ -63,8 +63,8 @@ Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageI * and tbuffer_output_directory (string) parameters. Additionally a vector of reals * for each of cameraPosition, lookAt and the upVector. */ -Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID, - const Config::BlockHandle& config) : forest_(forest), storageID_(storageID) { +Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID, const shared_ptr<BodyStorage> globalBodyStorage, + const Config::BlockHandle& config) : forest_(forest), storageID_(storageID), globalBodyStorage_(globalBodyStorage) { WALBERLA_CHECK(config.isValid(), "No valid config passed to raytracer"); pixelsHorizontal_ = config.getParameter<size_t>("image_x"); @@ -149,7 +149,7 @@ void Raytracer::writeTBufferToFile(const std::map<Coordinates, real_t, Coordinat if (realIsIdentical(t, INFINITY)) { r = g = b = (char)255; } else { - r = g = b = (char)(200 * ((t-t_min)/(t_max-t_min))); + r = g = b = (char)(240 * ((t-t_min)/(t_max-t_min))); } ofs << r << g << b; } diff --git a/src/pe/raytracing/Raytracer.h b/src/pe/raytracing/Raytracer.h index 2cd8430922f9db04402308eb96b57609c61cbf5b..0de46c1886f7aa48894e6ed40b910bae19da66b7 100644 --- a/src/pe/raytracing/Raytracer.h +++ b/src/pe/raytracing/Raytracer.h @@ -66,11 +66,11 @@ class Raytracer { public: /*!\name Constructors */ //@{ - explicit Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID, + explicit Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID, const shared_ptr<BodyStorage> globalBodyStorage, size_t pixelsHorizontal, size_t pixelsVertical, real_t fov_vertical, const Vec3& cameraPosition, const Vec3& lookAtPoint, const Vec3& upVector); - explicit Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID, + explicit Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID, const shared_ptr<BodyStorage> globalBodyStorage, const Config::BlockHandle& config); //@} @@ -80,6 +80,8 @@ private: const shared_ptr<BlockStorage> forest_; //!< The BlockForest the raytracer operates on. BlockDataID storageID_; /*!< The storage ID of the block data storage the raytracer operates on.*/ + const shared_ptr<BodyStorage> globalBodyStorage_; //!< The global body storage the raytracer operates on. + size_t pixelsHorizontal_; //!< The horizontal amount of pixels of the generated image. size_t pixelsVertical_; //!< The vertical amount of pixels of the generated image. real_t fov_vertical_; //!< The vertical field-of-view of the camera. @@ -89,6 +91,8 @@ private: Vec3 upVector_; //!< The vector indicating the upwards direction of the camera. bool tBufferOutputEnabled_; //!< Enable / disable dumping the tbuffer to a file std::string tBufferOutputDirectory_; //!< Path to the tbuffer output directory + std::set<walberla::id_t> invisibleBodyIDs_; //!< The set for invisible body IDs. + // std::set is used here because for a small number of elements it is often faster than std::unordered_set //@} Vec3 n; // normal vector of viewing plane @@ -113,12 +117,15 @@ public: inline const Vec3& getUpVector() const; inline bool getTBufferOutputEnabled() const; inline const std::string& getTBufferOutputDirectory() const; + inline bool isBodyInvisible(BodyID body) const; //@} /*!\name Set functions */ //@{ inline void setTBufferOutputEnabled(const bool enabled); inline void setTBufferOutputDirectory(const std::string& path); + inline void setBodyInvisible(BodyID body); + inline void setBodyVisible(BodyID body); //@} /*!\name Functions */ @@ -204,6 +211,14 @@ inline const std::string& Raytracer::getTBufferOutputDirectory() const { return tBufferOutputDirectory_; } +/*!\brief Returns if the specified body is invisible. + * + * \return True if body invisible, false otherwise. + */ +inline bool Raytracer::isBodyInvisible(BodyID body) const { + return invisibleBodyIDs_.find(body->getSystemID()) != invisibleBodyIDs_.end(); +} + /*!\brief Enabled / disable outputting the tBuffer to a file in the specified directory. * \param enabled Set to true / false to enable / disable tbuffer output. */ @@ -223,6 +238,20 @@ inline void Raytracer::setTBufferOutputDirectory(const std::string& path) { tBufferOutputDirectory_ = path; } +/*!\brief Mark the specified body as invisible for the raytracing algorithm. + * \param body Body to set invisible. + */ +inline void Raytracer::setBodyInvisible(BodyID body) { + invisibleBodyIDs_.insert(body->getSystemID()); +} + +/*!\brief Mark the specified body as visible for the raytracing algorithm. + * \param body Body to set invisible. + */ +inline void Raytracer::setBodyVisible(BodyID body) { + invisibleBodyIDs_.erase(body->getSystemID()); +} + /*!\brief Does one raytracing step. * * \param timestep The timestep after which the raytracing starts. @@ -252,7 +281,6 @@ void Raytracer::rayTrace(const size_t timestep) const { id_closest = 0; body_closest = NULL; for (auto blockIt = forest_->begin(); blockIt != forest_->end(); ++blockIt) { - // blockIt->getAABB(); #ifndef DISABLE_BLOCK_AABB_INTERSECTION_PRECHECK const AABB& blockAabb = blockIt->getAABB(); if (!intersects(blockAabb, ray, t)) { @@ -260,6 +288,29 @@ void Raytracer::rayTrace(const size_t timestep) const { } #endif for (auto bodyIt = LocalBodyIterator::begin(*blockIt, storageID_); bodyIt != LocalBodyIterator::end(); ++bodyIt) { + if (isBodyInvisible(*bodyIt)) { + continue; + } + + bool intersects = SingleCast<BodyTypeTuple, IntersectsFunctor, bool>::execute(*bodyIt, func); + + if (intersects && t < t_closest) { + // body was shot by ray and currently closest to camera + t_closest = t; + id_closest = bodyIt->getID(); + body_closest = *bodyIt; + } + } + } + + // only iterate over global body storage in one process. + // optimization required, e.g. split up global bodies over all processes. + WALBERLA_ROOT_SECTION() { + for( auto bodyIt = globalBodyStorage_->begin(); bodyIt != globalBodyStorage_->end(); ++bodyIt ) { + if (isBodyInvisible(*bodyIt)) { + continue; + } + bool intersects = SingleCast<BodyTypeTuple, IntersectsFunctor, bool>::execute(*bodyIt, func); if (intersects && t < t_closest) { @@ -306,7 +357,7 @@ void Raytracer::rayTrace(const size_t timestep) const { std::vector<BodyIntersectionInfo> gatheredIntersections; - std::map<walberla::id_t, bool> visibleBodyIDs; + std::set<walberla::id_t> visibleBodyIDs; //std::map<Coordinates, BodyIntersectionInfo, CoordinatesComparator> pixelIntersectionMap; @@ -348,7 +399,7 @@ void Raytracer::rayTrace(const size_t timestep) const { } for (auto& info: localPixelIntersectionMap) { - visibleBodyIDs[info.second.bodySystemID] = true; + visibleBodyIDs.insert(info.second.bodySystemID); } tp["Reduction"].end(); diff --git a/tests/pe/Raytracing.cpp b/tests/pe/Raytracing.cpp index f7374fbe53736506b01a366b59b070fa21bba3ac..43ca24d2b978b1c7acfd53b7ad044499d364341d 100644 --- a/tests/pe/Raytracing.cpp +++ b/tests/pe/Raytracing.cpp @@ -1,3 +1,4 @@ +#include <pe/basic.h> #include "pe/utility/BodyCast.h" #include "pe/Materials.h" @@ -15,14 +16,13 @@ #include "core/DataTypes.h" #include "core/math/Vector3.h" -#include <pe/raytracing/Ray.h> -#include <pe/raytracing/Intersects.h> +#include <pe/raytracing/Raytracer.h> using namespace walberla; using namespace walberla::pe; using namespace walberla::pe::raytracing; -typedef boost::tuple<Box, Capsule, Plane, Sphere> BodyTuple ; +typedef boost::tuple<Box, Plane, Sphere> BodyTuple ; void SphereIntersectsTest() { @@ -114,6 +114,56 @@ void BoxIntersectsTest() { WALBERLA_CHECK_FLOAT_EQUAL_EPSILON(t, real_t(2.67157), real_t(1e-4)); } +void RaytracerTest() { + WALBERLA_LOG_INFO("Raytracer"); + shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>(); + shared_ptr<BlockForest> forest = createBlockForest(AABB(0,-5,-5,10,5,5), Vec3(1,1,1), Vec3(false, false, false)); + auto storageID = forest->addBlockData(createStorageDataHandling<BodyTuple>(), "Storage"); + + Raytracer raytracer(forest, storageID, globalBodyStorage, + size_t(640), size_t(480), + 49.13, + Vec3(-5,0,0), Vec3(-1,0,0), Vec3(0,0,1)); + + MaterialID iron = Material::find("iron"); + Plane pl1(1, 1, Vec3(2, 0, 0), Vec3(1, 0, 0), real_t(1.0), iron); + + PlaneID xNegPlane = createPlane(*globalBodyStorage, 0, Vec3(-1,0,0), Vec3(5,0,0), iron); + // xNegPlane obstructs only the top left sphere and intersects some objects + WALBERLA_CHECK(xNegPlane != NULL); + WALBERLA_CHECK(!raytracer.isBodyInvisible(xNegPlane), "Body invisible but should be visible."); + raytracer.setBodyInvisible(xNegPlane); + WALBERLA_CHECK(raytracer.isBodyInvisible(xNegPlane), "Body visible but should be invisible."); + raytracer.setBodyVisible(xNegPlane); + WALBERLA_CHECK(!raytracer.isBodyInvisible(xNegPlane), "Body invisible but should be visible."); + raytracer.setBodyInvisible(xNegPlane); + + PlaneID xNegPlaneClose = createPlane(*globalBodyStorage, 0, Vec3(-1,0,0), Vec3(1,0,0), iron); + raytracer.setBodyInvisible(xNegPlaneClose); // xNegPlaneClose would obstruct all objects + + createPlane(*globalBodyStorage, 0, Vec3(0,1,0), Vec3(0,5,0), iron); // left wall + createPlane(*globalBodyStorage, 0, Vec3(0,1,0), Vec3(0,-5,0), iron); // right wall + createPlane(*globalBodyStorage, 0, Vec3(0,0,1), Vec3(0,0,-5), iron); // floor + createPlane(*globalBodyStorage, 0, Vec3(0,0,1), Vec3(0,0,5), iron); // ceiling + createPlane(*globalBodyStorage, 0, Vec3(1,0,0), Vec3(10,0,0), iron); // back wall + PlaneID frontWall = createPlane(*globalBodyStorage, 0, Vec3(1,0,0), Vec3(0,0,0), iron); // front wall + raytracer.setBodyInvisible(frontWall); + + createSphere(*globalBodyStorage, *forest, storageID, 2, Vec3(6,4.5,4.5), real_t(0.5)); + createSphere(*globalBodyStorage, *forest, storageID, 3, Vec3(3.5,-2,0), real_t(1)); + SphereID sp1 = createSphere(*globalBodyStorage, *forest, storageID, 6, Vec3(3,2,0), real_t(1)); + BoxID box = createBox(*globalBodyStorage, *forest, storageID, 7, Vec3(5,0,0), Vec3(2,4,3)); + box->rotate(0,math::M_PI/4,math::M_PI/4); + createBox(*globalBodyStorage, *forest, storageID, 7, Vec3(5,-4,3), Vec3(2,2,2)); + + raytracer.setBodyInvisible(sp1); + + raytracer.setTBufferOutputDirectory("/Users/ng/Desktop/walberla"); + raytracer.setTBufferOutputEnabled(true); + + raytracer.rayTrace<BodyTuple>(0); +} + int main( int argc, char** argv ) { walberla::debug::enterTestMode(); @@ -121,9 +171,10 @@ int main( int argc, char** argv ) SetBodyTypeIDs<BodyTuple>::execute(); - SphereIntersectsTest(); - PlaneIntersectsTest(); - BoxIntersectsTest(); + //SphereIntersectsTest(); + //PlaneIntersectsTest(); + //BoxIntersectsTest(); + RaytracerTest(); return EXIT_SUCCESS; }