Raytracer.h 12.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//======================================================================================================================
//
//  This file is part of waLBerla. waLBerla is free software: you can
//  redistribute it and/or modify it under the terms of the GNU General Public
//  License as published by the Free Software Foundation, either version 3 of
//  the License, or (at your option) any later version.
//
//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
//  for more details.
//
//  You should have received a copy of the GNU General Public License along
//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
//
//! \file Raytracer.h
//! \author Lukas Werner
//
//======================================================================================================================

#pragma once

#include <pe/basic.h>
#include <pe/Types.h>
#include <core/math/Vector3.h>
#include <core/mpi/all.h>
27
28
29
#include <core/config/Config.h>
#include "Ray.h"
#include "Intersects.h"
30
31
32
33
34

namespace walberla {
namespace pe {
namespace raytracing {

Lukas Werner's avatar
Lukas Werner committed
35
36
/*!\brief Contains information about a ray-body intersection.
 */
37
struct BodyIntersectionInfo {
Lukas Werner's avatar
Lukas Werner committed
38
39
40
41
   size_t imageX;                //!< viewing plane x pixel coordinate the ray belongs to.
   size_t imageY;                //!< viewing plane y pixel coordinate the ray belongs to.
   walberla::id_t bodySystemID;  //!< system ID of body which was hit.
   real_t t;                     //!< distance from camera to intersection point on body.
42
43
};

Lukas Werner's avatar
Lukas Werner committed
44
45
/*!\brief Simple struct for coordinates.
 */
46
47
48
49
50
struct Coordinates {
   size_t x;
   size_t y;
};

Lukas Werner's avatar
Lukas Werner committed
51
52
/*!\brief Comparator for Coordinates struct with standard lexicographical ordering.
 */
53
54
55
56
57
58
struct CoordinatesComparator {
   bool operator() (const Coordinates& lhs, const Coordinates& rhs) const {
      return (lhs.x < rhs.x) || (lhs.x == rhs.x && lhs.y < rhs.y);
   }
};

59
60
61
62
class Raytracer {
public:
   /*!\name Constructors */
   //@{
63
   explicit Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID,
64
                      size_t pixelsHorizontal, size_t pixelsVertical,
65
66
                      real_t fov_vertical,
                      const Vec3& cameraPosition, const Vec3& lookAtPoint, const Vec3& upVector);
67
   explicit Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID,
68
                      const Config::BlockHandle& config);
69
70
71
72
73
   //@}

private:
   /*!\name Member variables */
   //@{
74
   const shared_ptr<BlockStorage> forest_; //!< The BlockForest the raytracer operates on.
75
76
   BlockDataID storageID_;    /*!< The storage ID of the block data storage the raytracer operates
                               on.*/
77
78
   size_t pixelsHorizontal_;  //!< The horizontal amount of pixels of the generated image.
   size_t pixelsVertical_;    //!< The vertical amount of pixels of the generated image.
79
80
81
82
83
   real_t fov_vertical_;      //!< The vertical field-of-view of the camera.
   Vec3 cameraPosition_;      //!< The position of the camera in the global world frame.
   Vec3 lookAtPoint_;         /*!< The point the camera looks at in the global world frame,
                               marks the center of the view plane.*/
   Vec3 upVector_;            //!< The vector indicating the upwards direction of the camera.
84
85
   bool tBufferOutputEnabled_; //!< Enable / disable dumping the tbuffer to a file
   std::string tBufferOutputDirectory_; //!< Path to the tbuffer output directory
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
   //@}
   
   Vec3 n; // normal vector of viewing plane
   Vec3 u; // u and ...
   Vec3 v; // ... v span the viewing plane
   real_t d; // distance from camera to viewing plane
   real_t aspectRatio; // aspect ratio of the generated image and viewing plane
   real_t viewingPlaneHeight; // viewing plane height
   real_t viewingPlaneWidth; // viewing plane width
   Vec3 viewingPlaneOrigin; // origin of the viewing plane
   real_t pixelWidth; // width of a pixel of the generated image in the viewing plane
   real_t pixelHeight; // height of a pixel of the generated image in the viewing plane

public:
   /*!\name Get functions */
   //@{
102
103
104
105
106
107
108
109
110
111
112
113
114
115
   inline size_t getPixelsHorizontal() const;
   inline size_t getPixelsVertical() const;
   inline real_t getFOVVertical() const;
   inline const Vec3& getCameraPosition() const;
   inline const Vec3& getLookAtPoint() const;
   inline const Vec3& getUpVector() const;
   inline const bool getTBufferOutputEnabled() const;
   inline const std::string& getTBufferOutputDirectory() const;
   //@}

