vengine  0.0.1
3D graphics engine
Loading...
Searching...
No Matches
model.cpp
Go to the documentation of this file.
1#include <assimp/Importer.hpp>
2#include <assimp/postprocess.h>
3
4#define GLM_ENABLE_EXPERIMENTAL
5#include <glm/gtx/hash.hpp>
6
10
11template<>
12struct std::hash<ven::Model::Vertex> {
13 size_t operator()(ven::Model::Vertex const &vertex) const noexcept {
14 size_t seed = 0;
15 ven::hashCombine(seed, vertex.position, vertex.color, vertex.normal, vertex.uv);
16 return seed;
17 }
18};
19
20ven::Model::Model(Device &device, const Builder &builder) : m_device{device}, m_vertexCount(0), m_indexCount(0)
21{
24}
25
26void ven::Model::createVertexBuffer(const std::vector<Vertex> &vertices)
27{
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;
32
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};
34
35 stagingBuffer.map();
36 stagingBuffer.writeToBuffer(vertices.data());
37
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);
39
40 m_device.copyBuffer(stagingBuffer.getBuffer(), m_vertexBuffer->getBuffer(), bufferSize);
41}
42
43void ven::Model::createIndexBuffer(const std::vector<uint32_t> &indices)
44{
45 m_indexCount = static_cast<uint32_t>(indices.size());
46 m_hasIndexBuffer = m_indexCount > 0;
47
48 if (!m_hasIndexBuffer) {
49 return;
50 }
51
52 constexpr uint32_t indexSize = sizeof(indices[0]);
53
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};
55
56 stagingBuffer.map();
57 stagingBuffer.writeToBuffer(indices.data());
58
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);
60
61 m_device.copyBuffer(stagingBuffer.getBuffer(), m_indexBuffer->getBuffer(), sizeof(indices[0]) * m_indexCount);
62}
63
64void ven::Model::draw(const VkCommandBuffer commandBuffer) const
65{
66 if (m_hasIndexBuffer) {
67 vkCmdDrawIndexed(commandBuffer, m_indexCount, 1, 0, 0, 0);
68 } else {
69 vkCmdDraw(commandBuffer, m_vertexCount, 1, 0, 0);
70 }
71}
72
73void ven::Model::bind(const VkCommandBuffer commandBuffer) const
74{
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());
78
79 if (m_hasIndexBuffer) {
80 vkCmdBindIndexBuffer(commandBuffer, m_indexBuffer->getBuffer(), 0, VK_INDEX_TYPE_UINT32);
81 }
82}
83
84std::vector<VkVertexInputBindingDescription> ven::Model::Vertex::getBindingDescriptions()
85{
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;
91}
92
93std::vector<VkVertexInputAttributeDescription> ven::Model::Vertex::getAttributeDescriptions()
94{
95 std::vector<VkVertexInputAttributeDescription> attributeDescriptions{};
96
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)});
101
102 return attributeDescriptions;
103}
104
105void ven::Model::Builder::loadModel(const std::string &filename)
106{
107 Assimp::Importer importer;
108
109 const aiScene* scene = importer.ReadFile(filename, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace | aiProcess_GenNormals);
110
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()));
113 }
114
115 vertices.clear();
116 indices.clear();
117
118 processNode(scene->mRootNode, scene);
119}
120
121void ven::Model::Builder::processNode(const aiNode* node, const aiScene* scene) {
122 for (unsigned int i = 0; i < node->mNumMeshes; i++) {
123 const aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
124 processMesh(mesh, scene);
125 }
126
127 for (unsigned int i = 0; i < node->mNumChildren; i++) {
128 processNode(node->mChildren[i], scene);
129 }
130}
131
132void ven::Model::Builder::processMesh(const aiMesh* mesh, const aiScene* scene) {
133 std::unordered_map<Vertex, uint32_t> uniqueVertices;
134
135 for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
136 Vertex vertex{};
137
138 vertex.position = glm::vec3(
139 mesh->mVertices[i].x,
140 mesh->mVertices[i].y,
141 mesh->mVertices[i].z
142 );
143
144 if (mesh->HasNormals()) {
145 vertex.normal = glm::vec3(
146 mesh->mNormals[i].x,
147 mesh->mNormals[i].y,
148 mesh->mNormals[i].z
149 );
150 }
151
152 if (mesh->mTextureCoords[0] != nullptr) {
153 vertex.uv = glm::vec2(
154 mesh->mTextureCoords[0][i].x,
155 mesh->mTextureCoords[0][i].y
156 );
157 } else {
158 vertex.uv = glm::vec2(0.0F, 0.0F);
159 }
160
161 if (!uniqueVertices.contains(vertex)) {
162 uniqueVertices[vertex] = static_cast<uint32_t>(vertices.size());
163 vertices.push_back(vertex);
164 }
165
166 indices.push_back(uniqueVertices[vertex]);
167 }
168}
169
This file contains the Model class.
Class for buffer.
Definition Buffer.hpp:20
VkResult map(VkDeviceSize size=VK_WHOLE_SIZE, VkDeviceSize offset=0)
Map a memory range of this buffer.
Definition buffer.cpp:18
Class for device.
Definition Device.hpp:35
void draw(VkCommandBuffer commandBuffer) const
Definition model.cpp:64
Model(Device &device, const Builder &builder)
Definition model.cpp:20
void bind(VkCommandBuffer commandBuffer) const
Definition model.cpp:73
void createVertexBuffer(const std::vector< Vertex > &vertices)
Definition model.cpp:26
void createIndexBuffer(const std::vector< uint32_t > &indices)
Definition model.cpp:43
void hashCombine(std::size_t &seed, const T &v, const Rest &... rest)
size_t operator()(ven::Model::Vertex const &vertex) const noexcept
Definition model.cpp:13
void loadModel(const std::string &filename)
Definition model.cpp:105
std::vector< Vertex > vertices
Definition Model.hpp:46
void processMesh(const aiMesh *mesh, const aiScene *scene)
Definition model.cpp:132
std::vector< uint32_t > indices
Definition Model.hpp:47
void processNode(const aiNode *node, const aiScene *scene)
Definition model.cpp:121
glm::vec3 position
Definition Model.hpp:34
static std::vector< VkVertexInputAttributeDescription > getAttributeDescriptions()
Definition model.cpp:93
static std::vector< VkVertexInputBindingDescription > getBindingDescriptions()
Definition model.cpp:84