From ac402dbef8d72fc0b4fdd64102379eeea482a3fb Mon Sep 17 00:00:00 2001 From: Lillian Salehi Date: Mon, 14 Oct 2024 05:26:02 -0500 Subject: [PATCH] Depth buffering set up! Needs documentation and cleanup (again...) --- src/devicelibrary.cpp | 6 +-- src/devicelibrary.h | 3 +- src/entrypoint.cpp | 4 +- src/global.cpp | 3 ++ src/global.h | 20 +++++++--- src/graphics/buffers.cpp | 24 ++++++++---- src/graphics/graphicspipeline.cpp | 65 ++++++++++++++++++++++++++----- src/graphics/render.cpp | 7 ++++ src/graphics/texture.cpp | 41 ++++++++++++++++++- src/graphics/texture.h | 3 ++ src/shaders/vertex.vert | 6 ++- 11 files changed, 150 insertions(+), 32 deletions(-) diff --git a/src/devicelibrary.cpp b/src/devicelibrary.cpp index 7fab0ab..f41f6a1 100644 --- a/src/devicelibrary.cpp +++ b/src/devicelibrary.cpp @@ -291,14 +291,14 @@ namespace DeviceControl { vkDestroySwapchainKHR(Global::device, Global::swapChain, nullptr); if(Global::enableValidationLayers) std::cout << "Destroyed Swap Chain safely\n" << std::endl; } - VkImageView devicelibrary::createImageView(VkImage image, VkFormat format) { + VkImageView devicelibrary::createImageView(VkImage image, VkFormat format, VkImageAspectFlags flags) { // This defines the parameters of a newly created image object! VkImageViewCreateInfo viewInfo{}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = image; viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; viewInfo.format = format; - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.subresourceRange.aspectMask = flags; viewInfo.subresourceRange.baseMipLevel = 0; viewInfo.subresourceRange.levelCount = 1; viewInfo.subresourceRange.baseArrayLayer = 0; @@ -315,7 +315,7 @@ namespace DeviceControl { swapChainImageViews.resize(swapChainImages.size()); for (uint32_t i = 0; i < swapChainImages.size(); i++) { - swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat); + swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT); } } void devicelibrary::destroyImageViews() { diff --git a/src/devicelibrary.h b/src/devicelibrary.h index 1ce5561..dce297e 100644 --- a/src/devicelibrary.h +++ b/src/devicelibrary.h @@ -1,5 +1,6 @@ #pragma once #include "global.h" +#include #include #include #include @@ -16,7 +17,7 @@ class devicelibrary { void destroySurface(VkInstance& instance); void createSwapChain(GLFWwindow* window); void destroySwapChain(); - VkImageView createImageView(VkImage image, VkFormat format); + VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags flags); void createImageViews(); void destroyImageViews(); void createCommandPool(); diff --git a/src/entrypoint.cpp b/src/entrypoint.cpp index afd8ad6..1130b8a 100644 --- a/src/entrypoint.cpp +++ b/src/entrypoint.cpp @@ -6,6 +6,7 @@ RenderPresent::render renderPresentation; BuffersLibraries::buffers buffers; TextureLibraries::texture texture; VkInstance vulkaninstance; +//TODO: add global instances? // Getters and Setters! void EntryApp::setFramebufferResized(bool setter) { @@ -60,8 +61,9 @@ void initVulkan() { graphicsPipeline.createRenderPass(); buffers.createDescriptorSetLayout(); graphicsPipeline.createGraphicsPipeline(); - graphicsPipeline.createFramebuffers(); graphicsPipeline.createCommandPool(); + texture.createDepthResources(); + graphicsPipeline.createFramebuffers(); texture.createTextureImage(); texture.createTextureImageView(); texture.createTextureSampler(); diff --git a/src/global.cpp b/src/global.cpp index 59fcdbf..add6413 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -26,6 +26,9 @@ namespace Global { uint32_t currentFrame = 0; VkImageView textureImageView; VkSampler textureSampler; + VkImageView depthImageView; + VkImage depthImage; + VkDeviceMemory depthImageMemory; Global::QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) { // First we feed in a integer we want to use to hold the number of queued items, that fills it, then we create that amount of default constructed *VkQueueFamilyProperties* structs. diff --git a/src/global.h b/src/global.h index a9688ac..4a37e61 100644 --- a/src/global.h +++ b/src/global.h @@ -1,4 +1,5 @@ #pragma once +#include "graphics/texture.h" #include #include #include @@ -8,16 +9,20 @@ #include #include #include -#include "debug/vulkandebuglibs.h" +#include +#include + +#define GLM_FORCE_DEPTH_ZERO_TO_ONE +#include #include -#include #define GLFW_INCLUDE_VULKAN #include namespace Global { // Global variables and includes we are going to use almost everywhere, validation layers hook into everything, and you need to check if they are enabled first, // so that's one obvious global, as well as the glfw includes! + extern const std::vector validationLayers; extern const bool enableValidationLayers; extern VkDevice device; @@ -32,6 +37,9 @@ namespace Global { extern std::vector descriptorSets; extern VkImageView textureImageView; extern VkSampler textureSampler; + extern VkImageView depthImageView; + extern VkImage depthImage; + extern VkDeviceMemory depthImageMemory; struct UniformBufferObject { float time; @@ -40,7 +48,9 @@ namespace Global { alignas(16) glm::mat4 proj; }; struct Vertex { - glm::vec2 pos; + // This defines what a vertex is! + // We control the position, color and texture coordinate here! + glm::vec3 pos; glm::vec3 color; glm::vec2 texCoord; @@ -57,7 +67,7 @@ namespace Global { attributeDescriptions[0].binding = 0; attributeDescriptions[0].location = 0; - attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT; + attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT; attributeDescriptions[0].offset = offsetof(Vertex, pos); attributeDescriptions[1].binding = 0; @@ -73,7 +83,7 @@ namespace Global { } }; const uint32_t WIDTH = 800; - const uint32_t HEIGHT = 600; + const uint32_t HEIGHT = 800; struct QueueFamilyIndices { // We need to check that the Queue families support graphics operations and window presentation, sometimes they can support one or the other, diff --git a/src/graphics/buffers.cpp b/src/graphics/buffers.cpp index 85fcfc0..1bbf9e0 100644 --- a/src/graphics/buffers.cpp +++ b/src/graphics/buffers.cpp @@ -1,7 +1,6 @@ #include "buffers.h" #include -#include -#include +#include #include "../devicelibrary.h" VkBuffer vertexBuffer; @@ -20,14 +19,22 @@ namespace BuffersLibraries { const std::vector vertices = { - {{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f}}, - {{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}}, - {{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {0.0f, 1.0f}}, - {{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}} + // X Y Z | R G B | W Q + {{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f}}, + {{0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}}, + {{0.5f, 0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}, {0.0f, 1.0f}}, + {{-0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}}, + + + {{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}, + {{0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}}, + {{0.5f, 0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}, + {{-0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}} }; // Index buffer definition, showing which points to reuse. const std::vector indices = { - 0, 1, 2, 2, 3, 0 + 0, 1, 2, 2, 3, 0, + 4, 5, 6, 6, 7, 4 }; uint32_t buffers::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) { @@ -114,6 +121,7 @@ namespace BuffersLibraries { void* data; vkMapMemory(Global::device, stagingBufferMemory, 0, bufferSize, 0, &data); memcpy(data, indices.data(), (size_t) bufferSize); + vkUnmapMemory(Global::device, stagingBufferMemory); createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); @@ -226,7 +234,7 @@ namespace BuffersLibraries { ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f)); // Modify the view transformation to look at the object from above at a 45 degree angle. // This takes the eye position, center position, and the up direction. - ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); + ubo.view = glm::lookAt(glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); // 45 degree field of view, set aspect ratio, and near and far clipping range. ubo.proj = glm::perspective(glm::radians(45.0f), deviceLibrary.getSwapChainExtent().width / (float) deviceLibrary.getSwapChainExtent().height, 0.1f, 10.0f); diff --git a/src/graphics/graphicspipeline.cpp b/src/graphics/graphicspipeline.cpp index fa25bfb..fbe763b 100644 --- a/src/graphics/graphicspipeline.cpp +++ b/src/graphics/graphicspipeline.cpp @@ -1,7 +1,10 @@ #include "graphicspipeline.h" #include "buffers.h" +#include "texture.h" +#include #include +#include namespace Graphics { std::vector dynamicStates = { VK_DYNAMIC_STATE_VIEWPORT, @@ -14,6 +17,7 @@ namespace Graphics { VkPipeline graphicsPipeline; DeviceControl::devicelibrary deviceLibs; BuffersLibraries::buffers buffers; + TextureLibraries::texture textureLibs; std::vector swapChainFramebuffers; @@ -136,6 +140,15 @@ namespace Graphics { multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling.sampleShadingEnable = VK_FALSE; multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + // TODO: Document! + VkPipelineDepthStencilStateCreateInfo depthStencil{}; + depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencil.depthTestEnable = VK_TRUE; + depthStencil.depthWriteEnable = VK_TRUE; + depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; + depthStencil.depthBoundsTestEnable = VK_FALSE; + depthStencil.stencilTestEnable = VK_FALSE; // Most of the graphics pipeline is set in stone, some of the pipeline state can be modified without recreating it at runtime though! // There are TONS of settings, this would be another TODO to see what else we can mess with dynamically, but right now we just allow dynamic size of the viewport // and dynamic scissor states. Scissors are pretty straightforward, they are basically pixel masks for the rasterizer. @@ -168,6 +181,7 @@ namespace Graphics { pipelineInfo.layout = pipelineLayout; pipelineInfo.renderPass = renderPass; pipelineInfo.subpass = 0; + pipelineInfo.pDepthStencilState = &depthStencil; if (vkCreateGraphicsPipelines(Global::device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) { throw std::runtime_error("failed to create graphics pipeline!"); @@ -192,18 +206,45 @@ namespace Graphics { colorAttachmentRef.attachment = 0; colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkAttachmentDescription depthAttachment{}; + depthAttachment.format = textureLibs.findDepthFormat(); + depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkAttachmentReference depthAttachmentRef{}; + depthAttachmentRef.attachment = 1; + depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + VkSubpassDescription subpass{}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &colorAttachmentRef; + subpass.pDepthStencilAttachment = &depthAttachmentRef; + + VkSubpassDependency dependency{}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + dependency.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + std::array attachments = {colorAttachment, depthAttachment}; VkRenderPassCreateInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPassInfo.attachmentCount = 1; - renderPassInfo.pAttachments = &colorAttachment; + renderPassInfo.attachmentCount = static_cast(attachments.size()); + renderPassInfo.pAttachments = attachments.data(); renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; - + renderPassInfo.dependencyCount = 1; + renderPassInfo.pDependencies = &dependency; + + if (vkCreateRenderPass(Global::device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) { throw std::runtime_error("failed to create render pass!"); } @@ -219,15 +260,16 @@ namespace Graphics { swapChainFramebuffers.resize(framebuffersSize); for(size_t i = 0; i < framebuffersSize; i++) { - VkImageView attachments[] = { - deviceLibs.getSwapChainImageViews()[i] + std::array attachments = { + deviceLibs.getSwapChainImageViews()[i], + Global::depthImageView }; VkFramebufferCreateInfo framebufferInfo{}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = renderPass; - framebufferInfo.attachmentCount = 1; - framebufferInfo.pAttachments = attachments; + framebufferInfo.attachmentCount = static_cast(attachments.size()); + framebufferInfo.pAttachments = attachments.data(); framebufferInfo.width = deviceLibs.getSwapChainExtent().width; framebufferInfo.height = deviceLibs.getSwapChainExtent().height; framebufferInfo.layers = 1; @@ -285,9 +327,12 @@ namespace Graphics { renderPassInfo.renderArea.offset = {0, 0}; renderPassInfo.renderArea.extent = deviceLibs.getSwapChainExtent(); - VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; - renderPassInfo.clearValueCount = 1; - renderPassInfo.pClearValues = &clearColor; + std::array clearValues{}; + clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}}; + clearValues[1].depthStencil = {1.0f, 0}; + + renderPassInfo.clearValueCount = static_cast(clearValues.size()); + renderPassInfo.pClearValues = clearValues.data(); vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index 2542f0d..36f77d2 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -2,6 +2,8 @@ #include "graphicspipeline.h" #include "../devicelibrary.h" #include "../entrypoint.h" +#include "texture.h" +#include namespace RenderPresent { std::vector imageAvailableSemaphores; @@ -10,6 +12,7 @@ namespace RenderPresent { Graphics::graphicspipeline pipeline; DeviceControl::devicelibrary deviceLibs; BuffersLibraries::buffers buffers; + TextureLibraries::texture tex; void recreateSwapChain() { int width = 0, height = 0; @@ -30,6 +33,7 @@ namespace RenderPresent { deviceLibs.createSwapChain(Global::window); deviceLibs.createImageViews(); + tex.createDepthResources(); pipeline.createFramebuffers(); } // At a high level, rendering in Vulkan consists of 5 steps: @@ -153,6 +157,9 @@ namespace RenderPresent { } } void render::cleanupSwapChain() { + vkDestroyImageView(Global::device, Global::depthImageView, nullptr); + vkDestroyImage(Global::device, Global::depthImage, nullptr); + vkFreeMemory(Global::device, Global::depthImageMemory, nullptr); for(auto framebuffer : pipeline.getSwapChainFramebuffers()) { vkDestroyFramebuffer(Global::device, framebuffer, nullptr); } diff --git a/src/graphics/texture.cpp b/src/graphics/texture.cpp index 6b1262f..212be76 100644 --- a/src/graphics/texture.cpp +++ b/src/graphics/texture.cpp @@ -1,3 +1,4 @@ +#include #define STB_IMAGE_IMPLEMENTATION #include #include "texture.h" @@ -12,6 +13,7 @@ VkPipelineStageFlags sourceStage; VkPipelineStageFlags destinationStage; + namespace TextureLibraries { void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) { // This function specifies all the data in an image object, this is called directly after the creation of an image object. @@ -164,6 +166,25 @@ void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t endSingleTimeCommands(commandBuffer); } + VkFormat findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) { + for(VkFormat format : candidates) { + VkFormatProperties props; + vkGetPhysicalDeviceFormatProperties(Global::physicalDevice, format, &props); + + // Do we support linear tiling? + if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features) { + return format; + // Or do we support optimal tiling? + } else if (tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features) { + return format; + } + } + throw std::runtime_error("failed to find supported depth buffering format!"); + } + + bool hasStencilComponent(VkFormat format) { + return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT; + } // -------------------------------- Image Libraries ------------------------------- // void texture::createTextureImage() { // Import pixels from image with data on color channels, width and height, and colorspace! @@ -198,7 +219,7 @@ void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t } void texture::createTextureImageView() { // Create a texture image view, which is a struct of information about the image. - Global::textureImageView = deviceLibraries.createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB); + Global::textureImageView = deviceLibraries.createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT); } void texture::createTextureSampler() { // Create a sampler to access and parse the texture object. @@ -250,5 +271,21 @@ void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t vkDestroyImage(Global::device, textureImage, nullptr); vkFreeMemory(Global::device, textureImageMemory, nullptr); } - + VkFormat texture::findDepthFormat() { + return findSupportedFormat( + {VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT}, + VK_IMAGE_TILING_OPTIMAL, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT + ); + } + void texture::createDepthResources() { + VkFormat depthFormat = findDepthFormat(); + VkExtent2D swapChainExtent = deviceLibraries.getSwapChainExtent(); + createImage(swapChainExtent.width, swapChainExtent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, Global::depthImage, Global::depthImageMemory); + Global::depthImageView = deviceLibraries.createImageView(Global::depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT); + // Explicit transition from the layout of the image to the depth attachment is unnecessary here, since that will be handled in the render pass! + + + + } } diff --git a/src/graphics/texture.h b/src/graphics/texture.h index 8a333ac..b928b03 100644 --- a/src/graphics/texture.h +++ b/src/graphics/texture.h @@ -1,5 +1,6 @@ #pragma once #include "../global.h" +#include namespace TextureLibraries { class texture { @@ -9,5 +10,7 @@ namespace TextureLibraries { void createTextureSampler(); void destroyTextureImage(); void destroyTextureSampler(); + VkFormat findDepthFormat(); + void createDepthResources(); }; } diff --git a/src/shaders/vertex.vert b/src/shaders/vertex.vert index 058cfa0..36087b1 100644 --- a/src/shaders/vertex.vert +++ b/src/shaders/vertex.vert @@ -6,9 +6,11 @@ layout(binding = 0) uniform UniformBufferObject { mat4 view; mat4 proj; } ubo; + // inPosition and inColor are vertex attributes, per-vertex properties defined in the vertex buffer! // Layout assigns indices to access these inputs, dvec3 takes 2 slots so we must index it at 2. https://www.khronos.org/opengl/wiki/Layout_Qualifier_(GLSL) -layout(location = 0) in vec2 inPosition; + +layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inColor; layout(location = 2) in vec2 inTexCoord; @@ -16,7 +18,7 @@ layout(location = 0) out vec3 fragColor; layout(location = 1) out vec2 fragTexCoord; void main() { - gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0); + gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0); fragColor = inColor; fragTexCoord = inTexCoord; }