coral_mesh.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. #include "coral_mesh.h"
  2. #include "coral_pipeline.h"
  3. #include "vk_initializers.h"
  4. // TINY GLTF
  5. #define TINYGLTF_IMPLEMENTATION
  6. #define STB_IMAGE_IMPLEMENTATION
  7. #define STB_IMAGE_WRITE_IMPLEMENTATION
  8. #include "tiny_gltf.h"
  9. #define GLM_ENABLE_EXPERIMENTAL
  10. #include <gtx/hash.hpp>
  11. #include <gtc/type_ptr.hpp>
  12. #include <gtx/orthonormalize.hpp>
  13. // STD
  14. #include <iostream>
  15. #include <cassert>
  16. #include <unordered_map>
  17. #include "coral_utils.h"
  18. #include "coral_gameobject.h"
  19. #define CALC_TANGENTS
  20. using namespace coral_3d;
  21. namespace std
  22. {
  23. template<>
  24. struct hash<coral_3d::Vertex>
  25. {
  26. size_t operator()(coral_3d::Vertex const &vertex) const
  27. {
  28. size_t seed = 0;
  29. coral_3d::utils::hash_combine(seed, vertex.position, vertex.tangent, vertex.normal, vertex.uv);
  30. return seed;
  31. }
  32. };
  33. }
  34. VertexInputDescription Vertex::get_vert_desc()
  35. {
  36. VertexInputDescription desc;
  37. // We only have one vertex buffer binding, with a per-vertex rate
  38. VkVertexInputBindingDescription main_binding{};
  39. main_binding.binding = 0;
  40. main_binding.stride = sizeof(Vertex);
  41. main_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
  42. desc.bindings.emplace_back(main_binding);
  43. // Position will be stored at Location 0
  44. VkVertexInputAttributeDescription position_attrib{};
  45. position_attrib.binding = 0;
  46. position_attrib.location = 0;
  47. position_attrib.format = VK_FORMAT_R32G32B32_SFLOAT;
  48. position_attrib.offset = offsetof(Vertex, position);
  49. // Normal will be stored at Location 1
  50. VkVertexInputAttributeDescription normal_attrib{};
  51. normal_attrib.binding = 0;
  52. normal_attrib.location = 1;
  53. normal_attrib.format = VK_FORMAT_R32G32B32_SFLOAT;
  54. normal_attrib.offset = offsetof(Vertex, normal);
  55. // Tangent will be stored at Location 2
  56. VkVertexInputAttributeDescription tangent_attrib{};
  57. tangent_attrib.binding = 0;
  58. tangent_attrib.location = 2;
  59. tangent_attrib.format = VK_FORMAT_R32G32B32A32_SFLOAT;
  60. tangent_attrib.offset = offsetof(Vertex, tangent);
  61. // UV will be stored at Location 3
  62. VkVertexInputAttributeDescription texcoord_attrib{};
  63. texcoord_attrib.binding = 0;
  64. texcoord_attrib.location = 3;
  65. texcoord_attrib.format = VK_FORMAT_R32G32_SFLOAT;
  66. texcoord_attrib.offset = offsetof(Vertex, uv);
  67. desc.attributes.emplace_back(position_attrib);
  68. desc.attributes.emplace_back(normal_attrib);
  69. desc.attributes.emplace_back(tangent_attrib);
  70. desc.attributes.emplace_back(texcoord_attrib);
  71. return desc;
  72. }
  73. bool coral_mesh::Builder::load_from_gltf(coral_device& device, const std::string &file_path)
  74. {
  75. tinygltf::Model glTF_input;
  76. tinygltf::TinyGLTF loader;
  77. std::string err;
  78. std::string warn;
  79. if(!loader.LoadASCIIFromFile(&glTF_input, &err, &warn, file_path))
  80. {
  81. std::cerr << "ERROR! coral_mesh::load_from_gltf() >> failed to load glTF: " << file_path << std::endl;
  82. if(!err.empty())
  83. {
  84. std::cerr << "ERROR! coral_mesh::load_from_gltf() >> " << err << std::endl;
  85. return false;
  86. }
  87. }
  88. if(!warn.empty())
  89. {
  90. std::cerr << "WARNING! coral_mesh::load_from_gltf() >> " << warn << std::endl;
  91. }
  92. load_images(device, glTF_input);
  93. load_materials(glTF_input);
  94. load_textures(glTF_input);
  95. const tinygltf::Scene& scene = glTF_input.scenes[0];
  96. for(int i : scene.nodes)
  97. {
  98. const tinygltf::Node node = glTF_input.nodes[i];
  99. load_node(device, node, glTF_input, nullptr);
  100. }
  101. #ifdef CALC_TANGENTS
  102. // CALCULATE TANGENTS & BITANGENTS
  103. std::vector<glm::vec3> bitangents{vertices.size()};
  104. for (size_t i = 0; i < indices.size(); i += 3)
  105. {
  106. uint32_t i0 = indices[i];
  107. uint32_t i1 = indices[i + 1];
  108. uint32_t i2 = indices[i + 2];
  109. const glm::vec3& p0 = vertices[i0].position;
  110. const glm::vec3& p1 = vertices[i1].position;
  111. const glm::vec3& p2 = vertices[i2].position;
  112. const glm::vec2& uv0 = vertices[i0].uv;
  113. const glm::vec2& uv1 = vertices[i1].uv;
  114. const glm::vec2& uv2 = vertices[i2].uv;
  115. glm::vec3 edge1 = p1 - p0;
  116. glm::vec3 edge2 = p2 - p0;
  117. float x1 = uv1.x - uv0.x;
  118. float x2 = uv2.x - uv0.x;
  119. float y1 = uv1.y - uv0.y;
  120. float y2 = uv2.y - uv0.y;
  121. float r = 1.f / (x1 * y2 - x2 * y1);
  122. glm::vec3 tangent = (edge1 * y2 - edge2 * y1) * r;
  123. glm::vec3 bitangent = (edge2 * x1 - edge1 * x2) * r;
  124. vertices[i0].tangent += glm::vec4(tangent, 0.f);
  125. vertices[i1].tangent += glm::vec4(tangent, 0.f);
  126. vertices[i2].tangent += glm::vec4(tangent, 0.f);
  127. bitangents[i0] += bitangent;
  128. bitangents[i1] += bitangent;
  129. bitangents[i2] += bitangent;
  130. }
  131. // ORTHONORMALIZE TANGENT AND CALCULATE HANDEDNESS
  132. for(size_t i = 0; i < vertices.size(); i++)
  133. {
  134. const glm::vec3& t = vertices[i].tangent;
  135. const glm::vec3& b = bitangents[i];
  136. const glm::vec3& n = vertices[i].normal;
  137. vertices[i].tangent = glm::vec4(glm::normalize(glm::orthonormalize(t, n)), 0.f);
  138. vertices[i].tangent.w = (glm::dot(glm::cross(t,b), n) > 0.f) ? 1.f : -1.f;
  139. }
  140. #endif
  141. return true;
  142. }
  143. void coral_mesh::Builder::load_images(coral_device& device, tinygltf::Model &input)
  144. {
  145. images.resize(input.images.size());
  146. for (size_t i = 0; i < input.images.size(); ++i)
  147. {
  148. tinygltf::Image& glTF_image = input.images[i];
  149. bool is_normal_map{false};
  150. for(size_t j = 0; j < input.materials.size(); ++j)
  151. {
  152. tinygltf::Material glTFMaterial = input.materials[j];
  153. if(glTFMaterial.additionalValues.find("normalTexture") == glTFMaterial.additionalValues.end()) continue;
  154. if((size_t)input.textures[glTFMaterial.additionalValues["normalTexture"].TextureIndex()].source == i)
  155. {
  156. is_normal_map = true;
  157. break;
  158. }
  159. }
  160. images[i].texture = coral_texture::create_texture_from_file(
  161. device,
  162. "assets/textures/" + glTF_image.uri,
  163. is_normal_map ? VK_FORMAT_R8G8B8A8_UNORM : VK_FORMAT_R8G8B8A8_SRGB);
  164. }
  165. }
  166. void coral_mesh::Builder::load_textures(tinygltf::Model &input)
  167. {
  168. textures.resize(input.textures.size());
  169. for (size_t i = 0; i < input.textures.size(); i++)
  170. {
  171. textures[i].image_index = input.textures[i].source;
  172. }
  173. }
  174. void coral_mesh::Builder::load_materials(tinygltf::Model &input)
  175. {
  176. materials.resize(input.materials.size());
  177. for (size_t i = 0; i < input.materials.size(); i++)
  178. {
  179. tinygltf::Material glTFMaterial = input.materials[i];
  180. // Get the base color factor
  181. if (glTFMaterial.values.find("baseColorFactor") != glTFMaterial.values.end())
  182. {
  183. materials[i].base_color_factor = glm::make_vec4(
  184. glTFMaterial.values["baseColorFactor"].ColorFactor().data());
  185. }
  186. // Get base color texture index
  187. if (glTFMaterial.values.find("baseColorTexture") != glTFMaterial.values.end())
  188. {
  189. materials[i].base_color_texture_index = glTFMaterial.values["baseColorTexture"].TextureIndex();
  190. }
  191. // Get the normal map texture index
  192. if (glTFMaterial.additionalValues.find("normalTexture") != glTFMaterial.additionalValues.end())
  193. {
  194. materials[i].normal_texture_index = glTFMaterial.additionalValues["normalTexture"].TextureIndex();
  195. }
  196. // Get the occlusion map texture index
  197. if (glTFMaterial.additionalValues.find("occlusionTexture") != glTFMaterial.additionalValues.end())
  198. {
  199. materials[i].occlusion_texture_index = glTFMaterial.additionalValues["occlusionTexture"].TextureIndex();
  200. }
  201. // Get the metallic roughness map texture index
  202. if (glTFMaterial.values.find("metallicRoughnessTexture") != glTFMaterial.additionalValues.end())
  203. {
  204. materials[i].metallic_roughness_texture_index = glTFMaterial.values["metallicRoughnessTexture"].TextureIndex();
  205. }
  206. materials[i].alpha_mode = glTFMaterial.alphaMode;
  207. materials[i].alpha_cutoff = (float) glTFMaterial.alphaCutoff;
  208. materials[i].double_sided = glTFMaterial.doubleSided;
  209. }
  210. }
  211. void coral_mesh::Builder::load_node(coral_device& device, const tinygltf::Node &input_node, const tinygltf::Model &input, coral_3d::Node *parent)
  212. {
  213. auto* node = new coral_3d::Node{};
  214. node->name = input_node.name;
  215. node->parent = parent;
  216. // NODE TRANSFORM
  217. node->transform = glm::mat4(1.f);
  218. if(input_node.translation.size() == 3)
  219. node->transform = glm::translate(node->transform, glm::vec3(glm::make_vec3(input_node.translation.data())));
  220. if(input_node.rotation.size() == 4)
  221. {
  222. glm::quat q = glm::make_quat(input_node.rotation.data());
  223. node->transform *= glm::mat4(q);
  224. }
  225. if(input_node.scale.size() == 3)
  226. node->transform = glm::scale(node->transform, glm::vec3(glm::make_vec3(input_node.scale.data())));
  227. if(input_node.matrix.size() == 16)
  228. node->transform = glm::make_mat4x4(input_node.matrix.data());
  229. // LOAD CHILDREN
  230. if(!input_node.children.empty())
  231. {
  232. for (int i : input_node.children)
  233. load_node(device, input.nodes[i], input, node);
  234. }
  235. // LOAD VERTICES AND INDICES
  236. if(input_node.mesh > -1)
  237. {
  238. const tinygltf::Mesh mesh = input.meshes[input_node.mesh];
  239. // ITERATE PRIMITIVES
  240. for (size_t i = 0; i < mesh.primitives.size(); ++i)
  241. {
  242. const tinygltf::Primitive& glTF_primitive = mesh.primitives[i];
  243. auto first_index = static_cast<uint32_t>(indices.size());
  244. auto vertex_start = static_cast<uint32_t>(vertices.size());
  245. uint32_t index_count = 0;
  246. #pragma region VERTICES
  247. {
  248. const float* position_buffer = nullptr;
  249. const float* normal_buffer = nullptr;
  250. const float* tangent_buffer = nullptr;
  251. const float* tex_coord_buffer = nullptr;
  252. size_t vertex_count = 0;
  253. // VERTEX POSITIONS
  254. if(glTF_primitive.attributes.find("POSITION") != glTF_primitive.attributes.end())
  255. {
  256. const tinygltf::Accessor& accessor = input.accessors[glTF_primitive.attributes.find("POSITION")->second];
  257. const tinygltf::BufferView& view = input.bufferViews[accessor.bufferView];
  258. position_buffer = reinterpret_cast<const float*>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
  259. vertex_count = accessor.count;
  260. }
  261. // VERTEX NORMALS
  262. if(glTF_primitive.attributes.find("NORMAL") != glTF_primitive.attributes.end())
  263. {
  264. const tinygltf::Accessor& accessor = input.accessors[glTF_primitive.attributes.find("NORMAL")->second];
  265. const tinygltf::BufferView& view = input.bufferViews[accessor.bufferView];
  266. normal_buffer = reinterpret_cast<const float*>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
  267. }
  268. // VERTEX TANGENTS
  269. if(glTF_primitive.attributes.find("TANGENT") != glTF_primitive.attributes.end())
  270. {
  271. const tinygltf::Accessor& accessor = input.accessors[glTF_primitive.attributes.find("TANGENT")->second];
  272. const tinygltf::BufferView& view = input.bufferViews[accessor.bufferView];
  273. tangent_buffer = reinterpret_cast<const float*>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
  274. }
  275. // VERTEX TEX COORDS
  276. if(glTF_primitive.attributes.find("TEXCOORD_0") != glTF_primitive.attributes.end())
  277. {
  278. const tinygltf::Accessor& accessor = input.accessors[glTF_primitive.attributes.find("TEXCOORD_0")->second];
  279. const tinygltf::BufferView& view = input.bufferViews[accessor.bufferView];
  280. tex_coord_buffer = reinterpret_cast<const float*>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
  281. }
  282. for (size_t v = 0; v < vertex_count; v++)
  283. {
  284. Vertex vertex{};
  285. vertex.position = glm::make_vec3(&position_buffer[v * 3]);
  286. vertex.normal = glm::normalize(normal_buffer ? glm::make_vec3(&normal_buffer[v * 3]) : glm::vec3(0.f));
  287. vertex.tangent = tangent_buffer ? glm::make_vec4(&tangent_buffer[v * 4]) : glm::vec4(0.f);
  288. vertex.uv = tex_coord_buffer ? glm::make_vec2(&tex_coord_buffer[v * 2]) : glm::vec2(0.f);
  289. vertices.emplace_back(vertex);
  290. }
  291. }
  292. #pragma endregion
  293. #pragma region INDICES
  294. {
  295. const tinygltf::Accessor& accessor = input.accessors[glTF_primitive.indices];
  296. const tinygltf::BufferView& view = input.bufferViews[accessor.bufferView];
  297. const tinygltf::Buffer& buffer = input.buffers[view.buffer];
  298. index_count += static_cast<uint32_t>(accessor.count);
  299. switch(accessor.componentType)
  300. {
  301. case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT:
  302. {
  303. const auto* buf = reinterpret_cast<const uint32_t*>(&buffer.data[accessor.byteOffset + view.byteOffset]);
  304. for (size_t index = 0; index < accessor.count; index++)
  305. {
  306. indices.push_back(buf[index] + vertex_start);
  307. }
  308. break;
  309. }
  310. case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT:
  311. {
  312. const auto* buf = reinterpret_cast<const uint16_t*>(&buffer.data[accessor.byteOffset + view.byteOffset]);
  313. for (size_t index = 0; index < accessor.count; index++)
  314. {
  315. indices.push_back(buf[index] + vertex_start);
  316. }
  317. break;
  318. }
  319. case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE:
  320. {
  321. const auto* buf = reinterpret_cast<const uint8_t*>(&buffer.data[accessor.byteOffset + view.byteOffset]);
  322. for (size_t index = 0; index < accessor.count; index++)
  323. {
  324. indices.push_back(buf[index] + vertex_start);
  325. }
  326. break;
  327. }
  328. default:
  329. {
  330. std::cerr << "ERROR! coral_mesh::Builder::load_node() >> Index component type [" << accessor.componentType << "] not supported!" << std::endl;
  331. return;
  332. }
  333. }
  334. Primitive primitive{};
  335. primitive.first_index = first_index;
  336. primitive.index_count = index_count;
  337. primitive.material_index = glTF_primitive.material;
  338. node->mesh.primitives.emplace_back(primitive);
  339. }
  340. #pragma endregion
  341. }
  342. }
  343. if(parent)
  344. parent->children.emplace_back(node);
  345. else
  346. nodes.emplace_back(node);
  347. }
  348. coral_mesh::coral_mesh(coral_device& device, Builder& builder, coral_gameobject* parent)
  349. : device_{device}
  350. , ptr_parent_{parent}
  351. {
  352. create_vertex_buffers(builder.vertices);
  353. create_index_buffers(builder.indices);
  354. images_ = std::move(builder.images);
  355. textures_ = std::move(builder.textures);
  356. materials_ = std::move(builder.materials);
  357. nodes_ = std::move(builder.nodes);
  358. std::cout << "INFO! coral_mesh::create_mesh_from_file() >> Finished loading mesh!" << std::endl;
  359. }
  360. coral_mesh::~coral_mesh()
  361. {
  362. for(const Material& material : materials_)
  363. vkDestroyPipeline(device_.device(), material.pipeline, nullptr);
  364. }
  365. std::unique_ptr<coral_mesh> coral_mesh::create_mesh_from_file(coral_device& device, const std::string& file_path, coral_gameobject* parent)
  366. {
  367. std::cout<< "INFO! coral_mesh::load_from_gltf() >> Loading mesh..." << std::endl;
  368. Builder builder{};
  369. builder.load_from_gltf(device, file_path);
  370. std::cout << "[" << file_path << "] vertex count: " << builder.vertices.size() << "\n";
  371. std::cout << "[" << file_path << "] index count: " << builder.indices.size() << "\n";
  372. return std::make_unique<coral_mesh>(device, builder, parent);
  373. }
  374. void coral_mesh::load_materials(coral_descriptor_set_layout& material_set_layout,
  375. coral_descriptor_pool& material_set_pool)
  376. {
  377. for(auto& material : materials_)
  378. {
  379. auto color_desc = get_texture_descriptor(material.base_color_texture_index);
  380. auto normal_desc = get_texture_descriptor(material.normal_texture_index);
  381. auto occlusion_desc = get_texture_descriptor(material.occlusion_texture_index);
  382. auto metallic_roughness_desc = get_texture_descriptor(material.metallic_roughness_texture_index);
  383. coral_descriptor_writer writer{material_set_layout, material_set_pool};
  384. if(material.base_color_texture_index != -1)
  385. {
  386. writer.write_image(0, &color_desc);
  387. }
  388. if(material.normal_texture_index != -1)
  389. {
  390. writer.write_image(1, &normal_desc);
  391. }
  392. if(material.occlusion_texture_index != -1)
  393. {
  394. writer.write_image(2, &occlusion_desc);
  395. }
  396. if(material.metallic_roughness_texture_index != -1)
  397. {
  398. writer.write_image(3, &metallic_roughness_desc);
  399. }
  400. writer.build(material.descriptor_set);
  401. }
  402. }
  403. void coral_mesh::draw(VkCommandBuffer command_buffer, VkPipelineLayout pipeline_layout)
  404. {
  405. // All vertices and indices are stored in single buffers, so we only need to bind once
  406. VkBuffer buffers[]{ vertex_buffer_->get_buffer().buffer };
  407. VkDeviceSize offsets[]{ 0 };
  408. vkCmdBindVertexBuffers(command_buffer, 0, 1, buffers, offsets);
  409. vkCmdBindIndexBuffer(command_buffer, index_buffer_->get_buffer().buffer, 0, VK_INDEX_TYPE_UINT32);
  410. // Render all nodes at top-level
  411. for (auto& node : nodes_)
  412. draw_node(command_buffer, pipeline_layout, node);
  413. }
  414. void coral_mesh::draw_node(VkCommandBuffer command_buffer, VkPipelineLayout pipeline_layout, coral_3d::Node *node)
  415. {
  416. if (!node->visible) return;
  417. if (!node->mesh.primitives.empty())
  418. {
  419. // Traverse the node hierarchy to the top-most parent to get the final matrix of the current node
  420. glm::mat4 node_transform = node->transform;
  421. coral_3d::Node* current_parent = node->parent;
  422. while (current_parent)
  423. {
  424. node_transform = current_parent->transform * node_transform;
  425. current_parent = current_parent->parent;
  426. }
  427. PushConstant push{};
  428. push.node_transform = ptr_parent_->transform_.mat4() * node_transform;
  429. // Pass the final matrix to the vertex shader using push constants
  430. vkCmdPushConstants(
  431. command_buffer,
  432. pipeline_layout,
  433. VK_SHADER_STAGE_VERTEX_BIT,
  434. 0,
  435. sizeof(PushConstant),
  436. &push);
  437. for (coral_3d::Primitive& primitive : node->mesh.primitives)
  438. {
  439. if (primitive.index_count > 0)
  440. {
  441. coral_3d::Material& material = materials_[primitive.material_index];
  442. // Bind the pipeline for the node's material
  443. vkCmdBindPipeline(
  444. command_buffer,
  445. VK_PIPELINE_BIND_POINT_GRAPHICS,
  446. material.pipeline);
  447. vkCmdBindDescriptorSets(
  448. command_buffer,
  449. VK_PIPELINE_BIND_POINT_GRAPHICS,
  450. pipeline_layout,
  451. 1, 1,
  452. &material.descriptor_set,
  453. 0, nullptr);
  454. vkCmdDrawIndexed(
  455. command_buffer,
  456. primitive.index_count,
  457. 1,
  458. primitive.first_index,
  459. 0, 0);
  460. }
  461. }
  462. }
  463. for (auto& child : node->children)
  464. draw_node(command_buffer, pipeline_layout, child);
  465. }
  466. void coral_mesh::create_vertex_buffers(const std::vector<Vertex>& vertices)
  467. {
  468. uint32_t vertex_count = static_cast<uint32_t>(vertices.size());
  469. assert(vertex_count >= 3 && "ERROR! coral_mesh::create_vertex_buffers() >> Vertex count must be greater than or equal to 3");
  470. uint32_t vertex_size{ sizeof(vertices[0]) };
  471. VkDeviceSize buffer_size{ vertex_size * vertex_count};
  472. coral_buffer staging_buffer
  473. {
  474. device_,
  475. vertex_size,
  476. vertex_count,
  477. VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
  478. VMA_MEMORY_USAGE_AUTO,
  479. VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT
  480. };
  481. vertex_buffer_ = std::make_unique<coral_buffer>(
  482. device_,
  483. vertex_size,
  484. vertex_count,
  485. VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
  486. VMA_MEMORY_USAGE_GPU_ONLY);
  487. staging_buffer.map();
  488. staging_buffer.write_to_buffer((void*)vertices.data());
  489. device_.copy_buffer(staging_buffer.get_buffer(), vertex_buffer_->get_buffer(), buffer_size);
  490. }
  491. void coral_mesh::create_index_buffers(const std::vector<uint32_t>& indices)
  492. {
  493. uint32_t index_count = static_cast<uint32_t>(indices.size());
  494. if (index_count <= 0) return;
  495. uint32_t index_size{ sizeof(indices[0]) };
  496. VkDeviceSize buffer_size{ index_size * index_count };
  497. coral_buffer staging_buffer
  498. {
  499. device_,
  500. index_size,
  501. index_count,
  502. VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
  503. VMA_MEMORY_USAGE_AUTO,
  504. VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT
  505. };
  506. staging_buffer.map();
  507. staging_buffer.write_to_buffer((void*)indices.data());
  508. index_buffer_ = std::make_unique<coral_buffer>(
  509. device_,
  510. index_size,
  511. index_count,
  512. VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
  513. VMA_MEMORY_USAGE_GPU_ONLY);
  514. device_.copy_buffer(staging_buffer.get_buffer(), index_buffer_->get_buffer(), buffer_size);
  515. }
  516. VkDescriptorImageInfo coral_mesh::get_texture_descriptor(const int index)
  517. {
  518. if(index == -1)
  519. return VkDescriptorImageInfo{};
  520. return images_[index].texture->get_descriptor_info();
  521. }
  522. void coral_mesh::create_pipelines(
  523. const std::string& vert_file_path,
  524. const std::string& frag_file_path,
  525. VkRenderPass render_pass,
  526. VkPipelineLayout pipeline_layout)
  527. {
  528. assert(pipeline_layout != nullptr &&
  529. "ERROR! render_system::create_pipeline() >> Cannot create pipeline before pipeline layout!");
  530. PipelineConfigInfo config_info{};
  531. coral_pipeline::default_pipeline_config_info(config_info);
  532. config_info.render_pass = render_pass;
  533. config_info.pipeline_layout = pipeline_layout;
  534. assert(config_info.pipeline_layout != VK_NULL_HANDLE &&
  535. "ERROR! coral_pipeline::create_graphics_pipeline() >> no pipeline layout provided in config_info ");
  536. assert(config_info.render_pass != VK_NULL_HANDLE &&
  537. "ERROR! coral_pipeline::create_graphics_pipeline() >> no render pass provided in config_info ");
  538. auto vert_code = coral_pipeline::read_file(vert_file_path);
  539. auto frag_code = coral_pipeline::read_file(frag_file_path);
  540. VkShaderModule vert_shader_module;
  541. VkShaderModule frag_shader_module;
  542. coral_pipeline::create_shader_module(device_, vert_code, &vert_shader_module);
  543. coral_pipeline::create_shader_module(device_, frag_code, &frag_shader_module);
  544. VkPipelineShaderStageCreateInfo shader_stages[2];
  545. shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
  546. shader_stages[0].pNext = nullptr;
  547. shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
  548. shader_stages[0].module = vert_shader_module;
  549. shader_stages[0].pName = "main";
  550. shader_stages[0].flags = 0;
  551. shader_stages[0].pSpecializationInfo = nullptr;
  552. shader_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
  553. shader_stages[1].pNext = nullptr;
  554. shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
  555. shader_stages[1].module = frag_shader_module;
  556. shader_stages[1].pName = "main";
  557. shader_stages[1].flags = 0;
  558. shader_stages[1].pSpecializationInfo = nullptr;
  559. // VERTEX INPUT INFO
  560. VkPipelineVertexInputStateCreateInfo vertex_input_info{ vkinit::vertex_input_state_ci() };
  561. auto& binding_descriptions{config_info.binding_descriptions};
  562. auto& attribute_descriptions{config_info.attribute_descriptions};
  563. vertex_input_info.vertexAttributeDescriptionCount = static_cast<uint32_t>(attribute_descriptions.size());
  564. vertex_input_info.pVertexAttributeDescriptions = attribute_descriptions.data();
  565. vertex_input_info.vertexBindingDescriptionCount = static_cast<uint32_t>(binding_descriptions.size());
  566. vertex_input_info.pVertexBindingDescriptions = binding_descriptions.data();
  567. VkGraphicsPipelineCreateInfo pipeline_info{};
  568. pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
  569. pipeline_info.stageCount = 2;
  570. pipeline_info.pStages = shader_stages;
  571. pipeline_info.pVertexInputState = &vertex_input_info;
  572. pipeline_info.pInputAssemblyState = &config_info.input_assembly_info;
  573. pipeline_info.pViewportState = &config_info.viewport_info;
  574. pipeline_info.pRasterizationState = &config_info.rasterization_info;
  575. pipeline_info.pMultisampleState = &config_info.multisample_info;
  576. pipeline_info.pColorBlendState = &config_info.color_blend_info;
  577. pipeline_info.pDepthStencilState = &config_info.depth_stencil_info;
  578. pipeline_info.pDynamicState = &config_info.dynamic_state_info;
  579. pipeline_info.layout = config_info.pipeline_layout;
  580. pipeline_info.renderPass = config_info.render_pass;
  581. pipeline_info.subpass = config_info.subpass;
  582. pipeline_info.basePipelineIndex = -1;
  583. pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
  584. for(auto& material : materials_)
  585. {
  586. struct MaterialSpecializationData
  587. {
  588. VkBool32 use_alpha_mask;
  589. float alpha_cutoff;
  590. } material_specialization_data;
  591. std::vector<VkSpecializationMapEntry> specialization_map_entries
  592. {
  593. vkinit::specialization_map_entry(0, offsetof(MaterialSpecializationData, use_alpha_mask), sizeof(MaterialSpecializationData::use_alpha_mask)),
  594. vkinit::specialization_map_entry(1, offsetof(MaterialSpecializationData, alpha_cutoff), sizeof(MaterialSpecializationData::alpha_cutoff))
  595. };
  596. VkSpecializationInfo specialization_info{vkinit::specialization_info(specialization_map_entries, sizeof(material_specialization_data), &material_specialization_data)};
  597. shader_stages[1].pSpecializationInfo = &specialization_info;
  598. config_info.rasterization_info.cullMode = material.double_sided ? VK_CULL_MODE_NONE : VK_CULL_MODE_BACK_BIT;
  599. material_specialization_data.use_alpha_mask = material.alpha_mode == "MASK";
  600. material_specialization_data.alpha_cutoff = material.alpha_cutoff;
  601. if (vkCreateGraphicsPipelines(device_.device(), VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &material.pipeline)
  602. != VK_SUCCESS)
  603. throw std::runtime_error("ERROR! coral_pipeline::create_graphics_pipeline() >> Failed to create graphics pipeline!");
  604. }
  605. vkDestroyShaderModule(device_.device(), frag_shader_module, nullptr);
  606. vkDestroyShaderModule(device_.device(), vert_shader_module, nullptr);
  607. }