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>
27RA_CORE_API TriangleMesh makePlaneGrid(
const uint rows = 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 );
36RA_CORE_API TriangleMesh makeXNormalQuad(
const Vector2& halfExts = Vector2( .5_ra, .5_ra ),
37 const Utils::optional<Utils::Color>& color = {},
38 bool generateTexCoord = false );
42RA_CORE_API TriangleMesh makeYNormalQuad(
const Vector2& halfExts = Vector2( .5_ra, .5_ra ),
43 const Utils::optional<Utils::Color>& color = {},
44 bool generateTexCoord = false );
48RA_CORE_API TriangleMesh makeZNormalQuad(
const Vector2& halfExts = Vector2( .5_ra, .5_ra ),
49 const Utils::optional<Utils::Color>& color = {},
50 bool generateTexCoord = false );
53RA_CORE_API TriangleMesh makeBox(
const Vector3& halfExts = Vector3( .5_ra, .5_ra, .5_ra ),
54 const Utils::optional<Utils::Color>& color = {} );
57RA_CORE_API TriangleMesh makeBox(
const Aabb& aabb,
58 const Utils::optional<Utils::Color>& color = {} );
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 );
66RA_CORE_API TriangleMesh makeSharpBox(
const Aabb& aabb,
67 const Utils::optional<Utils::Color>& color = {},
68 bool generateTexCoord = false );
72template <u
int U = 16, u
int V = U>
73TriangleMesh makeParametricSphere( Scalar radius = 1_ra,
74 const Utils::optional<Utils::Color>& color = {},
75 bool generateTexCoord = false );
81template <u
int U = 16, u
int V = U>
82TriangleMesh makeParametricTorus( Scalar majorRadius,
84 const Utils::optional<Utils::Color>& color = {},
85 bool generateTexCoord = false );
88RA_CORE_API TriangleMesh makeGeodesicSphere( Scalar radius = 1_ra,
90 const Utils::optional<Utils::Color>& color = {} );
96RA_CORE_API TriangleMesh makeCylinder(
const Vector3& a,
99 uint sideSegments = 32,
100 uint fillSegments = 2,
101 const Utils::optional<Utils::Color>& color = {} );
106RA_CORE_API TriangleMesh makeCapsule( Scalar length,
109 const Utils::optional<Utils::Color>& color = {} );
113RA_CORE_API TriangleMesh makeTube(
const Vector3& a,
118 const Utils::optional<Utils::Color>& color = {} );
122RA_CORE_API TriangleMesh makeCone(
const Vector3& base,
126 const Utils::optional<Utils::Color>& color = {} );
128template <u
int SLICES, u
int STACKS>
130makeParametricSphere( Scalar radius,
const Utils::optional<Utils::Color>& color,
bool gtc ) {
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 ) );
139 color ? topoMesh.addWedgeAttrib<Vector4>( getAttribName( MeshAttrib::VERTEX_COLOR ) )
142 gtc ? topoMesh.addWedgeAttrib<Vector3>( getAttribName( MeshAttrib::VERTEX_TEXCOORD ) )
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 );
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 ) {
161 const Scalar theta = v * vFactor;
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 );
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 ) );
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 );
189 auto wedgeSetterGeneric = [wedgeSetter, &topoNormals, &topoTexCoords, whNormal, whTexCoord](
190 int vhIndex, TopologicalMesh::FaceHandle fh ) {
191 wedgeSetter( vhIndex, fh, topoNormals[vhIndex], topoTexCoords[vhIndex] );
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 );
203 auto wedgeSetterPole =
204 [wedgeSetter, &topoTexCoords, whNormal, whTexCoord](
bool north,
209 TopologicalMesh::FaceHandle fh ) {
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 ) );
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 );
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]] } );
233 wedgeSetterGeneric( baseSlice + v - 2, fh1 );
234 wedgeSetterGeneric( baseSlice + v - 1, fh1 );
235 wedgeSetterGeneric( baseSlice + v - 2, fh2 );
237 wedgeSetterSeam( u, nextSlice + v - 1, fh1 );
238 wedgeSetterSeam( u, nextSlice + v - 1, fh2 );
239 wedgeSetterSeam( u, nextSlice + v - 2, fh2 );
243 for ( uint u = 0; u < SLICES; ++u ) {
244 const uint nextSlice = ( ( u + 1 ) % SLICES ) * ( STACKS - 1 );
245 const uint baseSlice = u * ( STACKS - 1 );
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] } );
253 wedgeSetterGeneric( baseSlice, fh1 );
254 wedgeSetterGeneric( baseSlice + STACKS - 2, fh2 );
255 wedgeSetterSeam( u, nextSlice, fh1 );
256 wedgeSetterSeam( u, nextSlice + STACKS - 2, fh2 );
259 wedgeSetterPole(
true, topoNorthPoleIdx, baseSlice, nextSlice, u, fh1 );
260 wedgeSetterPole(
false, topoSouthPoleIdx, baseSlice, nextSlice, u, fh2 );
263 topoMesh.mergeEqualWedges();
264 topoMesh.garbage_collection();
265 TriangleMesh result = topoMesh.toTriangleMesh();
266 result.checkConsistency();
270template <u
int U, u
int V>
271TriangleMesh makeParametricTorus( Scalar majorRadius,
273 const Utils::optional<Utils::Color>& color,
274 bool generateTexCoord ) {
276 TriangleMesh::PointAttribHandle::Container vertices;
277 TriangleMesh::NormalAttribHandle::Container normals;
278 TriangleMesh::IndexContainerType indices;
279 Ra::Core::Vector3Array texCoords;
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 ) );
286 const Scalar du = 1_ra / U;
287 const Scalar dv = 1_ra / V;
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 );
293 for ( uint iv = 0; iv <= V; ++iv ) {
294 Scalar v = Scalar( iv ) * Core::Math::PiMul2 / Scalar( V );
296 Core::Vector3 vertex( ( majorRadius + minorRadius *
std::cos( v ) ) *
std::cos( u ),
300 vertices.push_back( vertex );
301 normals.push_back( ( vertex - circleCenter ).normalized() );
302 texCoords.emplace_back( iu * du, iv * dv, 0_ra );
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 ) ) );
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();
@ Geometry
"Geometry" render objects are those loaded using Radium::IO and generated by GeometrySystem
hepler function to manage enum as underlying types in VariableSet