Added vertex normal to the Agnosia_T::Vertex definition, pre-calculated using TinyObjLoader's built in vertex normal calculator
This commit is contained in:
parent
d862068c6e
commit
c42133f426
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -3,6 +3,6 @@ Pos=60,60
|
||||
Size=400,400
|
||||
|
||||
[Window][Agnosia Debug]
|
||||
Pos=40,377
|
||||
Pos=59,322
|
||||
Size=623,438
|
||||
|
||||
|
@ -87,8 +87,7 @@ void createInstance() {
|
||||
throw std::runtime_error("failed to create instance!");
|
||||
}
|
||||
}
|
||||
|
||||
void initVulkan() {
|
||||
void initAgnosia() {
|
||||
Material *vikingRoomMaterial =
|
||||
new Material("vikingRoomMaterial", "assets/textures/viking_room.png");
|
||||
Material *stanfordDragonMaterial =
|
||||
@ -104,7 +103,8 @@ void initVulkan() {
|
||||
Model *teapot =
|
||||
new Model("teapot", *teapotMaterial, "assets/models/teapot.obj",
|
||||
glm::vec3(1.0f, -3.0f, -1.0f));
|
||||
|
||||
}
|
||||
void initVulkan() {
|
||||
// Initialize volk and continue if successful.
|
||||
volkInitialize();
|
||||
// Initialize vulkan and set up pipeline.
|
||||
@ -122,9 +122,7 @@ void initVulkan() {
|
||||
Graphics::createCommandPool();
|
||||
// Image creation MUST be after command pool, because command
|
||||
// buffers.
|
||||
vikingRoom->populateData();
|
||||
stanfordDragon->populateData();
|
||||
teapot->populateData();
|
||||
Model::populateModels();
|
||||
Texture::createMaterialTextures(Model::getInstances());
|
||||
Texture::createColorResources();
|
||||
Texture::createDepthResources();
|
||||
@ -150,6 +148,11 @@ void mainLoop() {
|
||||
void cleanup() {
|
||||
Render::cleanupSwapChain();
|
||||
Graphics::destroyGraphicsPipeline();
|
||||
Buffers::destroyDescriptorPool();
|
||||
Model::destroyTextures();
|
||||
|
||||
vkDestroyDescriptorSetLayout(DeviceControl::getDevice(),
|
||||
Buffers::getDescriptorSetLayout(), nullptr);
|
||||
|
||||
Buffers::destroyBuffers();
|
||||
Render::destroyFenceSemaphores();
|
||||
@ -179,6 +182,7 @@ GLFWwindow *EntryApp::getWindow() { return window; }
|
||||
void EntryApp::run() {
|
||||
|
||||
initWindow();
|
||||
initAgnosia();
|
||||
initVulkan();
|
||||
mainLoop();
|
||||
cleanup();
|
||||
|
@ -122,6 +122,9 @@ void Buffers::createDescriptorPool() {
|
||||
throw std::runtime_error("failed to create descriptor pool!");
|
||||
}
|
||||
}
|
||||
void Buffers::destroyDescriptorPool() {
|
||||
vkDestroyDescriptorPool(DeviceControl::getDevice(), descriptorPool, nullptr);
|
||||
}
|
||||
void Buffers::createDescriptorSet(std::vector<Model *> models) {
|
||||
VkDescriptorSetAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
|
@ -19,6 +19,7 @@ public:
|
||||
static void createDescriptorSetLayout();
|
||||
static void createDescriptorSet(std::vector<Model *> models);
|
||||
static void createDescriptorPool();
|
||||
static void destroyDescriptorPool();
|
||||
static void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
||||
VkMemoryPropertyFlags props, VkBuffer &buffer,
|
||||
VkDeviceMemory &bufferMemory);
|
||||
|
@ -20,15 +20,21 @@
|
||||
|
||||
std::vector<Model *> Model::instances;
|
||||
VmaAllocator _allocator;
|
||||
// chatgpt did this and the haters can WEEP fuck hash functions.
|
||||
namespace std {
|
||||
template <> struct hash<Agnosia_T::Vertex> {
|
||||
size_t operator()(Agnosia_T::Vertex const &vertex) const {
|
||||
return ((hash<glm::vec3>()(vertex.pos) ^
|
||||
(hash<glm::vec3>()(vertex.color) << 1)) >>
|
||||
1) ^
|
||||
(hash<glm::vec2>()(vertex.texCoord) << 1);
|
||||
size_t hashPos = hash<glm::vec3>()(vertex.pos);
|
||||
size_t hashColor = hash<glm::vec3>()(vertex.color);
|
||||
size_t hashUV = hash<glm::vec2>()(vertex.uv);
|
||||
size_t hashNormal = hash<glm::vec3>()(vertex.normal);
|
||||
|
||||
// Combine all hashes
|
||||
return ((hashPos ^ (hashColor << 1)) >> 1) ^ (hashUV << 1) ^
|
||||
(hashNormal << 2);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
void Model::createMemoryAllocator(VkInstance vkInstance) {
|
||||
VmaVulkanFunctions vulkanFuncs{
|
||||
@ -105,112 +111,128 @@ Model::Model(const std::string &modelID, const Material &material,
|
||||
instances.push_back(this);
|
||||
}
|
||||
|
||||
void Model::populateData() {
|
||||
void Model::populateModels() {
|
||||
for (Model *model : getInstances()) {
|
||||
|
||||
std::vector<Agnosia_T::Vertex> vertices;
|
||||
// Index buffer definition, showing which points to reuse.
|
||||
std::vector<uint32_t> indices;
|
||||
tinyobj::ObjReaderConfig readerConfig;
|
||||
tinyobj::ObjReader reader;
|
||||
std::vector<Agnosia_T::Vertex> vertices;
|
||||
// Index buffer definition, showing which points to reuse.
|
||||
std::vector<uint32_t> indices;
|
||||
tinyobj::ObjReaderConfig readerConfig;
|
||||
tinyobj::ObjReader reader;
|
||||
|
||||
if (!reader.ParseFromFile(modelPath, readerConfig)) {
|
||||
if (!reader.Error().empty()) {
|
||||
throw std::runtime_error(reader.Error());
|
||||
}
|
||||
if (!reader.Warning().empty()) {
|
||||
throw std::runtime_error(reader.Warning());
|
||||
}
|
||||
}
|
||||
|
||||
auto &attrib = reader.GetAttrib();
|
||||
auto &shapes = reader.GetShapes();
|
||||
auto &materials = reader.GetMaterials();
|
||||
|
||||
std::unordered_map<Agnosia_T::Vertex, uint32_t> uniqueVertices{};
|
||||
|
||||
for (const auto &shape : shapes) {
|
||||
for (const auto &index : shape.mesh.indices) {
|
||||
Agnosia_T::Vertex vertex{};
|
||||
|
||||
vertex.pos = {attrib.vertices[3 * index.vertex_index + 0],
|
||||
attrib.vertices[3 * index.vertex_index + 1],
|
||||
attrib.vertices[3 * index.vertex_index + 2]};
|
||||
|
||||
// TODO: Small fix here, handle if there are no UV's unwrapped for the
|
||||
// model.
|
||||
// As of now, if it is not unwrapped, it segfaults on texCoord
|
||||
// assignment. Obviously we should always have UV's, but it
|
||||
// shouldn't crash, just unwrap in a default method.
|
||||
vertex.texCoord = {attrib.texcoords[2 * index.texcoord_index + 0],
|
||||
1.0f - attrib.texcoords[2 * index.texcoord_index + 1]};
|
||||
vertex.color = {1.0f, 1.0f, 1.0f};
|
||||
|
||||
if (uniqueVertices.count(vertex) == 0) {
|
||||
uniqueVertices[vertex] = static_cast<uint32_t>(vertices.size());
|
||||
vertices.push_back(vertex);
|
||||
if (!reader.ParseFromFile(model->modelPath, readerConfig)) {
|
||||
if (!reader.Error().empty()) {
|
||||
throw std::runtime_error(reader.Error());
|
||||
}
|
||||
if (!reader.Warning().empty()) {
|
||||
throw std::runtime_error(reader.Warning());
|
||||
}
|
||||
indices.push_back(uniqueVertices[vertex]);
|
||||
}
|
||||
|
||||
auto &attrib = reader.GetAttrib();
|
||||
auto &shapes = reader.GetShapes();
|
||||
auto &materials = reader.GetMaterials();
|
||||
|
||||
std::unordered_map<Agnosia_T::Vertex, uint32_t> uniqueVertices{};
|
||||
|
||||
for (const auto &shape : shapes) {
|
||||
for (const auto &index : shape.mesh.indices) {
|
||||
Agnosia_T::Vertex vertex{};
|
||||
|
||||
vertex.pos = {attrib.vertices[3 * index.vertex_index + 0],
|
||||
attrib.vertices[3 * index.vertex_index + 1],
|
||||
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
|
||||
// model.
|
||||
// As of now, if it is not unwrapped, it segfaults on texCoord
|
||||
// assignment. Obviously we should always have UV's, but it
|
||||
// shouldn't crash, just unwrap in a default method.
|
||||
vertex.uv = {attrib.texcoords[2 * index.texcoord_index + 0],
|
||||
1.0f - attrib.texcoords[2 * index.texcoord_index + 1]};
|
||||
vertex.color = {1.0f, 1.0f, 1.0f};
|
||||
|
||||
if (uniqueVertices.count(vertex) == 0) {
|
||||
uniqueVertices[vertex] = static_cast<uint32_t>(vertices.size());
|
||||
vertices.push_back(vertex);
|
||||
}
|
||||
indices.push_back(uniqueVertices[vertex]);
|
||||
}
|
||||
}
|
||||
|
||||
const size_t vertexBufferSize = vertices.size() * sizeof(Agnosia_T::Vertex);
|
||||
const size_t indexBufferSize = indices.size() * sizeof(uint32_t);
|
||||
|
||||
Agnosia_T::GPUMeshBuffers newSurface;
|
||||
|
||||
// Create a Vertex Buffer here, infinitely easier than the old Vulkan
|
||||
// method!
|
||||
newSurface.vertexBuffer = createBuffer(
|
||||
vertexBufferSize,
|
||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
||||
VMA_MEMORY_USAGE_GPU_ONLY);
|
||||
// Find the address of the vertex buffer!
|
||||
VkBufferDeviceAddressInfo deviceAddressInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
|
||||
.buffer = newSurface.vertexBuffer.buffer,
|
||||
};
|
||||
newSurface.vertexBufferAddress = vkGetBufferDeviceAddress(
|
||||
DeviceControl::getDevice(), &deviceAddressInfo);
|
||||
|
||||
// Create the index buffer to iterate over and check for duplicate vertices
|
||||
newSurface.indexBuffer = createBuffer(indexBufferSize,
|
||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VMA_MEMORY_USAGE_GPU_ONLY);
|
||||
|
||||
Agnosia_T::AllocatedBuffer stagingBuffer = createBuffer(
|
||||
vertexBufferSize + indexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VMA_MEMORY_USAGE_CPU_ONLY);
|
||||
|
||||
void *data = stagingBuffer.allocation->GetMappedData();
|
||||
|
||||
// Copy the vertex buffer
|
||||
memcpy(data, vertices.data(), vertexBufferSize);
|
||||
// Copy the index buffer
|
||||
memcpy((char *)data + vertexBufferSize, indices.data(), indexBufferSize);
|
||||
|
||||
immediate_submit([&](VkCommandBuffer cmd) {
|
||||
VkBufferCopy vertexCopy{0};
|
||||
vertexCopy.dstOffset = 0;
|
||||
vertexCopy.srcOffset = 0;
|
||||
vertexCopy.size = vertexBufferSize;
|
||||
|
||||
vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.vertexBuffer.buffer,
|
||||
1, &vertexCopy);
|
||||
|
||||
VkBufferCopy indexCopy{0};
|
||||
indexCopy.dstOffset = 0;
|
||||
indexCopy.srcOffset = vertexBufferSize;
|
||||
indexCopy.size = indexBufferSize;
|
||||
|
||||
vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.indexBuffer.buffer,
|
||||
1, &indexCopy);
|
||||
});
|
||||
vmaDestroyBuffer(_allocator, stagingBuffer.buffer,
|
||||
stagingBuffer.allocation);
|
||||
|
||||
model->buffers = newSurface;
|
||||
model->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);
|
||||
}
|
||||
|
||||
const size_t vertexBufferSize = vertices.size() * sizeof(Agnosia_T::Vertex);
|
||||
const size_t indexBufferSize = indices.size() * sizeof(uint32_t);
|
||||
|
||||
Agnosia_T::GPUMeshBuffers newSurface;
|
||||
|
||||
// Create a Vertex Buffer here, infinitely easier than the old Vulkan method!
|
||||
newSurface.vertexBuffer = createBuffer(
|
||||
vertexBufferSize,
|
||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
||||
VMA_MEMORY_USAGE_GPU_ONLY);
|
||||
// Find the address of the vertex buffer!
|
||||
VkBufferDeviceAddressInfo deviceAddressInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
|
||||
.buffer = newSurface.vertexBuffer.buffer,
|
||||
};
|
||||
newSurface.vertexBufferAddress =
|
||||
vkGetBufferDeviceAddress(DeviceControl::getDevice(), &deviceAddressInfo);
|
||||
|
||||
// Create the index buffer to iterate over and check for duplicate vertices
|
||||
newSurface.indexBuffer = createBuffer(indexBufferSize,
|
||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VMA_MEMORY_USAGE_GPU_ONLY);
|
||||
|
||||
Agnosia_T::AllocatedBuffer stagingBuffer =
|
||||
createBuffer(vertexBufferSize + indexBufferSize,
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY);
|
||||
|
||||
void *data = stagingBuffer.allocation->GetMappedData();
|
||||
|
||||
// Copy the vertex buffer
|
||||
memcpy(data, vertices.data(), vertexBufferSize);
|
||||
// Copy the index buffer
|
||||
memcpy((char *)data + vertexBufferSize, indices.data(), indexBufferSize);
|
||||
|
||||
immediate_submit([&](VkCommandBuffer cmd) {
|
||||
VkBufferCopy vertexCopy{0};
|
||||
vertexCopy.dstOffset = 0;
|
||||
vertexCopy.srcOffset = 0;
|
||||
vertexCopy.size = vertexBufferSize;
|
||||
|
||||
vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.vertexBuffer.buffer,
|
||||
1, &vertexCopy);
|
||||
|
||||
VkBufferCopy indexCopy{0};
|
||||
indexCopy.dstOffset = 0;
|
||||
indexCopy.srcOffset = vertexBufferSize;
|
||||
indexCopy.size = indexBufferSize;
|
||||
|
||||
vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.indexBuffer.buffer, 1,
|
||||
&indexCopy);
|
||||
});
|
||||
vmaDestroyBuffer(_allocator, stagingBuffer.buffer, stagingBuffer.allocation);
|
||||
|
||||
this->buffers = newSurface;
|
||||
this->objPosition = objPosition;
|
||||
this->indiceCount = indices.size();
|
||||
}
|
||||
|
||||
std::string Model::getID() { return this->ID; }
|
||||
|
@ -28,7 +28,8 @@ public:
|
||||
static void createMemoryAllocator(VkInstance instance);
|
||||
static const std::vector<Model *> &getInstances();
|
||||
|
||||
void populateData();
|
||||
static void populateModels();
|
||||
static void destroyTextures();
|
||||
|
||||
Agnosia_T::GPUMeshBuffers getBuffers();
|
||||
std::string getID();
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
struct Vertex {
|
||||
vec3 pos;
|
||||
vec3 normal;
|
||||
vec3 color;
|
||||
vec2 texCoord;
|
||||
};
|
||||
|
@ -11,5 +11,5 @@ layout(location = 1) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outColor = texture(texSampler[PushConstants.textureID], fragTexCoord);
|
||||
outColor = texture(texSampler[PushConstants.textureID], fragTexCoord) * vec4(fragColor, 1.0f);
|
||||
}
|
||||
|
@ -10,12 +10,13 @@ public:
|
||||
// This defines what a vertex is!
|
||||
// We control the position, color and texture coordinate here!
|
||||
glm::vec3 pos;
|
||||
glm::vec3 normal;
|
||||
glm::vec3 color;
|
||||
glm::vec2 texCoord;
|
||||
glm::vec2 uv;
|
||||
|
||||
bool operator==(const Vertex &other) const {
|
||||
return pos == other.pos && color == other.color &&
|
||||
texCoord == other.texCoord;
|
||||
return pos == other.pos && normal == other.normal &&
|
||||
color == other.color && uv == other.uv;
|
||||
}
|
||||
};
|
||||
struct AllocatedBuffer {
|
||||
|
Loading…
Reference in New Issue
Block a user