1#include <Core/Containers/Grid.hpp>
2#include <Core/Geometry/MeshPrimitives.hpp>
3#include <Core/Geometry/StandardAttribNames.hpp>
4#include <Core/Math/Math.hpp>
14TriangleMesh makeXNormalQuad(
const Vector2& halfExts,
15 const Utils::optional<Utils::Color>& color,
16 bool generateTexCoord ) {
17 Transform T = Transform::Identity();
18 T.linear().col( 0 ).swap( T.linear().col( 1 ) );
19 T.linear().col( 1 ).swap( T.linear().col( 2 ) );
20 return makePlaneGrid( 1, 1, halfExts, T, color, generateTexCoord );
23TriangleMesh makeYNormalQuad(
const Vector2& halfExts,
24 const Utils::optional<Utils::Color>& color,
25 bool generateTexCoord ) {
26 Transform T = Transform::Identity();
27 T.linear().col( 1 ).swap( T.linear().col( 2 ) );
28 T.linear().col( 0 ).swap( T.linear().col( 1 ) );
29 return makePlaneGrid( 1, 1, halfExts, T, color, generateTexCoord );
32TriangleMesh makeZNormalQuad(
const Vector2& halfExts,
33 const Utils::optional<Utils::Color>& color,
34 bool generateTexCoord ) {
35 return makePlaneGrid( 1, 1, halfExts, Transform::Identity(), color, generateTexCoord );
38TriangleMesh makeBox(
const Vector3& halfExts,
const Utils::optional<Utils::Color>& color ) {
39 Aabb aabb( -halfExts, halfExts );
40 return makeBox( aabb, color );
43TriangleMesh makeBox(
const Aabb& aabb,
const Utils::optional<Utils::Color>& color ) {
45 result.setVertices( { aabb.corner( Aabb::BottomLeftFloor ),
46 aabb.corner( Aabb::BottomRightFloor ),
47 aabb.corner( Aabb::TopLeftFloor ),
48 aabb.corner( Aabb::TopRightFloor ),
49 aabb.corner( Aabb::BottomLeftCeil ),
50 aabb.corner( Aabb::BottomRightCeil ),
51 aabb.corner( Aabb::TopLeftCeil ),
52 aabb.corner( Aabb::TopRightCeil ) } );
54 static const Scalar a = 1_ra /
std::sqrt( 3_ra );
56 result.setNormals( { Vector3( -a, -a, -a ),
57 Vector3( +a, -a, -a ),
58 Vector3( -a, +a, -a ),
59 Vector3( +a, +a, -a ),
60 Vector3( -a, -a, +a ),
61 Vector3( +a, -a, +a ),
62 Vector3( -a, +a, +a ),
63 Vector3( +a, +a, +a ) } );
80 if (
bool( color ) ) result.colorize( *color );
81 result.checkConsistency();
86TriangleMesh makeSharpBox(
const Vector3& halfExts,
87 const Utils::optional<Utils::Color>& color,
88 bool generateTexCoord ) {
89 Aabb aabb( -halfExts, halfExts );
90 return makeSharpBox( aabb, color, generateTexCoord );
93TriangleMesh makeSharpBox(
const Aabb& aabb,
94 const Utils::optional<Utils::Color>& color,
95 bool generateTexCoord ) {
98 aabb.corner( Aabb::BottomLeftFloor ),
99 aabb.corner( Aabb::TopLeftFloor ),
100 aabb.corner( Aabb::TopRightFloor ),
101 aabb.corner( Aabb::BottomRightFloor ),
104 aabb.corner( Aabb::BottomLeftCeil ),
105 aabb.corner( Aabb::BottomRightCeil ),
106 aabb.corner( Aabb::TopRightCeil ),
107 aabb.corner( Aabb::TopLeftCeil ),
110 aabb.corner( Aabb::TopLeftFloor ),
111 aabb.corner( Aabb::BottomLeftFloor ),
112 aabb.corner( Aabb::BottomLeftCeil ),
113 aabb.corner( Aabb::TopLeftCeil ),
116 aabb.corner( Aabb::BottomRightFloor ),
117 aabb.corner( Aabb::TopRightFloor ),
118 aabb.corner( Aabb::TopRightCeil ),
119 aabb.corner( Aabb::BottomRightCeil ),
122 aabb.corner( Aabb::BottomLeftFloor ),
123 aabb.corner( Aabb::BottomRightFloor ),
124 aabb.corner( Aabb::BottomRightCeil ),
125 aabb.corner( Aabb::BottomLeftCeil ),
128 aabb.corner( Aabb::TopLeftFloor ),
129 aabb.corner( Aabb::TopLeftCeil ),
130 aabb.corner( Aabb::TopRightCeil ),
131 aabb.corner( Aabb::TopRightFloor ) } );
162 Vector3( 0, +1, 0 ) } );
164 if ( generateTexCoord ) {
165 Vector3Array texCoords {
198 result.addAttrib(
"in_texcoord",
std::move( texCoords ) );
203 Vector3ui( 0, 1, 2 ),
204 Vector3ui( 0, 2, 3 ),
205 Vector3ui( 4, 5, 6 ),
206 Vector3ui( 4, 6, 7 ),
207 Vector3ui( 8, 9, 10 ),
208 Vector3ui( 8, 10, 11 ),
209 Vector3ui( 12, 13, 14 ),
210 Vector3ui( 12, 14, 15 ),
211 Vector3ui( 16, 17, 18 ),
212 Vector3ui( 16, 18, 19 ),
213 Vector3ui( 20, 21, 22 ),
214 Vector3ui( 20, 22, 23 )
217 if (
bool( color ) ) result.colorize( *color );
218 result.checkConsistency();
224makeGeodesicSphere( Scalar radius, uint numSubdiv,
const Utils::optional<Utils::Color>& color ) {
226 uint faceCount = uint(
std::pow( 4, numSubdiv ) ) * 20;
228 TriangleMesh::PointAttribHandle::Container vertices;
229 TriangleMesh::NormalAttribHandle::Container normals;
230 TriangleMesh::IndexContainerType indices;
231 vertices.reserve( faceCount - 8 );
232 normals.reserve( faceCount - 8 );
233 indices.reserve( faceCount );
237 vertices.emplace_back( 0, 0, radius );
238 normals.emplace_back( 0, 0, 1 );
240 const Scalar sq5_5 = radius *
std::sqrt( 5_ra ) / 5_ra;
243 for (
int i = 0; i < 5; ++i ) {
244 for (
int j = 0; j < 2; ++j ) {
245 const Scalar theta = ( Scalar( i ) + ( j * 0.5_ra ) ) * Math::PiMul2 / 5_ra;
247 const Scalar x = 2_ra * sq5_5 *
std::cos( theta );
248 const Scalar y = 2_ra * sq5_5 *
std::sin( theta );
249 const Scalar z = j == 0 ? sq5_5 : -sq5_5;
250 vertices.emplace_back( x, y, z );
251 normals.push_back( vertices.back().normalized() );
256 vertices.emplace_back( 0, 0, -radius );
257 normals.emplace_back( 0, 0, -1 );
259 for (
int i = 0; i < 5; ++i ) {
260 uint i1 = ( i + 1 ) % 5;
262 indices.emplace_back( 0, 2 * i + 1, ( 2 * i1 + 1 ) );
265 indices.emplace_back( 2 * i + 2, 11, ( 2 * i1 + 2 ) );
267 for ( uint i = 0; i < 10; ++i ) {
268 uint i1 = ( i + 0 ) % 10 + 1;
269 uint i2 = ( i + 1 ) % 10 + 1;
270 uint i3 = ( i + 2 ) % 10 + 1;
271 ( i % 2 ) ? indices.emplace_back( i3, i2, i1 ) : indices.emplace_back( i2, i3, i1 );
274 for ( uint n = 0; n < numSubdiv; ++n ) {
275 VectorArray<Vector3ui> newTris;
277 for ( uint i = 0; i < indices.size(); ++i ) {
278 const Vector3ui& tri = indices[i];
280 { vertices[tri[0]], vertices[tri[1]], vertices[tri[2]] } };
283 for ( uint v = 0; v < 3; ++v ) {
284 middles[v] = uint( vertices.size() );
286 Vector3 vertex = 0.5_ra * ( triVertices[v] + triVertices[( v + 1 ) % 3] );
289 vertices.push_back( radius * vertex );
290 normals.push_back( vertex );
293 newTris.emplace_back( tri[0], middles[0], middles[2] );
294 newTris.emplace_back( middles[0], tri[1], middles[1] );
295 newTris.emplace_back( middles[2], middles[1], tri[2] );
296 newTris.emplace_back( middles[0], middles[1], middles[2] );
301 result.setVertices(
std::move( vertices ) );
302 result.setNormals(
std::move( normals ) );
303 result.setIndices(
std::move( indices ) );
304 if (
bool( color ) ) result.colorize( *color );
305 result.checkConsistency();
310TriangleMesh makeCylinder(
const Vector3& a,
315 const Utils::optional<Utils::Color>& color ) {
318 TriangleMesh::PointAttribHandle::Container vertices;
319 TriangleMesh::NormalAttribHandle::Container normals;
320 TriangleMesh::IndexContainerType indices;
322 const Vector3 ab = b - a;
323 const Vector3 dir = ab.normalized();
327 Vector3 xPlane, yPlane;
332 vertices.push_back( a );
333 normals.push_back( -dir );
334 vertices.push_back( b );
335 normals.push_back( dir );
337 const Scalar thetaInc( Core::Math::PiMul2 / Scalar( sideSegments ) );
338 for ( uint i = 0; i < sideSegments; ++i ) {
339 const Scalar theta = i * thetaInc;
340 const Vector3 normal =
std::cos( theta ) * xPlane +
std::sin( theta ) * yPlane;
343 vertices.push_back( a + radius * normal );
344 normals.push_back( -dir );
346 vertices.push_back( b + radius * normal );
347 normals.push_back( dir );
350 for ( uint i = 0; i < sideSegments; ++i ) {
352 uint br = 2 + ( 2 * ( ( i + 1 ) % sideSegments ) );
354 uint tr = 3 + ( 2 * ( ( i + 1 ) % sideSegments ) );
356 indices.emplace_back( 0, br, bl );
357 indices.emplace_back( 1, tl, tr );
361 const uint offset = vertices.size();
363 const Vector3 dh = ab / Scalar( fillSegments );
364 for ( uint j = 0; j <= fillSegments; ++j ) {
365 for ( uint i = 0; i < sideSegments; ++i ) {
366 const Scalar theta = i * thetaInc;
369 vertices.push_back( c + radius * normal );
370 normals.push_back( normal );
375 for ( uint j = 0; j < fillSegments; ++j ) {
376 for ( uint i = 0; i < sideSegments; ++i ) {
377 uint i0 = offset + i + j * sideSegments;
378 uint i1 = offset + ( i + 1 ) % sideSegments + j * sideSegments;
379 uint i2 = i0 + sideSegments;
380 uint i3 = i1 + sideSegments;
382 indices.emplace_back( i0, i1, i2 );
383 indices.emplace_back( i2, i1, i3 );
387 result.setVertices(
std::move( vertices ) );
388 result.setNormals(
std::move( normals ) );
389 result.setIndices(
std::move( indices ) );
390 if (
bool( color ) ) result.colorize( *color );
391 result.checkConsistency();
396TriangleMesh makeCapsule( Scalar length,
399 const Utils::optional<Utils::Color>& color ) {
402 TriangleMesh::PointAttribHandle::Container vertices;
403 TriangleMesh::NormalAttribHandle::Container normals;
404 TriangleMesh::IndexContainerType indices;
406 vertices.reserve( nFaces * nFaces + nFaces + 2 );
407 normals.reserve( nFaces * nFaces + nFaces + 2 );
408 indices.reserve( 2 * ( nFaces * nFaces + nFaces ) );
410 const Scalar l = length / 2_ra;
416 const Scalar thetaInc( Core::Math::PiMul2 / Scalar( nFaces ) );
417 for ( uint i = 0; i < nFaces; ++i ) {
418 const Scalar theta = i * thetaInc;
422 Vector3 vertex = radius * normal;
423 vertices.emplace_back( vertex[0], vertex[1], -l );
424 vertices.emplace_back( vertex[0], vertex[1], 0.0 );
425 vertices.emplace_back( vertex[0], vertex[1], l );
427 normals.push_back( normal );
428 normals.push_back( normal );
429 normals.push_back( normal );
433 for ( uint i = 0; i < nFaces; ++i ) {
435 uint br = 3 * ( ( i + 1 ) % nFaces );
441 indices.emplace_back( bl, br, ml );
442 indices.emplace_back( br, mr, ml );
444 indices.emplace_back( ml, mr, tl );
445 indices.emplace_back( mr, tr, tl );
449 const Scalar phiInc = Core::Math::Pi / Scalar( nFaces );
450 uint vert_count = uint( vertices.size() );
453 for ( uint j = 1; j <= nFaces / 2 - 1; ++j ) {
454 const Scalar phi = Core::Math::PiDiv2 + j * phiInc;
456 for ( uint i = 0; i < nFaces; ++i ) {
457 const Scalar theta = i * thetaInc;
463 Vector3 vertex = radius * normal;
466 vertices.push_back( vertex );
467 normals.push_back( normal );
471 vertices.emplace_back( 0, 0, -( l + radius ) );
472 normals.emplace_back( 0, 0, -1 );
475 for ( uint i = 0; i < nFaces; ++i ) {
477 uint br = 3 * ( ( i + 1 ) % nFaces );
479 uint tl = vert_count + i;
480 uint tr = vert_count + ( i + 1 ) % nFaces;
482 indices.emplace_back( br, bl, tl );
483 indices.emplace_back( br, tl, tr );
487 for ( uint j = 0; j < ( nFaces / 2 ) - 2; ++j ) {
488 for ( uint i = 0; i < nFaces; ++i ) {
489 uint bl = vert_count + j * nFaces + i;
490 uint br = vert_count + j * nFaces + ( i + 1 ) % nFaces;
492 uint tl = vert_count + ( j + 1 ) * nFaces + i;
493 uint tr = vert_count + ( j + 1 ) * nFaces + ( i + 1 ) % nFaces;
495 indices.emplace_back( br, bl, tl );
496 indices.emplace_back( br, tl, tr );
501 for ( uint i = 0; i < nFaces; ++i ) {
502 const uint j = nFaces / 2 - 2;
503 uint bl = vert_count + j * nFaces + i;
504 uint br = vert_count + j * nFaces + ( i + 1 ) % nFaces;
505 uint bot = uint( vertices.size() - 1 );
506 indices.emplace_back( br, bl, bot );
510 vert_count = uint( vertices.size() );
513 for ( uint j = 1; j <= nFaces / 2 - 1; ++j ) {
514 const Scalar phi = Core::Math::PiDiv2 - j * phiInc;
516 for ( uint i = 0; i < nFaces; ++i ) {
517 const Scalar theta = i * thetaInc;
523 Vector3 vertex = radius * normal;
526 vertices.push_back( vertex );
527 normals.push_back( normal );
532 vertices.emplace_back( 0, 0, ( l + radius ) );
533 normals.emplace_back( 0, 0, 1 );
536 for ( uint i = 0; i < nFaces; ++i ) {
538 uint br = 3 * ( ( i + 1 ) % nFaces ) + 2;
540 uint tl = vert_count + i;
541 uint tr = vert_count + ( i + 1 ) % nFaces;
543 indices.emplace_back( bl, br, tl );
544 indices.emplace_back( br, tr, tl );
548 for ( uint j = 0; j < ( nFaces / 2 ) - 2; ++j ) {
549 for ( uint i = 0; i < nFaces; ++i ) {
550 uint bl = vert_count + j * nFaces + i;
551 uint br = vert_count + j * nFaces + ( i + 1 ) % nFaces;
553 uint tl = vert_count + ( j + 1 ) * nFaces + i;
554 uint tr = vert_count + ( j + 1 ) * nFaces + ( i + 1 ) % nFaces;
556 indices.emplace_back( bl, br, tl );
557 indices.emplace_back( br, tr, tl );
562 for ( uint i = 0; i < nFaces; ++i ) {
563 const uint j = nFaces / 2 - 2;
564 uint bl = vert_count + j * nFaces + i;
565 uint br = vert_count + j * nFaces + ( i + 1 ) % nFaces;
566 uint top = uint( vertices.size() ) - 1;
567 indices.emplace_back( bl, br, top );
569 result.setVertices(
std::move( vertices ) );
570 result.setNormals(
std::move( normals ) );
571 result.setIndices(
std::move( indices ) );
572 if (
bool( color ) ) result.colorize( *color );
573 result.checkConsistency();
578TriangleMesh makeTube(
const Vector3& a,
583 const Utils::optional<Utils::Color>& color ) {
585 CORE_ASSERT( outerRadius > innerRadius,
"Outer radius must be bigger than inner." );
588 TriangleMesh::PointAttribHandle::Container vertices;
589 TriangleMesh::NormalAttribHandle::Container normals;
590 TriangleMesh::IndexContainerType indices;
591 vertices.reserve( 6 * nFaces );
592 normals.reserve( 6 * nFaces );
593 indices.reserve( 12 * nFaces );
596 Vector3 dir = ab.normalized();
599 Vector3 xPlane, yPlane;
604 Vector3 c = 0.5 * ( a + b );
606 const Scalar thetaInc( Core::Math::PiMul2 / Scalar( nFaces ) );
607 for ( uint i = 0; i < nFaces; ++i ) {
608 const Scalar theta = i * thetaInc;
612 vertices.push_back( a + outerRadius * normal );
613 vertices.push_back( c + outerRadius * normal );
614 vertices.push_back( b + outerRadius * normal );
616 vertices.push_back( a + innerRadius * normal );
617 vertices.push_back( c + innerRadius * normal );
618 vertices.push_back( b + innerRadius * normal );
620 normals.push_back( ( -dir + normal ).normalized() );
621 normals.push_back( normal );
622 normals.push_back( ( dir + normal ).normalized() );
624 normals.push_back( ( -dir - normal ).normalized() );
625 normals.push_back( -normal );
626 normals.push_back( ( dir - normal ).normalized() );
629 for ( uint i = 0; i < nFaces; ++i ) {
632 uint obr = 6 * ( ( i + 1 ) % nFaces );
639 uint ibl = 6 * i + 3;
640 uint ibr = 6 * ( ( i + 1 ) % nFaces ) + 3;
648 indices.emplace_back( obl, obr, oml );
649 indices.emplace_back( obr, omr, oml );
651 indices.emplace_back( oml, omr, otl );
652 indices.emplace_back( omr, otr, otl );
656 indices.emplace_back( ibr, ibl, iml );
657 indices.emplace_back( ibr, iml, imr );
659 indices.emplace_back( imr, iml, itl );
660 indices.emplace_back( imr, itl, itr );
663 indices.emplace_back( ibr, obr, ibl );
664 indices.emplace_back( obl, ibl, obr );
667 indices.emplace_back( otr, itr, itl );
668 indices.emplace_back( itl, otl, otr );
670 result.setVertices(
std::move( vertices ) );
671 result.setNormals(
std::move( normals ) );
672 result.setIndices(
std::move( indices ) );
673 if (
bool( color ) ) result.colorize( *color );
674 result.checkConsistency();
679TriangleMesh makeCone(
const Vector3& base,
683 const Utils::optional<Utils::Color>& color ) {
685 TriangleMesh::PointAttribHandle::Container vertices;
686 TriangleMesh::NormalAttribHandle::Container normals;
687 TriangleMesh::IndexContainerType indices;
688 vertices.reserve( 2 + nFaces );
689 normals.reserve( 2 + nFaces );
690 indices.reserve( 2 * nFaces );
692 Vector3 ab = tip - base;
693 Vector3 dir = ab.normalized();
696 Vector3 xPlane, yPlane;
701 vertices.push_back( base );
702 vertices.push_back( tip );
703 normals.push_back( -dir );
704 normals.push_back( dir );
706 const Scalar thetaInc( Core::Math::PiMul2 / Scalar( nFaces ) );
707 for ( uint i = 0; i < nFaces; ++i ) {
708 const Scalar theta = i * thetaInc;
711 vertices.push_back( base + radius * normal );
712 normals.push_back( ( normal - dir ).normalized() );
715 for ( uint i = 0; i < nFaces; ++i ) {
717 uint br = ( ( i + 1 ) % nFaces ) + 2;
719 indices.emplace_back( 0, br, bl );
720 indices.emplace_back( 1, bl, br );
722 result.setVertices(
std::move( vertices ) );
723 result.setNormals(
std::move( normals ) );
724 result.setIndices(
std::move( indices ) );
725 if (
bool( color ) ) result.colorize( *color );
726 result.checkConsistency();
731TriangleMesh makePlaneGrid(
const uint rows,
733 const Vector2& halfExts,
735 const Utils::optional<Utils::Color>& color,
736 bool generateTexCoord ) {
738 TriangleMesh::PointAttribHandle::Container vertices;
739 TriangleMesh::NormalAttribHandle::Container normals;
740 TriangleMesh::IndexContainerType indices;
741 Ra::Core::Vector3Array texCoords;
743 const uint R = ( rows + 1 );
744 const uint C = ( cols + 1 );
745 const uint v_size = C * R;
746 const uint t_size = 2 * cols * rows;
748 vertices.resize( v_size );
749 normals.resize( v_size );
750 indices.reserve( t_size );
751 texCoords.reserve( v_size );
753 const Vector3 X = T.linear().col( 0 ).normalized();
754 const Vector3 Y = T.linear().col( 1 ).normalized();
755 const Vector3 Z = T.linear().col( 2 ).normalized();
757 const Vector3 x = ( 2_ra * halfExts[0] * X ) / Scalar( cols );
758 const Vector3 y = ( 2_ra * halfExts[1] * Y ) / Scalar( rows );
759 const Vector3 o = T.translation() - ( halfExts[0] * X ) - ( halfExts[1] * Y );
761 const Scalar du = 1_ra / rows;
762 const Scalar dv = 1_ra / cols;
764 Grid<uint, 2> v( { R, C } );
765 for ( uint i = 0; i < R; ++i ) {
766 for ( uint j = 0; j < C; ++j ) {
767 const uint
id = ( i * C ) + j;
768 v.at( { i, j } ) =
id;
769 vertices[id] = o + ( i * y ) + ( j * x );
771 texCoords.emplace_back( i * du, j * dv, 0_ra );
775 for ( uint i = 0; i < rows; ++i ) {
776 for ( uint j = 0; j < cols; ++j ) {
777 indices.emplace_back(
778 v.at( { i, j } ), v.at( { i, j + 1 } ), v.at( { i + 1, j + 1 } ) );
779 indices.emplace_back(
780 v.at( { i, j } ), v.at( { i + 1, j + 1 } ), v.at( { i + 1, j } ) );
783 result.setVertices(
std::move( vertices ) );
784 result.setNormals(
std::move( normals ) );
785 result.setIndices(
std::move( indices ) );
786 if ( generateTexCoord )
787 result.addAttrib( getAttribName( MeshAttrib::VERTEX_TEXCOORD ),
std::move( texCoords ) );
788 if (
bool( color ) ) result.colorize( *color );
789 result.checkConsistency();
void getOrthogonalVectors(const Vector3 &fx, Eigen::Ref< Vector3 > fy, Eigen::Ref< Vector3 > fz)
@ Geometry
"Geometry" render objects are those loaded using Radium::IO and generated by GeometrySystem
hepler function to manage enum as underlying types in VariableSet