Loading [MathJax]/jax/output/HTML-CSS/config.js
Radium Engine  1.5.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
MeshPrimitives.hpp
1 #pragma once
2 
3 #include <Core/Geometry/TopologicalMesh.hpp>
4 #include <Core/Geometry/TriangleMesh.hpp>
5 #include <Core/Math/LinearAlgebra.hpp>
6 #include <Core/RaCore.hpp>
7 #include <Core/Utils/Color.hpp>
8 #include <Core/Utils/StdOptional.hpp>
9 
10 #include <random>
11 
12 namespace Ra {
13 namespace Core {
14 namespace Geometry {
15 //
16 // Primitive construction
17 //
18 
27 RA_CORE_API TriangleMesh makePlaneGrid( const uint rows = 1,
28  const uint cols = 1,
29  const Vector2& halfExts = Vector2( .5_ra, .5_ra ),
30  const Transform& T = Transform::Identity(),
31  const Utils::optional<Utils::Color>& color = {},
32  bool generateTexCoord = false );
33 
36 RA_CORE_API TriangleMesh makeXNormalQuad( const Vector2& halfExts = Vector2( .5_ra, .5_ra ),
37  const Utils::optional<Utils::Color>& color = {},
38  bool generateTexCoord = false );
39 
42 RA_CORE_API TriangleMesh makeYNormalQuad( const Vector2& halfExts = Vector2( .5_ra, .5_ra ),
43  const Utils::optional<Utils::Color>& color = {},
44  bool generateTexCoord = false );
45 
48 RA_CORE_API TriangleMesh makeZNormalQuad( const Vector2& halfExts = Vector2( .5_ra, .5_ra ),
49  const Utils::optional<Utils::Color>& color = {},
50  bool generateTexCoord = false );
51 
53 RA_CORE_API TriangleMesh makeBox( const Vector3& halfExts = Vector3( .5_ra, .5_ra, .5_ra ),
54  const Utils::optional<Utils::Color>& color = {} );
55 
57 RA_CORE_API TriangleMesh makeBox( const Aabb& aabb,
58  const Utils::optional<Utils::Color>& color = {} );
59 
61 RA_CORE_API TriangleMesh makeSharpBox( const Vector3& halfExts = Vector3( .5_ra, .5_ra, .5_ra ),
62  const Utils::optional<Utils::Color>& color = {},
63  bool generateTexCoord = false );
64 
66 RA_CORE_API TriangleMesh makeSharpBox( const Aabb& aabb,
67  const Utils::optional<Utils::Color>& color = {},
68  bool generateTexCoord = false );
69 
72 template <uint U = 16, uint V = U>
73 TriangleMesh makeParametricSphere( Scalar radius = 1_ra,
74  const Utils::optional<Utils::Color>& color = {},
75  bool generateTexCoord = false );
76 
81 template <uint U = 16, uint V = U>
82 TriangleMesh makeParametricTorus( Scalar majorRadius,
83  Scalar minorRadius,
84  const Utils::optional<Utils::Color>& color = {},
85  bool generateTexCoord = false );
86 
88 RA_CORE_API TriangleMesh makeGeodesicSphere( Scalar radius = 1_ra,
89  uint numSubdiv = 3,
90  const Utils::optional<Utils::Color>& color = {} );
91 
96 RA_CORE_API TriangleMesh makeCylinder( const Vector3& a,
97  const Vector3& b,
98  Scalar radius,
99  uint sideSegments = 32,
100  uint fillSegments = 2,
101  const Utils::optional<Utils::Color>& color = {} );
102 
106 RA_CORE_API TriangleMesh makeCapsule( Scalar length,
107  Scalar radius,
108  uint nFaces = 32,
109  const Utils::optional<Utils::Color>& color = {} );
110 
113 RA_CORE_API TriangleMesh makeTube( const Vector3& a,
114  const Vector3& b,
115  Scalar outerRadius,
116  Scalar InnerRadius,
117  uint nFaces = 32,
118  const Utils::optional<Utils::Color>& color = {} );
119 
122 RA_CORE_API TriangleMesh makeCone( const Vector3& base,
123  const Vector3& tip,
124  Scalar radius,
125  uint nFaces = 32,
126  const Utils::optional<Utils::Color>& color = {} );
127 
128 template <uint SLICES, uint STACKS>
129 TriangleMesh
130 makeParametricSphere( Scalar radius, const Utils::optional<Utils::Color>& color, bool gtc ) {
131 
132  const Scalar du = 1_ra / SLICES;
133  const Scalar dv = 1_ra / STACKS;
134  using WAI = TopologicalMesh::WedgeAttribIndex;
135  TopologicalMesh topoMesh;
136  auto whNormal = topoMesh.addWedgeAttrib<Vector3>( getAttribName( MeshAttrib::VERTEX_NORMAL ) );
137 
138  WAI whColor =
139  color ? topoMesh.addWedgeAttrib<Vector4>( getAttribName( MeshAttrib::VERTEX_COLOR ) )
140  : WAI::Invalid();
141  WAI whTexCoord =
142  gtc ? topoMesh.addWedgeAttrib<Vector3>( getAttribName( MeshAttrib::VERTEX_TEXCOORD ) )
143  : WAI::Invalid();
144 
145  TopologicalMesh::VertexHandle vhandles[( STACKS - 1 ) * SLICES + 2];
146  Vector3Array topoTexCoords;
147  topoTexCoords.reserve( ( STACKS - 1 ) * SLICES + 2 + 2 * SLICES );
148  Vector3Array topoNormals;
149  topoNormals.reserve( ( STACKS - 1 ) * SLICES + 2 );
150 
151  uint index = 0;
152  // check https://en.wikipedia.org/wiki/Spherical_coordinate_system
153  // theta \in [0, pi]
154  // phi \in [0, 2pi]
155  const Scalar uFactor = 2_ra / Scalar { SLICES } * Core::Math::Pi;
156  const Scalar vFactor = Core::Math::Pi / STACKS;
157  for ( uint u = 0; u < SLICES; ++u ) {
158  const Scalar phi = u * uFactor;
159  for ( uint v = 1; v < STACKS; ++v ) {
160  // Regular vertices on the sphere.
161  const Scalar theta = v * vFactor;
162  Vector3 p = Vector3( radius * std::cos( phi ) * std::sin( theta ),
163  radius * std::sin( phi ) * std::sin( theta ),
164  radius * std::cos( theta ) );
165  vhandles[index++] = topoMesh.add_vertex( p );
166  topoNormals.push_back( p.normalized() );
167  topoTexCoords.emplace_back( 1_ra - u * du, v * dv, 0_ra );
168  }
169  }
170 
171  // Add the pole vertices.
172  auto topoNorthPoleIdx = ( STACKS - 1 ) * SLICES;
173  auto topoSouthPoleIdx = topoNorthPoleIdx + 1;
174  vhandles[topoNorthPoleIdx] = topoMesh.add_vertex( Vector3( 0, 0, radius ) );
175  vhandles[topoSouthPoleIdx] = topoMesh.add_vertex( Vector3( 0, 0, -radius ) );
176 
177  // Set wedge for fh, vhIndex to n and t.
178  auto wedgeSetter = [&topoMesh, &vhandles, color, whNormal, whTexCoord, whColor, gtc](
179  int vhIndex, TopologicalMesh::FaceHandle fh, Vector3 n, Vector3 t ) {
180  auto heh = topoMesh.halfedge_handle( vhandles[vhIndex], fh );
181  auto wd = topoMesh.newWedgeData( heh );
182  wd.m_vector3Attrib[whNormal] = n;
183  if ( gtc ) wd.m_vector3Attrib[whTexCoord] = t;
184  if ( color ) wd.m_vector4Attrib[whColor] = *color;
185  topoMesh.replaceWedge( heh, wd );
186  };
187 
188  // For general vertices retrieve normals and texCoords from vhIndex
189  auto wedgeSetterGeneric = [wedgeSetter, &topoNormals, &topoTexCoords, whNormal, whTexCoord](
190  int vhIndex, TopologicalMesh::FaceHandle fh ) {
191  wedgeSetter( vhIndex, fh, topoNormals[vhIndex], topoTexCoords[vhIndex] );
192  };
193 
194  // take seams into account when u =1
195  auto wedgeSetterSeam = [wedgeSetter, &topoTexCoords, &topoNormals, whNormal, whTexCoord](
196  int u, int vhIndex, TopologicalMesh::FaceHandle fh ) {
197  Vector3 t = topoTexCoords[vhIndex];
198  if ( u == SLICES - 1 ) t[0] = 0_ra;
199  wedgeSetter( vhIndex, fh, topoNormals[vhIndex], t );
200  };
201 
202  // special for poles
203  auto wedgeSetterPole =
204  [wedgeSetter, &topoTexCoords, whNormal, whTexCoord]( bool north,
205  int id,
206  int baseSlice,
207  int nextSlice,
208  int u,
209  TopologicalMesh::FaceHandle fh ) {
210  // pole vertex use "midpoint" texCoord
211  Scalar bu = topoTexCoords[baseSlice][0];
212  Scalar nu = ( u == SLICES - 1 ) ? 0_ra : topoTexCoords[nextSlice][0];
213  Scalar tu = ( bu + nu ) * .5_ra;
214  wedgeSetter( id, fh, Vector3( 0, 0, north ? 1 : -1 ), Vector3( tu, north ? 0 : 1, 0 ) );
215  };
216 
217  for ( uint u = 0; u < SLICES; ++u ) {
218  for ( uint v = 2; v < STACKS; ++v ) {
219  const uint nextSlice = ( ( u + 1 ) % SLICES ) * ( STACKS - 1 );
220  const uint baseSlice = u * ( STACKS - 1 );
221  std::vector vindices = { baseSlice + v - 2,
222  baseSlice + v - 1,
223  nextSlice + v - 1,
224  baseSlice + v - 2,
225  nextSlice + v - 1,
226  nextSlice + v - 2 };
227 
228  auto fh1 = topoMesh.add_face(
229  { vhandles[vindices[0]], vhandles[vindices[1]], vhandles[vindices[2]] } );
230  auto fh2 = topoMesh.add_face(
231  { vhandles[vindices[3]], vhandles[vindices[4]], vhandles[vindices[5]] } );
232 
233  wedgeSetterGeneric( baseSlice + v - 2, fh1 );
234  wedgeSetterGeneric( baseSlice + v - 1, fh1 );
235  wedgeSetterGeneric( baseSlice + v - 2, fh2 );
236 
237  wedgeSetterSeam( u, nextSlice + v - 1, fh1 );
238  wedgeSetterSeam( u, nextSlice + v - 1, fh2 );
239  wedgeSetterSeam( u, nextSlice + v - 2, fh2 );
240  }
241  }
242  // caps faces
243  for ( uint u = 0; u < SLICES; ++u ) {
244  const uint nextSlice = ( ( u + 1 ) % SLICES ) * ( STACKS - 1 );
245  const uint baseSlice = u * ( STACKS - 1 );
246 
247  auto fh1 = topoMesh.add_face(
248  { vhandles[topoNorthPoleIdx], vhandles[baseSlice], vhandles[nextSlice] } );
249  auto fh2 = topoMesh.add_face( { vhandles[topoSouthPoleIdx],
250  vhandles[nextSlice + STACKS - 2],
251  vhandles[baseSlice + STACKS - 2] } );
252 
253  wedgeSetterGeneric( baseSlice, fh1 );
254  wedgeSetterGeneric( baseSlice + STACKS - 2, fh2 );
255  wedgeSetterSeam( u, nextSlice, fh1 );
256  wedgeSetterSeam( u, nextSlice + STACKS - 2, fh2 );
257 
258  // pole vertex use "midpoint" texCoord
259  wedgeSetterPole( true, topoNorthPoleIdx, baseSlice, nextSlice, u, fh1 );
260  wedgeSetterPole( false, topoSouthPoleIdx, baseSlice, nextSlice, u, fh2 );
261  }
262 
263  topoMesh.mergeEqualWedges();
264  topoMesh.garbage_collection();
265  TriangleMesh result = topoMesh.toTriangleMesh();
266  result.checkConsistency();
267  return result;
268 }
269 
270 template <uint U, uint V>
271 TriangleMesh makeParametricTorus( Scalar majorRadius,
272  Scalar minorRadius,
273  const Utils::optional<Utils::Color>& color,
274  bool generateTexCoord ) {
275  TriangleMesh result;
276  TriangleMesh::PointAttribHandle::Container vertices;
277  TriangleMesh::NormalAttribHandle::Container normals;
278  TriangleMesh::IndexContainerType indices;
279  Ra::Core::Vector3Array texCoords;
280 
281  vertices.reserve( ( U + 1 ) * ( V + 1 ) );
282  normals.reserve( ( U + 1 ) * ( V + 1 ) );
283  indices.reserve( 2 * U * V );
284  texCoords.reserve( ( U + 1 ) * ( V + 1 ) );
285 
286  const Scalar du = 1_ra / U;
287  const Scalar dv = 1_ra / V;
288 
289  for ( uint iu = 0; iu <= U; ++iu ) {
290  Scalar u = Scalar( iu ) * Core::Math::PiMul2 / Scalar( U );
291  Core::Vector3 circleCenter( majorRadius * std::cos( u ), majorRadius * std::sin( u ), 0.f );
292 
293  for ( uint iv = 0; iv <= V; ++iv ) {
294  Scalar v = Scalar( iv ) * Core::Math::PiMul2 / Scalar( V );
295 
296  Core::Vector3 vertex( ( majorRadius + minorRadius * std::cos( v ) ) * std::cos( u ),
297  ( majorRadius + minorRadius * std::cos( v ) ) * std::sin( u ),
298  minorRadius * std::sin( v ) );
299 
300  vertices.push_back( vertex );
301  normals.push_back( ( vertex - circleCenter ).normalized() );
302  texCoords.emplace_back( iu * du, iv * dv, 0_ra );
303 
304  if ( iu != U && iv != V ) {
305  indices.push_back( Vector3ui( iu * ( V + 1 ) + iv,
306  ( iu + 1 ) * ( V + 1 ) + iv,
307  iu * ( V + 1 ) + ( iv + 1 ) ) );
308  indices.push_back( Vector3ui( ( iu + 1 ) * ( V + 1 ) + iv,
309  ( iu + 1 ) * ( V + 1 ) + ( iv + 1 ),
310  iu * ( V + 1 ) + ( iv + 1 ) ) );
311  }
312  }
313  }
314 
315  result.setVertices( std::move( vertices ) );
316  result.setNormals( std::move( normals ) );
317  result.setIndices( std::move( indices ) );
318  if ( generateTexCoord )
319  result.addAttrib( getAttribName( MeshAttrib::VERTEX_TEXCOORD ), std::move( texCoords ) );
320  if ( color ) result.colorize( *color );
321  result.checkConsistency();
322 
323  return result;
324 }
325 } // namespace Geometry
326 } // namespace Core
327 } // namespace Ra
Definition: Cage.cpp:3