From b3cdf37045c5b0e2be03aaa8603e88f5476c0eda Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Fri, 6 Feb 2026 11:55:32 -0500 Subject: [PATCH] Total mess. The instructions significantly fall apart at this point and I'll have to go reverse engineer the working version from the course's git repo. --- meson.build | 1 + vk_engine.cpp | 153 ++++++++++++++---------------------- vk_engine.h | 5 +- vk_initializers.cpp | 20 +++++ vk_initializers.h | 2 + vk_loader.cpp | 187 +++++++++++++++++++++----------------------- vk_pipelines.cpp | 12 +++ vk_pipelines.h | 1 + 8 files changed, 185 insertions(+), 196 deletions(-) diff --git a/meson.build b/meson.build index 9383111..21cf34e 100644 --- a/meson.build +++ b/meson.build @@ -15,6 +15,7 @@ cpp_args=[ '-Wno-unused-parameter', '-Wno-unused-function', '-Wno-unused-variable', + '-Wno-unused-but-set-variable', '-Wno-conversion', '-Wno-missing-field-initializers' ] diff --git a/vk_engine.cpp b/vk_engine.cpp index 6119da7..2561548 100644 --- a/vk_engine.cpp +++ b/vk_engine.cpp @@ -1,4 +1,6 @@ -#include "vk_engine.h" +#define GLM_ENABLE_EXPERIMENTAL 1 +#include +#include "vk_engine.h" #include "vk_images.h" #include "vk_pipelines.h" #include @@ -58,6 +60,11 @@ void VulkanEngine::cleanup() _frames[i]._deletionQueue.flush(); } + for(auto& mesh : testMeshes) { + destroy_buffer(mesh->meshBuffers.indexBuffer); + destroy_buffer(mesh->meshBuffers.vertexBuffer); + } + _mainDeletionQueue.flush(); destroy_swapchain(); @@ -145,14 +152,21 @@ void VulkanEngine::draw() draw_background(t.cmd); - vkutil::transition_image(t.cmd, _drawImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + vkutil::transition_image(t.cmd, _drawImage.image, + VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + vkutil::transition_image(t.cmd, _depthImage.image, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL); + + // ZED: why does removing this make the monkey work? + vkutil::transition_image(t.cmd, _drawImage.image, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); draw_geometry(t.cmd); - // ZED: ? - vkutil::transition_image(t.cmd, _drawImage.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - // ZED: ? vkutil::transition_image(t.cmd, _swapchainImages[t.swapchainImageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); @@ -173,14 +187,17 @@ void VulkanEngine::draw() commit_transaction(t); } + void VulkanEngine::draw_geometry(VkCommandBuffer cmd) { - VkRenderingAttachmentInfo colorAttachment = vkinit::attachment_info(_drawImage.imageView, nullptr, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + auto colorAttachment = vkinit::attachment_info(_drawImage.imageView, nullptr, VK_IMAGE_LAYOUT_GENERAL); + auto depthAttachment = vkinit::depth_attachment_info(_depthImage.imageView, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL); - VkRenderingInfo renderInfo = vkinit::rendering_info(_drawExtent, &colorAttachment, nullptr); + // ZED: this changed from _drawExtent to _windowExtent. Why? + auto renderInfo = vkinit::rendering_info(_windowExtent, &colorAttachment, &depthAttachment); vkCmdBeginRendering(cmd, &renderInfo); - vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _trianglePipeline); + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _meshPipeline); VkViewport viewport{ .x = 0, @@ -200,28 +217,25 @@ void VulkanEngine::draw_geometry(VkCommandBuffer cmd) vkCmdSetScissor(cmd, 0, 1, &scissor); - vkCmdDraw(cmd, 3, 1, 0, 0); - - // draw rectangle - vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _meshPipeline); - - GPUDrawPushConstants push_constants{ - .worldMatrix = glm::mat4{ 1.0f }, - .vertexBuffer = rectangle.vertexBufferAddress, - }; + GPUDrawPushConstants push_constants{}; vkCmdPushConstants(cmd, _meshPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(GPUDrawPushConstants), &push_constants); - vkCmdBindIndexBuffer(cmd, rectangle.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - - vkCmdDrawIndexed(cmd, 6, 1, 0, 0, 0); - // draw monkey size_t model_idx = 2; // 0 cube; 1 sphere; 2 monkey push_constants.vertexBuffer = testMeshes[model_idx]->meshBuffers.vertexBufferAddress; + glm::mat4 view = glm::translate(glm::vec3{0, 0, -5}); + // camera projection + glm::mat4 projection = glm::perspective(glm::radians(70.0f), (float)_drawExtent.width / (float)_drawExtent.height, 10000.0f, 0.1f); + + // invert Y direction on projection matrix so that we are smaller to opengl and gltf axis + projection[1][1] *= -1; + + push_constants.worldMatrix = projection * view; + vkCmdPushConstants(cmd, _meshPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, @@ -392,10 +406,30 @@ void VulkanEngine::init_swapchain() { VK_CHECK(vkCreateImageView(_device, &rview_info, nullptr, &_drawImage.imageView)); + + // add depth image + _depthImage.imageFormat = VK_FORMAT_D32_SFLOAT; + _depthImage.imageExtent = drawImageExtent; + VkImageUsageFlags depthImageUsages{}; + depthImageUsages |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + VkImageCreateInfo dimg_info = vkinit::image_create_info(_depthImage.imageFormat, depthImageUsages, drawImageExtent); + + vmaCreateImage(_allocator, &dimg_info, &rimg_allocinfo, &_depthImage.image, &_depthImage.allocation, nullptr); + + VkImageViewCreateInfo dview_info = vkinit::imageview_create_info(_depthImage.imageFormat, _depthImage.image, VK_IMAGE_ASPECT_DEPTH_BIT); + + VK_CHECK(vkCreateImageView(_device, &dview_info, nullptr, &_depthImage.imageView)); + + + //add to deletion queues _mainDeletionQueue.push_function([=, this]() { vkDestroyImageView(_device, _drawImage.imageView, nullptr); vmaDestroyImage(_allocator, _drawImage.image, _drawImage.allocation); + + vkDestroyImageView(_device, _depthImage.imageView, nullptr); + vmaDestroyImage(_allocator, _depthImage.image, _depthImage.allocation); }); } @@ -503,7 +537,6 @@ void VulkanEngine::init_descriptors() { void VulkanEngine::init_pipelines() { init_background_pipelines(); - init_triangle_pipelines(); init_mesh_pipeline(); init_shaders(); } @@ -646,9 +679,11 @@ void VulkanEngine::init_mesh_pipeline() pipelineBuilder.set_cull_mode(VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE); pipelineBuilder.set_multisampling_none(); pipelineBuilder.disable_blending(); - pipelineBuilder.disable_depthtest(); + + pipelineBuilder.enable_depthtest(true, VK_COMPARE_OP_GREATER_OR_EQUAL); + pipelineBuilder.set_color_attachment_format(_drawImage.imageFormat); - pipelineBuilder.set_depth_format(VK_FORMAT_UNDEFINED); + pipelineBuilder.set_depth_format(_depthImage.imageFormat); _meshPipeline = pipelineBuilder.build_pipeline(_device); vkDestroyShaderModule(_device, triangleFragShader, nullptr); @@ -661,53 +696,6 @@ void VulkanEngine::init_mesh_pipeline() } -void VulkanEngine::init_triangle_pipelines() -{ - VkShaderModule triangleFragShader; - - if(!vkutil::load_shader_module("colored_triangle.frag.spv",_device, &triangleFragShader)) { - std::print("Error when building the triangle fragment shaders module"); - } else { - std::print("Triangle fragment shader successfully loaded"); - } - - VkShaderModule triangleVertexShader; - if(!vkutil::load_shader_module("colored_triangle.vert.spv", _device, &triangleVertexShader)) { - std::println("Error when building the triangle, vertex shader module"); - } else { - std::println("Triangle vertex shader successfully loaded"); - } - - VkPipelineLayoutCreateInfo pipeline_layout_info = vkinit::pipeline_layout_create_info(); - - VK_CHECK(vkCreatePipelineLayout(_device, &pipeline_layout_info, nullptr, &_trianglePipelineLayout)); - - PipelineBuilder pipelineBuilder; - - pipelineBuilder._pipelineLayout = _trianglePipelineLayout; - pipelineBuilder.set_shaders(triangleVertexShader, triangleFragShader); - pipelineBuilder.set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); - pipelineBuilder.set_polygon_mode(VK_POLYGON_MODE_FILL); - pipelineBuilder.set_cull_mode(VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE); - pipelineBuilder.set_multisampling_none(); - pipelineBuilder.disable_blending(); - pipelineBuilder.disable_depthtest(); - - // connect the image format we will drw into, from draw image - pipelineBuilder.set_color_attachment_format(_drawImage.imageFormat); - pipelineBuilder.set_depth_format(VK_FORMAT_UNDEFINED); - - _trianglePipeline = pipelineBuilder.build_pipeline(_device); - - vkDestroyShaderModule(_device, triangleFragShader, nullptr); - vkDestroyShaderModule(_device, triangleVertexShader, nullptr); - - _mainDeletionQueue.push_function([&]() { - vkDestroyPipelineLayout(_device, _trianglePipelineLayout, nullptr); - vkDestroyPipeline(_device, _trianglePipeline, nullptr); - }); -} - AllocatedBuffer VulkanEngine::create_buffer(size_t allocSize, VkBufferUsageFlags usage, VmaMemoryUsage memoryUsage) { @@ -796,29 +784,8 @@ GPUMeshBuffers VulkanEngine::uploadMesh(std::span indices, std::span rect_vertices; - - rect_vertices[0].position = {0.5,-0.5,0}; - rect_vertices[1].position = {0.5,0.5,0}; - rect_vertices[2].position = {-0.5,-0.5,0}; - rect_vertices[3].position = {-0.5,0.5,0}; - - rect_vertices[0].color = { 0, 0, 0, 1 }; - rect_vertices[1].color = { 0.5,0.5,0.5,1 }; - rect_vertices[2].color = { 1,0, 0,1 }; - rect_vertices[3].color = { 0,1, 0,1 }; - - std::array rect_indices{0, 1, 2, 2, 1, 3}; - - rectangle = uploadMesh(rect_indices, rect_vertices); - auto basicmesh = loadGltfMeshes(this, "./basicmesh.glb"); assert(basicmesh != std::nullopt && "Failed to load basicmesh.glb"); testMeshes = *basicmesh; - - _mainDeletionQueue.push_function([&](){ - destroy_buffer(rectangle.indexBuffer); - destroy_buffer(rectangle.vertexBuffer); - }); } diff --git a/vk_engine.h b/vk_engine.h index 1875146..fdd79b4 100644 --- a/vk_engine.h +++ b/vk_engine.h @@ -67,10 +67,10 @@ public: std::vector _swapchainImageViews; VkExtent2D _swapchainExtent; - // VMA stuff VmaAllocator _allocator; + // frames/command buffer unsigned int _frameNumber = 0; FrameData _frames[FRAME_OVERLAP]; @@ -84,6 +84,7 @@ public: // draw resources AllocatedImage _drawImage; + AllocatedImage _depthImage; VkExtent2D _drawExtent; // internal data @@ -100,7 +101,6 @@ public: VkPipelineLayout _meshPipelineLayout; VkPipeline _meshPipeline; - GPUMeshBuffers rectangle; std::vector> testMeshes; // ZED's REFACTOR @@ -136,7 +136,6 @@ private: void init_pipelines(); void init_background_pipelines(); void init_shaders(); - void init_triangle_pipelines(); void init_mesh_pipeline(); void init_default_data(); diff --git a/vk_initializers.cpp b/vk_initializers.cpp index b54c78c..6641f6a 100644 --- a/vk_initializers.cpp +++ b/vk_initializers.cpp @@ -143,6 +143,26 @@ VkRenderingAttachmentInfo vkinit::attachment_info( } +VkRenderingAttachmentInfo vkinit::depth_attachment_info( +VkImageView view, VkImageLayout layout /*= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL*/) +{ + + VkRenderingAttachmentInfo depthAttachment{ + .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + .pNext = nullptr, + + .imageView = view, + .imageLayout = layout, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + }; + + depthAttachment.clearValue.depthStencil.depth = 0.0f; + + return depthAttachment; +} + + VkRenderingInfo vkinit::rendering_info(VkExtent2D renderExtent, VkRenderingAttachmentInfo* colorAttachment, VkRenderingAttachmentInfo* depthAttachment) { diff --git a/vk_initializers.h b/vk_initializers.h index 3cec09a..30caa42 100644 --- a/vk_initializers.h +++ b/vk_initializers.h @@ -39,5 +39,7 @@ namespace vkinit { VkPipelineShaderStageCreateInfo pipeline_shader_stage_create_info(VkShaderStageFlagBits stage, VkShaderModule shader, const char* entry="main"); VkPipelineLayoutCreateInfo pipeline_layout_create_info(); + +VkRenderingAttachmentInfo depth_attachment_info(VkImageView view, VkImageLayout layout= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); } diff --git a/vk_loader.cpp b/vk_loader.cpp index 8d077d1..dcebbb8 100644 --- a/vk_loader.cpp +++ b/vk_loader.cpp @@ -11,125 +11,112 @@ #include #include +constexpr bool OverrideColors = true; + std::optional>> loadGltfMeshes(VulkanEngine* engine, std::filesystem::path filePath) { -//> openmesh - std::cout << "\nLoading GLTF: " << filePath << std::endl; + std::print("Loading GLTF {}", filePath.string()); - fastgltf::GltfDataBuffer data; - data.loadFromFile(filePath); + fastgltf::GltfDataBuffer data{}; + data.loadFromFile(filePath); - constexpr auto gltfOptions = fastgltf::Options::LoadGLBBuffers - | fastgltf::Options::LoadExternalBuffers; + constexpr auto gltfOptions = fastgltf::Options::LoadGLBBuffers | fastgltf::Options::LoadExternalBuffers; - fastgltf::Asset gltf; - fastgltf::Parser parser {}; + fastgltf::Asset gltf; + fastgltf::Parser parser{}; - auto load = parser.loadBinaryGLTF(&data, filePath.parent_path(), gltfOptions); - if (load) { - gltf = std::move(load.get()); - } else { - std::print("Failed to load glTF: {} \n", fastgltf::to_underlying(load.error())); - return {}; - } -//< openmesh -//> loadmesh - std::vector> meshes; + if(auto load = parser.loadBinaryGLTF(&data, filePath.parent_path(), gltfOptions)) { + gltf = std::move(load.get()); + } else { + std::print("Failed to load glTF: {}\n", fastgltf::to_underlying(load.error())); + } - // use the same vectors for all meshes so that the memory doesnt reallocate as - // often - std::vector indices; - std::vector vertices; - for (fastgltf::Mesh& mesh : gltf.meshes) { - MeshAsset newmesh; + std::vector> meshes; - newmesh.name = mesh.name; + std::vector indices; + std::vector vertices; - // clear the mesh arrays each mesh, we dont want to merge them by error - indices.clear(); - vertices.clear(); + for(fastgltf::Mesh& mesh : gltf.meshes) { + auto newmesh = std::make_shared(); + newmesh->name = mesh.name; - for (auto&& p : mesh.primitives) { - GeoSurface newSurface; - newSurface.startIndex = (uint32_t)indices.size(); - newSurface.count = (uint32_t)gltf.accessors[p.indicesAccessor.value()].count; + indices.clear(); + vertices.clear(); - size_t initial_vtx = vertices.size(); + for(auto&& p : mesh.primitives) { + // have to do this here because p.indicesAccessor changes...for reasons + newmesh->surfaces.emplace_back( + (uint32_t)indices.size(), + (uint32_t)gltf.accessors[p.indicesAccessor.value()].count); - // load indexes - { - fastgltf::Accessor& indexaccessor = gltf.accessors[p.indicesAccessor.value()]; - indices.reserve(indices.size() + indexaccessor.count); + size_t initial_vtx = vertices.size(); - fastgltf::iterateAccessor(gltf, indexaccessor, - [&](std::uint32_t idx) { - indices.push_back(idx + initial_vtx); - }); - } + // load indexes + { + fastgltf::Accessor& indexaccessor = gltf.accessors[p.indicesAccessor.value()]; + indices.reserve(indices.size() + indexaccessor.count); + fastgltf::iterateAccessor(gltf, indexaccessor, + [&](std::uint32_t idx) { + indices.emplace_back(idx + initial_vtx); + }); + } - // load vertex positions - { - fastgltf::Accessor& posAccessor = gltf.accessors[p.findAttribute("POSITION")->second]; - vertices.resize(vertices.size() + posAccessor.count); + // load vertex positions + { + fastgltf::Accessor& posAccessor = gltf.accessors[p.findAttribute("POSITION")->second]; + vertices.resize(vertices.size() + posAccessor.count); - fastgltf::iterateAccessorWithIndex(gltf, posAccessor, - [&](glm::vec3 v, size_t index) { - Vertex newvtx; - newvtx.position = v; - newvtx.normal = { 1, 0, 0 }; - newvtx.color = glm::vec4 { 1.f }; - newvtx.uv_x = 0; - newvtx.uv_y = 0; - vertices[initial_vtx + index] = newvtx; - }); - } + fastgltf::iterateAccessorWithIndex(gltf, posAccessor, + [&](glm::vec3 v, size_t index) { + vertices[initial_vtx + index] = { + .position = v, + .uv_x = 0, + .normal = { 1, 0, 0 }, + .uv_y = 0, + .color = glm::vec4 { 1.0f}, + }; + }); + } - // load vertex normals - auto normals = p.findAttribute("NORMAL"); - if (normals != p.attributes.end()) { + // load vertex normals + auto normals = p.findAttribute("NORMAL"); + if(normals != p.attributes.end()) { + fastgltf::iterateAccessorWithIndex(gltf, gltf.accessors[(*normals).second], + [&](glm::vec3 v, size_t index) { + vertices[initial_vtx + index].normal = v; + }); + } - fastgltf::iterateAccessorWithIndex(gltf, gltf.accessors[(*normals).second], - [&](glm::vec3 v, size_t index) { - vertices[initial_vtx + index].normal = v; - }); - } + // load UVs + auto uv = p.findAttribute("TEXCOORD_0"); + if(uv != p.attributes.end()) { + fastgltf::iterateAccessorWithIndex(gltf, gltf.accessors[(*uv).second], + [&](glm::vec2 v, size_t index) { + vertices[initial_vtx + index].uv_x = v.x; + vertices[initial_vtx + index].uv_y = v.y; + }); + } - // load UVs - auto uv = p.findAttribute("TEXCOORD_0"); - if (uv != p.attributes.end()) { - - fastgltf::iterateAccessorWithIndex(gltf, gltf.accessors[(*uv).second], - [&](glm::vec2 v, size_t index) { - vertices[initial_vtx + index].uv_x = v.x; - vertices[initial_vtx + index].uv_y = v.y; - }); - } - - // load vertex colors - auto colors = p.findAttribute("COLOR_0"); - if (colors != p.attributes.end()) { - - fastgltf::iterateAccessorWithIndex(gltf, gltf.accessors[(*colors).second], - [&](glm::vec4 v, size_t index) { - vertices[initial_vtx + index].color = v; - }); - } - newmesh.surfaces.push_back(newSurface); - } - - // display the vertex normals - constexpr bool OverrideColors = true; - if (OverrideColors) { - for (Vertex& vtx : vertices) { - vtx.color = glm::vec4(vtx.normal, 1.f); - } - } - newmesh.meshBuffers = engine->uploadMesh(indices, vertices); - - meshes.emplace_back(std::make_shared(std::move(newmesh))); + // load vertex colors + auto colors = p.findAttribute("COLOR_0"); + if(colors != p.attributes.end()) { + fastgltf::iterateAccessorWithIndex(gltf, gltf.accessors[(*colors).second], + [&](glm::vec4 v, size_t index) { + vertices[initial_vtx + index].color = v; + }); + } } - return meshes; + if(OverrideColors) { + for(Vertex& vtx : vertices) { + vtx.color = glm::vec4(vtx.normal, 1.0f); + } + } -//< loadmesh + newmesh->meshBuffers = engine->uploadMesh(indices, vertices); + + meshes.emplace_back(newmesh); + } + + return meshes; } diff --git a/vk_pipelines.cpp b/vk_pipelines.cpp index b7b3c8d..dd47fa3 100644 --- a/vk_pipelines.cpp +++ b/vk_pipelines.cpp @@ -202,3 +202,15 @@ void PipelineBuilder::disable_depthtest() _depthStencil.minDepthBounds = 0.0f; _depthStencil.maxDepthBounds = 1.0f; } + +void PipelineBuilder::enable_depthtest(bool depthWriteEnable, VkCompareOp op) { + _depthStencil.depthTestEnable = VK_TRUE; + _depthStencil.depthWriteEnable = depthWriteEnable; + _depthStencil.depthCompareOp = op; + _depthStencil.depthBoundsTestEnable = VK_FALSE; + _depthStencil.stencilTestEnable = VK_FALSE; + _depthStencil.front = {}; + _depthStencil.back = {}; + _depthStencil.minDepthBounds = 0.0f; + _depthStencil.maxDepthBounds = 1.0f; +} diff --git a/vk_pipelines.h b/vk_pipelines.h index 16b4067..782eafe 100644 --- a/vk_pipelines.h +++ b/vk_pipelines.h @@ -31,6 +31,7 @@ class PipelineBuilder { void set_color_attachment_format(VkFormat format); void set_depth_format(VkFormat format); void disable_depthtest(); + void enable_depthtest(bool depthWriteEnable, VkCompareOp op); }; namespace vkutil {