mesh_fbx.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /*
  2. * Copyright (c) 2012-2025 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: MIT
  4. */
  5. #include "config.h"
  6. #if CROWN_CAN_COMPILE
  7. #include "core/containers/array.inl"
  8. #include "core/containers/hash_map.inl"
  9. #include "core/math/matrix4x4.inl"
  10. #include "core/math/vector2.inl"
  11. #include "core/math/vector3.inl"
  12. #include "core/memory/temp_allocator.inl"
  13. #include "core/strings/dynamic_string.inl"
  14. #include "device/log.h"
  15. #include "resource/compile_options.inl"
  16. #include "resource/fbx_document.h"
  17. #include "resource/mesh_fbx.h"
  18. #include <stdlib.h>
  19. #include <ufbx.h>
  20. LOG_SYSTEM(FBX_RESOURCE, "fbx_resource")
  21. namespace crown
  22. {
  23. namespace fbx
  24. {
  25. void generate_indices(Array<u32> &triangle_indices, Array<f32> &vertex_data, size_t vertex_size)
  26. {
  27. ufbx_vertex_stream streams[1] =
  28. {
  29. { array::begin(vertex_data), array::size(vertex_data), vertex_size },
  30. };
  31. size_t num_vertices = ufbx_generate_indices(streams
  32. , 1
  33. , array::begin(triangle_indices)
  34. , array::size(triangle_indices)
  35. , NULL
  36. , NULL
  37. );
  38. array::resize(vertex_data, (u32)num_vertices * vertex_size);
  39. }
  40. /// See: https://ufbx.github.io/elements/meshes/#example
  41. size_t convert_mesh_part(Geometry &g, FBXDocument &fbx, const ufbx_mesh *mesh, const ufbx_mesh_part *part)
  42. {
  43. size_t num_triangles = part->num_triangles;
  44. // Reserve space for the maximum triangle indices.
  45. size_t num_tri_indices = mesh->max_face_triangles * 3;
  46. uint32_t *tri_indices = (uint32_t *)calloc(num_tri_indices, sizeof(uint32_t));
  47. // Iterate over each face using the specific material.
  48. for (size_t face_ix = 0; face_ix < part->num_faces; face_ix++) {
  49. ufbx_face face = mesh->faces.data[part->face_indices.data[face_ix]];
  50. // Triangulate the face into `tri_indices[]`.
  51. uint32_t num_tris = ufbx_triangulate_face(tri_indices, num_tri_indices, mesh, face);
  52. // Iterate over each triangle corner contiguously.
  53. for (size_t i = 0; i < num_tris * 3; i++) {
  54. uint32_t index = tri_indices[i];
  55. ufbx_vec3 v = ufbx_get_vertex_vec3(&mesh->vertex_position, index);
  56. array::push_back(g._positions, (f32)v.x);
  57. array::push_back(g._positions, (f32)v.y);
  58. array::push_back(g._positions, (f32)v.z);
  59. if (mesh->vertex_normal.exists) {
  60. ufbx_vec3 v = ufbx_get_vertex_vec3(&mesh->vertex_normal, index);
  61. array::push_back(g._normals, (f32)v.x);
  62. array::push_back(g._normals, (f32)v.y);
  63. array::push_back(g._normals, (f32)v.z);
  64. }
  65. if (mesh->vertex_uv.exists) {
  66. ufbx_vec2 v = ufbx_get_vertex_vec2(&mesh->vertex_uv, index);
  67. array::push_back(g._uvs, (f32)v.x);
  68. array::push_back(g._uvs, 1.0f - (f32)v.y);
  69. }
  70. if (mesh->vertex_tangent.exists) {
  71. ufbx_vec3 v = ufbx_get_vertex_vec3(&mesh->vertex_tangent, index);
  72. array::push_back(g._tangents, (f32)v.x);
  73. array::push_back(g._tangents, (f32)v.y);
  74. array::push_back(g._tangents, (f32)v.z);
  75. }
  76. if (mesh->vertex_bitangent.exists) {
  77. ufbx_vec3 v = ufbx_get_vertex_vec3(&mesh->vertex_bitangent, index);
  78. array::push_back(g._bitangents, (f32)v.x);
  79. array::push_back(g._bitangents, (f32)v.y);
  80. array::push_back(g._bitangents, (f32)v.z);
  81. }
  82. }
  83. }
  84. free(tri_indices);
  85. return num_triangles * 3;
  86. }
  87. s32 parse_geometry(Geometry &g, FBXDocument &fbx, const ufbx_mesh *mesh)
  88. {
  89. size_t num_indices = 0;
  90. for (size_t i = 0; i < mesh->material_parts.count; ++i) {
  91. const ufbx_mesh_part *mesh_part = &mesh->material_parts.data[i];
  92. num_indices += convert_mesh_part(g, fbx, mesh, mesh_part);
  93. }
  94. array::resize(g._position_indices, (u32)num_indices);
  95. generate_indices(g._position_indices, g._positions, sizeof(f32)*3);
  96. if (mesh::has_normals(g)) {
  97. array::resize(g._normal_indices, (u32)num_indices);
  98. generate_indices(g._normal_indices, g._normals, sizeof(f32)*3);
  99. }
  100. if (mesh::has_uvs(g)) {
  101. array::resize(g._uv_indices, (u32)num_indices);
  102. generate_indices(g._uv_indices, g._uvs, sizeof(f32)*2);
  103. }
  104. if (mesh::has_tangents(g)) {
  105. array::resize(g._tangent_indices, (u32)num_indices);
  106. generate_indices(g._tangent_indices, g._tangents, sizeof(f32)*3);
  107. }
  108. if (mesh::has_bitangents(g)) {
  109. array::resize(g._bitangent_indices, (u32)num_indices);
  110. generate_indices(g._bitangent_indices, g._bitangents, sizeof(f32)*3);
  111. }
  112. return 0;
  113. }
  114. s32 parse_geometries(Mesh &m, FBXDocument &fbx, const ufbx_mesh_list *meshes, CompileOptions &opts)
  115. {
  116. for (size_t i = 0; i < meshes->count; ++i) {
  117. const ufbx_mesh *mesh = meshes->data[i];
  118. Geometry geo(default_allocator());
  119. s32 err = fbx::parse_geometry(geo, fbx, mesh);
  120. ENSURE_OR_RETURN(err == 0, opts);
  121. DynamicString geometry_name(default_allocator());
  122. geometry_name.from_string_id(StringId32((const char *)&mesh, sizeof(mesh)));
  123. RETURN_IF_FALSE(!hash_map::has(m._geometries, geometry_name)
  124. , opts
  125. , "Geometry redefined: '%s'"
  126. , geometry_name.c_str()
  127. );
  128. hash_map::set(m._geometries, geometry_name, geo);
  129. }
  130. return 0;
  131. }
  132. s32 parse_node(Node &n, const ufbx_node *node)
  133. {
  134. Vector3 pos;
  135. pos.x = (f32)node->local_transform.translation.x;
  136. pos.y = (f32)node->local_transform.translation.y;
  137. pos.z = (f32)node->local_transform.translation.z;
  138. Quaternion rot;
  139. rot.x = (f32)node->local_transform.rotation.x;
  140. rot.y = (f32)node->local_transform.rotation.y;
  141. rot.z = (f32)node->local_transform.rotation.z;
  142. rot.w = (f32)node->local_transform.rotation.w;
  143. Vector3 scl;
  144. scl.x = (f32)node->local_transform.scale.x;
  145. scl.y = (f32)node->local_transform.scale.y;
  146. scl.z = (f32)node->local_transform.scale.z;
  147. n._local_pose = from_quaternion_translation(rot, pos);
  148. set_scale(n._local_pose, scl);
  149. if (node->mesh != NULL)
  150. n._geometry.from_string_id(StringId32((const char *)&node->mesh, sizeof(node->mesh)));
  151. return 0;
  152. }
  153. s32 parse_nodes(Mesh &m, const ufbx_node_list *nodes, CompileOptions &opts)
  154. {
  155. for (size_t i = 0; i < nodes->count; ++i) {
  156. const ufbx_node *node = nodes->data[i];
  157. Node new_node(default_allocator());
  158. DynamicString node_name(default_allocator());
  159. node_name.set(node->name.data, node->name.length);
  160. s32 err = fbx::parse_node(new_node, node);
  161. ENSURE_OR_RETURN(err == 0, opts);
  162. hash_map::set(m._nodes, node_name, new_node);
  163. }
  164. return 0;
  165. }
  166. s32 parse(Mesh &m, Buffer &buf, CompileOptions &opts)
  167. {
  168. FBXDocument fbx(default_allocator());
  169. s32 err = fbx::parse(fbx, buf, opts);
  170. ENSURE_OR_RETURN(err == 0, opts);
  171. err = parse_geometries(m, fbx, &fbx.scene->meshes, opts);
  172. ENSURE_OR_RETURN(err == 0, opts);
  173. return parse_nodes(m, &fbx.scene->nodes, opts);
  174. }
  175. } // namespace fbx
  176. } // namespace crown
  177. #endif // if CROWN_CAN_COMPILE