From 47c3bd16c47cbb4ac34dc8d1a61dc38356293914 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sun, 14 Jan 2024 15:23:58 +0100 Subject: [PATCH] Code cleanup, refactoring and simplification --- examples/texture/texture.cpp | 376 ++++++------------ examples/texture3d/texture3d.cpp | 376 ++++++------------ examples/texturearray/texturearray.cpp | 196 +++++---- examples/texturecubemap/texturecubemap.cpp | 228 +++-------- .../texturecubemaparray.cpp | 195 ++++----- shaders/glsl/texturearray/instancing.vert | 4 +- shaders/glsl/texturearray/instancing.vert.spv | Bin 2104 -> 2084 bytes shaders/glsl/texturecubemap/skybox.vert | 4 +- shaders/glsl/texturecubemap/skybox.vert.spv | Bin 1508 -> 2228 bytes shaders/glsl/texturecubemaparray/skybox.vert | 4 +- shaders/hlsl/texturearray/instancing.vert | 4 +- shaders/hlsl/texturearray/instancing.vert.spv | Bin 2608 -> 1788 bytes shaders/hlsl/texturecubemap/skybox.vert | 7 +- shaders/hlsl/texturecubemap/skybox.vert.spv | Bin 1196 -> 1296 bytes shaders/hlsl/texturecubemaparray/skybox.vert | 7 +- .../hlsl/texturecubemaparray/skybox.vert.spv | Bin 1376 -> 1476 bytes 16 files changed, 500 insertions(+), 901 deletions(-) diff --git a/examples/texture/texture.cpp b/examples/texture/texture.cpp index 9c9dfbaa..d8dee7cb 100644 --- a/examples/texture/texture.cpp +++ b/examples/texture/texture.cpp @@ -1,7 +1,9 @@ /* * Vulkan Example - Texture loading (and display) example (including mip maps) +* +* This sample shows how to upload a 2D texture to the device and how to display it. In Vulkan this is done using images, views and samplers. * -* Copyright (C) 2016-2017 by Sascha Willems - www.saschawillems.de +* Copyright (C) 2016-2023 by Sascha Willems - www.saschawillems.de * * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) */ @@ -23,41 +25,33 @@ public: // Contains all Vulkan objects that are required to store and use a texture // Note that this repository contains a texture class (VulkanTexture.hpp) that encapsulates texture loading functionality in a class that is used in subsequent demos struct Texture { - VkSampler sampler; - VkImage image; + VkSampler sampler{ VK_NULL_HANDLE }; + VkImage image{ VK_NULL_HANDLE }; VkImageLayout imageLayout; - VkDeviceMemory deviceMemory; - VkImageView view; - uint32_t width, height; - uint32_t mipLevels; + VkDeviceMemory deviceMemory{ VK_NULL_HANDLE }; + VkImageView view{ VK_NULL_HANDLE }; + uint32_t width{ 0 }; + uint32_t height{ 0 }; + uint32_t mipLevels{ 0 }; } texture; - struct { - VkPipelineVertexInputStateCreateInfo inputState; - std::vector bindingDescriptions; - std::vector attributeDescriptions; - } vertices; - vks::Buffer vertexBuffer; vks::Buffer indexBuffer; - uint32_t indexCount; + uint32_t indexCount{ 0 }; - vks::Buffer uniformBufferVS; - - struct { + struct UniformData { glm::mat4 projection; glm::mat4 modelView; glm::vec4 viewPos; + // This is used to change the bias for the level-of-detail (mips) in the fragment shader float lodBias = 0.0f; - } uboVS; + } uniformData; + vks::Buffer uniformBuffer; - struct { - VkPipeline solid; - } pipelines; - - VkPipelineLayout pipelineLayout; - VkDescriptorSet descriptorSet; - VkDescriptorSetLayout descriptorSetLayout; + VkPipeline pipeline{ VK_NULL_HANDLE }; + VkPipelineLayout pipelineLayout{ VK_NULL_HANDLE }; + VkDescriptorSet descriptorSet{ VK_NULL_HANDLE }; + VkDescriptorSetLayout descriptorSetLayout{ VK_NULL_HANDLE }; VulkanExample() : VulkanExampleBase() { @@ -70,19 +64,15 @@ public: ~VulkanExample() { - // Clean up used Vulkan resources - // Note : Inherited destructor cleans up resources stored in base class - - destroyTextureImage(texture); - - vkDestroyPipeline(device, pipelines.solid, nullptr); - - vkDestroyPipelineLayout(device, pipelineLayout, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); - - vertexBuffer.destroy(); - indexBuffer.destroy(); - uniformBufferVS.destroy(); + if (device) { + destroyTextureImage(texture); + vkDestroyPipeline(device, pipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vertexBuffer.destroy(); + indexBuffer.destroy(); + uniformBuffer.destroy(); + } } // Enable physical device features required for this example @@ -480,8 +470,8 @@ public: VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); - vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL); - vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.solid); + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); VkDeviceSize offsets[1] = { 0 }; vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &vertexBuffer.buffer, offsets); @@ -497,20 +487,8 @@ public: } } - void draw() - { - VulkanExampleBase::prepareFrame(); - - // Command buffer to be submitted to the queue - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; - - // Submit to queue - VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - - VulkanExampleBase::submitFrame(); - } - + // Creates a vertex and index buffer for a quad made of two triangles + // This is used to display the texture on void generateQuad() { // Setup vertices for a single uv-mapped quad made from two triangles @@ -526,213 +504,115 @@ public: std::vector indices = { 0,1,2, 2,3,0 }; indexCount = static_cast(indices.size()); - // Create buffers - // For the sake of simplicity we won't stage the vertex data to the gpu memory - // Vertex buffer - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &vertexBuffer, - vertices.size() * sizeof(Vertex), - vertices.data())); - // Index buffer - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &indexBuffer, - indices.size() * sizeof(uint32_t), - indices.data())); + // Create buffers and upload data to the GPU + struct StagingBuffers { + vks::Buffer vertices; + vks::Buffer indices; + } stagingBuffers; + + // Host visible source buffers (staging) + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &stagingBuffers.vertices, vertices.size() * sizeof(Vertex), vertices.data())); + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &stagingBuffers.indices, indices.size() * sizeof(uint32_t), indices.data())); + + // Device local destination buffers + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &vertexBuffer, vertices.size() * sizeof(Vertex))); + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &indexBuffer, indices.size() * sizeof(uint32_t))); + + // Copy from host do device + vulkanDevice->copyBuffer(&stagingBuffers.vertices, &vertexBuffer, queue); + vulkanDevice->copyBuffer(&stagingBuffers.indices, &indexBuffer, queue); + + // Clean up + stagingBuffers.vertices.destroy(); + stagingBuffers.indices.destroy(); } - void setupVertexDescriptions() + void setupDescriptors() { - // Binding description - vertices.bindingDescriptions.resize(1); - vertices.bindingDescriptions[0] = - vks::initializers::vertexInputBindingDescription( - 0, - sizeof(Vertex), - VK_VERTEX_INPUT_RATE_VERTEX); - - // Attribute descriptions - // Describes memory layout and shader positions - vertices.attributeDescriptions.resize(3); - // Location 0 : Position - vertices.attributeDescriptions[0] = - vks::initializers::vertexInputAttributeDescription( - 0, - 0, - VK_FORMAT_R32G32B32_SFLOAT, - offsetof(Vertex, pos)); - // Location 1 : Texture coordinates - vertices.attributeDescriptions[1] = - vks::initializers::vertexInputAttributeDescription( - 0, - 1, - VK_FORMAT_R32G32_SFLOAT, - offsetof(Vertex, uv)); - // Location 1 : Vertex normal - vertices.attributeDescriptions[2] = - vks::initializers::vertexInputAttributeDescription( - 0, - 2, - VK_FORMAT_R32G32B32_SFLOAT, - offsetof(Vertex, normal)); - - vertices.inputState = vks::initializers::pipelineVertexInputStateCreateInfo(); - vertices.inputState.vertexBindingDescriptionCount = static_cast(vertices.bindingDescriptions.size()); - vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data(); - vertices.inputState.vertexAttributeDescriptionCount = static_cast(vertices.attributeDescriptions.size()); - vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data(); - } - - void setupDescriptorPool() - { - // Example uses one ubo and one image sampler - std::vector poolSizes = - { + // Pool + std::vector poolSizes = { vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), + // The sample uses a combined image + sampler descriptor to sample the texture in the fragment shader vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1) }; - - VkDescriptorPoolCreateInfo descriptorPoolInfo = - vks::initializers::descriptorPoolCreateInfo( - static_cast(poolSizes.size()), - poolSizes.data(), - 2); - + VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); - } - void setupDescriptorSetLayout() - { - std::vector setLayoutBindings = - { + // Layout + std::vector setLayoutBindings = { // Binding 0 : Vertex shader uniform buffer - vks::initializers::descriptorSetLayoutBinding( - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - VK_SHADER_STAGE_VERTEX_BIT, - 0), + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), // Binding 1 : Fragment shader image sampler - vks::initializers::descriptorSetLayoutBinding( - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - VK_SHADER_STAGE_FRAGMENT_BIT, - 1) + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1) }; - - VkDescriptorSetLayoutCreateInfo descriptorLayout = - vks::initializers::descriptorSetLayoutCreateInfo( - setLayoutBindings.data(), - static_cast(setLayoutBindings.size())); - + VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); - VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = - vks::initializers::pipelineLayoutCreateInfo( - &descriptorSetLayout, - 1); - - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout)); - } - - void setupDescriptorSet() - { - VkDescriptorSetAllocateInfo allocInfo = - vks::initializers::descriptorSetAllocateInfo( - descriptorPool, - &descriptorSetLayout, - 1); - + // Set + VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); // Setup a descriptor image info for the current texture to be used as a combined image sampler VkDescriptorImageInfo textureDescriptor; - textureDescriptor.imageView = texture.view; // The image's view (images are never directly accessed by the shader, but rather through views defining subresources) - textureDescriptor.sampler = texture.sampler; // The sampler (Telling the pipeline how to sample the texture, including repeat, border, etc.) - textureDescriptor.imageLayout = texture.imageLayout; // The current layout of the image (Note: Should always fit the actual use, e.g. shader read) + // The image's view (images are never directly accessed by the shader, but rather through views defining subresources) + textureDescriptor.imageView = texture.view; + // The sampler (Telling the pipeline how to sample the texture, including repeat, border, etc.) + textureDescriptor.sampler = texture.sampler; + // The current layout of the image(Note: Should always fit the actual use, e.g.shader read) + textureDescriptor.imageLayout = texture.imageLayout; - std::vector writeDescriptorSets = - { + std::vector writeDescriptorSets = { // Binding 0 : Vertex shader uniform buffer - vks::initializers::writeDescriptorSet( - descriptorSet, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - 0, - &uniformBufferVS.descriptor), + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor), // Binding 1 : Fragment shader texture sampler // Fragment shader: layout (binding = 1) uniform sampler2D samplerColor; - vks::initializers::writeDescriptorSet( - descriptorSet, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, // The descriptor set will use a combined image sampler (sampler and image could be split) + vks::initializers::writeDescriptorSet(descriptorSet, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, // The descriptor set will use a combined image sampler (as opposed to splitting image and sampler) 1, // Shader binding point 1 &textureDescriptor) // Pointer to the descriptor image for our texture }; - - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); } void preparePipelines() { - VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = - vks::initializers::pipelineInputAssemblyStateCreateInfo( - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, - 0, - VK_FALSE); + // Layout + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); - VkPipelineRasterizationStateCreateInfo rasterizationState = - vks::initializers::pipelineRasterizationStateCreateInfo( - VK_POLYGON_MODE_FILL, - VK_CULL_MODE_NONE, - VK_FRONT_FACE_COUNTER_CLOCKWISE, - 0); - - VkPipelineColorBlendAttachmentState blendAttachmentState = - vks::initializers::pipelineColorBlendAttachmentState( - 0xf, - VK_FALSE); - - VkPipelineColorBlendStateCreateInfo colorBlendState = - vks::initializers::pipelineColorBlendStateCreateInfo( - 1, - &blendAttachmentState); - - VkPipelineDepthStencilStateCreateInfo depthStencilState = - vks::initializers::pipelineDepthStencilStateCreateInfo( - VK_TRUE, - VK_TRUE, - VK_COMPARE_OP_LESS_OR_EQUAL); - - VkPipelineViewportStateCreateInfo viewportState = - vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); - - VkPipelineMultisampleStateCreateInfo multisampleState = - vks::initializers::pipelineMultisampleStateCreateInfo( - VK_SAMPLE_COUNT_1_BIT, - 0); - - std::vector dynamicStateEnables = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR - }; - VkPipelineDynamicStateCreateInfo dynamicState = - vks::initializers::pipelineDynamicStateCreateInfo( - dynamicStateEnables.data(), - static_cast(dynamicStateEnables.size()), - 0); - - // Load shaders + // Pipeline + VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); + VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0); + VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); + VkPipelineColorBlendStateCreateInfo colorBlendState = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState); + VkPipelineDepthStencilStateCreateInfo depthStencilState = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL); + VkPipelineViewportStateCreateInfo viewportState = vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); + VkPipelineMultisampleStateCreateInfo multisampleState = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT, 0); + std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables); std::array shaderStages; + // Shaders shaderStages[0] = loadShader(getShadersPath() + "texture/texture.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[1] = loadShader(getShadersPath() + "texture/texture.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - VkGraphicsPipelineCreateInfo pipelineCreateInfo = - vks::initializers::pipelineCreateInfo( - pipelineLayout, - renderPass, - 0); + // Vertex input state + std::vector vertexInputBindings = { + vks::initializers::vertexInputBindingDescription(0, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX) + }; + std::vector vertexInputAttributes = { + vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, pos)), + vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, uv)), + vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, normal)), + }; + VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo(); + vertexInputState.vertexBindingDescriptionCount = static_cast(vertexInputBindings.size()); + vertexInputState.pVertexBindingDescriptions = vertexInputBindings.data(); + vertexInputState.vertexAttributeDescriptionCount = static_cast(vertexInputAttributes.size()); + vertexInputState.pVertexAttributeDescriptions = vertexInputAttributes.data(); - pipelineCreateInfo.pVertexInputState = &vertices.inputState; + VkGraphicsPipelineCreateInfo pipelineCreateInfo = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0); + pipelineCreateInfo.pVertexInputState = &vertexInputState; pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; pipelineCreateInfo.pRasterizationState = &rasterizationState; pipelineCreateInfo.pColorBlendState = &colorBlendState; @@ -742,31 +622,23 @@ public: pipelineCreateInfo.pDynamicState = &dynamicState; pipelineCreateInfo.stageCount = static_cast(shaderStages.size()); pipelineCreateInfo.pStages = shaderStages.data(); - - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.solid)); + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline)); } // Prepare and initialize uniform buffer containing shader uniforms void prepareUniformBuffers() { // Vertex shader uniform buffer block - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &uniformBufferVS, - sizeof(uboVS), - &uboVS)); - VK_CHECK_RESULT(uniformBufferVS.map()); - - updateUniformBuffers(); + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniformBuffer, sizeof(uniformData), &uniformData)); + VK_CHECK_RESULT(uniformBuffer.map()); } void updateUniformBuffers() { - uboVS.projection = camera.matrices.perspective; - uboVS.modelView = camera.matrices.view; - uboVS.viewPos = camera.viewPos; - memcpy(uniformBufferVS.mapped, &uboVS, sizeof(uboVS)); + uniformData.projection = camera.matrices.perspective; + uniformData.modelView = camera.matrices.view; + uniformData.viewPos = camera.viewPos; + memcpy(uniformBuffer.mapped, &uniformData, sizeof(uniformData)); } void prepare() @@ -774,32 +646,34 @@ public: VulkanExampleBase::prepare(); loadTexture(); generateQuad(); - setupVertexDescriptions(); prepareUniformBuffers(); - setupDescriptorSetLayout(); + setupDescriptors(); preparePipelines(); - setupDescriptorPool(); - setupDescriptorSet(); buildCommandBuffers(); prepared = true; } + void draw() + { + VulkanExampleBase::prepareFrame(); + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + VulkanExampleBase::submitFrame(); + } + virtual void render() { if (!prepared) return; - draw(); - } - - virtual void viewChanged() - { updateUniformBuffers(); + draw(); } virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { - if (overlay->sliderFloat("LOD bias", &uboVS.lodBias, 0.0f, (float)texture.mipLevels)) { + if (overlay->sliderFloat("LOD bias", &uniformData.lodBias, 0.0f, (float)texture.mipLevels)) { updateUniformBuffers(); } } diff --git a/examples/texture3d/texture3d.cpp b/examples/texture3d/texture3d.cpp index f7de92b3..a7ac3320 100644 --- a/examples/texture3d/texture3d.cpp +++ b/examples/texture3d/texture3d.cpp @@ -134,36 +134,30 @@ public: VkImageView view = VK_NULL_HANDLE; VkDescriptorImageInfo descriptor; VkFormat format; - uint32_t width, height, depth; - uint32_t mipLevels; + uint32_t width{ 0 }; + uint32_t height{ 0 }; + uint32_t depth{ 0 }; + uint32_t mipLevels{ 0 }; } texture; - struct { - VkPipelineVertexInputStateCreateInfo inputState; - std::vector inputBinding; - std::vector inputAttributes; - } vertices; - vks::Buffer vertexBuffer; vks::Buffer indexBuffer; - uint32_t indexCount; + uint32_t indexCount{ 0 }; - vks::Buffer uniformBufferVS; - - struct UboVS { + struct UniformData { glm::mat4 projection; glm::mat4 modelView; glm::vec4 viewPos; + // The current depth level of the texture to display + // This is animated float depth = 0.0f; - } uboVS; + } uniformData; + vks::Buffer uniformBuffer; - struct { - VkPipeline solid; - } pipelines; - - VkPipelineLayout pipelineLayout; - VkDescriptorSet descriptorSet; - VkDescriptorSetLayout descriptorSetLayout; + VkPipeline pipeline{ VK_NULL_HANDLE }; + VkPipelineLayout pipelineLayout{ VK_NULL_HANDLE }; + VkDescriptorSet descriptorSet{ VK_NULL_HANDLE }; + VkDescriptorSetLayout descriptorSetLayout{ VK_NULL_HANDLE }; VulkanExample() : VulkanExampleBase() { @@ -177,19 +171,15 @@ public: ~VulkanExample() { - // Clean up used Vulkan resources - // Note : Inherited destructor cleans up resources stored in base class - - destroyTextureImage(texture); - - vkDestroyPipeline(device, pipelines.solid, nullptr); - - vkDestroyPipelineLayout(device, pipelineLayout, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); - - vertexBuffer.destroy(); - indexBuffer.destroy(); - uniformBufferVS.destroy(); + if (device) { + destroyTextureImage(texture); + vkDestroyPipeline(device, pipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vertexBuffer.destroy(); + indexBuffer.destroy(); + uniformBuffer.destroy(); + } } // Prepare all Vulkan resources for the 3D texture (including descriptors) @@ -312,14 +302,8 @@ public: float nx = (float)x / (float)texture.width; float ny = (float)y / (float)texture.height; float nz = (float)z / (float)texture.depth; -#define FRACTAL -#ifdef FRACTAL float n = fractalNoise.noise(nx * noiseScale, ny * noiseScale, nz * noiseScale); -#else - float n = 20.0 * perlinNoise.noise(nx, ny, nz); -#endif n = n - floor(n); - data[x + y * texture.width + z * texture.width * texture.height] = static_cast(floor(n * 255)); } } @@ -457,7 +441,7 @@ public: vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL); - vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.solid); + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); VkDeviceSize offsets[1] = { 0 }; vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &vertexBuffer.buffer, offsets); @@ -472,20 +456,8 @@ public: } } - void draw() - { - VulkanExampleBase::prepareFrame(); - - // Command buffer to be submitted to the queue - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; - - // Submit to queue - VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - - VulkanExampleBase::submitFrame(); - } - + // Creates a vertex and index buffer for a quad made of two triangles + // This is used to display the texture on void generateQuad() { // Setup vertices for a single uv-mapped quad made from two triangles @@ -501,206 +473,108 @@ public: std::vector indices = { 0,1,2, 2,3,0 }; indexCount = static_cast(indices.size()); - // Create buffers - // For the sake of simplicity we won't stage the vertex data to the gpu memory - // Vertex buffer - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &vertexBuffer, - vertices.size() * sizeof(Vertex), - vertices.data())); - // Index buffer - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &indexBuffer, - indices.size() * sizeof(uint32_t), - indices.data())); + // Create buffers and upload data to the GPU + struct StagingBuffers { + vks::Buffer vertices; + vks::Buffer indices; + } stagingBuffers; + + // Host visible source buffers (staging) + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &stagingBuffers.vertices, vertices.size() * sizeof(Vertex), vertices.data())); + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &stagingBuffers.indices, indices.size() * sizeof(uint32_t), indices.data())); + + // Device local destination buffers + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &vertexBuffer, vertices.size() * sizeof(Vertex))); + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &indexBuffer, indices.size() * sizeof(uint32_t))); + + // Copy from host do device + vulkanDevice->copyBuffer(&stagingBuffers.vertices, &vertexBuffer, queue); + vulkanDevice->copyBuffer(&stagingBuffers.indices, &indexBuffer, queue); + + // Clean up + stagingBuffers.vertices.destroy(); + stagingBuffers.indices.destroy(); } - void setupVertexDescriptions() + void setupDescriptors() { - // Binding description - vertices.inputBinding.resize(1); - vertices.inputBinding[0] = - vks::initializers::vertexInputBindingDescription( - 0, - sizeof(Vertex), - VK_VERTEX_INPUT_RATE_VERTEX); - - // Attribute descriptions - // Describes memory layout and shader positions - vertices.inputAttributes.resize(3); - // Location 0 : Position - vertices.inputAttributes[0] = - vks::initializers::vertexInputAttributeDescription( - 0, - 0, - VK_FORMAT_R32G32B32_SFLOAT, - offsetof(Vertex, pos)); - // Location 1 : Texture coordinates - vertices.inputAttributes[1] = - vks::initializers::vertexInputAttributeDescription( - 0, - 1, - VK_FORMAT_R32G32_SFLOAT, - offsetof(Vertex, uv)); - // Location 1 : Vertex normal - vertices.inputAttributes[2] = - vks::initializers::vertexInputAttributeDescription( - 0, - 2, - VK_FORMAT_R32G32B32_SFLOAT, - offsetof(Vertex, normal)); - - vertices.inputState = vks::initializers::pipelineVertexInputStateCreateInfo(); - vertices.inputState.vertexBindingDescriptionCount = static_cast(vertices.inputBinding.size()); - vertices.inputState.pVertexBindingDescriptions = vertices.inputBinding.data(); - vertices.inputState.vertexAttributeDescriptionCount = static_cast(vertices.inputAttributes.size()); - vertices.inputState.pVertexAttributeDescriptions = vertices.inputAttributes.data(); - } - - void setupDescriptorPool() - { - // Example uses one ubo and one image sampler - std::vector poolSizes = - { + // Pool + std::vector poolSizes = { vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1) }; - - VkDescriptorPoolCreateInfo descriptorPoolInfo = - vks::initializers::descriptorPoolCreateInfo( - static_cast(poolSizes.size()), - poolSizes.data(), - 2); - + VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); - } - void setupDescriptorSetLayout() - { - std::vector setLayoutBindings = - { + // Layout + std::vector setLayoutBindings = { // Binding 0 : Vertex shader uniform buffer - vks::initializers::descriptorSetLayoutBinding( - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - VK_SHADER_STAGE_VERTEX_BIT, - 0), + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), // Binding 1 : Fragment shader image sampler - vks::initializers::descriptorSetLayoutBinding( - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - VK_SHADER_STAGE_FRAGMENT_BIT, - 1) + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1) }; - - VkDescriptorSetLayoutCreateInfo descriptorLayout = - vks::initializers::descriptorSetLayoutCreateInfo( - setLayoutBindings.data(), - static_cast(setLayoutBindings.size())); - + VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); - VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = - vks::initializers::pipelineLayoutCreateInfo( - &descriptorSetLayout, - 1); - - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout)); - } - - void setupDescriptorSet() - { - VkDescriptorSetAllocateInfo allocInfo = - vks::initializers::descriptorSetAllocateInfo( - descriptorPool, - &descriptorSetLayout, - 1); - + // Set + VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); - std::vector writeDescriptorSets = - { - // Binding 0 : Vertex shader uniform buffer - vks::initializers::writeDescriptorSet( - descriptorSet, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - 0, - &uniformBufferVS.descriptor), - // Binding 1 : Fragment shader texture sampler - vks::initializers::writeDescriptorSet( - descriptorSet, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - 1, - &texture.descriptor) - }; + // Image descriptor for the 3D texture + VkDescriptorImageInfo textureDescriptor = + vks::initializers::descriptorImageInfo( + texture.sampler, + texture.view, + texture.imageLayout); - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + std::vector writeDescriptorSets = { + // Binding 0 : Vertex shader uniform buffer + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor), + // Binding 1 : Fragment shader texture sampler + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &textureDescriptor) + }; + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); } void preparePipelines() { - VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = - vks::initializers::pipelineInputAssemblyStateCreateInfo( - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, - 0, - VK_FALSE); + // Layout + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); - VkPipelineRasterizationStateCreateInfo rasterizationState = - vks::initializers::pipelineRasterizationStateCreateInfo( - VK_POLYGON_MODE_FILL, - VK_CULL_MODE_NONE, - VK_FRONT_FACE_COUNTER_CLOCKWISE, - 0); - - VkPipelineColorBlendAttachmentState blendAttachmentState = - vks::initializers::pipelineColorBlendAttachmentState( - 0xf, - VK_FALSE); - - VkPipelineColorBlendStateCreateInfo colorBlendState = - vks::initializers::pipelineColorBlendStateCreateInfo( - 1, - &blendAttachmentState); - - VkPipelineDepthStencilStateCreateInfo depthStencilState = - vks::initializers::pipelineDepthStencilStateCreateInfo( - VK_TRUE, - VK_TRUE, - VK_COMPARE_OP_LESS_OR_EQUAL); - - VkPipelineViewportStateCreateInfo viewportState = - vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); - - VkPipelineMultisampleStateCreateInfo multisampleState = - vks::initializers::pipelineMultisampleStateCreateInfo( - VK_SAMPLE_COUNT_1_BIT, - 0); - - std::vector dynamicStateEnables = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR - }; - VkPipelineDynamicStateCreateInfo dynamicState = - vks::initializers::pipelineDynamicStateCreateInfo( - dynamicStateEnables.data(), - static_cast(dynamicStateEnables.size()), - 0); - - // Load shaders + // Pipeline + VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); + VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0); + VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); + VkPipelineColorBlendStateCreateInfo colorBlendState = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState); + VkPipelineDepthStencilStateCreateInfo depthStencilState = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL); + VkPipelineViewportStateCreateInfo viewportState = vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); + VkPipelineMultisampleStateCreateInfo multisampleState = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT, 0); + std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables); std::array shaderStages; + // Shaders shaderStages[0] = loadShader(getShadersPath() + "texture3d/texture3d.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[1] = loadShader(getShadersPath() + "texture3d/texture3d.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - VkGraphicsPipelineCreateInfo pipelineCreateInfo = - vks::initializers::pipelineCreateInfo( - pipelineLayout, - renderPass, - 0); + // Vertex input state + std::vector vertexInputBindings = { + vks::initializers::vertexInputBindingDescription(0, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX) + }; + std::vector vertexInputAttributes = { + vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, pos)), + vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, uv)), + vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, normal)), + }; + VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo(); + vertexInputState.vertexBindingDescriptionCount = static_cast(vertexInputBindings.size()); + vertexInputState.pVertexBindingDescriptions = vertexInputBindings.data(); + vertexInputState.vertexAttributeDescriptionCount = static_cast(vertexInputAttributes.size()); + vertexInputState.pVertexAttributeDescriptions = vertexInputAttributes.data(); - pipelineCreateInfo.pVertexInputState = &vertices.inputState; + VkGraphicsPipelineCreateInfo pipelineCreateInfo = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0); + pipelineCreateInfo.pVertexInputState = &vertexInputState; pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; pipelineCreateInfo.pRasterizationState = &rasterizationState; pipelineCreateInfo.pColorBlendState = &colorBlendState; @@ -710,59 +584,59 @@ public: pipelineCreateInfo.pDynamicState = &dynamicState; pipelineCreateInfo.stageCount = static_cast(shaderStages.size()); pipelineCreateInfo.pStages = shaderStages.data(); - - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.solid)); + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline)); } // Prepare and initialize uniform buffer containing shader uniforms void prepareUniformBuffers() { // Vertex shader uniform buffer block - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &uniformBufferVS, - sizeof(uboVS), - &uboVS)); - VK_CHECK_RESULT(uniformBufferVS.map()); - updateUniformBuffers(); + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniformBuffer, sizeof(UniformData), &uniformData)); + VK_CHECK_RESULT(uniformBuffer.map()); } void updateUniformBuffers() { - uboVS.projection = camera.matrices.perspective; - uboVS.modelView = camera.matrices.view; - uboVS.viewPos = camera.viewPos; - uboVS.depth += frameTimer * 0.15f; - if (uboVS.depth > 1.0f) { - uboVS.depth = uboVS.depth - 1.0f; + uniformData.projection = camera.matrices.perspective; + uniformData.modelView = camera.matrices.view; + uniformData.viewPos = camera.viewPos; + if (!paused) { + // Animate depth + uniformData.depth += frameTimer * 0.15f; + if (uniformData.depth > 1.0f) { + uniformData.depth = uniformData.depth - 1.0f; + } } - memcpy(uniformBufferVS.mapped, &uboVS, sizeof(uboVS)); + memcpy(uniformBuffer.mapped, &uniformData, sizeof(UniformData)); } void prepare() { VulkanExampleBase::prepare(); generateQuad(); - setupVertexDescriptions(); prepareUniformBuffers(); prepareNoiseTexture(128, 128, 128); - setupDescriptorSetLayout(); + setupDescriptors(); preparePipelines(); - setupDescriptorPool(); - setupDescriptorSet(); buildCommandBuffers(); prepared = true; } + void draw() + { + VulkanExampleBase::prepareFrame(); + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + VulkanExampleBase::submitFrame(); + } + virtual void render() { if (!prepared) return; + updateUniformBuffers(); draw(); - if (!paused) { - updateUniformBuffers(); - } } virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) diff --git a/examples/texturearray/texturearray.cpp b/examples/texturearray/texturearray.cpp index 414007da..ca7e2c59 100644 --- a/examples/texturearray/texturearray.cpp +++ b/examples/texturearray/texturearray.cpp @@ -1,5 +1,8 @@ /* * Vulkan Example - Texture arrays and instanced rendering +* +* This sample shows how to load and render a texture array. This is a single layered texture where each layer contains different image data. +* The different layers are displayed on cubes using instancing, where each instance selects a different layer from the texture * * Copyright (C) 2016-2023 Sascha Willems - www.saschawillems.de * @@ -23,38 +26,36 @@ class VulkanExample : public VulkanExampleBase public: // Number of array layers in texture array // Also used as instance count - uint32_t layerCount; + uint32_t layerCount{ 0 }; vks::Texture textureArray; vks::Buffer vertexBuffer; vks::Buffer indexBuffer; - uint32_t indexCount; + uint32_t indexCount{ 0 }; - vks::Buffer uniformBufferVS; - - struct UboInstanceData { + // Values passed to the shader per drawn instance + struct alignas(16) PerInstanceData { // Model matrix glm::mat4 model; - // Texture array index - // Vec4 due to padding - glm::vec4 arrayIndex; + // Layer index from which this instance will sample in the fragment shader + float arrayIndex{ 0 }; }; - struct { + struct UniformData { // Global matrices struct { glm::mat4 projection; glm::mat4 view; } matrices; // Separate data for each instance - UboInstanceData *instance; - } uboVS; + PerInstanceData* instance{ nullptr }; + } uniformData; + vks::Buffer uniformBuffer; - - VkPipeline pipeline; - VkPipelineLayout pipelineLayout; - VkDescriptorSet descriptorSet; - VkDescriptorSetLayout descriptorSetLayout; + VkPipeline pipeline{ VK_NULL_HANDLE }; + VkPipelineLayout pipelineLayout{ VK_NULL_HANDLE }; + VkDescriptorSet descriptorSet{ VK_NULL_HANDLE }; + VkDescriptorSetLayout descriptorSetLayout{ VK_NULL_HANDLE }; VulkanExample() : VulkanExampleBase() { @@ -67,25 +68,19 @@ public: ~VulkanExample() { - // Clean up used Vulkan resources - // Note : Inherited destructor cleans up resources stored in base class - - vkDestroyImageView(device, textureArray.view, nullptr); - vkDestroyImage(device, textureArray.image, nullptr); - vkDestroySampler(device, textureArray.sampler, nullptr); - vkFreeMemory(device, textureArray.deviceMemory, nullptr); - - vkDestroyPipeline(device, pipeline, nullptr); - - vkDestroyPipelineLayout(device, pipelineLayout, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); - - vertexBuffer.destroy(); - indexBuffer.destroy(); - - uniformBufferVS.destroy(); - - delete[] uboVS.instance; + if (device) { + vkDestroyImageView(device, textureArray.view, nullptr); + vkDestroyImage(device, textureArray.image, nullptr); + vkDestroySampler(device, textureArray.sampler, nullptr); + vkFreeMemory(device, textureArray.deviceMemory, nullptr); + vkDestroyPipeline(device, pipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vertexBuffer.destroy(); + indexBuffer.destroy(); + uniformBuffer.destroy(); + delete[] uniformData.instance; + } } void loadTextureArray(std::string filename, VkFormat format) @@ -324,6 +319,8 @@ public: } } + // Creates a vertex and index buffer for a cube + // This is used to display the texture on void generateCube() { std::vector vertices = { @@ -363,49 +360,50 @@ public: indexCount = static_cast(indices.size()); - // Create buffers - // For the sake of simplicity we won't stage the vertex data to the gpu memory - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &vertexBuffer, - vertices.size() * sizeof(Vertex), - vertices.data())); - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &indexBuffer, - indices.size() * sizeof(uint32_t), - indices.data())); + // Create buffers and upload data to the GPU + struct StagingBuffers { + vks::Buffer vertices; + vks::Buffer indices; + } stagingBuffers; + + // Host visible source buffers (staging) + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &stagingBuffers.vertices, vertices.size() * sizeof(Vertex), vertices.data())); + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &stagingBuffers.indices, indices.size() * sizeof(uint32_t), indices.data())); + + // Device local destination buffers + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &vertexBuffer, vertices.size() * sizeof(Vertex))); + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &indexBuffer, indices.size() * sizeof(uint32_t))); + + // Copy from host do device + vulkanDevice->copyBuffer(&stagingBuffers.vertices, &vertexBuffer, queue); + vulkanDevice->copyBuffer(&stagingBuffers.indices, &indexBuffer, queue); + + // Clean up + stagingBuffers.vertices.destroy(); + stagingBuffers.indices.destroy(); } - void setupDescriptorPool() + void setupDescriptors() { + // Pool std::vector poolSizes = { vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1) }; VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); - } - void setupDescriptorSetLayout() - { + // Layout std::vector setLayoutBindings = { // Binding 0 : Vertex shader uniform buffer vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), - // Binding 1 : Fragment shader image sampler (texture array) + // Binding 1 : Fragment shader image sampler vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1) }; VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); - } - - void setupDescriptorSet() - { + // Set VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); @@ -418,8 +416,8 @@ public: std::vector writeDescriptorSets = { // Binding 0 : Vertex shader uniform buffer - vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBufferVS.descriptor), - // Binding 1 : Fragment shader cubemap sampler + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor), + // Binding 1 : Fragment shader texture sampler vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &textureDescriptor) }; vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); @@ -427,6 +425,11 @@ public: void preparePipelines() { + // Layout + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); + + // Pipeline VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); VkPipelineRasterizationStateCreateInfo rasterizationStateCI = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0); VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); @@ -466,64 +469,46 @@ public: pipelineCI.pDynamicState = &dynamicStateCI; pipelineCI.stageCount = static_cast(shaderStages.size()); pipelineCI.pStages = shaderStages.data(); - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); } void prepareUniformBuffers() { - uboVS.instance = new UboInstanceData[layerCount]; + uniformData.instance = new PerInstanceData[layerCount]; - uint32_t uboSize = sizeof(uboVS.matrices) + (MAX_LAYERS * sizeof(UboInstanceData)); + uint32_t uboSize = sizeof(uniformData.matrices) + (MAX_LAYERS * sizeof(PerInstanceData)); // Vertex shader uniform buffer block - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &uniformBufferVS, - uboSize)); + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniformBuffer, uboSize)); // Array indices and model matrices are fixed float offset = -1.5f; float center = (layerCount*offset) / 2.0f - (offset * 0.5f); for (uint32_t i = 0; i < layerCount; i++) { // Instance model matrix - uboVS.instance[i].model = glm::translate(glm::mat4(1.0f), glm::vec3(i * offset - center, 0.0f, 0.0f)); - uboVS.instance[i].model = glm::scale(uboVS.instance[i].model, glm::vec3(0.5f)); + uniformData.instance[i].model = glm::translate(glm::mat4(1.0f), glm::vec3(i * offset - center, 0.0f, 0.0f)); + uniformData.instance[i].model = glm::scale(uniformData.instance[i].model, glm::vec3(0.5f)); // Instance texture array index - uboVS.instance[i].arrayIndex.x = (float)i; + uniformData.instance[i].arrayIndex = (float)i; } // Update instanced part of the uniform buffer uint8_t *pData; - uint32_t dataOffset = sizeof(uboVS.matrices); - uint32_t dataSize = layerCount * sizeof(UboInstanceData); - VK_CHECK_RESULT(vkMapMemory(device, uniformBufferVS.memory, dataOffset, dataSize, 0, (void **)&pData)); - memcpy(pData, uboVS.instance, dataSize); - vkUnmapMemory(device, uniformBufferVS.memory); + uint32_t dataOffset = sizeof(uniformData.matrices); + uint32_t dataSize = layerCount * sizeof(PerInstanceData); + VK_CHECK_RESULT(vkMapMemory(device, uniformBuffer.memory, dataOffset, dataSize, 0, (void **)&pData)); + memcpy(pData, uniformData.instance, dataSize); + vkUnmapMemory(device, uniformBuffer.memory); // Map persistent - VK_CHECK_RESULT(uniformBufferVS.map()); - - updateUniformBuffersCamera(); + VK_CHECK_RESULT(uniformBuffer.map()); } void updateUniformBuffersCamera() { - uboVS.matrices.projection = camera.matrices.perspective; - uboVS.matrices.view = camera.matrices.view; - memcpy(uniformBufferVS.mapped, &uboVS.matrices, sizeof(uboVS.matrices)); - } - - void draw() - { - VulkanExampleBase::prepareFrame(); - - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; - VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - - VulkanExampleBase::submitFrame(); + uniformData.matrices.projection = camera.matrices.perspective; + uniformData.matrices.view = camera.matrices.view; + memcpy(uniformBuffer.mapped, &uniformData.matrices, sizeof(uniformData.matrices)); } void prepare() @@ -532,26 +517,27 @@ public: loadAssets(); generateCube(); prepareUniformBuffers(); - setupDescriptorSetLayout(); + setupDescriptors(); preparePipelines(); - setupDescriptorPool(); - setupDescriptorSet(); buildCommandBuffers(); prepared = true; } + void draw() + { + VulkanExampleBase::prepareFrame(); + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + VulkanExampleBase::submitFrame(); + } + virtual void render() { if (!prepared) return; - draw(); - if (camera.updated) - updateUniformBuffersCamera(); - } - - virtual void viewChanged() - { updateUniformBuffersCamera(); + draw(); } }; diff --git a/examples/texturecubemap/texturecubemap.cpp b/examples/texturecubemap/texturecubemap.cpp index a398153c..c426916d 100644 --- a/examples/texturecubemap/texturecubemap.cpp +++ b/examples/texturecubemap/texturecubemap.cpp @@ -1,6 +1,9 @@ /* * Vulkan Example - Cube map texture loading and displaying * +* This sample shows how to load and render a cubemap. A cubemap is a textures that contains 6 images, one per cube face. +* The sample displays the cubemap as a skybox (background) and as a reflection on a selectable object +* * Copyright (C) 2016-2023 by Sascha Willems - www.saschawillems.de * * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) @@ -18,36 +21,29 @@ public: vks::Texture cubeMap; - struct Meshes { + struct Models { vkglTF::Model skybox; + // The sample lets you select different models to apply the cubemap to std::vector objects; int32_t objectIndex = 0; } models; - struct { - vks::Buffer object; - vks::Buffer skybox; - } uniformBuffers; - struct UBOVS { glm::mat4 projection; glm::mat4 modelView; glm::mat4 inverseModelview; float lodBias = 0.0f; } uboVS; + vks::Buffer uniformBuffer; struct { - VkPipeline skybox; - VkPipeline reflect; + VkPipeline skybox{ VK_NULL_HANDLE }; + VkPipeline reflect{ VK_NULL_HANDLE }; } pipelines; - struct { - VkDescriptorSet object; - VkDescriptorSet skybox; - } descriptorSets; - - VkPipelineLayout pipelineLayout; - VkDescriptorSetLayout descriptorSetLayout; + VkPipelineLayout pipelineLayout{ VK_NULL_HANDLE }; + VkDescriptorSet descriptorSet{ VK_NULL_HANDLE }; + VkDescriptorSetLayout descriptorSetLayout{ VK_NULL_HANDLE }; std::vector objectNames; @@ -63,23 +59,17 @@ public: ~VulkanExample() { - // Clean up used Vulkan resources - // Note : Inherited destructor cleans up resources stored in base class - - // Clean up texture resources - vkDestroyImageView(device, cubeMap.view, nullptr); - vkDestroyImage(device, cubeMap.image, nullptr); - vkDestroySampler(device, cubeMap.sampler, nullptr); - vkFreeMemory(device, cubeMap.deviceMemory, nullptr); - - vkDestroyPipeline(device, pipelines.skybox, nullptr); - vkDestroyPipeline(device, pipelines.reflect, nullptr); - - vkDestroyPipelineLayout(device, pipelineLayout, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); - - uniformBuffers.object.destroy(); - uniformBuffers.skybox.destroy(); + if (device) { + vkDestroyImageView(device, cubeMap.view, nullptr); + vkDestroyImage(device, cubeMap.image, nullptr); + vkDestroySampler(device, cubeMap.sampler, nullptr); + vkFreeMemory(device, cubeMap.deviceMemory, nullptr); + vkDestroyPipeline(device, pipelines.skybox, nullptr); + vkDestroyPipeline(device, pipelines.reflect, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + uniformBuffer.destroy(); + } } // Enable physical device features required for this example @@ -90,7 +80,8 @@ public: } } - void loadCubemap(std::string filename, VkFormat format, bool forceLinearTiling) + // Loads a cubemap from a file, uploads it to the device and create all Vulkan resources required to display it + void loadCubemap(std::string filename, VkFormat format) { ktxResult result; ktxTexture* ktxTexture; @@ -315,16 +306,16 @@ public: VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); + // Skybox if (displaySkybox) { - vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets.skybox, 0, NULL); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.skybox); models.skybox.draw(drawCmdBuffers[i]); } // 3D object - vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets.object, 0, NULL); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.reflect); models.objects[models.objectIndex].draw(drawCmdBuffers[i]); @@ -349,111 +340,53 @@ public: models.objects[i].loadFromFile(getAssetPath() + "models/" + filenames[i], vulkanDevice, queue, glTFLoadingFlags); } // Cubemap texture - const bool forceLinearTiling = false; - loadCubemap(getAssetPath() + "textures/cubemap_yokohama_rgba.ktx", VK_FORMAT_R8G8B8A8_UNORM, forceLinearTiling); + loadCubemap(getAssetPath() + "textures/cubemap_yokohama_rgba.ktx", VK_FORMAT_R8G8B8A8_UNORM); } - void setupDescriptorPool() + void setupDescriptors() { - std::vector poolSizes = - { - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2), - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2) + // Pool + std::vector poolSizes = { + vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), + vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1) }; - - VkDescriptorPoolCreateInfo descriptorPoolInfo = - vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); - + VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); - } - void setupDescriptorSetLayout() - { - std::vector setLayoutBindings = - { - // Binding 0 : Uniform buffer - vks::initializers::descriptorSetLayoutBinding( - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - 0), + // Layout + std::vector setLayoutBindings = { + // Binding 0 : Vertex shader uniform buffer + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0), // Binding 1 : Fragment shader image sampler - vks::initializers::descriptorSetLayoutBinding( - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - VK_SHADER_STAGE_FRAGMENT_BIT, - 1) + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1) }; - - VkDescriptorSetLayoutCreateInfo descriptorLayout = - vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); - + VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); - VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = - vks::initializers::pipelineLayoutCreateInfo( - &descriptorSetLayout, - 1); + // Set + VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout)); - } - - void setupDescriptorSets() - { // Image descriptor for the cube map texture - VkDescriptorImageInfo textureDescriptor = - vks::initializers::descriptorImageInfo( - cubeMap.sampler, - cubeMap.view, - cubeMap.imageLayout); - - VkDescriptorSetAllocateInfo allocInfo = - vks::initializers::descriptorSetAllocateInfo( - descriptorPool, - &descriptorSetLayout, - 1); - - // 3D object descriptor set - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.object)); + VkDescriptorImageInfo textureDescriptor = vks::initializers::descriptorImageInfo(cubeMap.sampler, cubeMap.view, cubeMap.imageLayout); std::vector writeDescriptorSets = { // Binding 0 : Vertex shader uniform buffer - vks::initializers::writeDescriptorSet( - descriptorSets.object, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - 0, - &uniformBuffers.object.descriptor), + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor), // Binding 1 : Fragment shader cubemap sampler - vks::initializers::writeDescriptorSet( - descriptorSets.object, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - 1, - &textureDescriptor) - }; - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); - - // Sky box descriptor set - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.skybox)); - - writeDescriptorSets = - { - // Binding 0 : Vertex shader uniform buffer - vks::initializers::writeDescriptorSet( - descriptorSets.skybox, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - 0, - &uniformBuffers.skybox.descriptor), - // Binding 1 : Fragment shader cubemap sampler - vks::initializers::writeDescriptorSet( - descriptorSets.skybox, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - 1, - &textureDescriptor) + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &textureDescriptor) }; vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); } void preparePipelines() { + // Layout + const VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout)); + + // Pipeline VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0); VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); @@ -496,39 +429,28 @@ public: // Prepare and initialize uniform buffer containing shader uniforms void prepareUniformBuffers() { - // Object vertex shader uniform buffer - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &uniformBuffers.object, - sizeof(uboVS))); - - // Skybox vertex shader uniform buffer - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &uniformBuffers.skybox, - sizeof(uboVS))); - - // Map persistent - VK_CHECK_RESULT(uniformBuffers.object.map()); - VK_CHECK_RESULT(uniformBuffers.skybox.map()); - - updateUniformBuffers(); + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniformBuffer, sizeof(uboVS))); + VK_CHECK_RESULT(uniformBuffer.map()); } void updateUniformBuffers() { - // 3D object uboVS.projection = camera.matrices.perspective; + // Note: Both the object and skybox use the same uniform data, the translation part of the skybox is removed in the shader (see skybox.vert) uboVS.modelView = camera.matrices.view; uboVS.inverseModelview = glm::inverse(camera.matrices.view); - memcpy(uniformBuffers.object.mapped, &uboVS, sizeof(uboVS)); - // Skybox - uboVS.modelView = camera.matrices.view; - // Cancel out translation - uboVS.modelView[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); - memcpy(uniformBuffers.skybox.mapped, &uboVS, sizeof(uboVS)); + memcpy(uniformBuffer.mapped, &uboVS, sizeof(uboVS)); + } + + void prepare() + { + VulkanExampleBase::prepare(); + loadAssets(); + prepareUniformBuffers(); + setupDescriptors(); + preparePipelines(); + buildCommandBuffers(); + prepared = true; } void draw() @@ -539,30 +461,12 @@ public: VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); VulkanExampleBase::submitFrame(); } - - void prepare() - { - VulkanExampleBase::prepare(); - loadAssets(); - prepareUniformBuffers(); - setupDescriptorSetLayout(); - preparePipelines(); - setupDescriptorPool(); - setupDescriptorSets(); - buildCommandBuffers(); - prepared = true; - } - virtual void render() { if (!prepared) return; - draw(); - } - - virtual void viewChanged() - { updateUniformBuffers(); + draw(); } virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) diff --git a/examples/texturecubemaparray/texturecubemaparray.cpp b/examples/texturecubemaparray/texturecubemaparray.cpp index 74a6cf3c..f5b62885 100644 --- a/examples/texturecubemaparray/texturecubemaparray.cpp +++ b/examples/texturecubemaparray/texturecubemaparray.cpp @@ -1,7 +1,10 @@ /* * Vulkan Example - Cube map array texture loading and displaying * -* Copyright (C) 2020 by Sascha Willems - www.saschawillems.de +* This sample shows how load and render an cubemap array texture. A single image contains multiple cube maps. +* The cubemap to be displayed is selected in the fragment shader +* +* Copyright (C) 2020-2023 by Sascha Willems - www.saschawillems.de * * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) */ @@ -24,31 +27,24 @@ public: int32_t objectIndex = 0; } models; - struct { - vks::Buffer object; - vks::Buffer skybox; - } uniformBuffers; - - struct ShaderData { + struct UniformData { glm::mat4 projection; glm::mat4 modelView; glm::mat4 inverseModelview; float lodBias = 0.0f; + // Used by the fragment shader to select the cubemap from the array cubemap int cubeMapIndex = 1; - } shaderData; + } uniformData; + vks::Buffer uniformBuffer; struct { - VkPipeline skybox; - VkPipeline reflect; + VkPipeline skybox{ VK_NULL_HANDLE }; + VkPipeline reflect{ VK_NULL_HANDLE }; } pipelines; - struct { - VkDescriptorSet object; - VkDescriptorSet skybox; - } descriptorSets; - - VkPipelineLayout pipelineLayout; - VkDescriptorSetLayout descriptorSetLayout; + VkPipelineLayout pipelineLayout{ VK_NULL_HANDLE }; + VkDescriptorSet descriptorSet{ VK_NULL_HANDLE }; + VkDescriptorSetLayout descriptorSetLayout{ VK_NULL_HANDLE }; std::vector objectNames; @@ -63,25 +59,23 @@ public: ~VulkanExample() { - // Clean up texture resources - vkDestroyImageView(device, cubeMapArray.view, nullptr); - vkDestroyImage(device, cubeMapArray.image, nullptr); - vkDestroySampler(device, cubeMapArray.sampler, nullptr); - vkFreeMemory(device, cubeMapArray.deviceMemory, nullptr); - - vkDestroyPipeline(device, pipelines.skybox, nullptr); - vkDestroyPipeline(device, pipelines.reflect, nullptr); - - vkDestroyPipelineLayout(device, pipelineLayout, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); - - uniformBuffers.object.destroy(); - uniformBuffers.skybox.destroy(); + if (device) { + vkDestroyImageView(device, cubeMapArray.view, nullptr); + vkDestroyImage(device, cubeMapArray.image, nullptr); + vkDestroySampler(device, cubeMapArray.sampler, nullptr); + vkFreeMemory(device, cubeMapArray.deviceMemory, nullptr); + vkDestroyPipeline(device, pipelines.skybox, nullptr); + vkDestroyPipeline(device, pipelines.reflect, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + uniformBuffer.destroy(); + } } // Enable physical device features required for this example virtual void getEnabledFeatures() { + // This sample requires support for cube map arrays if (deviceFeatures.imageCubeArray) { enabledFeatures.imageCubeArray = VK_TRUE; } else { @@ -93,7 +87,8 @@ public: } }; - void loadCubemapArray(std::string filename, VkFormat format, bool forceLinearTiling) + // Loads a cubemap array from a file, uploads it to the device and create all Vulkan resources required to display it + void loadCubemapArray(std::string filename, VkFormat format) { ktxResult result; ktxTexture* ktxTexture; @@ -320,16 +315,16 @@ public: VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); + // Skybox if (displaySkybox) { - vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets.skybox, 0, NULL); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.skybox); models.skybox.draw(drawCmdBuffers[i]); } // 3D object - vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets.object, 0, NULL); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.reflect); models.objects[models.objectIndex].draw(drawCmdBuffers[i]); @@ -354,66 +349,53 @@ public: models.objects[i].loadFromFile(getAssetPath() + "models/" + filenames[i], vulkanDevice, queue, glTFLoadingFlags); } // Load the cube map array from a ktx texture file - loadCubemapArray(getAssetPath() + "textures/cubemap_array.ktx", VK_FORMAT_R8G8B8A8_UNORM, false); + loadCubemapArray(getAssetPath() + "textures/cubemap_array.ktx", VK_FORMAT_R8G8B8A8_UNORM); } - void setupDescriptorPool() + void setupDescriptors() { - const std::vector poolSizes = { - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2), - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2) + // Pool + std::vector poolSizes = { + vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), + vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1) }; - const VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); + VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); - } - void setupDescriptorSetLayout() - { - const std::vector setLayoutBindings = { - // Binding 0 : Uniform buffer + // Layout + std::vector setLayoutBindings = { + // Binding 0 : Vertex shader uniform buffer vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0), // Binding 1 : Fragment shader image sampler vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1) }; - - const VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); + VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); - const VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout)); - } - - void setupDescriptorSets() - { - // Image descriptor for the cube map texture - VkDescriptorImageInfo textureDescriptor = vks::initializers::descriptorImageInfo(cubeMapArray.sampler, cubeMapArray.view, cubeMapArray.imageLayout); + // Set VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); + + // Image descriptor for the cube map array texture + VkDescriptorImageInfo textureDescriptor = vks::initializers::descriptorImageInfo(cubeMapArray.sampler, cubeMapArray.view, cubeMapArray.imageLayout); - // 3D object descriptor set - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.object)); std::vector writeDescriptorSets = { // Binding 0 : Vertex shader uniform buffer - vks::initializers::writeDescriptorSet(descriptorSets.object, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.object.descriptor), + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor), // Binding 1 : Fragment shader cubemap sampler - vks::initializers::writeDescriptorSet(descriptorSets.object, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &textureDescriptor) - }; - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); - - // Sky box descriptor set - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.skybox)); - writeDescriptorSets = - { - // Binding 0 : Vertex shader uniform buffer - vks::initializers::writeDescriptorSet(descriptorSets.skybox, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.skybox.descriptor), - // Binding 1 : Fragment shader cubemap sampler - vks::initializers::writeDescriptorSet(descriptorSets.skybox, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &textureDescriptor) + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &textureDescriptor) }; vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); } void preparePipelines() { + // Layout + const VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout)); + + // Pipelines VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0); VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); @@ -457,39 +439,28 @@ public: void prepareUniformBuffers() { // Object vertex shader uniform buffer - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &uniformBuffers.object, - sizeof(ShaderData))); - - // Skybox vertex shader uniform buffer - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &uniformBuffers.skybox, - sizeof(ShaderData))); - + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniformBuffer, sizeof(UniformData))); // Map persistent - VK_CHECK_RESULT(uniformBuffers.object.map()); - VK_CHECK_RESULT(uniformBuffers.skybox.map()); - - updateUniformBuffers(); + VK_CHECK_RESULT(uniformBuffer.map()); } void updateUniformBuffers() { - // 3D object - shaderData.projection = camera.matrices.perspective; - shaderData.modelView = camera.matrices.view; - shaderData.inverseModelview = glm::inverse(camera.matrices.view); - memcpy(uniformBuffers.object.mapped, &shaderData, sizeof(ShaderData)); + uniformData.projection = camera.matrices.perspective; + uniformData.modelView = camera.matrices.view; + uniformData.inverseModelview = glm::inverse(camera.matrices.view); + memcpy(uniformBuffer.mapped, &uniformData, sizeof(UniformData)); + } - // Skybox - shaderData.modelView = camera.matrices.view; - // Cancel out translation - shaderData.modelView[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); - memcpy(uniformBuffers.skybox.mapped, &shaderData, sizeof(ShaderData)); + void prepare() + { + VulkanExampleBase::prepare(); + loadAssets(); + prepareUniformBuffers(); + setupDescriptors(); + preparePipelines(); + buildCommandBuffers(); + prepared = true; } void draw() @@ -501,43 +472,19 @@ public: VulkanExampleBase::submitFrame(); } - void prepare() - { - VulkanExampleBase::prepare(); - loadAssets(); - prepareUniformBuffers(); - setupDescriptorSetLayout(); - preparePipelines(); - setupDescriptorPool(); - setupDescriptorSets(); - buildCommandBuffers(); - prepared = true; - } - virtual void render() { if (!prepared) return; - draw(); - if (camera.updated) { - updateUniformBuffers(); - } - } - - virtual void viewChanged() - { updateUniformBuffers(); + draw(); } virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { - if (overlay->sliderInt("Cube map", &shaderData.cubeMapIndex, 0, cubeMapArray.layerCount - 1)) { - updateUniformBuffers(); - } - if (overlay->sliderFloat("LOD bias", &shaderData.lodBias, 0.0f, (float)cubeMapArray.mipLevels)) { - updateUniformBuffers(); - } + overlay->sliderInt("Cube map", &uniformData.cubeMapIndex, 0, cubeMapArray.layerCount - 1); + overlay->sliderFloat("LOD bias", &uniformData.lodBias, 0.0f, (float)cubeMapArray.mipLevels); if (overlay->comboBox("Object type", &models.objectIndex, objectNames)) { buildCommandBuffers(); } diff --git a/shaders/glsl/texturearray/instancing.vert b/shaders/glsl/texturearray/instancing.vert index 45570505..cbfd27c7 100644 --- a/shaders/glsl/texturearray/instancing.vert +++ b/shaders/glsl/texturearray/instancing.vert @@ -6,7 +6,7 @@ layout (location = 1) in vec2 inUV; struct Instance { mat4 model; - vec4 arrayIndex; + float arrayIndex; }; layout (binding = 0) uniform UBO @@ -20,7 +20,7 @@ layout (location = 0) out vec3 outUV; void main() { - outUV = vec3(inUV, ubo.instance[gl_InstanceIndex].arrayIndex.x); + outUV = vec3(inUV, ubo.instance[gl_InstanceIndex].arrayIndex); mat4 modelView = ubo.view * ubo.instance[gl_InstanceIndex].model; gl_Position = ubo.projection * modelView * vec4(inPos, 1.0); } diff --git a/shaders/glsl/texturearray/instancing.vert.spv b/shaders/glsl/texturearray/instancing.vert.spv index 363adc9e18a3c94a3022f90410ffb10d727cd927..63849a67e394bf172a934852badd664abaa1e841 100644 GIT binary patch literal 2084 zcmY+D+fGwK6oyAi3yOk>98@fY;t>T@KomKt36PLjL+GukbjNH{c1c@2UGWO~NIsP} zCjQ^-S#&$i>a71?$C))d*Hi9u?t&X|{chW(YuNROapDSo-`PLdpKo{S^GnN%cnrFn zcf@DNUGjRb{*P;M0=Ou-EV(IpB6%*!>DQzEw}SGnSHG@5n3(2i=dh|BOnjVpD4cg! zh4+$nrH%j`8hi3 z#7%WgK75G%5=URLn=gIGncCzV6Lew4WB+5b5`E^jwKa^SZmA@_*(f}|oL zH#1;aZo}E!#&vV2apca%WouF2=G%=+Iqr}AXOf-pR^aH5InPK~hNn~LF>ic8GAE&i z%@B@d9KFD?8%GVeT!ur3ws;$>uU57Jgbj#GsE!<1R~*ab@6~VC*H~{-DFJ z1fM%3 zEN1|hwR3;;1iqskJJ{+ykj}C*K9){?&N#1~TyRBc3)<}-u_5GL)XrS6(mY$gt3;vH7z8z|nwa-e(y)MlBuSl3Zn7g|r z;oi38#U1f3nFDu?jXT7bKBgqt->X7;k7+(p=iIb(YS4d0UeunElqA^5v7t_RukhQ- z#ogbPP}k})hkJpyUhfNAuf#l*Sg+Wa7ryBXQ~NLF2S1XKZ%#se?gh^3Kb20dY>sEb z@RoB)I&qeBSvo%O_;A)$3G=f%dKoxv=iFN0xFhp>6*%TuQ6}cQE+HO&?7V}YIuEuD Z3H9;e47`gi32%!ta7HkGe>II&$v^k6eYF4p literal 2104 zcmY+DYflqV5QdMGwkQfBa#67q5WJvx14I!hXaXc8))4q=Ds0S}vP;_H?Gt}Nf0Dn- zFDAav*)y=7W;!$PT+hteLf2H;xeKoBdfbM~&VcI@;#{vQdA_-`yEE7B9L~)zJi(*S z6}%%p{qB;NyY+w6h!d2HqRXP2qGzHdQ9-{h@!tw6x^Df>{n3d@Pda=1;^@T3iC3i; z-Bsz^NxRcX4kC%_EW?nG(!;3fv6Arj)oYd2{_-5Ee1)~l+yFjOhE$QrnQxt9K-}EVu{*UQ#dAs?M1HYPx+=JpJ zQC&oCcEGXRrss1TcAh(nBX>S7UyJ&--}AT(V}9g66>WyM0!DxAc~ZnNeIir6&KvI) z&5EeOt~g*E!{`MJZWuMd3ONiJjPHY9$Y;H-QQ1A))5Q97{iCI=fBg()%(Xm&h z_XHVyIp}->~iWg=BKtZqa!!VAQ3?E0J@jYvij*B9>ZD(Dj;a&iotlnlll>hhxgln7sJ zRne-tw`AXV~k2F(dO^2^c%AD-%0j l6%mg=cHY8I-3Qy6i2C?&hnnZv`{EAVaa|n0zuLx<=pUlvew6?K diff --git a/shaders/glsl/texturecubemap/skybox.vert b/shaders/glsl/texturecubemap/skybox.vert index d1f8887d..6fd365c1 100644 --- a/shaders/glsl/texturecubemap/skybox.vert +++ b/shaders/glsl/texturecubemap/skybox.vert @@ -15,5 +15,7 @@ void main() outUVW = inPos; // Convert cubemap coordinates into Vulkan coordinate space outUVW.xy *= -1.0; - gl_Position = ubo.projection * ubo.model * vec4(inPos.xyz, 1.0); + // Remove translation from view matrix + mat4 viewMat = mat4(mat3(ubo.model)); + gl_Position = ubo.projection * viewMat * vec4(inPos.xyz, 1.0); } diff --git a/shaders/glsl/texturecubemap/skybox.vert.spv b/shaders/glsl/texturecubemap/skybox.vert.spv index fc6b9862176375def6964fe8214275107ac1f964..147cdaa228be9c280cf6e71cc87c45017a9c442f 100644 GIT binary patch literal 2228 zcmZ9N*-jKu5QYy73@8dBvbaGHfQW8a z@PWkiC=Y5A@9#tn^i$$4aYbCvPpjl_1-C0IABRnBe3Wc$zf1k(MU7hAl*E5k@^ch^ zS=&iu7u>Myt;KasR`j||cW@Yg3U`wzR`;T!h+($# za63Fq!ml!YJ#YwL+>Cs|qU-SS)bn`MNH(KyA#vtoKlzsG(ZO=mOm-T(;farv!go}! zpZJ)kLIF`VI|F8husH*>S7e*sE_@~1kJvK5M0re?>CSm9&13F-9yWOkV#@=wylQsF z?8GdAqA6AWn>HNiL&!_dKa7xX5VxIXS3WBx(u^rYUU%*U=nvM)=5VKe^~NoE5dmd(AR!}v!enFXBvumiEpSIX=bN%~`t zim}NrOA<>x`rnYGA2Zwj_BawZV?A0fP9YH>#VO*~l|u?r~1h+&8xQdZdG`E0X)< z+W>>17V&pg$JZ;y&l{)+<39Vv!ARZMnJ9l(l3{DNs=4OUTXrE5M`>hPe2T`B%vz*(~sRM2~ccg>E(EmAO!pNbH z<=mAH4nvkx(~0no?unU&+Qe=M=dAdLfzQbBhXM?zmf??bc)CYg=W&J;3t9Yxbn1ZT z>rCeGe4VKb2ZOB66Y10e&)1pG;rMDgb?)M+nBCZenfXr4_e?tTG8=Q`eKWF|fqvA^ z`<`bu7|gdwP2R$+n4Z+82C=*&z6E^tj+Uec;zhB&qh;yfX1|b5-cP+NYQGc{18(0< zRXX34z26n-V31+2q=TjBm3|wqGc12rZ-kLgJbw22k-h0v>GUUt9o8h@dOh8N9kGe~ It4`D6f6Wwkr~m)} literal 1508 zcmYk6ZA%nU7>3Wfty-35=1XNZYVVd6R0Pp`uznCUMEe+~LrknYvO5dWCx1aue<&yFDk>y?3kuu)7N~{CkW1m~; z8+1Cyz83Slhev$@x&3y7oZ(WJKkVgS)4g&8*jC9q!$H2Ec97;J$ie44wCkO%~;%RjGe z-&6FTL2sP!YsdRrA>LZ&KnO>_tv`+?XK(F`we3AlV^1R!;4xo&2H0aBdlqTF+ya{S z9&6|m&V32#jQX8hyZT$H`dq!FUVA>}1z5-49{Im8zKa*Iev7lfdwz-6@1Y%i6X@|fgXRNb0m-EHm`rlB`otHoYyi4o3|1yw| zF*nc?;C;lHo9ObtsAJA8V4i%O>o&SOe;~&Dy9?wzky}BRbH~Wtt2t-hWFznRJ}}>S g{eFv|)YZ2N>~D-S`)&NE?E7&q_trM@#llk6xe4doq+8YhtZ7#WOwnVaQ|`o(znk{@fP##SlB_JN zcwF@Uwt{8-Q*k#w7-r4A?SWk7lstzIRaS*#@;|<6D^~G7vEgX&CEFSI2I^E%7CGqH z?`7YKTP_-U{cq#6zmvh!^SJg_#Bm;uwL9o$U$t`{j+*IclpeJD-Rwu+3!b{4hiO-v zP8a>{bG=m`>-C%a>8ROhe`syB+HaThysDo^h;6<3^t#=CzkU>BK7+lnKNttgnh82= zt{cM4^rWmI12bPR3yi*+M>*ylz|>NEg_cG$p2e&SxAKKB>k#UaqWX1iAi~AX8{p>r4`x*D|IdsM6Ow*xwG?33S4I6qr zIP&J?pVFSl=2hjib};q8lK~gC&k9dzPh|9L1kB80JS|LZi=UOx0#kd&qr(>q!sq1E zlYZ2n)t<;$ykIBUTIdg-?_}uN{5N0KA|b{nX>m z=e1Lx9O4(W6Nd+13^>j9(rsW2M( zcF6&w5q~0JH1Q^e(Zmc5qlw=VIh;pR{&&l{6-DefB--oxt?G;NpD7pJd@J+=bMLD% zYJs`;H5vWZH0?zDbs2hjYu=wY-v#;H@rI0?cj^tkDWfLKxLfk!xI;&3(Q#WwE-`AX ziLYyK$gH3BVRm;y3|-{ijq*$v8qr05Gvxe|F7Um;QO9~M%eP+f+56&&nf?dznH$Tv zhw|aLlW~s%$9y~b3i)mx%Q#OyaegB|rHR;zj5ykidlGmwJlD(c)^PZ|Gjsc+uB)=Y Dl7(8w literal 2608 zcmZvd+jCP@6o(H@lWE7VUQD#m;l-JzG-|*mF--~u#H#S_ z_}BX4jNf;%S9@gK%wp}|Z(a6UYwwemX6CC|wlB-F!`UnTcOA=S5>v{t)+5=$-Tg+V z*B8tnddwnaq>|%OzF)&w=HGs}mF3oCJe-W#;xn6b?%RXSUF;e6R;Dq>*^jq}-Ns~X zpr0{vE~zr7o?w6Pix##@zSlM!4IXwMjC%vBtKg-NdAEAq$J)c!x_kZ2ai{;FD{q}= z(ai#9yqs%eu-^R%ZM>X0JEKu&yV+mwJ~6(OF~n3`HJ?kb-`MJm8tv9{^KP^C^(D;s zRr7fz+ufV@zihR>{c6|d{05V89#}M%>EAPB?&6E!mE~sNu{s~ID`qO*n`tF`4?OIQ zIvaWRULNP|Ec}O$2}~QiO@4SUG{wFLv1eDYWOe5q*3Qu43-sin)V}-0_YgcjWTC*W=`h zan8rM9mKeJ$5F#=UWA-}r`Y?I)sWLqC1eilx22DK16KS7auVB{=o(@@ ziwPfo4Icq}ZrGizOYAwvaS*`&a1pINa(ZXpx4b#tPuMf+^yG(Z|N3du=Q7$DdGVEm?OS{`;W*<{usy{b zt|uIIFC}d6#@|Al-#W!jwDFPuJNDX*zlPnpiuDmYSNHo8c8{wDhcw7$+_74dwrv*;AC_O$|@XYcP;_&d{ugg+zRo-3$-MgGU^_wrBcd;%w5%)1SikGh|-H&@K#8GG+FVw~M` zL_X&GOX5(w+>69H^YHsMalXek)g3_ZAja#j-QUzd=~3Hn$PQvn!Tru&-ny;P@AnU6 z6|qKVA=b~H_M=}StBAI>gv0hRSk4+fvw_ID^e?03wA=e9h<5wZUP;_PFjtX(0l3kn A@Bjb+ diff --git a/shaders/hlsl/texturecubemap/skybox.vert b/shaders/hlsl/texturecubemap/skybox.vert index 632f3cea..4395feb4 100644 --- a/shaders/hlsl/texturecubemap/skybox.vert +++ b/shaders/hlsl/texturecubemap/skybox.vert @@ -20,6 +20,11 @@ VSOutput main([[vk::location(0)]] float3 Pos : POSITION0) output.UVW = Pos; // Convert cubemap coordinates into Vulkan coordinate space output.UVW.xy *= -1.0; - output.Pos = mul(ubo.projection, mul(ubo.model, float4(Pos.xyz, 1.0))); + // Remove translation from view matrix + float4x4 viewMat = ubo.model; + viewMat[0][3] = 0.0; + viewMat[1][3] = 0.0; + viewMat[2][3] = 0.0; + output.Pos = mul(ubo.projection, mul(viewMat, float4(Pos.xyz, 1.0))); return output; } diff --git a/shaders/hlsl/texturecubemap/skybox.vert.spv b/shaders/hlsl/texturecubemap/skybox.vert.spv index e95a2708bd7b45afa728bc967f8756015759899f..94b7c48d15fa35060d31110168ed26bae62df242 100644 GIT binary patch literal 1296 zcmZva+fGwa5QZ16Z9RgB96Z4;^^9q}GA72e2Dot}V&W}mFKUEMNHOuwCosN|ujP%2 z-?#Q!rfFPcnDx&;GylxmZ8mzH5T-&1)8QWfJ+q;aBF%_pXTr&U_x;`BfuMnzaU%L= zXyNw=w&Gt1qi=_U{_$Q#IJC)<_ZVtX+2;QKMTz&XK8Huu=fTI(utK3tmT~p>t51V3 zc)JTM_lL2&rD$VCI9IX z{bsp2L;a@p8yM4;)7-vGLB<8VJGhH@4)0vfEWU_$Zu^Pn6PBN&asl5ZV-fG&eV6dg zXkTkCrMvo%z-s!|@?tf;t1Hf$>WbBL7x4ooRmWV9y1%KujDJj)b6vsgSEAx9S5wTm z$J!tCk-LV;``#r}Tkr4CTsbw>w%>DpP42RSIlte;@20N16`0&MthkH$oeIojugtA- zmosMy8|Qk7Ge=#ytbLt()>c1j-{3Cymc4xYn^@jA$8M#VdO3DG#njoNv)}m+X1)3H i{pb-AUpGLhvMlxGT|%;|g9A%^{*02~qIo6Nqo*Yk3j;zn*Rh z!48$`zt+F1Cz&W@jOj4O4475@bFwDkEJ=&;4w|mN`%}4A2P7m!bXuJ>Dd~!gDf=^~ z`Sx5bzEmQaO$Vc(yLL;xd+3^wPA>>*L$QFuXj%nUcrWbaRx1nWL9P9Wb-aTNGnv zY{hWMxA?(1hff@DVBsGdu|tv*_3?94-{--NyuCJCdmeE<&+pdvD`_HZ%rUMzuNO!r zl+i5>CKue}Fgq9%W)Fdc`fCpNwP14lCC0pedH;aLaXkJ(i{E!AmCvm7jCUB%j18H0 zJlR8_h^#c6;SL^_h6fzMBhv7s9(dGY{3FU7lg=q(T$(%cO-RFuy5vl{JN>tW>B(;K zgXzhgzF^;zzF>MX3wT3J=|e1szTe88lHOJnyrw183)KZKGtP#cL+*#_;G31;XTPCX zlRqaR79Tz7O}%}6J>S3w@zC$^ZZW diff --git a/shaders/hlsl/texturecubemaparray/skybox.vert b/shaders/hlsl/texturecubemaparray/skybox.vert index 37f07a08..6076e2f7 100644 --- a/shaders/hlsl/texturecubemaparray/skybox.vert +++ b/shaders/hlsl/texturecubemaparray/skybox.vert @@ -22,6 +22,11 @@ VSOutput main([[vk::location(0)]] float3 Pos : POSITION0) VSOutput output = (VSOutput)0; output.UVW = Pos; output.UVW.yz *= -1.0; - output.Pos = mul(ubo.projection, mul(ubo.model, float4(Pos.xyz, 1.0))); + // Remove translation from view matrix + float4x4 viewMat = ubo.model; + viewMat[0][3] = 0.0; + viewMat[1][3] = 0.0; + viewMat[2][3] = 0.0; + output.Pos = mul(ubo.projection, mul(viewMat, float4(Pos.xyz, 1.0))); return output; } diff --git a/shaders/hlsl/texturecubemaparray/skybox.vert.spv b/shaders/hlsl/texturecubemaparray/skybox.vert.spv index a086e9d619932fb2c8b24c7355f593f24a790573..fb4a1ae9d7c4a5f7a96029426cdd465aaa3c83d5 100644 GIT binary patch literal 1476 zcmZvaT~AX%5Qdl5wulM>@}XiqrOJnxhAU!X{6Y!z0uLf4-nR5y90NTKwnXpv1;&4* z7yKx1Onjg1EIDc1X1e>%J2UUh?kN`P73apBbCd3={#nzmV4kAKuv2dQ>U`QtyMTg> zh--c?x{~&`oF)HruK&H4GzRTVZdXkGGEtzu{zXCt$ z@h~2KY6Nqiihs4Jdeb`51Nv3_mhc55pB}0<18)#1dPY0*Fc)}MJ3Z1r_>OjFpf-5U zF#N1C=e5@qv7ntZvoC5#kGkaCwKKgu7e8C`JDL>G)EbAh+iDLTZm(EX$A zd)i+pioWj4s259xUY5*Y9AMd1B#M=%W8dUoNvel+i!$!yBT@ zY>^D^P%OA6LSZ**`^- BN)7-3 delta 592 zcmX|;Yc4}k6ot2YFQwdi6fLbj)N2Gn1Tlg#5I>BdMj(=o#2gI7F!&+yea$&;va(-m z@3qgqpX*=Ex-2G*h^2^V#l=VcQ%qj(yHUj!nKe*>K{R3oYi@!0b=jM36BS??jNt8H zozqNl8(RXWSl>;t^){V**fETKtbPYh2fGTKYfm@%s@@Q*$-35Oi-e+*6_$`i6*gAX zCm3I{szP%86#l0B0DB9|#SVe