Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

BlenderTessellator.cpp 18 KiB

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