1#include <Core/Geometry/CatmullClarkSubdivider.hpp>
7bool CatmullClarkSubdivider::prepare( deprecated::TopologicalMesh& mesh ) {
8 mesh.add_property( m_vpPos );
9 mesh.add_property( m_epH );
10 mesh.add_property( m_fpH );
11 mesh.add_property( m_creaseWeights );
12 mesh.createAllPropsOnFaces(
13 m_normalPropF, m_floatPropsF, m_vec2PropsF, m_vec3PropsF, m_vec4PropsF );
14 mesh.add_property( m_hV );
15 for ( uint i = 0; i < mesh.n_halfedges(); ++i ) {
16 auto h = mesh.halfedge_handle( i );
17 if ( !mesh.is_boundary( h ) ) { mesh.property( m_hV, h ) = mesh.to_vertex_handle( h ); }
21 for (
auto e_it = mesh.edges_begin(); e_it != mesh.edges_end(); ++e_it )
22 mesh.property( m_creaseWeights, *e_it ) = 0.0;
27bool CatmullClarkSubdivider::cleanup( deprecated::TopologicalMesh& mesh ) {
28 mesh.remove_property( m_vpPos );
29 mesh.remove_property( m_epH );
30 mesh.remove_property( m_fpH );
31 mesh.remove_property( m_creaseWeights );
32 mesh.clearAllProps( m_normalPropF, m_floatPropsF, m_vec2PropsF, m_vec3PropsF, m_vec4PropsF );
33 mesh.remove_property( m_hV );
37bool CatmullClarkSubdivider::subdivide( deprecated::TopologicalMesh& mesh,
39 const bool update_points ) {
40 m_oldVertexOps.clear();
41 m_newFaceVertexOps.clear();
42 m_newEdgeVertexOps.clear();
43 m_newEdgePropOps.clear();
44 m_newFacePropOps.clear();
45 m_oldVertexOps.resize( n );
46 m_newFaceVertexOps.resize( n );
47 m_newEdgeVertexOps.resize( n );
48 m_newEdgePropOps.resize( n );
49 m_newFacePropOps.resize( n );
51 for (
size_t iter = 0; iter < n; ++iter ) {
53 const size_t NV = mesh.n_vertices();
54 m_newFaceVertexOps[iter].reserve( mesh.n_faces() );
55#pragma omp parallel for
56 for (
int i = 0; i < int( mesh.n_faces() ); ++i ) {
57 const auto& fh = mesh.face_handle( i );
59 deprecated::TopologicalMesh::Point centroid;
60 mesh.calc_face_centroid( fh, centroid );
61 deprecated::TopologicalMesh::VertexHandle vh;
63 { vh = mesh.new_vertex( centroid ); }
64 mesh.property( m_fpH, fh ) = vh;
66 const uint v = mesh.valence( fh );
67 const Scalar inv_v = 1.f / v;
69 auto heh = mesh.halfedge_handle( fh );
70 for ( uint j = 0; j < v; ++j ) {
71 ops[j] = V_OP( inv_v, mesh.to_vertex_handle( heh ) );
72 heh = mesh.next_halfedge_handle( heh );
75 { m_newFaceVertexOps[iter].push_back( V_OPS( vh, ops ) ); }
77 mesh.interpolateAllPropsOnFaces(
78 fh, m_normalPropF, m_floatPropsF, m_vec2PropsF, m_vec3PropsF, m_vec4PropsF );
82 m_newEdgeVertexOps[iter].reserve( mesh.n_edges() );
83#pragma omp parallel for
84 for (
int i = 0; i < int( mesh.n_edges() ); ++i ) {
85 const auto& eh = mesh.edge_handle( i );
86 compute_midpoint( mesh, eh, update_points, iter );
90 if ( update_points ) {
92 m_oldVertexOps[iter].reserve( NV );
93#pragma omp parallel for
94 for (
int i = 0; i < int( NV ); ++i ) {
95 const auto& vh = mesh.vertex_handle( i );
96 update_vertex( mesh, vh, iter );
100#pragma omp parallel for
101 for (
int i = 0; i < int( NV ); ++i ) {
102 const auto& vh = mesh.vertex_handle( i );
103 mesh.set_point( vh, mesh.property( m_vpPos, vh ) );
109 auto e_end = mesh.edges_end();
110 m_newEdgePropOps[iter].reserve( 3 * mesh.n_edges() );
111 for (
auto e_itr = mesh.edges_begin(); e_itr != e_end; ++e_itr ) {
112 split_edge( mesh, *e_itr, iter );
114 m_newEdgePropOps[iter].shrink_to_fit();
118 auto f_end = mesh.faces_end();
119 m_newFacePropOps[iter].reserve( 2 * 4 * mesh.n_faces() );
120 for (
auto f_itr = mesh.faces_begin(); f_itr != f_end; ++f_itr ) {
121 split_face( mesh, *f_itr, iter );
123 m_newFacePropOps[iter].shrink_to_fit();
125 CORE_ASSERT( OpenMesh::Utils::MeshCheckerT<deprecated::TopologicalMesh>( mesh ).check(),
126 "CatmullClarkSubdivision ended with a bad topology." );
132 m_triangulationPropOps.
clear();
133 m_triangulationPropOps.
reserve( 2 * mesh.n_faces() );
135 auto f_end = mesh.faces_end();
136 for (
auto f_itr = mesh.faces_begin(); f_itr != f_end; ++f_itr ) {
138 auto heh1 = mesh.halfedge_handle( *f_itr );
139 auto heh2 = mesh.next_halfedge_handle( heh1 );
140 auto heh3 = mesh.next_halfedge_handle( heh2 );
141 auto heh4 = mesh.next_halfedge_handle( heh3 );
142 auto heh5 = mesh.new_edge( mesh.to_vertex_handle( heh1 ), mesh.to_vertex_handle( heh3 ) );
143 auto heh6 = mesh.opposite_halfedge_handle( heh5 );
146 auto fnew = mesh.new_face();
147 mesh.set_halfedge_handle( fnew, heh2 );
148 mesh.set_face_handle( heh5, *f_itr );
149 mesh.set_face_handle( heh2, fnew );
150 mesh.set_face_handle( heh3, fnew );
151 mesh.set_face_handle( heh6, fnew );
152 mesh.set_next_halfedge_handle( heh1, heh5 );
153 mesh.set_next_halfedge_handle( heh5, heh4 );
154 mesh.set_next_halfedge_handle( heh3, heh6 );
155 mesh.set_next_halfedge_handle( heh6, heh2 );
158 mesh.copyAllProps( heh3, heh5 );
159 mesh.copyAllProps( heh1, heh6 );
160 m_triangulationPropOps.
push_back( { heh5, { { 1, heh3 } } } );
161 m_triangulationPropOps.
push_back( { heh6, { { 1, heh1 } } } );
167void CatmullClarkSubdivider::split_face( deprecated::TopologicalMesh& mesh,
168 const deprecated::TopologicalMesh::FaceHandle& fh,
179 size_t valence = mesh.valence( fh ) / 2;
182 auto vh = mesh.property( m_fpH, fh );
185 auto hend = mesh.halfedge_handle( fh );
186 auto hh = mesh.next_halfedge_handle( hend );
187 auto hold = mesh.new_edge( mesh.to_vertex_handle( hend ), vh );
188 mesh.set_next_halfedge_handle( hend, hold );
189 mesh.set_face_handle( hold, fh );
192 mesh.copyAllPropsFromFace(
193 fh, hold, m_normalPropF, m_floatPropsF, m_vec2PropsF, m_vec3PropsF, m_vec4PropsF );
196 hold = mesh.opposite_halfedge_handle( hold );
199 mesh.copyAllProps( hend, hold );
200 m_newFacePropOps[iter].push_back( { hold, { { 1, hend } } } );
202 const Scalar inv_val = Scalar( 1 ) / valence;
204 p_ops[0] = { inv_val, hh };
206 for (
size_t i = 1; i < valence; i++ ) {
208 auto hnext = mesh.next_halfedge_handle( hh );
209 auto hnew = mesh.new_edge( mesh.to_vertex_handle( hnext ), vh );
212 auto fnew = mesh.new_face();
213 mesh.set_halfedge_handle( fnew, hh );
214 mesh.set_face_handle( hnew, fnew );
215 mesh.set_face_handle( hold, fnew );
216 mesh.set_face_handle( hh, fnew );
217 mesh.set_face_handle( hnext, fnew );
218 mesh.set_next_halfedge_handle( hnew, hold );
219 mesh.set_next_halfedge_handle( hold, hh );
222 mesh.copyAllPropsFromFace(
223 fh, hnew, m_normalPropF, m_floatPropsF, m_vec2PropsF, m_vec3PropsF, m_vec4PropsF );
226 hh = mesh.next_halfedge_handle( hnext );
227 hold = mesh.opposite_halfedge_handle( hnew );
228 mesh.set_next_halfedge_handle( hnext, hnew );
231 mesh.copyAllProps( hnext, hold );
232 m_newFacePropOps[iter].push_back( { hold, { { 1, hnext } } } );
233 p_ops[i] = { inv_val, hh };
237 mesh.set_next_halfedge_handle( hold, hh );
238 mesh.set_next_halfedge_handle( hh, hend );
239 hh = mesh.next_halfedge_handle( hend );
240 mesh.set_next_halfedge_handle( hh, hold );
241 mesh.set_face_handle( hold, fh );
242 mesh.set_halfedge_handle( vh, hold );
245 for (
auto vh_iter = mesh.vih_iter( vh ); vh_iter.is_valid(); ++vh_iter ) {
246 m_newFacePropOps[iter].push_back( { *vh_iter, p_ops } );
250void CatmullClarkSubdivider::split_edge( deprecated::TopologicalMesh& mesh,
251 const deprecated::TopologicalMesh::EdgeHandle& eh,
253 using HeHandle = deprecated::TopologicalMesh::HalfedgeHandle;
254 using VHandle = deprecated::TopologicalMesh::VertexHandle;
257 HeHandle heh = mesh.halfedge_handle( eh, 0 );
258 HeHandle opp_heh = mesh.halfedge_handle( eh, 1 );
260 HeHandle opp_new_heh;
263 VHandle vh1( mesh.to_vertex_handle( heh ) );
266 vh = mesh.property( m_epH, eh );
269 if ( mesh.is_boundary( eh ) ) {
271 for ( t_heh = heh; mesh.next_halfedge_handle( t_heh ) != opp_heh;
272 t_heh = mesh.opposite_halfedge_handle( mesh.next_halfedge_handle( t_heh ) ) )
277 for ( t_heh = mesh.next_halfedge_handle( opp_heh );
278 mesh.next_halfedge_handle( t_heh ) != opp_heh;
279 t_heh = mesh.next_halfedge_handle( t_heh ) )
283 new_heh = mesh.new_edge( vh, vh1 );
284 opp_new_heh = mesh.opposite_halfedge_handle( new_heh );
285 mesh.set_vertex_handle( heh, vh );
287 mesh.set_next_halfedge_handle( t_heh, opp_new_heh );
288 mesh.set_next_halfedge_handle( new_heh, mesh.next_halfedge_handle( heh ) );
289 mesh.set_next_halfedge_handle( heh, new_heh );
290 mesh.set_next_halfedge_handle( opp_new_heh, opp_heh );
292 if ( mesh.face_handle( opp_heh ).is_valid() ) {
293 mesh.set_face_handle( opp_new_heh, mesh.face_handle( opp_heh ) );
294 mesh.set_halfedge_handle( mesh.face_handle( opp_new_heh ), opp_new_heh );
297 mesh.interpolateAllProps( t_heh, opp_heh, opp_new_heh, 0.5 );
298 m_newEdgePropOps[iter].push_back( { opp_new_heh, { { 0.5, t_heh }, { 0.5, opp_heh } } } );
301 if ( mesh.face_handle( heh ).is_valid() ) {
302 mesh.set_face_handle( new_heh, mesh.face_handle( heh ) );
303 mesh.set_halfedge_handle( mesh.face_handle( heh ), heh );
306 mesh.copyAllProps( heh, new_heh );
307 m_newEdgePropOps[iter].push_back( { new_heh, { { 1, heh } } } );
308 HeHandle heh_prev = mesh.prev_halfedge_handle( heh );
309 mesh.interpolateAllProps( heh_prev, new_heh, heh, 0.5 );
310 m_newEdgePropOps[iter].push_back( { heh, { { 0.5, heh_prev }, { 0.5, new_heh } } } );
313 mesh.set_halfedge_handle( vh, new_heh );
314 mesh.set_halfedge_handle( vh1, opp_new_heh );
317 mesh.adjust_outgoing_halfedge( vh );
318 mesh.adjust_outgoing_halfedge( vh1 );
321void CatmullClarkSubdivider::compute_midpoint( deprecated::TopologicalMesh& mesh,
322 const deprecated::TopologicalMesh::EdgeHandle& eh,
323 const bool update_points,
325 deprecated::TopologicalMesh::HalfedgeHandle heh = mesh.halfedge_handle( eh, 0 );
326 deprecated::TopologicalMesh::HalfedgeHandle opp_heh = mesh.halfedge_handle( eh, 1 );
328 deprecated::TopologicalMesh::Point pos = mesh.point( mesh.to_vertex_handle( heh ) );
329 pos += mesh.point( mesh.to_vertex_handle( opp_heh ) );
336 if ( mesh.is_boundary( eh ) || !update_points ) {
340 ops[0] = V_OP( 0.5, mesh.to_vertex_handle( heh ) );
341 ops[1] = V_OP( 0.5, mesh.to_vertex_handle( opp_heh ) );
346 pos += mesh.point( mesh.property( m_fpH, mesh.face_handle( heh ) ) );
347 pos += mesh.point( mesh.property( m_fpH, mesh.face_handle( opp_heh ) ) );
351 ops[0] = V_OP( 0.25, mesh.to_vertex_handle( heh ) );
352 ops[1] = V_OP( 0.25, mesh.to_vertex_handle( opp_heh ) );
353 ops[2] = V_OP( 0.25, mesh.property( m_fpH, mesh.face_handle( heh ) ) );
354 ops[3] = V_OP( 0.25, mesh.property( m_fpH, mesh.face_handle( opp_heh ) ) );
360 auto vh = mesh.new_vertex( pos );
361 mesh.property( m_epH, eh ) = vh;
363 m_newEdgeVertexOps[iter].push_back( V_OPS( vh, ops ) );
367void CatmullClarkSubdivider::update_vertex( deprecated::TopologicalMesh& mesh,
368 const deprecated::TopologicalMesh::VertexHandle& vh,
370 deprecated::TopologicalMesh::Point pos( 0.0, 0.0, 0.0 );
379 if ( mesh.is_boundary( vh ) ) {
380 pos = mesh.point( vh );
382 ops[0] = V_OP( 1.f / 3.f, vh );
384 for (
auto ve_itr = mesh.ve_iter( vh ); ve_itr.is_valid(); ++ve_itr ) {
385 if ( mesh.is_boundary( *ve_itr ) ) {
386 pos += mesh.point( mesh.property( m_epH, *ve_itr ) );
387 ops[i++] = V_OP( 1.f / 3.f, mesh.property( m_epH, *ve_itr ) );
401 const uint valence = mesh.valence( vh );
402 const Scalar inv_v2 = 1.f / ( valence * valence );
403 ops.
resize( valence * 2 + 1 );
406 for (
auto voh_it = mesh.voh_iter( vh ); voh_it.is_valid(); ++voh_it ) {
407 pos += mesh.point( mesh.to_vertex_handle( *voh_it ) );
408 ops[i++] = V_OP( inv_v2, mesh.to_vertex_handle( *voh_it ) );
412 deprecated::TopologicalMesh::Point Q( 0, 0, 0 );
413 for (
auto vf_itr = mesh.vf_iter( vh ); vf_itr.is_valid(); ++vf_itr ) {
414 Q += mesh.point( mesh.property( m_fpH, *vf_itr ) );
415 ops[i++] = V_OP( inv_v2, mesh.property( m_fpH, *vf_itr ) );
420 pos += mesh.point( vh ) * ( valence - 2.0 ) / valence + Q;
421 ops[i] = V_OP( ( valence - 2.0 ) / valence, vh );
425 mesh.property( m_vpPos, vh ) = pos;
428 { m_oldVertexOps[iter].push_back( V_OPS( vh, ops ) ); }
432 const Vector3Array& newCoarseNormals,
433 Vector3Array& newSubdivVertices,
434 Vector3Array& newSubdivNormals,
438 auto hNormalProp = mesh.halfedge_normals_pph();
439#pragma omp parallel for
440 for (
int i = 0; i < int( mesh.n_halfedges() ); ++i ) {
443 auto vh = mesh.property( m_hV, h );
444 if ( vh.idx() != -1 )
446 auto idx = mesh.property( inTriIndexProp, h );
447 mesh.set_point( vh, newCoarseVertices[idx] );
448 mesh.property( hNormalProp, h ) = newCoarseNormals[idx];
452 for (
int i = 0; i < int( m_oldVertexOps.size() ); ++i ) {
454#pragma omp parallel for
455 for (
int j = 0; j < int( m_newFaceVertexOps[i].size() ); ++j ) {
456 Ra::Core::Vector3 pos( 0, 0, 0 );
457 const auto& ops = m_newFaceVertexOps[i][j];
458 for (
const auto& op : ops.second ) {
459 pos += op.first * mesh.point( op.second );
461 mesh.set_point( ops.first, pos );
464#pragma omp parallel for
465 for (
int j = 0; j < int( m_newEdgeVertexOps[i].size() ); ++j ) {
466 Ra::Core::Vector3 pos( 0, 0, 0 );
467 const auto& ops = m_newEdgeVertexOps[i][j];
468 for (
const auto& op : ops.second ) {
469 pos += op.first * mesh.point( op.second );
471 mesh.set_point( ops.first, pos );
475#pragma omp parallel for
476 for (
int j = 0; j < int( m_oldVertexOps[i].size() ); ++j ) {
477 pos[j] = Ra::Core::Vector3( 0, 0, 0 );
478 const auto& ops = m_oldVertexOps[i][j];
479 for (
const auto& op : ops.second ) {
480 pos[j] += op.first * mesh.point( op.second );
484#pragma omp parallel for schedule( static )
485 for (
int j = 0; j < int( m_oldVertexOps[i].size() ); ++j ) {
486 mesh.set_point( m_oldVertexOps[i][j].first, pos[j] );
491 for (
int j = 0; j < int( m_newEdgePropOps[i].size() ); ++j ) {
492 Ra::Core::Vector3 nor( 0, 0, 0 );
493 const auto& ops = m_newEdgePropOps[i][j];
494 for (
const auto& op : ops.second ) {
495 nor += op.first * mesh.property( hNormalProp, op.second );
497 mesh.property( hNormalProp, ops.first ) = nor.normalized();
501#pragma omp parallel for
502 for (
int j = 0; j < int( m_newFacePropOps[i].size() ); ++j ) {
503 Ra::Core::Vector3 nor( 0, 0, 0 );
504 const auto& ops = m_newFacePropOps[i][j];
505 for (
const auto& op : ops.second ) {
506 nor += op.first * mesh.property( hNormalProp, op.second );
508 mesh.property( hNormalProp, ops.first ) = nor.normalized();
513#pragma omp parallel for
514 for (
int j = 0; j < int( m_triangulationPropOps.
size() ); ++j ) {
515 Ra::Core::Vector3 nor( 0, 0, 0 );
516 const auto& ops = m_triangulationPropOps[j];
517 for (
const auto& op : ops.second ) {
518 nor += op.first * mesh.property( hNormalProp, op.second );
520 mesh.property( hNormalProp, ops.first ) = nor.normalized();
524#pragma omp parallel for
525 for (
int i = 0; i < int( mesh.n_halfedges() ); ++i ) {
527 if ( !mesh.is_boundary( h ) ) {
528 auto idx = mesh.property( outTriIndexProp, h );
529 newSubdivVertices[idx] = mesh.point( mesh.to_vertex_handle( h ) );
530 newSubdivNormals[idx] = mesh.property( hNormalProp, h );
void recompute(const Vector3Array &newCoarseVertices, const Vector3Array &newCoarseNormals, Vector3Array &newSubdivVertices, Vector3Array &newSubdivNormals, deprecated::TopologicalMesh &mesh)
const OpenMesh::HPropHandleT< Index > & getInputTriangleMeshIndexPropHandle() const
const OpenMesh::HPropHandleT< Index > & getOutputTriangleMeshIndexPropHandle() const
HalfedgeHandle halfedge_handle(VertexHandle vh, FaceHandle fh) const
@ Geometry
"Geometry" render objects are those loaded using Radium::IO and generated by GeometrySystem
hepler function to manage enum as underlying types in VariableSet