GltfImporterMesh.cpp 21 KB

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