voxelTerrain
 All Classes Functions Variables Typedefs Enumerations Pages
mesh.hpp
1 #ifndef BLUB_PROCEDURAL_VOXEL_EDIT_MESH_HPP
2 #define BLUB_PROCEDURAL_VOXEL_EDIT_MESH_HPP
3 
4 #include "blub/log/global.hpp"
5 #include "blub/core/map.hpp"
6 #include "blub/core/pair.hpp"
7 #include "blub/core/sharedPointer.hpp"
8 #include "blub/core/vector.hpp"
9 #include "blub/math/axisAlignedBox.hpp"
10 #include "blub/math/intersection.hpp"
11 #include "blub/math/plane.hpp"
12 #include "blub/math/ray.hpp"
13 #include "blub/math/transform.hpp"
14 #include "blub/math/triangleVector3.hpp"
15 #include "blub/procedural/voxel/edit/base.hpp"
16 #include "blub/procedural/voxel/tile/container.hpp"
17 
18 #include <utility>
19 
20 #ifdef BLUB_USE_ASSIMP
21 #include <assimp/Importer.hpp>
22 #include <assimp/postprocess.h>
23 #include <assimp/material.h>
24 #include <assimp/mesh.h>
25 #include <assimp/scene.h>
26 #endif
27 
28 #include <boost/geometry.hpp>
29 #include <boost/geometry/geometries/box.hpp>
30 #include <boost/geometry/geometries/point.hpp>
31 #include <boost/geometry/geometries/polygon.hpp>
32 #include <boost/geometry/index/rtree.hpp>
33 
34 
35 namespace blub
36 {
37 namespace procedural
38 {
39 namespace voxel
40 {
41 namespace edit
42 {
43 
44 
49 template <class voxelType>
50 class mesh : public base<voxelType>
51 {
52 public:
53  typedef sharedPointer<mesh<voxelType> > pointer;
54 
55  typedef base<voxelType> t_base;
56 
57  typedef tile::container<voxelType> t_tileContainer;
58 
59  typedef boost::geometry::model::point<real, 3, boost::geometry::cs::cartesian> t_point;
60  typedef boost::geometry::model::box<t_point> t_box;
61  typedef boost::geometry::model::segment<t_point> t_segment;
62  typedef std::pair<t_box, triangleVector3> t_value;
63  typedef boost::geometry::index::rtree<t_value, boost::geometry::index::quadratic<16> > t_tree;
64 
69  static pointer create()
70  {
71  return pointer(new mesh());
72  }
76  virtual ~mesh()
77  {
78  for (t_trees::const_iterator it = m_trees.cbegin(); it != m_trees.cend(); ++it)
79  {
80  delete (*it);
81  }
82  }
83 
84 #ifdef BLUB_USE_ASSIMP
85 
90  bool load(const blub::string &path, const blub::transform &trans)
91  {
92  Assimp::Importer* importer(new Assimp::Importer());
93 
94  const aiScene *scene = importer->ReadFile(path.c_str(), aiProcess_Triangulate);
95  if (scene == nullptr)
96  {
97  BLUB_PROCEDURAL_LOG_ERROR() << "scene == nullptr loader->GetErrorString():" << importer->GetErrorString();
98  delete importer;
99  return false;
100  }
101 
102  bool result(loadScene(*scene, trans));
103 
104  delete importer;
105 
106  return result;
107  }
108 
114  virtual bool loadScene(const aiScene &scene, const blub::transform &trans)
115  {
116  if (!scene.HasMeshes())
117  {
118  BLUB_PROCEDURAL_LOG_ERROR() << "!scene.HasMeshes()";
119  return false;
120  }
121 
122 #ifdef BLUB_LOG_PROCEDURAL_VOXEL_EDIT_MESH
123  BLUB_LOG_OUT() << "scene.mNumMeshes:" << scene.mNumMeshes << " scene.mRootNode->mNumChildren:" << scene.mRootNode->mNumChildren;
124 #endif
125 
126  for(uint32 indMesh = 0; indMesh < scene.mNumMeshes; ++indMesh)
127  {
128  aiMesh *mesh(scene.mMeshes[indMesh]);
129  loadMesh(*mesh, trans); // ignore result
130  }
131  return true;
132  }
133 
139  virtual bool loadMesh(const aiMesh &mesh, const blub::transform &trans)
140  {
141  typedef vector<vector3> t_positions;
142 
143 #ifdef BLUB_LOG_PROCEDURAL_VOXEL_EDIT_MESH
144  BLUB_PROCEDURAL_LOG_OUT() << "mesh.mName:" << blub::string(mesh.mName.C_Str(), mesh.mName.length);
145 #endif
146  if (!mesh.HasFaces())
147  {
148  BLUB_PROCEDURAL_LOG_ERROR() << "!scene.mMeshes[indMesh]->HasFaces()";
149  return false;
150  }
151  if (!mesh.HasPositions())
152  {
153  BLUB_PROCEDURAL_LOG_ERROR() << "!mesh.HasPositions()";
154  return false;
155  }
156 
157  t_tree *tree = new t_tree();
158  m_trees.push_back(tree);
159 
160  t_positions positions;
161  positions.resize(mesh.mNumVertices);
162  for (blub::uint32 indVertex = 0; indVertex < mesh.mNumVertices; ++indVertex)
163  {
164  const aiVector3D &posToCast(mesh.mVertices[indVertex]);
165  vector3 casted(posToCast.x, posToCast.y, posToCast.z);
166  casted *= trans.scale;
167  positions[indVertex] = casted;
168  m_aabb.merge(casted);
169  }
170  for (blub::uint32 indFace = 0; indFace < mesh.mNumFaces; ++indFace)
171  {
172  const aiFace &faceToCast(mesh.mFaces[indFace]);
173  BASSERT(faceToCast.mNumIndices == 3);
174  if (faceToCast.mNumIndices != 3)
175  {
176  BLUB_PROCEDURAL_LOG_WARNING() << "faceToCast.mNumIndices != 3";
177  continue;
178  }
179  const triangleVector3 resultTriangle( positions[faceToCast.mIndices[0]],
180  positions[faceToCast.mIndices[1]],
181  positions[faceToCast.mIndices[2]]);
182 
183  const blub::axisAlignedBox &aabb(resultTriangle.getAxisAlignedBoundingBox());
184  const blub::vector3 &aabbMin(aabb.getMinimum());
185  const blub::vector3 &aabbMax(aabb.getMaximum());
186  t_box toInsert(t_point(aabbMin.x, aabbMin.y, aabbMin.z), t_point(aabbMax.x, aabbMax.y, aabbMax.z));
187  tree->insert(std::make_pair(toInsert, resultTriangle));
188  }
189 
190  return !tree->empty();
191  }
192 #endif
193 
194 protected:
199  {
200 
201  }
202 
209  {
210  BLUB_LOG_OUT() << "trans:" << trans;
211 
212  return blub::axisAlignedBox(m_aabb.getMinimum()*trans.scale + trans.position,
213  m_aabb.getMaximum()*trans.scale + trans.position);
214  }
215 
222  void calculateVoxel(t_tileContainer *voxelContainer, const vector3int32 &voxelContainerOffset, const transform &/*trans*/) const
223  {
224  const vector3int32 posContainerAbsolut(voxelContainerOffset*t_tileContainer::voxelLength);
225 
226  vector3int32 toLoop[] = {{1, t_tileContainer::voxelLength, t_tileContainer::voxelLength},
227  {t_tileContainer::voxelLength, 1, t_tileContainer::voxelLength},
228  {t_tileContainer::voxelLength, t_tileContainer::voxelLength, 1}
229  };
230  vector3 rayDir[] = {{1., 0., 0.},
231  {0., 1., 0.},
232  {0., 0., 1.}};
233  for (uint32 indMesh = 0; indMesh < m_trees.size(); ++indMesh)
234  {
235  t_tree *tree(static_cast<t_tree*>(m_trees[indMesh]));
236  for (int32 indAxis = 0; indAxis < 3; ++indAxis)
237  {
238  for (int32 indX = 0; indX < toLoop[indAxis].x; ++indX)
239  {
240  for (int32 indY = 0; indY < toLoop[indAxis].y; ++indY)
241  {
242  for (int32 indZ = 0; indZ < toLoop[indAxis].z; ++indZ)
243  {
244  const vector3int32 posVoxel(indX, indY, indZ);
245  vector3 posAbsolut(posContainerAbsolut + posVoxel);
246 
247  // posAbsolut = posAbsolut / trans.scale;
248  // posAbsolut -= trans.position;
249 
250  const ray test(posAbsolut, rayDir[indAxis]);
251 
252  const vector3 segmentStart (posAbsolut+rayDir[indAxis]*(-10000.)); // TODO: fix me after ray support for boost::geometry is of their todolist
253  const vector3 segmentEnd (posAbsolut+rayDir[indAxis]*(+10000.));
254 
255  t_segment segment(t_point(segmentStart.x, segmentStart.y, segmentStart.z), t_point(segmentEnd.x, segmentEnd.y, segmentEnd.z));
256  typedef std::vector<t_value> t_resultTriangles;
257  t_resultTriangles resultTriangles;
258  tree->query(boost::geometry::index::intersects(segment), std::back_inserter(resultTriangles));
259 
260  typedef pair<real, blub::plane> t_cutPoint;
261  typedef vector<t_cutPoint> t_cutPoints;
262  t_cutPoints cutPoints;
263  vector3 cutPoint;
264  for (t_resultTriangles::const_iterator it = resultTriangles.cbegin(); it != resultTriangles.cend(); ++it)
265  {
266  const triangleVector3 &triangleWork(it->second);
267  if (intersection::intersect(test, triangleWork, &cutPoint))
268  {
269  bool insert(true);
270 // if (!cutPoints.empty())
271 // {
272 // const plane planeTriBefore(cutPoints.at(cutPoints.size()-1).second);
273 // if (/*math::abs*/(planeTriBefore.normal.dotProduct(triangleWork.getPlane().normal)) < 0.)
274 // {
275 // insert = false;
276 // }
277 // }
278  if (insert)
279  {
280  real cutPointStart = cutPoint[indAxis] - static_cast<real>(posContainerAbsolut[indAxis]);
281  cutPoints.push_back(t_cutPoint(cutPointStart, triangleWork.getPlane()));
282  }
283  }
284  }
285  if(cutPoints.size() < 2)
286  {
287  continue;
288  }
289 
290  typedef vector<t_cutPoint> t_cutPointsFiltered;
291  t_cutPointsFiltered cutPointsFiltered;
292  for (t_cutPoints::const_iterator it = cutPoints.cbegin(); it != cutPoints.cend(); ++it)
293  {
294  if (cutPointsFiltered.empty())
295  {
296  cutPointsFiltered.push_back(*it);
297  continue;
298  }
299  if (math::abs(cutPointsFiltered.back().first - it->first) < 1e-4f)
300  {
301  continue;
302  }
303  cutPointsFiltered.push_back(*it);
304  }
305 
306  if(cutPointsFiltered.size()%2 != 0 && cutPointsFiltered.size() > 0)
307  {
308  BLUB_PROCEDURAL_LOG_WARNING() << "cutPointsFiltered.size()%2 != 0 cutPointsFiltered.size():" << cutPointsFiltered.size();
309  cutPointsFiltered.pop_back();
310  }
311  for (t_cutPointsFiltered::const_iterator it = cutPointsFiltered.cbegin(); it != cutPointsFiltered.cend(); ++it)
312  {
313  real cutPointsSorted[2];
314  blub::plane cutPlanes[2];
315  cutPointsSorted[0] = it->first;
316  cutPlanes[0] = it->second;
317  ++it;
318  BASSERT(it != cutPointsFiltered.cend());
319  cutPointsSorted[1] = it->first;
320  cutPlanes[1] = it->second;
321 
322  const real length(cutPointsSorted[1]-cutPointsSorted[0]);
323  if (length < 1.)
324  {
325 #ifdef BLUB_LOG_PROCEDURAL_VOXEL_EDIT_MESH
326 // blub::BOUT("length < 1.");
327 #endif
328 // continue;
329  }
330  //BLUB_LOG_OUT() << "creating line length:" << length;
331  switch (indAxis)
332  {
333  case 0:
334  t_base::createLine(voxelContainer, posVoxel, cutPointsSorted[0], length, t_base::axis::x, cutPlanes[0], cutPlanes[1]);
335  break;
336  case 1:
337  t_base::createLine(voxelContainer, posVoxel, cutPointsSorted[0], length, t_base::axis::y, cutPlanes[0], cutPlanes[1]);
338  break;
339  case 2:
340  t_base::createLine(voxelContainer, posVoxel, cutPointsSorted[0], length, t_base::axis::z, cutPlanes[0], cutPlanes[1]);
341  break;
342  default:
343  BASSERT(false);
344  break;
345  }
346  }
347  }
348  }
349  }
350  }
351  }
352  }
353 
354 protected:
355  typedef vector<t_tree*> t_trees;
356  t_trees m_trees;
357 
358  blub::axisAlignedBox m_aabb;
359 
360 };
361 
362 
363 }
364 }
365 }
366 }
367 
368 
369 #endif // BLUB_PROCEDURAL_VOXEL_EDIT_MESH_HPP
virtual void createLine(t_voxelContainerTile *voxelContainer, const vector3int32 &posVoxel, const real &from, const real &len, const axis &ax, const blub::plane &planeA, const blub::plane &planeB) const
createLine creates a voxel-line on one axis with a specific length
Definition: base.hpp:198
Definition: vector.hpp:19
Definition: triangleVector3.hpp:10
blub::axisAlignedBox getAxisAlignedBoundingBox(const transform &trans) const override
getAxisAlignedBoundingBox returns the transformed bounding box that includes the mesh.
Definition: mesh.hpp:208
Definition: transform.hpp:20
virtual ~mesh()
~mesh destructor
Definition: mesh.hpp:76
void merge(const axisAlignedBox &rhs)
Definition: axisAlignedBox.hpp:284
mesh()
mesh contructor
Definition: mesh.hpp:198
Definition: pair.hpp:9
Definition: string.hpp:22
Definition: ray.hpp:16
static pointer create()
creates an instance of the class.
Definition: mesh.hpp:69
Definition: vector3.hpp:26
Definition: axisAlignedBox.hpp:20
Definition: plane.hpp:16
const vector3 & getMinimum(void) const
Definition: axisAlignedBox.hpp:126
const vector3 & getMaximum(void) const
Definition: axisAlignedBox.hpp:141
Definition: deadlineTimer.hpp:10
void calculateVoxel(t_tileContainer *voxelContainer, const vector3int32 &voxelContainerOffset, const transform &) const
calculateVoxel The tree, which got generated in load() gets intersected for every voxel line...
Definition: mesh.hpp:222