vengine  0.1.0
3D graphics engine made with Vulkan
Loading...
Searching...
No Matches
model.cpp
Go to the documentation of this file.
1#include <cassert>
2#include <cstring>
3#include <unordered_map>
4
5#define TINYOBJLOADER_IMPLEMENTATION
6#include <tiny_obj_loader.h>
7
8#define GLM_ENABLE_EXPERIMENTAL
9#include <glm/gtx/hash.hpp>
10
11#include "VEngine/Model.hpp"
12#include "VEngine/Utils.hpp"
13
14namespace std {
15 template<>
16 struct hash<ven::Model::Vertex> {
17 size_t operator()(ven::Model::Vertex const &vertex) const {
18 size_t seed = 0;
19 ven::hashCombine(seed, vertex.position, vertex.color, vertex.normal, vertex.uv);
20 return seed;
21 }
22 };
23}
24
25ven::Model::Model(Device &device, const Builder &builder) : m_device{device}, m_vertexCount(0), m_indexCount(0)
26{
29}
30
31ven::Model::~Model() = default;
32
33void ven::Model::createVertexBuffer(const std::vector<Vertex> &vertices)
34{
35 m_vertexCount = static_cast<uint32_t>(vertices.size());
36 assert(m_vertexCount >= 3 && "Vertex count must be at least 3");
37 const VkDeviceSize bufferSize = sizeof(vertices[0]) * m_vertexCount;
38 uint32_t vertexSize = sizeof(vertices[0]);
39
40 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};
41
42 stagingBuffer.map();
43 stagingBuffer.writeToBuffer(vertices.data());
44
45 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);
46
47 m_device.copyBuffer(stagingBuffer.getBuffer(), m_vertexBuffer->getBuffer(), bufferSize);
48}
49
50void ven::Model::createIndexBuffer(const std::vector<uint32_t> &indices)
51{
52 m_indexCount = static_cast<uint32_t>(indices.size());
53 m_hasIndexBuffer = m_indexCount > 0;
54
55 if (!m_hasIndexBuffer) {
56 return;
57 }
58
59 const VkDeviceSize bufferSize = sizeof(indices[0]) * m_indexCount;
60 uint32_t indexSize = sizeof(indices[0]);
61
62 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};
63
64 stagingBuffer.map();
65 stagingBuffer.writeToBuffer(indices.data());
66
67 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);
68
69 m_device.copyBuffer(stagingBuffer.getBuffer(), m_indexBuffer->getBuffer(), bufferSize);
70}
71
72void ven::Model::draw(const VkCommandBuffer commandBuffer) const
73{
74 if (m_hasIndexBuffer) {
75 vkCmdDrawIndexed(commandBuffer, m_indexCount, 1, 0, 0, 0);
76 } else {
77 vkCmdDraw(commandBuffer, m_vertexCount, 1, 0, 0);
78 }
79}
80
81void ven::Model::bind(const VkCommandBuffer commandBuffer) const
82{
83 const VkBuffer buffers[] = {m_vertexBuffer->getBuffer()};
84 constexpr VkDeviceSize offsets[] = {0};
85 vkCmdBindVertexBuffers(commandBuffer, 0, 1, buffers, offsets);
86
87 if (m_hasIndexBuffer) {
88 vkCmdBindIndexBuffer(commandBuffer, m_indexBuffer->getBuffer(), 0, VK_INDEX_TYPE_UINT32);
89 }
90}
91
92std::unique_ptr<ven::Model> ven::Model::createModelFromFile(Device &device, const std::string &filename)
93{
94 Builder builder{};
95 builder.loadModel(filename);
96 return std::make_unique<Model>(device, builder);
97}
98
99std::vector<VkVertexInputBindingDescription> ven::Model::Vertex::getBindingDescriptions()
100{
101 std::vector<VkVertexInputBindingDescription> bindingDescriptions(1);
102 bindingDescriptions[0].binding = 0;
103 bindingDescriptions[0].stride = sizeof(Vertex);
104 bindingDescriptions[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
105 return bindingDescriptions;
106}
107
108std::vector<VkVertexInputAttributeDescription> ven::Model::Vertex::getAttributeDescriptions()
109{
110 std::vector<VkVertexInputAttributeDescription> attributeDescriptions{};
111
112 attributeDescriptions.push_back({0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, position)});
113 attributeDescriptions.push_back({1, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, color)});
114 attributeDescriptions.push_back({2, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, normal)});
115 attributeDescriptions.push_back({3, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, uv)});
116
117 return attributeDescriptions;
118}
119
120void ven::Model::Builder::loadModel(const std::string &filename)
121{
122 tinyobj::attrib_t attrib;
123 std::vector<tinyobj::shape_t> shapes;
124 std::vector<tinyobj::material_t> materials;
125 std::string warn;
126 std::string err;
127
128 if (!LoadObj(&attrib, &shapes, &materials, &warn, &err, filename.c_str()))
129 {
130 throw std::runtime_error(warn + err);
131 }
132
133 vertices.clear();
134 indices.clear();
135
136 std::unordered_map<Vertex, uint32_t> uniqueVertices{};
137 for (const auto &shape : shapes) {
138 for (const auto &index : shape.mesh.indices) {
139 Vertex vertex{};
140 if (index.vertex_index >= 0) {
141 vertex.position = {
142 attrib.vertices[3 * static_cast<size_t>(index.vertex_index) + 0],
143 attrib.vertices[3 * static_cast<size_t>(index.vertex_index) + 1],
144 attrib.vertices[3 * static_cast<size_t>(index.vertex_index) + 2]
145 };
146
147 vertex.color = {
148 attrib.colors[3 * static_cast<size_t>(index.vertex_index) + 0],
149 attrib.colors[3 * static_cast<size_t>(index.vertex_index) + 1],
150 attrib.colors[3 * static_cast<size_t>(index.vertex_index) + 2]
151 };
152 }
153
154 if (index.normal_index >= 0) {
155 vertex.normal = {
156 attrib.normals[3 * static_cast<size_t>(index.normal_index) + 0],
157 attrib.normals[3 * static_cast<size_t>(index.normal_index) + 1],
158 attrib.normals[3 * static_cast<size_t>(index.normal_index) + 2]
159 };
160 }
161
162 if (index.texcoord_index >= 0) {
163 vertex.uv = {
164 attrib.texcoords[2 * static_cast<size_t>(index.texcoord_index) + 0],
165 attrib.texcoords[2 * static_cast<size_t>(index.texcoord_index) + 1]
166 };
167 }
168
169 if (!uniqueVertices.contains(vertex)) {
170 uniqueVertices[vertex] = static_cast<uint32_t>(vertices.size());
171 vertices.push_back(vertex);
172 }
173 indices.push_back(uniqueVertices[vertex]);
174 }
175 }
176}
This file contains the Model class.
Class for buffer.
Definition Buffer.hpp:17
VkResult map(VkDeviceSize size=VK_WHOLE_SIZE, VkDeviceSize offset=0)
Map a memory range of this buffer.
Definition buffer.cpp:26
void draw(VkCommandBuffer commandBuffer) const
Definition model.cpp:72
static std::unique_ptr< Model > createModelFromFile(Device &device, const std::string &filename)
Definition model.cpp:92
Model(Device &device, const Builder &builder)
Definition model.cpp:25
void bind(VkCommandBuffer commandBuffer) const
Definition model.cpp:81
void createVertexBuffer(const std::vector< Vertex > &vertices)
Definition model.cpp:33
void createIndexBuffer(const std::vector< uint32_t > &indices)
Definition model.cpp:50
STL namespace.
void hashCombine(std::size_t &seed, const T &v, const Rest &... rest)
Definition Utils.hpp:14
size_t operator()(ven::Model::Vertex const &vertex) const
Definition model.cpp:17
void loadModel(const std::string &filename)
Definition model.cpp:120
std::vector< Vertex > vertices
Definition Model.hpp:35
std::vector< uint32_t > indices
Definition Model.hpp:36
glm::vec3 position
Definition Model.hpp:21
static std::vector< VkVertexInputAttributeDescription > getAttributeDescriptions()
Definition model.cpp:108
glm::vec3 color
Definition Model.hpp:22
static std::vector< VkVertexInputBindingDescription > getBindingDescriptions()
Definition model.cpp:99
glm::vec3 normal
Definition Model.hpp:23
glm::vec2 uv
Definition Model.hpp:24