1#include <assimp/Importer.hpp>
2#include <assimp/postprocess.h>
4#define GLM_ENABLE_EXPERIMENTAL
5#include <glm/gtx/hash.hpp>
12struct std::hash<
ven::Model::Vertex> {
15 ven::hashCombine(seed, vertex.position, vertex.color, vertex.normal, vertex.uv);
28 m_vertexCount =
static_cast<uint32_t
>(vertices.size());
29 assert(m_vertexCount >= 3 &&
"Vertex count must be at least 3");
30 constexpr unsigned long vertexSize =
sizeof(vertices[0]);
31 const VkDeviceSize bufferSize = vertexSize * m_vertexCount;
33 Buffer stagingBuffer{m_device, vertexSize, m_vertexCount, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT};
36 stagingBuffer.writeToBuffer(vertices.data());
38 m_vertexBuffer = std::make_unique<Buffer>(m_device, vertexSize, m_vertexCount, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
40 m_device.copyBuffer(stagingBuffer.getBuffer(), m_vertexBuffer->getBuffer(), bufferSize);
45 m_indexCount =
static_cast<uint32_t
>(indices.size());
46 m_hasIndexBuffer = m_indexCount > 0;
48 if (!m_hasIndexBuffer) {
52 constexpr uint32_t indexSize =
sizeof(indices[0]);
54 Buffer stagingBuffer{m_device, indexSize, m_indexCount, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT};
57 stagingBuffer.writeToBuffer(indices.data());
59 m_indexBuffer = std::make_unique<Buffer>(m_device, indexSize, m_indexCount, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
61 m_device.copyBuffer(stagingBuffer.getBuffer(), m_indexBuffer->getBuffer(),
sizeof(indices[0]) * m_indexCount);
66 if (m_hasIndexBuffer) {
67 vkCmdDrawIndexed(commandBuffer, m_indexCount, 1, 0, 0, 0);
69 vkCmdDraw(commandBuffer, m_vertexCount, 1, 0, 0);
75 const std::array buffers{m_vertexBuffer->getBuffer()};
76 constexpr std::array<VkDeviceSize, 1> offsets{0};
77 vkCmdBindVertexBuffers(commandBuffer, 0, 1, buffers.data(), offsets.data());
79 if (m_hasIndexBuffer) {
80 vkCmdBindIndexBuffer(commandBuffer, m_indexBuffer->getBuffer(), 0, VK_INDEX_TYPE_UINT32);
86 std::vector<VkVertexInputBindingDescription> bindingDescriptions(1);
87 bindingDescriptions[0].binding = 0;
88 bindingDescriptions[0].stride =
sizeof(
Vertex);
89 bindingDescriptions[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
90 return bindingDescriptions;
95 std::vector<VkVertexInputAttributeDescription> attributeDescriptions{};
97 attributeDescriptions.push_back({0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(
Vertex, position)});
98 attributeDescriptions.push_back({1, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(
Vertex, color)});
99 attributeDescriptions.push_back({2, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(
Vertex, normal)});
100 attributeDescriptions.push_back({3, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(
Vertex, uv)});
102 return attributeDescriptions;
107 Assimp::Importer importer;
109 const aiScene* scene = importer.ReadFile(filename, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace | aiProcess_GenNormals);
111 if ((scene ==
nullptr) || ((scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) != 0U) || (scene->mRootNode ==
nullptr)) {
112 throw std::runtime_error(
"Failed to load model with Assimp: " + std::string(importer.GetErrorString()));
118 processNode(scene->mRootNode, scene);
122 for (
unsigned int i = 0; i < node->mNumMeshes; i++) {
123 const aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
124 processMesh(mesh, scene);
127 for (
unsigned int i = 0; i < node->mNumChildren; i++) {
128 processNode(node->mChildren[i], scene);
133 std::unordered_map<Vertex, uint32_t> uniqueVertices;
135 for (
unsigned int i = 0; i < mesh->mNumVertices; i++) {
139 mesh->mVertices[i].x,
140 mesh->mVertices[i].y,
144 if (mesh->HasNormals()) {
145 vertex.normal = glm::vec3(
152 if (mesh->mTextureCoords[0] !=
nullptr) {
153 vertex.uv = glm::vec2(
154 mesh->mTextureCoords[0][i].x,
155 mesh->mTextureCoords[0][i].y
158 vertex.uv = glm::vec2(0.0F, 0.0F);
161 if (!uniqueVertices.contains(vertex)) {
162 uniqueVertices[vertex] =
static_cast<uint32_t
>(vertices.size());
163 vertices.push_back(vertex);
166 indices.push_back(uniqueVertices[vertex]);
This file contains the Model class.
VkResult map(VkDeviceSize size=VK_WHOLE_SIZE, VkDeviceSize offset=0)
Map a memory range of this buffer.
void draw(VkCommandBuffer commandBuffer) const
Model(Device &device, const Builder &builder)
void bind(VkCommandBuffer commandBuffer) const
void createVertexBuffer(const std::vector< Vertex > &vertices)
void createIndexBuffer(const std::vector< uint32_t > &indices)
void hashCombine(std::size_t &seed, const T &v, const Rest &... rest)
size_t operator()(ven::Model::Vertex const &vertex) const noexcept
void loadModel(const std::string &filename)
std::vector< Vertex > vertices
void processMesh(const aiMesh *mesh, const aiScene *scene)
std::vector< uint32_t > indices
void processNode(const aiNode *node, const aiScene *scene)
static std::vector< VkVertexInputAttributeDescription > getAttributeDescriptions()
static std::vector< VkVertexInputBindingDescription > getBindingDescriptions()