BlenderTessellator.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. /*
  2. Open Asset Import Library (assimp)
  3. ----------------------------------------------------------------------
  4. Copyright (c) 2006-2013, assimp team
  5. All rights reserved.
  6. Redistribution and use of this software in source and binary forms,
  7. with or without modification, are permitted provided that the
  8. following conditions are met:
  9. * Redistributions of source code must retain the above
  10. copyright notice, this list of conditions and the
  11. following disclaimer.
  12. * Redistributions in binary form must reproduce the above
  13. copyright notice, this list of conditions and the
  14. following disclaimer in the documentation and/or other
  15. materials provided with the distribution.
  16. * Neither the name of the assimp team, nor the names of its
  17. contributors may be used to endorse or promote products
  18. derived from this software without specific prior
  19. written permission of the assimp team.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. ----------------------------------------------------------------------
  32. */
  33. /** @file BlenderTessellator.cpp
  34. * @brief A simple tessellation wrapper
  35. */
  36. #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
  37. #include "BlenderDNA.h"
  38. #include "BlenderScene.h"
  39. #include "BlenderBMesh.h"
  40. #include "BlenderTessellator.h"
  41. static const unsigned int BLEND_TESS_MAGIC = 0x83ed9ac3;
  42. #if ASSIMP_BLEND_WITH_GLU_TESSELLATE
  43. namspace Assimp
  44. {
  45. template< > const std::string LogFunctions< BlenderTessellatorGL >::log_prefix = "BLEND_TESS_GL: ";
  46. }
  47. using namespace Assimp;
  48. using namespace Assimp::Blender;
  49. #ifndef CALLBACK
  50. #define CALLBACK
  51. #endif
  52. // ------------------------------------------------------------------------------------------------
  53. BlenderTessellatorGL::BlenderTessellatorGL( BlenderBMeshConverter& converter ):
  54. converter( &converter )
  55. {
  56. }
  57. // ------------------------------------------------------------------------------------------------
  58. BlenderTessellatorGL::~BlenderTessellatorGL( )
  59. {
  60. }
  61. // ------------------------------------------------------------------------------------------------
  62. void BlenderTessellatorGL::Tessellate( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
  63. {
  64. AssertVertexCount( vertexCount );
  65. std::vector< VertexGL > polyLoopGL;
  66. GenerateLoopVerts( polyLoopGL, polyLoop, vertexCount, vertices );
  67. TessDataGL tessData;
  68. Tesssellate( polyLoopGL, tessData );
  69. TriangulateDrawCalls( tessData );
  70. }
  71. // ------------------------------------------------------------------------------------------------
  72. void BlenderTessellatorGL::AssertVertexCount( int vertexCount )
  73. {
  74. if ( vertexCount <= 4 )
  75. {
  76. ThrowException( "Expected more than 4 vertices for tessellation" );
  77. }
  78. }
  79. // ------------------------------------------------------------------------------------------------
  80. void BlenderTessellatorGL::GenerateLoopVerts( std::vector< VertexGL >& polyLoopGL, const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
  81. {
  82. for ( int i = 0; i < vertexCount; ++i )
  83. {
  84. const MLoop& loopItem = polyLoop[ i ];
  85. const MVert& vertex = vertices[ loopItem.v ];
  86. polyLoopGL.push_back( VertexGL( vertex.co[ 0 ], vertex.co[ 1 ], vertex.co[ 2 ], loopItem.v, BLEND_TESS_MAGIC ) );
  87. }
  88. }
  89. // ------------------------------------------------------------------------------------------------
  90. void BlenderTessellatorGL::Tesssellate( std::vector< VertexGL >& polyLoopGL, TessDataGL& tessData )
  91. {
  92. GLUtesselator* tessellator = gluNewTess( );
  93. gluTessCallback( tessellator, GLU_TESS_BEGIN_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateBegin ) );
  94. gluTessCallback( tessellator, GLU_TESS_END_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEnd ) );
  95. gluTessCallback( tessellator, GLU_TESS_VERTEX_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateVertex ) );
  96. gluTessCallback( tessellator, GLU_TESS_COMBINE_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateCombine ) );
  97. gluTessCallback( tessellator, GLU_TESS_EDGE_FLAG_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEdgeFlag ) );
  98. gluTessCallback( tessellator, GLU_TESS_ERROR_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateError ) );
  99. gluTessProperty( tessellator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO );
  100. gluTessBeginPolygon( tessellator, &tessData );
  101. gluTessBeginContour( tessellator );
  102. for ( unsigned int i = 0; i < polyLoopGL.size( ); ++i )
  103. {
  104. gluTessVertex( tessellator, reinterpret_cast< GLdouble* >( &polyLoopGL[ i ] ), &polyLoopGL[ i ] );
  105. }
  106. gluTessEndContour( tessellator );
  107. gluTessEndPolygon( tessellator );
  108. }
  109. // ------------------------------------------------------------------------------------------------
  110. void BlenderTessellatorGL::TriangulateDrawCalls( const TessDataGL& tessData )
  111. {
  112. // NOTE - Because we are supplying a callback to GLU_TESS_EDGE_FLAG_DATA we don't technically
  113. // need support for GL_TRIANGLE_STRIP and GL_TRIANGLE_FAN but we'll keep it here in case
  114. // GLU tessellate changes or tristrips and fans are wanted.
  115. // See: http://www.opengl.org/sdk/docs/man2/xhtml/gluTessCallback.xml
  116. for ( unsigned int i = 0; i < tessData.drawCalls.size( ); ++i )
  117. {
  118. const DrawCallGL& drawCallGL = tessData.drawCalls[ i ];
  119. const VertexGL* vertices = &tessData.vertices[ drawCallGL.baseVertex ];
  120. if ( drawCallGL.drawMode == GL_TRIANGLES )
  121. {
  122. MakeFacesFromTris( vertices, drawCallGL.vertexCount );
  123. }
  124. else if ( drawCallGL.drawMode == GL_TRIANGLE_STRIP )
  125. {
  126. MakeFacesFromTriStrip( vertices, drawCallGL.vertexCount );
  127. }
  128. else if ( drawCallGL.drawMode == GL_TRIANGLE_FAN )
  129. {
  130. MakeFacesFromTriFan( vertices, drawCallGL.vertexCount );
  131. }
  132. }
  133. }
  134. // ------------------------------------------------------------------------------------------------
  135. void BlenderTessellatorGL::MakeFacesFromTris( const VertexGL* vertices, int vertexCount )
  136. {
  137. int triangleCount = vertexCount / 3;
  138. for ( int i = 0; i < triangleCount; ++i )
  139. {
  140. int vertexBase = i * 3;
  141. converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
  142. }
  143. }
  144. // ------------------------------------------------------------------------------------------------
  145. void BlenderTessellatorGL::MakeFacesFromTriStrip( const VertexGL* vertices, int vertexCount )
  146. {
  147. int triangleCount = vertexCount - 2;
  148. for ( int i = 0; i < triangleCount; ++i )
  149. {
  150. int vertexBase = i;
  151. converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
  152. }
  153. }
  154. // ------------------------------------------------------------------------------------------------
  155. void BlenderTessellatorGL::MakeFacesFromTriFan( const VertexGL* vertices, int vertexCount )
  156. {
  157. int triangleCount = vertexCount - 2;
  158. for ( int i = 0; i < triangleCount; ++i )
  159. {
  160. int vertexBase = i;
  161. converter->AddFace( vertices[ 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
  162. }
  163. }
  164. // ------------------------------------------------------------------------------------------------
  165. void BlenderTessellatorGL::TessellateBegin( GLenum drawModeGL, void* userData )
  166. {
  167. TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData );
  168. tessData.drawCalls.push_back( DrawCallGL( drawModeGL, tessData.vertices.size( ) ) );
  169. }
  170. // ------------------------------------------------------------------------------------------------
  171. void BlenderTessellatorGL::TessellateEnd( void* )
  172. {
  173. // Do nothing
  174. }
  175. // ------------------------------------------------------------------------------------------------
  176. void BlenderTessellatorGL::TessellateVertex( const void* vtxData, void* userData )
  177. {
  178. TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData );
  179. const VertexGL& vertex = *reinterpret_cast< const VertexGL* >( vtxData );
  180. if ( vertex.magic != BLEND_TESS_MAGIC )
  181. {
  182. ThrowException( "Point returned by GLU Tessellate was probably not one of ours. This indicates we need a new way to store vertex information" );
  183. }
  184. tessData.vertices.push_back( vertex );
  185. if ( tessData.drawCalls.size( ) == 0 )
  186. {
  187. ThrowException( "\"Vertex\" callback received before \"Begin\"" );
  188. }
  189. ++( tessData.drawCalls.back( ).vertexCount );
  190. }
  191. // ------------------------------------------------------------------------------------------------
  192. void BlenderTessellatorGL::TessellateCombine( const GLdouble intersection[ 3 ], const GLdouble* [ 4 ], const GLfloat [ 4 ], GLdouble** out, void* userData )
  193. {
  194. ThrowException( "Intersected polygon loops are not yet supported" );
  195. }
  196. // ------------------------------------------------------------------------------------------------
  197. void BlenderTessellatorGL::TessellateEdgeFlag( GLboolean, void* )
  198. {
  199. // Do nothing
  200. }
  201. // ------------------------------------------------------------------------------------------------
  202. void BlenderTessellatorGL::TessellateError( GLenum errorCode, void* )
  203. {
  204. ThrowException( reinterpret_cast< const char* >( gluErrorString( errorCode ) ) );
  205. }
  206. #endif // ASSIMP_BLEND_WITH_GLU_TESSELLATE
  207. #if ASSIMP_BLEND_WITH_POLY_2_TRI
  208. namespace Assimp
  209. {
  210. template< > const std::string LogFunctions< BlenderTessellatorP2T >::log_prefix = "BLEND_TESS_P2T: ";
  211. }
  212. using namespace Assimp;
  213. using namespace Assimp::Blender;
  214. // ------------------------------------------------------------------------------------------------
  215. BlenderTessellatorP2T::BlenderTessellatorP2T( BlenderBMeshConverter& converter ):
  216. converter( &converter )
  217. {
  218. }
  219. // ------------------------------------------------------------------------------------------------
  220. BlenderTessellatorP2T::~BlenderTessellatorP2T( )
  221. {
  222. }
  223. // ------------------------------------------------------------------------------------------------
  224. void BlenderTessellatorP2T::Tessellate( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
  225. {
  226. AssertVertexCount( vertexCount );
  227. // NOTE - We have to hope that points in a Blender polygon are roughly on the same plane.
  228. // There may be some triangulation artifacts if they are wildly different.
  229. std::vector< PointP2T > points;
  230. Copy3DVertices( polyLoop, vertexCount, vertices, points );
  231. PlaneP2T plane = FindLLSQPlane( points );
  232. aiMatrix4x4 transform = GeneratePointTransformMatrix( plane );
  233. TransformAndFlattenVectices( transform, points );
  234. std::vector< p2t::Point* > pointRefs;
  235. ReferencePoints( points, pointRefs );
  236. p2t::CDT cdt( pointRefs );
  237. cdt.Triangulate( );
  238. std::vector< p2t::Triangle* > triangles = cdt.GetTriangles( );
  239. MakeFacesFromTriangles( triangles );
  240. }
  241. // ------------------------------------------------------------------------------------------------
  242. void BlenderTessellatorP2T::AssertVertexCount( int vertexCount )
  243. {
  244. if ( vertexCount <= 4 )
  245. {
  246. ThrowException( "Expected more than 4 vertices for tessellation" );
  247. }
  248. }
  249. // ------------------------------------------------------------------------------------------------
  250. void BlenderTessellatorP2T::Copy3DVertices( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices, std::vector< PointP2T >& points ) const
  251. {
  252. points.resize( vertexCount );
  253. for ( int i = 0; i < vertexCount; ++i )
  254. {
  255. const MLoop& loop = polyLoop[ i ];
  256. const MVert& vert = vertices[ loop.v ];
  257. PointP2T& point = points[ i ];
  258. point.point3D.Set( vert.co[ 0 ], vert.co[ 1 ], vert.co[ 2 ] );
  259. point.index = loop.v;
  260. point.magic = BLEND_TESS_MAGIC;
  261. }
  262. }
  263. // ------------------------------------------------------------------------------------------------
  264. aiMatrix4x4 BlenderTessellatorP2T::GeneratePointTransformMatrix( const Blender::PlaneP2T& plane ) const
  265. {
  266. aiVector3D sideA( 1.0f, 0.0f, 0.0f );
  267. if ( std::fabs( plane.normal * sideA ) > 0.999f )
  268. {
  269. sideA = aiVector3D( 0.0f, 1.0f, 0.0f );
  270. }
  271. aiVector3D sideB( plane.normal ^ sideA );
  272. sideB.Normalize( );
  273. sideA = sideB ^ plane.normal;
  274. aiMatrix4x4 result;
  275. result.a1 = sideA.x;
  276. result.a2 = sideA.y;
  277. result.a3 = sideA.z;
  278. result.b1 = sideB.x;
  279. result.b2 = sideB.y;
  280. result.b3 = sideB.z;
  281. result.c1 = plane.normal.x;
  282. result.c2 = plane.normal.y;
  283. result.c3 = plane.normal.z;
  284. result.a4 = plane.centre.x;
  285. result.b4 = plane.centre.y;
  286. result.c4 = plane.centre.z;
  287. result.Inverse( );
  288. return result;
  289. }
  290. // ------------------------------------------------------------------------------------------------
  291. void BlenderTessellatorP2T::TransformAndFlattenVectices( const aiMatrix4x4& transform, std::vector< Blender::PointP2T >& vertices ) const
  292. {
  293. for ( unsigned int i = 0; i < vertices.size( ); ++i )
  294. {
  295. PointP2T& point = vertices[ i ];
  296. point.point3D = transform * point.point3D;
  297. point.point2D.set( point.point3D.y, point.point3D.z );
  298. }
  299. }
  300. // ------------------------------------------------------------------------------------------------
  301. void BlenderTessellatorP2T::ReferencePoints( std::vector< Blender::PointP2T >& points, std::vector< p2t::Point* >& pointRefs ) const
  302. {
  303. pointRefs.resize( points.size( ) );
  304. for ( unsigned int i = 0; i < points.size( ); ++i )
  305. {
  306. pointRefs[ i ] = &points[ i ].point2D;
  307. }
  308. }
  309. // ------------------------------------------------------------------------------------------------
  310. // Yes this is filthy... but we have no choice
  311. #define OffsetOf( Class, Member ) ( static_cast< unsigned int >( \
  312. reinterpret_cast<uint8_t*>(&( reinterpret_cast< Class* >( NULL )->*( &Class::Member ) )) - \
  313. static_cast<uint8_t*>(NULL) ) )
  314. inline PointP2T& BlenderTessellatorP2T::GetActualPointStructure( p2t::Point& point ) const
  315. {
  316. unsigned int pointOffset = OffsetOf( PointP2T, point2D );
  317. PointP2T& pointStruct = *reinterpret_cast< PointP2T* >( reinterpret_cast< char* >( &point ) - pointOffset );
  318. if ( pointStruct.magic != static_cast<int>( BLEND_TESS_MAGIC ) )
  319. {
  320. ThrowException( "Point returned by poly2tri was probably not one of ours. This indicates we need a new way to store vertex information" );
  321. }
  322. return pointStruct;
  323. }
  324. // ------------------------------------------------------------------------------------------------
  325. void BlenderTessellatorP2T::MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const
  326. {
  327. for ( unsigned int i = 0; i < triangles.size( ); ++i )
  328. {
  329. p2t::Triangle& Triangle = *triangles[ i ];
  330. PointP2T& pointA = GetActualPointStructure( *Triangle.GetPoint( 0 ) );
  331. PointP2T& pointB = GetActualPointStructure( *Triangle.GetPoint( 1 ) );
  332. PointP2T& pointC = GetActualPointStructure( *Triangle.GetPoint( 2 ) );
  333. converter->AddFace( pointA.index, pointB.index, pointC.index );
  334. }
  335. }
  336. // ------------------------------------------------------------------------------------------------
  337. inline float p2tMax( float a, float b )
  338. {
  339. return a > b ? a : b;
  340. }
  341. // ------------------------------------------------------------------------------------------------
  342. // Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
  343. float BlenderTessellatorP2T::FindLargestMatrixElem( const aiMatrix3x3& mtx ) const
  344. {
  345. float result = 0.0f;
  346. for ( int x = 0; x < 3; ++x )
  347. {
  348. for ( int y = 0; y < 3; ++y )
  349. {
  350. result = p2tMax( std::fabs( mtx[ x ][ y ] ), result );
  351. }
  352. }
  353. return result;
  354. }
  355. // ------------------------------------------------------------------------------------------------
  356. // Aparently Assimp doesn't have matrix scaling
  357. aiMatrix3x3 BlenderTessellatorP2T::ScaleMatrix( const aiMatrix3x3& mtx, float scale ) const
  358. {
  359. aiMatrix3x3 result;
  360. for ( int x = 0; x < 3; ++x )
  361. {
  362. for ( int y = 0; y < 3; ++y )
  363. {
  364. result[ x ][ y ] = mtx[ x ][ y ] * scale;
  365. }
  366. }
  367. return result;
  368. }
  369. // ------------------------------------------------------------------------------------------------
  370. // Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
  371. aiVector3D BlenderTessellatorP2T::GetEigenVectorFromLargestEigenValue( const aiMatrix3x3& mtx ) const
  372. {
  373. float scale = FindLargestMatrixElem( mtx );
  374. aiMatrix3x3 mc = ScaleMatrix( mtx, 1.0f / scale );
  375. mc = mc * mc * mc;
  376. aiVector3D v( 1.0f );
  377. aiVector3D lastV = v;
  378. for ( int i = 0; i < 100; ++i )
  379. {
  380. v = mc * v;
  381. v.Normalize( );
  382. if ( ( v - lastV ).SquareLength( ) < 1e-16f )
  383. {
  384. break;
  385. }
  386. lastV = v;
  387. }
  388. return v;
  389. }
  390. // ------------------------------------------------------------------------------------------------
  391. // Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
  392. PlaneP2T BlenderTessellatorP2T::FindLLSQPlane( const std::vector< PointP2T >& points ) const
  393. {
  394. PlaneP2T result;
  395. aiVector3D sum( 0.0f );
  396. for ( unsigned int i = 0; i < points.size( ); ++i )
  397. {
  398. sum += points[ i ].point3D;
  399. }
  400. result.centre = sum * ( 1.0f / points.size( ) );
  401. float sumXX = 0.0f;
  402. float sumXY = 0.0f;
  403. float sumXZ = 0.0f;
  404. float sumYY = 0.0f;
  405. float sumYZ = 0.0f;
  406. float sumZZ = 0.0f;
  407. for ( unsigned int i = 0; i < points.size( ); ++i )
  408. {
  409. aiVector3D offset = points[ i ].point3D - result.centre;
  410. sumXX += offset.x * offset.x;
  411. sumXY += offset.x * offset.y;
  412. sumXZ += offset.x * offset.z;
  413. sumYY += offset.y * offset.y;
  414. sumYZ += offset.y * offset.z;
  415. sumZZ += offset.z * offset.z;
  416. }
  417. aiMatrix3x3 mtx( sumXX, sumXY, sumXZ, sumXY, sumYY, sumYZ, sumXZ, sumYZ, sumZZ );
  418. float det = mtx.Determinant( );
  419. if ( det == 0.0f )
  420. {
  421. result.normal = aiVector3D( 0.0f );
  422. }
  423. else
  424. {
  425. aiMatrix3x3 invMtx = mtx;
  426. invMtx.Inverse( );
  427. result.normal = GetEigenVectorFromLargestEigenValue( invMtx );
  428. }
  429. return result;
  430. }
  431. #endif // ASSIMP_BLEND_WITH_POLY_2_TRI
  432. #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER