GltfImporterMesh.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Importer/GltfImporter.h>
  6. #include <AnKi/Util/StringList.h>
  7. #include <AnKi/Collision/Plane.h>
  8. #include <AnKi/Collision/Functions.h>
  9. #include <AnKi/Resource/MeshBinary.h>
  10. #include <AnKi/Shaders/Include/ModelTypes.h>
  11. #include <MeshOptimizer/meshoptimizer.h>
  12. namespace anki {
  13. static U cgltfComponentCount(cgltf_type type)
  14. {
  15. U out;
  16. switch(type)
  17. {
  18. case cgltf_type_scalar:
  19. out = 1;
  20. break;
  21. case cgltf_type_vec2:
  22. out = 2;
  23. break;
  24. case cgltf_type_vec3:
  25. out = 3;
  26. break;
  27. case cgltf_type_vec4:
  28. out = 4;
  29. break;
  30. default:
  31. ANKI_ASSERT(!"TODO");
  32. out = 0;
  33. }
  34. return out;
  35. }
  36. static U cgltfComponentSize(cgltf_component_type type)
  37. {
  38. U out;
  39. switch(type)
  40. {
  41. case cgltf_component_type_r_32f:
  42. out = sizeof(F32);
  43. break;
  44. case cgltf_component_type_r_16u:
  45. out = sizeof(U16);
  46. break;
  47. default:
  48. ANKI_ASSERT(!"TODO");
  49. out = 0;
  50. }
  51. return out;
  52. }
  53. #if 0
  54. static U calcImplicitStride(const cgltf_attribute& attrib)
  55. {
  56. return cgltfComponentCount(attrib.data->type) * cgltfComponentSize(attrib.data->component_type);
  57. }
  58. #endif
  59. template<typename T>
  60. static Error checkAttribute(const cgltf_attribute& attrib)
  61. {
  62. if(cgltfComponentCount(attrib.data->type) != T::COMPONENT_COUNT)
  63. {
  64. ANKI_IMPORTER_LOGE("Wrong component count for attribute: %s", attrib.name);
  65. return Error::USER_DATA;
  66. }
  67. if(cgltfComponentSize(attrib.data->component_type) != sizeof(typename T::Scalar))
  68. {
  69. ANKI_IMPORTER_LOGE("Incompatible type: %s", attrib.name);
  70. return Error::USER_DATA;
  71. }
  72. ANKI_ASSERT(attrib.data);
  73. const U count = attrib.data->count;
  74. if(count == 0)
  75. {
  76. ANKI_IMPORTER_LOGE("Zero vertex count");
  77. return Error::USER_DATA;
  78. }
  79. return Error::NONE;
  80. }
  81. /// Align after laying a buffer in a file.
  82. static Error alignBufferInFile(PtrSize bufferSize, File& file)
  83. {
  84. const PtrSize alignedBufferSize = getAlignedRoundUp(MESH_BINARY_BUFFER_ALIGNMENT, bufferSize);
  85. const PtrSize extraBytes = alignedBufferSize - bufferSize;
  86. for(U32 i = 0; i < extraBytes; ++i)
  87. {
  88. U8 value = 0;
  89. ANKI_CHECK(file.write(&value, sizeof(value)));
  90. }
  91. return Error::NONE;
  92. }
  93. class TempVertex
  94. {
  95. public:
  96. Vec3 m_position;
  97. F32 m_padding0;
  98. Vec4 m_tangent;
  99. Vec4 m_boneWeights;
  100. Vec3 m_normal;
  101. Vec2 m_uv;
  102. U16Vec4 m_boneIds;
  103. F32 m_padding1;
  104. TempVertex()
  105. {
  106. zeroMemory(*this);
  107. }
  108. };
  109. static_assert(sizeof(TempVertex) == 5 * sizeof(Vec4), "Will be hashed");
  110. class SubMesh
  111. {
  112. public:
  113. DynamicArrayAuto<TempVertex> m_verts;
  114. DynamicArrayAuto<U32> m_indices;
  115. Vec3 m_aabbMin = Vec3(MAX_F32);
  116. Vec3 m_aabbMax = Vec3(MIN_F32);
  117. U32 m_firstIdx = MAX_U32;
  118. U32 m_idxCount = MAX_U32;
  119. SubMesh(GenericMemoryPoolAllocator<U8>& alloc)
  120. : m_verts(alloc)
  121. , m_indices(alloc)
  122. {
  123. }
  124. };
  125. static void reindexSubmesh(SubMesh& submesh, GenericMemoryPoolAllocator<U8> alloc)
  126. {
  127. const U32 vertSize = sizeof(submesh.m_verts[0]);
  128. DynamicArrayAuto<U32> remap(alloc);
  129. remap.create(submesh.m_verts.getSize(), 0);
  130. const U32 vertCount = U32(meshopt_generateVertexRemap(&remap[0], &submesh.m_indices[0], submesh.m_indices.getSize(),
  131. &submesh.m_verts[0], submesh.m_verts.getSize(), vertSize));
  132. DynamicArrayAuto<U32> newIdxArray(alloc);
  133. newIdxArray.create(submesh.m_indices.getSize(), 0);
  134. DynamicArrayAuto<TempVertex> newVertArray(alloc);
  135. newVertArray.create(vertCount);
  136. meshopt_remapIndexBuffer(&newIdxArray[0], &submesh.m_indices[0], submesh.m_indices.getSize(), &remap[0]);
  137. meshopt_remapVertexBuffer(&newVertArray[0], &submesh.m_verts[0], submesh.m_verts.getSize(), vertSize, &remap[0]);
  138. submesh.m_indices = std::move(newIdxArray);
  139. submesh.m_verts = std::move(newVertArray);
  140. }
  141. /// Optimize a submesh using meshoptimizer.
  142. static void optimizeSubmesh(SubMesh& submesh, GenericMemoryPoolAllocator<U8> alloc)
  143. {
  144. const PtrSize vertSize = sizeof(submesh.m_verts[0]);
  145. // Vert cache
  146. {
  147. DynamicArrayAuto<U32> newIdxArray(alloc);
  148. newIdxArray.create(submesh.m_indices.getSize(), 0);
  149. meshopt_optimizeVertexCache(&newIdxArray[0], &submesh.m_indices[0], submesh.m_indices.getSize(),
  150. submesh.m_verts.getSize());
  151. submesh.m_indices = std::move(newIdxArray);
  152. }
  153. // Overdraw
  154. {
  155. DynamicArrayAuto<U32> newIdxArray(alloc);
  156. newIdxArray.create(submesh.m_indices.getSize(), 0);
  157. meshopt_optimizeOverdraw(&newIdxArray[0], &submesh.m_indices[0], submesh.m_indices.getSize(),
  158. &submesh.m_verts[0].m_position.x(), submesh.m_verts.getSize(), vertSize, 1.05f);
  159. submesh.m_indices = std::move(newIdxArray);
  160. }
  161. // Vert fetch
  162. {
  163. DynamicArrayAuto<TempVertex> newVertArray(alloc);
  164. newVertArray.create(submesh.m_verts.getSize());
  165. const U32 newVertCount = U32(meshopt_optimizeVertexFetch(&newVertArray[0],
  166. &submesh.m_indices[0], // Inplace
  167. submesh.m_indices.getSize(), &submesh.m_verts[0],
  168. submesh.m_verts.getSize(), vertSize));
  169. if(newVertCount != submesh.m_verts.getSize())
  170. {
  171. newVertArray.resize(newVertCount);
  172. }
  173. ANKI_ASSERT(newVertArray.getSize() == newVertCount);
  174. submesh.m_verts = std::move(newVertArray);
  175. }
  176. }
  177. /// Decimate a submesh using meshoptimizer.
  178. static void decimateSubmesh(F32 factor, SubMesh& submesh, GenericMemoryPoolAllocator<U8> alloc)
  179. {
  180. ANKI_ASSERT(factor > 0.0f && factor < 1.0f);
  181. const PtrSize targetIndexCount = PtrSize(F32(submesh.m_indices.getSize() / 3) * factor) * 3;
  182. if(targetIndexCount == 0)
  183. {
  184. return;
  185. }
  186. // Decimate
  187. DynamicArrayAuto<U32> newIndices(alloc, submesh.m_indices.getSize());
  188. newIndices.resize(U32(meshopt_simplify(&newIndices[0], &submesh.m_indices[0], submesh.m_indices.getSize(),
  189. &submesh.m_verts[0].m_position.x(), submesh.m_verts.getSize(),
  190. sizeof(TempVertex), targetIndexCount, 1e-2f)));
  191. // Re-pack
  192. DynamicArrayAuto<U32> reindexedIndices(alloc);
  193. DynamicArrayAuto<TempVertex> newVerts(alloc);
  194. HashMapAuto<U32, U32> vertexStored(alloc);
  195. for(U32 idx = 0; idx < newIndices.getSize(); ++idx)
  196. {
  197. U32 newIdx;
  198. auto it = vertexStored.find(newIndices[idx]);
  199. if(it == vertexStored.getEnd())
  200. {
  201. // Store the vertex
  202. newVerts.emplaceBack(submesh.m_verts[newIndices[idx]]);
  203. newIdx = newVerts.getSize() - 1;
  204. vertexStored.emplace(newIndices[idx], newIdx);
  205. }
  206. else
  207. {
  208. // Already stored
  209. newIdx = *it;
  210. }
  211. // Store the new index
  212. reindexedIndices.emplaceBack(newIdx);
  213. }
  214. // Move back
  215. submesh.m_indices = std::move(reindexedIndices);
  216. submesh.m_verts = std::move(newVerts);
  217. }
  218. U32 GltfImporter::getMeshTotalVertexCount(const cgltf_mesh& mesh)
  219. {
  220. U32 totalVertexCount = 0;
  221. for(const cgltf_primitive* primitive = mesh.primitives; primitive < mesh.primitives + mesh.primitives_count;
  222. ++primitive)
  223. {
  224. totalVertexCount += U32(primitive->attributes[0].data->count);
  225. }
  226. return totalVertexCount;
  227. }
  228. Error GltfImporter::writeMesh(const cgltf_mesh& mesh, CString nameOverride, F32 decimateFactor)
  229. {
  230. StringAuto fname(m_alloc);
  231. fname.sprintf("%s%s.ankimesh", m_outDir.cstr(), (nameOverride.isEmpty()) ? mesh.name : nameOverride.cstr());
  232. ANKI_IMPORTER_LOGI("Importing mesh (%s, decimate factor %f): %s", (m_optimizeMeshes) ? "optimze" : "WON'T optimize",
  233. decimateFactor, fname.cstr());
  234. ListAuto<SubMesh> submeshes(m_alloc);
  235. U32 totalIndexCount = 0;
  236. U32 totalVertexCount = 0;
  237. Vec3 aabbMin(MAX_F32);
  238. Vec3 aabbMax(MIN_F32);
  239. F32 maxUvDistance = MIN_F32;
  240. F32 minUvDistance = MAX_F32;
  241. Bool hasBoneWeights = false;
  242. // Iterate primitives. Every primitive is a submesh
  243. for(const cgltf_primitive* primitive = mesh.primitives; primitive < mesh.primitives + mesh.primitives_count;
  244. ++primitive)
  245. {
  246. if(primitive->type != cgltf_primitive_type_triangles)
  247. {
  248. ANKI_IMPORTER_LOGE("Expecting triangles got %d", primitive->type);
  249. return Error::USER_DATA;
  250. }
  251. SubMesh& submesh = *submeshes.emplaceBack(m_alloc);
  252. U minVertCount = MAX_U;
  253. U maxVertCount = MIN_U;
  254. for(const cgltf_attribute* attrib = primitive->attributes;
  255. attrib < primitive->attributes + primitive->attributes_count; ++attrib)
  256. {
  257. minVertCount = min(minVertCount, U(attrib->data->count));
  258. maxVertCount = max(maxVertCount, U(attrib->data->count));
  259. }
  260. if(maxVertCount == 0 || minVertCount != maxVertCount)
  261. {
  262. ANKI_IMPORTER_LOGE("Wrong number of vertices");
  263. return Error::USER_DATA;
  264. }
  265. U32 vertCount = U32(primitive->attributes[0].data->count);
  266. submesh.m_verts.create(vertCount);
  267. //
  268. // Gather positions + normals + UVs
  269. //
  270. for(const cgltf_attribute* attrib = primitive->attributes;
  271. attrib < primitive->attributes + primitive->attributes_count; ++attrib)
  272. {
  273. if(attrib->type == cgltf_attribute_type_position)
  274. {
  275. U32 count = 0;
  276. ANKI_CHECK(checkAttribute<Vec3>(*attrib));
  277. visitAccessor<Vec3>(*attrib->data, [&](const Vec3& pos) {
  278. submesh.m_aabbMin = submesh.m_aabbMin.min(pos);
  279. submesh.m_aabbMax = submesh.m_aabbMax.max(pos);
  280. submesh.m_verts[count++].m_position = pos;
  281. });
  282. }
  283. else if(attrib->type == cgltf_attribute_type_normal)
  284. {
  285. U32 count = 0;
  286. ANKI_CHECK(checkAttribute<Vec3>(*attrib));
  287. visitAccessor<Vec3>(*attrib->data, [&](const Vec3& normal) {
  288. submesh.m_verts[count++].m_normal = normal;
  289. });
  290. }
  291. else if(attrib->type == cgltf_attribute_type_texcoord && CString(attrib->name) == "TEXCOORD_0")
  292. {
  293. U32 count = 0;
  294. ANKI_CHECK(checkAttribute<Vec2>(*attrib));
  295. visitAccessor<Vec2>(*attrib->data, [&](const Vec2& uv) {
  296. maxUvDistance = max(maxUvDistance, max(uv.x(), uv.y()));
  297. minUvDistance = min(minUvDistance, min(uv.x(), uv.y()));
  298. submesh.m_verts[count++].m_uv = uv;
  299. });
  300. }
  301. else if(attrib->type == cgltf_attribute_type_joints)
  302. {
  303. U32 count = 0;
  304. ANKI_CHECK(checkAttribute<U16Vec4>(*attrib));
  305. visitAccessor<U16Vec4>(*attrib->data, [&](const U16Vec4& x) {
  306. submesh.m_verts[count++].m_boneIds = x;
  307. });
  308. hasBoneWeights = true;
  309. }
  310. else if(attrib->type == cgltf_attribute_type_weights)
  311. {
  312. U32 count = 0;
  313. ANKI_CHECK(checkAttribute<Vec4>(*attrib));
  314. visitAccessor<Vec4>(*attrib->data, [&](const Vec4& bw) {
  315. submesh.m_verts[count++].m_boneWeights = bw;
  316. });
  317. }
  318. else
  319. {
  320. ANKI_IMPORTER_LOGW("Ignoring attribute: %s", attrib->name);
  321. }
  322. }
  323. aabbMin = aabbMin.min(submesh.m_aabbMin);
  324. // Bump aabbMax a bit
  325. submesh.m_aabbMax += EPSILON * 10.0f;
  326. aabbMax = aabbMax.max(submesh.m_aabbMax);
  327. //
  328. // Fix normals. If normal A and normal B have the same position then try to merge them
  329. //
  330. for(U32 v = 0; v < vertCount; ++v)
  331. {
  332. const Vec3& pos = submesh.m_verts[v].m_position;
  333. Vec3& normal = submesh.m_verts[v].m_normal;
  334. for(U32 prevV = 0; prevV < v; ++prevV)
  335. {
  336. const Vec3& otherPos = submesh.m_verts[prevV].m_position;
  337. // Check the positions dist
  338. const F32 posDist = (otherPos - pos).getLengthSquared();
  339. if(posDist > EPSILON * EPSILON)
  340. {
  341. continue;
  342. }
  343. // Check angle of the normals
  344. Vec3& otherNormal = submesh.m_verts[prevV].m_normal;
  345. const F32 ang = acos(clamp(otherNormal.dot(normal), -1.0f, 1.0f));
  346. if(ang > m_normalsMergeAngle)
  347. {
  348. continue;
  349. }
  350. // Merge normals
  351. const Vec3 newNormal = (otherNormal + normal).getNormalized();
  352. normal = newNormal;
  353. otherNormal = newNormal;
  354. }
  355. }
  356. //
  357. // Load indices
  358. //
  359. {
  360. ANKI_ASSERT(primitive->indices);
  361. if(primitive->indices->count == 0 || (primitive->indices->count % 3) != 0)
  362. {
  363. ANKI_IMPORTER_LOGE("Incorect index count: %lu", primitive->indices->count);
  364. return Error::USER_DATA;
  365. }
  366. submesh.m_indices.create(U32(primitive->indices->count));
  367. const U8* base = static_cast<const U8*>(primitive->indices->buffer_view->buffer->data)
  368. + primitive->indices->offset + primitive->indices->buffer_view->offset;
  369. for(U32 i = 0; i < primitive->indices->count; ++i)
  370. {
  371. U32 idx;
  372. if(primitive->indices->component_type == cgltf_component_type_r_32u)
  373. {
  374. idx = *reinterpret_cast<const U32*>(base + sizeof(U32) * i);
  375. }
  376. else if(primitive->indices->component_type == cgltf_component_type_r_16u)
  377. {
  378. idx = *reinterpret_cast<const U16*>(base + sizeof(U16) * i);
  379. }
  380. else
  381. {
  382. ANKI_ASSERT(0);
  383. idx = 0;
  384. }
  385. submesh.m_indices[i] = idx;
  386. }
  387. }
  388. // Re-index meshes now and
  389. // - before the tanget calculation because that will create many unique verts
  390. // - after normal fix because that will create verts with same attributes
  391. if(m_optimizeMeshes || decimateFactor < 1.0f)
  392. {
  393. reindexSubmesh(submesh, m_alloc);
  394. vertCount = submesh.m_verts.getSize();
  395. }
  396. //
  397. // Compute tangent
  398. //
  399. {
  400. DynamicArrayAuto<Vec3> bitangents(m_alloc);
  401. bitangents.create(vertCount, Vec3(0.0f));
  402. for(U32 i = 0; i < submesh.m_indices.getSize(); i += 3)
  403. {
  404. const U32 i0 = submesh.m_indices[i + 0];
  405. const U32 i1 = submesh.m_indices[i + 1];
  406. const U32 i2 = submesh.m_indices[i + 2];
  407. const Vec3& v0 = submesh.m_verts[i0].m_position;
  408. const Vec3& v1 = submesh.m_verts[i1].m_position;
  409. const Vec3& v2 = submesh.m_verts[i2].m_position;
  410. const Vec3 edge01 = v1 - v0;
  411. const Vec3 edge02 = v2 - v0;
  412. const Vec2 uvedge01 = submesh.m_verts[i1].m_uv - submesh.m_verts[i0].m_uv;
  413. const Vec2 uvedge02 = submesh.m_verts[i2].m_uv - submesh.m_verts[i0].m_uv;
  414. F32 det = (uvedge01.y() * uvedge02.x()) - (uvedge01.x() * uvedge02.y());
  415. det = (isZero(det)) ? 0.0001f : (1.0f / det);
  416. Vec3 t = (edge02 * uvedge01.y() - edge01 * uvedge02.y()) * det;
  417. Vec3 b = (edge02 * uvedge01.x() - edge01 * uvedge02.x()) * det;
  418. if(t.getLengthSquared() < EPSILON)
  419. {
  420. t = Vec3(1.0f, 0.0f, 0.0f); // Something random
  421. }
  422. else
  423. {
  424. t.normalize();
  425. }
  426. if(b.getLengthSquared() < EPSILON)
  427. {
  428. b = Vec3(0.0f, 1.0f, 0.0f); // Something random
  429. }
  430. else
  431. {
  432. b.normalize();
  433. }
  434. submesh.m_verts[i0].m_tangent += Vec4(t, 0.0f);
  435. submesh.m_verts[i1].m_tangent += Vec4(t, 0.0f);
  436. submesh.m_verts[i2].m_tangent += Vec4(t, 0.0f);
  437. bitangents[i0] += b;
  438. bitangents[i1] += b;
  439. bitangents[i2] += b;
  440. }
  441. for(U32 i = 0; i < vertCount; ++i)
  442. {
  443. Vec3 t = Vec3(submesh.m_verts[i].m_tangent.xyz());
  444. const Vec3& n = submesh.m_verts[i].m_normal;
  445. Vec3& b = bitangents[i];
  446. if(t.getLengthSquared() < EPSILON)
  447. {
  448. t = Vec3(1.0f, 0.0f, 0.0f); // Something random
  449. }
  450. else
  451. {
  452. t.normalize();
  453. }
  454. if(b.getLengthSquared() < EPSILON)
  455. {
  456. b = Vec3(0.0f, 1.0f, 0.0f); // Something random
  457. }
  458. else
  459. {
  460. b.normalize();
  461. }
  462. const F32 w = ((n.cross(t)).dot(b) < 0.0f) ? 1.0f : -1.0f;
  463. submesh.m_verts[i].m_tangent = Vec4(t, w);
  464. }
  465. }
  466. // Optimize
  467. if(m_optimizeMeshes)
  468. {
  469. optimizeSubmesh(submesh, m_alloc);
  470. }
  471. // Simplify
  472. if(decimateFactor < 1.0f)
  473. {
  474. decimateSubmesh(decimateFactor, submesh, m_alloc);
  475. }
  476. // Finalize
  477. if(submesh.m_indices.getSize() == 0 || submesh.m_verts.getSize() == 0)
  478. {
  479. // Digenerate
  480. submeshes.popBack();
  481. }
  482. else
  483. {
  484. // Finalize
  485. submesh.m_firstIdx = totalIndexCount;
  486. submesh.m_idxCount = submesh.m_indices.getSize();
  487. totalIndexCount += submesh.m_idxCount;
  488. totalVertexCount += submesh.m_verts.getSize();
  489. }
  490. }
  491. if(submeshes.getSize() == 0)
  492. {
  493. ANKI_IMPORTER_LOGE("Mesh contains degenerate geometry");
  494. return Error::USER_DATA;
  495. }
  496. // Find if it's a convex shape
  497. Bool convex = true;
  498. for(const SubMesh& submesh : submeshes)
  499. {
  500. for(U32 i = 0; i < submesh.m_indices.getSize(); i += 3)
  501. {
  502. const U32 i0 = submesh.m_indices[i + 0];
  503. const U32 i1 = submesh.m_indices[i + 1];
  504. const U32 i2 = submesh.m_indices[i + 2];
  505. const Vec3& v0 = submesh.m_verts[i0].m_position;
  506. const Vec3& v1 = submesh.m_verts[i1].m_position;
  507. const Vec3& v2 = submesh.m_verts[i2].m_position;
  508. if(computeTriangleArea(v0, v1, v2) <= EPSILON)
  509. {
  510. continue;
  511. }
  512. // Check that all positions are behind the plane
  513. const Plane plane(v0.xyz0(), v1.xyz0(), v2.xyz0());
  514. for(const SubMesh& submeshB : submeshes)
  515. {
  516. for(const TempVertex& vertB : submeshB.m_verts)
  517. {
  518. const F32 test = testPlane(plane, vertB.m_position.xyz0());
  519. if(test > EPSILON)
  520. {
  521. convex = false;
  522. break;
  523. }
  524. }
  525. if(!convex)
  526. {
  527. break;
  528. }
  529. }
  530. if(!convex)
  531. {
  532. break;
  533. }
  534. }
  535. }
  536. // Chose the formats of the attributes
  537. MeshBinaryHeader header;
  538. memset(&header, 0, sizeof(header));
  539. {
  540. // Positions
  541. MeshBinaryVertexAttribute& posa = header.m_vertexAttributes[VertexAttributeId::POSITION];
  542. posa.m_bufferBinding = 0;
  543. posa.m_format = Format::R32G32B32_SFLOAT;
  544. posa.m_relativeOffset = 0;
  545. posa.m_scale = 1.0f;
  546. // Normals
  547. MeshBinaryVertexAttribute& na = header.m_vertexAttributes[VertexAttributeId::NORMAL];
  548. na.m_bufferBinding = 1;
  549. na.m_format = Format::A2B10G10R10_SNORM_PACK32;
  550. na.m_relativeOffset = 0;
  551. na.m_scale = 1.0f;
  552. // Tangents
  553. MeshBinaryVertexAttribute& ta = header.m_vertexAttributes[VertexAttributeId::TANGENT];
  554. ta.m_bufferBinding = 1;
  555. ta.m_format = Format::A2B10G10R10_SNORM_PACK32;
  556. ta.m_relativeOffset = sizeof(U32);
  557. ta.m_scale = 1.0f;
  558. // UVs
  559. MeshBinaryVertexAttribute& uva = header.m_vertexAttributes[VertexAttributeId::UV0];
  560. uva.m_bufferBinding = 1;
  561. uva.m_format = Format::R32G32_SFLOAT;
  562. uva.m_relativeOffset = sizeof(U32) * 2;
  563. uva.m_scale = 1.0f;
  564. // Bone weight
  565. if(hasBoneWeights)
  566. {
  567. MeshBinaryVertexAttribute& bidxa = header.m_vertexAttributes[VertexAttributeId::BONE_INDICES];
  568. bidxa.m_bufferBinding = 2;
  569. bidxa.m_format = Format::R8G8B8A8_UINT;
  570. bidxa.m_relativeOffset = 0;
  571. bidxa.m_scale = 1.0f;
  572. MeshBinaryVertexAttribute& wa = header.m_vertexAttributes[VertexAttributeId::BONE_WEIGHTS];
  573. wa.m_bufferBinding = 2;
  574. wa.m_format = Format::R8G8B8A8_UNORM;
  575. wa.m_relativeOffset = sizeof(U8Vec4);
  576. wa.m_scale = 1.0f;
  577. }
  578. }
  579. // Arange the attributes into vert buffers
  580. {
  581. // First buff has positions
  582. header.m_vertexBuffers[0].m_vertexStride = sizeof(Vec3);
  583. ++header.m_vertexBufferCount;
  584. // 2nd buff has normal + tangent + texcoords
  585. header.m_vertexBuffers[1].m_vertexStride = sizeof(MainVertex);
  586. ++header.m_vertexBufferCount;
  587. // 3rd has bone weights
  588. if(hasBoneWeights)
  589. {
  590. header.m_vertexBuffers[2].m_vertexStride = sizeof(BoneInfoVertex);
  591. ++header.m_vertexBufferCount;
  592. }
  593. }
  594. // Write some other header stuff
  595. {
  596. memcpy(&header.m_magic[0], MESH_MAGIC, 8);
  597. header.m_flags = MeshBinaryFlag::NONE;
  598. if(convex)
  599. {
  600. header.m_flags |= MeshBinaryFlag::CONVEX;
  601. }
  602. header.m_indexType = IndexType::U16;
  603. header.m_totalIndexCount = totalIndexCount;
  604. header.m_totalVertexCount = totalVertexCount;
  605. header.m_subMeshCount = U32(submeshes.getSize());
  606. header.m_aabbMin = aabbMin;
  607. header.m_aabbMax = aabbMax;
  608. }
  609. // Open file
  610. File file;
  611. ANKI_CHECK(file.open(fname.toCString(), FileOpenFlag::WRITE | FileOpenFlag::BINARY));
  612. // Write header
  613. ANKI_CHECK(file.write(&header, sizeof(header)));
  614. // Write sub meshes
  615. for(const SubMesh& in : submeshes)
  616. {
  617. MeshBinarySubMesh out;
  618. out.m_firstIndex = in.m_firstIdx;
  619. out.m_indexCount = in.m_idxCount;
  620. out.m_aabbMin = in.m_aabbMin;
  621. out.m_aabbMax = in.m_aabbMax;
  622. ANKI_CHECK(file.write(&out, sizeof(out)));
  623. }
  624. // Write indices
  625. U32 vertCount = 0;
  626. for(const SubMesh& submesh : submeshes)
  627. {
  628. DynamicArrayAuto<U16> indices(m_alloc);
  629. indices.create(submesh.m_indices.getSize());
  630. for(U32 i = 0; i < indices.getSize(); ++i)
  631. {
  632. const U32 idx = submesh.m_indices[i] + vertCount;
  633. if(idx > MAX_U16)
  634. {
  635. ANKI_IMPORTER_LOGE("Only supports 16bit indices for now");
  636. return Error::USER_DATA;
  637. }
  638. indices[i] = U16(idx);
  639. }
  640. ANKI_CHECK(file.write(&indices[0], indices.getSizeInBytes()));
  641. vertCount += submesh.m_verts.getSize();
  642. }
  643. ANKI_CHECK(alignBufferInFile(header.m_totalIndexCount * sizeof(U16), file));
  644. // Write position vert buffer
  645. for(const SubMesh& submesh : submeshes)
  646. {
  647. DynamicArrayAuto<Vec3> positions(m_alloc);
  648. positions.create(submesh.m_verts.getSize());
  649. for(U32 v = 0; v < submesh.m_verts.getSize(); ++v)
  650. {
  651. positions[v] = submesh.m_verts[v].m_position;
  652. }
  653. ANKI_CHECK(file.write(&positions[0], positions.getSizeInBytes()));
  654. }
  655. ANKI_CHECK(alignBufferInFile(header.m_totalVertexCount * sizeof(Vec3), file));
  656. // Write the 2nd vert buffer
  657. for(const SubMesh& submesh : submeshes)
  658. {
  659. DynamicArrayAuto<MainVertex> verts(m_alloc);
  660. verts.create(submesh.m_verts.getSize());
  661. for(U32 i = 0; i < verts.getSize(); ++i)
  662. {
  663. const Vec3& normal = submesh.m_verts[i].m_normal;
  664. const Vec4& tangent = submesh.m_verts[i].m_tangent;
  665. const Vec2& uv = submesh.m_verts[i].m_uv;
  666. verts[i].m_normal = packColorToR10G10B10A2SNorm(normal.x(), normal.y(), normal.z(), 0.0f);
  667. verts[i].m_tangent = packColorToR10G10B10A2SNorm(tangent.x(), tangent.y(), tangent.z(), tangent.w());
  668. verts[i].m_uv0 = uv;
  669. }
  670. ANKI_CHECK(file.write(&verts[0], verts.getSizeInBytes()));
  671. }
  672. ANKI_CHECK(alignBufferInFile(header.m_totalVertexCount * sizeof(MainVertex), file));
  673. // Write 3rd vert buffer
  674. if(hasBoneWeights)
  675. {
  676. for(const SubMesh& submesh : submeshes)
  677. {
  678. DynamicArrayAuto<BoneInfoVertex> verts(m_alloc);
  679. verts.create(submesh.m_verts.getSize());
  680. for(U32 i = 0; i < verts.getSize(); ++i)
  681. {
  682. BoneInfoVertex vert;
  683. for(U32 c = 0; c < 4; ++c)
  684. {
  685. if(submesh.m_verts[i].m_boneIds[c] > 0XFF)
  686. {
  687. ANKI_IMPORTER_LOGE("Only 256 bones are supported");
  688. return Error::USER_DATA;
  689. }
  690. vert.m_boneIndices[c] = U8(submesh.m_verts[i].m_boneIds[c]);
  691. vert.m_boneWeights[c] = U8(submesh.m_verts[i].m_boneWeights[c] * F32(MAX_U8));
  692. }
  693. verts[i] = vert;
  694. }
  695. ANKI_CHECK(file.write(&verts[0], verts.getSizeInBytes()));
  696. }
  697. ANKI_CHECK(alignBufferInFile(header.m_totalVertexCount * sizeof(BoneInfoVertex), file));
  698. }
  699. return Error::NONE;
  700. }
  701. } // end namespace anki