   /*!\name Set functions */
   //@{
   inline void setTBufferOutputEnabled(const bool enabled);
   inline void setTBufferOutputDirectory(const std::string& path);
116
117
118
119
   //@}
   
   /*!\name Functions */
   //@{
120
   void setupView_();
121
   template <typename BodyTypeTuple>
122
123
124
125
126
   void rayTrace(const size_t timestep) const;
   
private:
   void writeTBufferToFile(const std::map<Coordinates, real_t, CoordinatesComparator>& tBuffer) const;
   void writeTBufferToFile(const std::map<Coordinates, real_t, CoordinatesComparator>& tBuffer, const std::string& fileName) const;
127
128
129
130
131
132
133
   //@}
};
   
/*!\brief Returns the horizontal amount of pixels of the generated image.
 *
 * \return The horizontal amount of pixels of the generated image.
 */
134
inline size_t Raytracer::getPixelsHorizontal() const {
135
136
137
138
139
140
141
   return pixelsHorizontal_;
}

/*!\brief Returns the vertical amount of pixels of the generated image.
 *
 * \return The vertical amount of pixels of the generated image.
 */
142
inline size_t Raytracer::getPixelsVertical() const {
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
   return pixelsVertical_;
}

/*!\brief Returns the vertical field-of-view of the camera.
 *
 * \return The vertical field-of-view of the camera.
 */
inline real_t Raytracer::getFOVVertical() const {
   return fov_vertical_;
}

/*!\brief Returns the position of the camera in the global world frame.
 *
 * \return The position of the camera.
 *
 * Returns the position of the camera in the global world frame.
 */
inline const Vec3& Raytracer::getCameraPosition() const {
   return cameraPosition_;
}

/*!\brief Returns the point the camera looks at in the global world frame.
 *
 * \return The looked at point.
 *
 * Returns the point the camera looks at in the global world frame, which also marks the center of
 * the view plane.
 */
inline const Vec3& Raytracer::getLookAtPoint() const {
   return lookAtPoint_;
}

/*!\brief Returns the vector indicating the upwards direction of the camera.
 *
 * \return The upwards vector of the camera.
 *
 * Returns the vector indicating the upwards direction of the camera.
 */
inline const Vec3& Raytracer::getUpVector() const {
   return upVector_;
}
184
   
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/*!\brief Returns true if tbuffer output to a file is enabled.
 *
 * \return True if tbuffer output enabled, otherwise false.
 */
inline const bool Raytracer::getTBufferOutputEnabled() const {
   return tBufferOutputEnabled_;
}

/*!\brief Returns the directory where the tbuffer output file will be saved in.
 *
 * \return Path to the tbuffer output directory.
 */
inline const std::string& Raytracer::getTBufferOutputDirectory() const {
   return tBufferOutputDirectory_;
}
   
/*!\brief Enabled / disable outputting the tBuffer to a file in the specified directory.
 * \param enabled Set to true / false to enable / disable tbuffer output.
 */
inline void Raytracer::setTBufferOutputEnabled(const bool enabled) {
   tBufferOutputEnabled_ = enabled;
}

/*!\brief Enabled / disable outputting the tBuffer to a file in the specified directory.
 * \param enabled Set to true / false to enable / disable tbuffer output.
 */
inline void Raytracer::setTBufferOutputDirectory(const std::string& path) {
   tBufferOutputDirectory_ = path;
}
   
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
/*!\brief Does one raytracing step.
 *
 * \param timestep The timestep after which the raytracing starts.
 */
template <typename BodyTypeTuple>
void Raytracer::rayTrace(const size_t timestep) const {
   std::map<Coordinates, real_t, CoordinatesComparator> tBuffer; // t values for each pixel
   std::map<Coordinates, walberla::id_t, CoordinatesComparator> idBuffer; // ids of the intersected body for each pixel
   std::vector<BodyIntersectionInfo> intersections; // contains for each pixel information about an intersection, if existent
   
   std::map<Coordinates, BodyIntersectionInfo, CoordinatesComparator> localPixelIntersectionMap;
   
   real_t t, t_closest;
   walberla::id_t id_closest;
   RigidBody* body_closest = NULL;
   Ray ray(cameraPosition_, Vec3(1,0,0));
   IntersectsFunctor func(ray, t);
   for (size_t x = 0; x < pixelsHorizontal_; x++) {
      for (size_t y = 0; y < pixelsVertical_; y++) {
         //WALBERLA_LOG_INFO(x << "/" << y);
         Vec3 pixelLocation = viewingPlaneOrigin + u*(real_c(x)+real_t(0.5))*pixelWidth + v*(real_c(y)+real_t(0.5))*pixelHeight;
         Vec3 direction = (pixelLocation - cameraPosition_).getNormalized();
         ray.setDirection(direction);
         
         t_closest = INFINITY;
         id_closest = 0;
         body_closest = NULL;
         for (auto blockIt = forest_->begin(); blockIt != forest_->end(); ++blockIt) {
            // blockIt->getAABB();
            /*const AABB& blockAabb = blockIt->getAABB();
             if (!intersects(blockAabb, ray, t)) {
             continue;
             }*/
            for (auto bodyIt = LocalBodyIterator::begin(*blockIt, storageID_); bodyIt != LocalBodyIterator::end(); ++bodyIt) {
               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;
               }
            }
         }
         
         //std::cout << (t_closest != INFINITY ? size_t(t_closest) : 0) << " ";
         
         Coordinates c = {
            x,
            y
         };
         
         if (!realIsIdentical(t_closest, INFINITY) && body_closest != NULL) {
            BodyIntersectionInfo intersectionInfo = {
               x,
               y,
               body_closest->getSystemID(),
               t_closest
            };
            intersections.push_back(intersectionInfo);
            localPixelIntersectionMap[c] = intersectionInfo;
         }
         
         tBuffer[c] = t_closest;
         idBuffer[c] = id_closest;
      }
      //std::cout << std::endl;
   }
   
