Radium Engine  1.5.20
Loading...
Searching...
No Matches
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
12namespace Ra {
13namespace Core {
14namespace Geometry {
15//
16// Primitive construction
17//
18
27RA_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
36RA_CORE_API TriangleMesh makeXNormalQuad( const Vector2& halfExts = Vector2( .5_ra, .5_ra ),
37 const Utils::optional<Utils::Color>& color = {},
38 bool generateTexCoord = false );
39
42RA_CORE_API TriangleMesh makeYNormalQuad( const Vector2& halfExts = Vector2( .5_ra, .5_ra ),
43 const Utils::optional<Utils::Color>& color = {},
44 bool generateTexCoord = false );
45
48RA_CORE_API TriangleMesh makeZNormalQuad( const Vector2& halfExts = Vector2( .5_ra, .5_ra ),
49 const Utils::optional<Utils::Color>& color = {},
50 bool generateTexCoord = false );
51
53RA_CORE_API TriangleMesh makeBox( const Vector3& halfExts = Vector3( .5_ra, .5_ra, .5_ra ),
54 const Utils::optional<Utils::Color>& color = {} );
55
57RA_CORE_API TriangleMesh makeBox( const Aabb& aabb,
58 const Utils::optional<Utils::Color>& color = {} );
59
61RA_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
66RA_CORE_API TriangleMesh makeSharpBox( const Aabb& aabb,
67 const Utils::optional<Utils::Color>& color = {},
68 bool generateTexCoord = false );
69
72template <uint U = 16, uint V = U>
73TriangleMesh makeParametricSphere( Scalar radius = 1_ra,
74 const Utils::optional<Utils::Color>& color = {},
75 bool generateTexCoord = false );
76
81template <uint U = 16, uint V = U>
82TriangleMesh makeParametricTorus( Scalar majorRadius,
83 Scalar minorRadius,
84 const Utils::optional<Utils::Color>& color = {},
85 bool generateTexCoord = false );
86
88RA_CORE_API TriangleMesh makeGeodesicSphere( Scalar radius = 1_ra,
89 uint numSubdiv = 3,
90 const Utils::optional<Utils::Color>& color = {} );
91
96RA_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
106RA_CORE_API TriangleMesh makeCapsule( Scalar length,
107 Scalar radius,
108 uint nFaces = 32,
109 const Utils::optional<Utils::Color>& color = {} );
110
113RA_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
122RA_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
128template <uint SLICES, uint STACKS>
129TriangleMesh
130makeParametricSphere( 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
270template <uint U, uint V>
271TriangleMesh 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
T cos(T... args)
T move(T... args)
@ Geometry
"Geometry" render objects are those loaded using Radium::IO and generated by GeometrySystem
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
T sin(T... args)