Added vertex normal to the Agnosia_T::Vertex definition, pre-calculated using TinyObjLoader's built in vertex normal calculator

This commit is contained in:
Lillian Salehi 2024-12-04 01:55:40 -06:00
parent d862068c6e
commit c42133f426
13 changed files with 150 additions and 117 deletions

View File

@ -3,6 +3,6 @@ Pos=60,60
Size=400,400 Size=400,400
[Window][Agnosia Debug] [Window][Agnosia Debug]
Pos=40,377 Pos=59,322
Size=623,438 Size=623,438

View File

@ -87,8 +87,7 @@ void createInstance() {
throw std::runtime_error("failed to create instance!"); throw std::runtime_error("failed to create instance!");
} }
} }
void initAgnosia() {
void initVulkan() {
Material *vikingRoomMaterial = Material *vikingRoomMaterial =
new Material("vikingRoomMaterial", "assets/textures/viking_room.png"); new Material("vikingRoomMaterial", "assets/textures/viking_room.png");
Material *stanfordDragonMaterial = Material *stanfordDragonMaterial =
@ -104,7 +103,8 @@ void initVulkan() {
Model *teapot = Model *teapot =
new Model("teapot", *teapotMaterial, "assets/models/teapot.obj", new Model("teapot", *teapotMaterial, "assets/models/teapot.obj",
glm::vec3(1.0f, -3.0f, -1.0f)); glm::vec3(1.0f, -3.0f, -1.0f));
}
void initVulkan() {
// Initialize volk and continue if successful. // Initialize volk and continue if successful.
volkInitialize(); volkInitialize();
// Initialize vulkan and set up pipeline. // Initialize vulkan and set up pipeline.
@ -122,9 +122,7 @@ void initVulkan() {
Graphics::createCommandPool(); Graphics::createCommandPool();
// Image creation MUST be after command pool, because command // Image creation MUST be after command pool, because command
// buffers. // buffers.
vikingRoom->populateData(); Model::populateModels();
stanfordDragon->populateData();
teapot->populateData();
Texture::createMaterialTextures(Model::getInstances()); Texture::createMaterialTextures(Model::getInstances());
Texture::createColorResources(); Texture::createColorResources();
Texture::createDepthResources(); Texture::createDepthResources();
@ -150,6 +148,11 @@ void mainLoop() {
void cleanup() { void cleanup() {
Render::cleanupSwapChain(); Render::cleanupSwapChain();
Graphics::destroyGraphicsPipeline(); Graphics::destroyGraphicsPipeline();
Buffers::destroyDescriptorPool();
Model::destroyTextures();
vkDestroyDescriptorSetLayout(DeviceControl::getDevice(),
Buffers::getDescriptorSetLayout(), nullptr);
Buffers::destroyBuffers(); Buffers::destroyBuffers();
Render::destroyFenceSemaphores(); Render::destroyFenceSemaphores();
@ -179,6 +182,7 @@ GLFWwindow *EntryApp::getWindow() { return window; }
void EntryApp::run() { void EntryApp::run() {
initWindow(); initWindow();
initAgnosia();
initVulkan(); initVulkan();
mainLoop(); mainLoop();
cleanup(); cleanup();

View File

@ -122,6 +122,9 @@ void Buffers::createDescriptorPool() {
throw std::runtime_error("failed to create descriptor pool!"); throw std::runtime_error("failed to create descriptor pool!");
} }
} }
void Buffers::destroyDescriptorPool() {
vkDestroyDescriptorPool(DeviceControl::getDevice(), descriptorPool, nullptr);
}
void Buffers::createDescriptorSet(std::vector<Model *> models) { void Buffers::createDescriptorSet(std::vector<Model *> models) {
VkDescriptorSetAllocateInfo allocInfo{}; VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;

View File

@ -19,6 +19,7 @@ public:
static void createDescriptorSetLayout(); static void createDescriptorSetLayout();
static void createDescriptorSet(std::vector<Model *> models); static void createDescriptorSet(std::vector<Model *> models);
static void createDescriptorPool(); static void createDescriptorPool();
static void destroyDescriptorPool();
static void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, static void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
VkMemoryPropertyFlags props, VkBuffer &buffer, VkMemoryPropertyFlags props, VkBuffer &buffer,
VkDeviceMemory &bufferMemory); VkDeviceMemory &bufferMemory);

View File

@ -20,15 +20,21 @@
std::vector<Model *> Model::instances; std::vector<Model *> Model::instances;
VmaAllocator _allocator; VmaAllocator _allocator;
// chatgpt did this and the haters can WEEP fuck hash functions.
namespace std { namespace std {
template <> struct hash<Agnosia_T::Vertex> { template <> struct hash<Agnosia_T::Vertex> {
size_t operator()(Agnosia_T::Vertex const &vertex) const { size_t operator()(Agnosia_T::Vertex const &vertex) const {
return ((hash<glm::vec3>()(vertex.pos) ^ size_t hashPos = hash<glm::vec3>()(vertex.pos);
(hash<glm::vec3>()(vertex.color) << 1)) >> size_t hashColor = hash<glm::vec3>()(vertex.color);
1) ^ size_t hashUV = hash<glm::vec2>()(vertex.uv);
(hash<glm::vec2>()(vertex.texCoord) << 1); size_t hashNormal = hash<glm::vec3>()(vertex.normal);
// Combine all hashes
return ((hashPos ^ (hashColor << 1)) >> 1) ^ (hashUV << 1) ^
(hashNormal << 2);
} }
}; };
} // namespace std } // namespace std
void Model::createMemoryAllocator(VkInstance vkInstance) { void Model::createMemoryAllocator(VkInstance vkInstance) {
VmaVulkanFunctions vulkanFuncs{ VmaVulkanFunctions vulkanFuncs{
@ -105,7 +111,8 @@ Model::Model(const std::string &modelID, const Material &material,
instances.push_back(this); instances.push_back(this);
} }
void Model::populateData() { void Model::populateModels() {
for (Model *model : getInstances()) {
std::vector<Agnosia_T::Vertex> vertices; std::vector<Agnosia_T::Vertex> vertices;
// Index buffer definition, showing which points to reuse. // Index buffer definition, showing which points to reuse.
@ -113,7 +120,7 @@ void Model::populateData() {
tinyobj::ObjReaderConfig readerConfig; tinyobj::ObjReaderConfig readerConfig;
tinyobj::ObjReader reader; tinyobj::ObjReader reader;
if (!reader.ParseFromFile(modelPath, readerConfig)) { if (!reader.ParseFromFile(model->modelPath, readerConfig)) {
if (!reader.Error().empty()) { if (!reader.Error().empty()) {
throw std::runtime_error(reader.Error()); throw std::runtime_error(reader.Error());
} }
@ -136,12 +143,15 @@ void Model::populateData() {
attrib.vertices[3 * index.vertex_index + 1], attrib.vertices[3 * index.vertex_index + 1],
attrib.vertices[3 * index.vertex_index + 2]}; attrib.vertices[3 * index.vertex_index + 2]};
vertex.normal = {attrib.normals[3 * index.normal_index + 0],
attrib.normals[3 * index.normal_index + 1],
attrib.normals[3 * index.normal_index + 2]};
// TODO: Small fix here, handle if there are no UV's unwrapped for the // TODO: Small fix here, handle if there are no UV's unwrapped for the
// model. // model.
// As of now, if it is not unwrapped, it segfaults on texCoord // As of now, if it is not unwrapped, it segfaults on texCoord
// assignment. Obviously we should always have UV's, but it // assignment. Obviously we should always have UV's, but it
// shouldn't crash, just unwrap in a default method. // shouldn't crash, just unwrap in a default method.
vertex.texCoord = {attrib.texcoords[2 * index.texcoord_index + 0], vertex.uv = {attrib.texcoords[2 * index.texcoord_index + 0],
1.0f - attrib.texcoords[2 * index.texcoord_index + 1]}; 1.0f - attrib.texcoords[2 * index.texcoord_index + 1]};
vertex.color = {1.0f, 1.0f, 1.0f}; vertex.color = {1.0f, 1.0f, 1.0f};
@ -158,7 +168,8 @@ void Model::populateData() {
Agnosia_T::GPUMeshBuffers newSurface; Agnosia_T::GPUMeshBuffers newSurface;
// Create a Vertex Buffer here, infinitely easier than the old Vulkan method! // Create a Vertex Buffer here, infinitely easier than the old Vulkan
// method!
newSurface.vertexBuffer = createBuffer( newSurface.vertexBuffer = createBuffer(
vertexBufferSize, vertexBufferSize,
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
@ -169,8 +180,8 @@ void Model::populateData() {
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
.buffer = newSurface.vertexBuffer.buffer, .buffer = newSurface.vertexBuffer.buffer,
}; };
newSurface.vertexBufferAddress = newSurface.vertexBufferAddress = vkGetBufferDeviceAddress(
vkGetBufferDeviceAddress(DeviceControl::getDevice(), &deviceAddressInfo); DeviceControl::getDevice(), &deviceAddressInfo);
// Create the index buffer to iterate over and check for duplicate vertices // Create the index buffer to iterate over and check for duplicate vertices
newSurface.indexBuffer = createBuffer(indexBufferSize, newSurface.indexBuffer = createBuffer(indexBufferSize,
@ -178,9 +189,9 @@ void Model::populateData() {
VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VMA_MEMORY_USAGE_GPU_ONLY); VMA_MEMORY_USAGE_GPU_ONLY);
Agnosia_T::AllocatedBuffer stagingBuffer = Agnosia_T::AllocatedBuffer stagingBuffer = createBuffer(
createBuffer(vertexBufferSize + indexBufferSize, vertexBufferSize + indexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); VMA_MEMORY_USAGE_CPU_ONLY);
void *data = stagingBuffer.allocation->GetMappedData(); void *data = stagingBuffer.allocation->GetMappedData();
@ -203,14 +214,25 @@ void Model::populateData() {
indexCopy.srcOffset = vertexBufferSize; indexCopy.srcOffset = vertexBufferSize;
indexCopy.size = indexBufferSize; indexCopy.size = indexBufferSize;
vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.indexBuffer.buffer, 1, vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.indexBuffer.buffer,
&indexCopy); 1, &indexCopy);
}); });
vmaDestroyBuffer(_allocator, stagingBuffer.buffer, stagingBuffer.allocation); vmaDestroyBuffer(_allocator, stagingBuffer.buffer,
stagingBuffer.allocation);
this->buffers = newSurface; model->buffers = newSurface;
this->objPosition = objPosition; model->indiceCount = indices.size();
this->indiceCount = indices.size(); }
}
void Model::destroyTextures() {
for (Model *model : Model::getInstances()) {
vkDestroySampler(DeviceControl::getDevice(),
model->getMaterial().getTextureSampler(), nullptr);
vkDestroyImageView(DeviceControl::getDevice(),
model->getMaterial().getTextureView(), nullptr);
vkDestroyImage(DeviceControl::getDevice(),
model->getMaterial().getTextureImage(), nullptr);
}
} }
std::string Model::getID() { return this->ID; } std::string Model::getID() { return this->ID; }

View File

@ -28,7 +28,8 @@ public:
static void createMemoryAllocator(VkInstance instance); static void createMemoryAllocator(VkInstance instance);
static const std::vector<Model *> &getInstances(); static const std::vector<Model *> &getInstances();
void populateData(); static void populateModels();
static void destroyTextures();
Agnosia_T::GPUMeshBuffers getBuffers(); Agnosia_T::GPUMeshBuffers getBuffers();
std::string getID(); std::string getID();

View File

@ -4,6 +4,7 @@
struct Vertex { struct Vertex {
vec3 pos; vec3 pos;
vec3 normal;
vec3 color; vec3 color;
vec2 texCoord; vec2 texCoord;
}; };

View File

@ -11,5 +11,5 @@ layout(location = 1) in vec2 fragTexCoord;
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;
void main() { void main() {
outColor = texture(texSampler[PushConstants.textureID], fragTexCoord); outColor = texture(texSampler[PushConstants.textureID], fragTexCoord) * vec4(fragColor, 1.0f);
} }

View File

@ -10,12 +10,13 @@ public:
// This defines what a vertex is! // This defines what a vertex is!
// We control the position, color and texture coordinate here! // We control the position, color and texture coordinate here!
glm::vec3 pos; glm::vec3 pos;
glm::vec3 normal;
glm::vec3 color; glm::vec3 color;
glm::vec2 texCoord; glm::vec2 uv;
bool operator==(const Vertex &other) const { bool operator==(const Vertex &other) const {
return pos == other.pos && color == other.color && return pos == other.pos && normal == other.normal &&
texCoord == other.texCoord; color == other.color && uv == other.uv;
} }
}; };
struct AllocatedBuffer { struct AllocatedBuffer {