   // intersections synchronisieren
   mpi::SendBuffer sendBuffer;
   for (auto& info: intersections) {
      sendBuffer << info.imageX << info.imageY << info.bodySystemID << info.t;
   }
   
   std::vector<BodyIntersectionInfo> gatheredIntersections;
   
   std::map<walberla::id_t, bool> visibleBodyIDs;
   
   //std::map<Coordinates, BodyIntersectionInfo, CoordinatesComparator> pixelIntersectionMap;
   
   mpi::RecvBuffer recvBuffer;
   mpi::allGathervBuffer(sendBuffer, recvBuffer);
   while (!recvBuffer.isEmpty()) {
      BodyIntersectionInfo info;
      
      recvBuffer >> info.imageX;
      recvBuffer >> info.imageY;
      recvBuffer >> info.bodySystemID;
      recvBuffer >> info.t;
      
      Coordinates c = {
         info.imageX,
         info.imageY
      };
      
      /*if (pixelIntersectionMap.find(c) == pixelIntersectionMap.end()) {
       // map didnt contain coordinates
       pixelIntersectionMap.insert(std::make_pair(c, info));
       } else {
       // map already contains info at coordinates, check if current info is closer
       BodyIntersectionInfo& existingInfo = pixelIntersectionMap.at(c);
       if (existingInfo.t < info.t) {
       pixelIntersectionMap[c] = info;
       }
       }*/
      auto it = localPixelIntersectionMap.find(c);
      if (it != localPixelIntersectionMap.end()) {
         // there was a local hit at coordinate c
         BodyIntersectionInfo& localInfo = localPixelIntersectionMap.at(c);
         if (localInfo.t < info.t) {
            localPixelIntersectionMap.erase(it);
         }
      }
      
      //gatheredIntersections.push_back(info);
   }
   
   for (auto& info: localPixelIntersectionMap) {
      visibleBodyIDs[info.second.bodySystemID] = true;
   }
   
   WALBERLA_LOG_INFO("#particles visible: " << visibleBodyIDs.size());
   //WALBERLA_LOG_INFO_ON_ROOT("#gatheredIntersections: " << gatheredIntersections.size());
   
340
341
342
   if (getTBufferOutputEnabled()) {
      writeTBufferToFile(tBuffer);
   }
343
344
}

345
346
347
}
}
}