diff --git a/data/shaders/texturearray/instancing.frag.spv b/data/shaders/texturearray/instancing.frag.spv index 16f0a1a1..106300c6 100644 Binary files a/data/shaders/texturearray/instancing.frag.spv and b/data/shaders/texturearray/instancing.frag.spv differ diff --git a/data/shaders/texturearray/instancing.vert b/data/shaders/texturearray/instancing.vert index 81624043..45570505 100644 --- a/data/shaders/texturearray/instancing.vert +++ b/data/shaders/texturearray/instancing.vert @@ -1,6 +1,6 @@ #version 450 -layout (location = 0) in vec4 inPos; +layout (location = 0) in vec3 inPos; layout (location = 1) in vec2 inUV; struct Instance @@ -22,5 +22,5 @@ void main() { outUV = vec3(inUV, ubo.instance[gl_InstanceIndex].arrayIndex.x); mat4 modelView = ubo.view * ubo.instance[gl_InstanceIndex].model; - gl_Position = ubo.projection * modelView * inPos; + gl_Position = ubo.projection * modelView * vec4(inPos, 1.0); } diff --git a/data/shaders/texturearray/instancing.vert.spv b/data/shaders/texturearray/instancing.vert.spv index cd35b9f3..363adc9e 100644 Binary files a/data/shaders/texturearray/instancing.vert.spv and b/data/shaders/texturearray/instancing.vert.spv differ diff --git a/examples/texturearray/texturearray.cpp b/examples/texturearray/texturearray.cpp index 6484f4bb..eaca5801 100644 --- a/examples/texturearray/texturearray.cpp +++ b/examples/texturearray/texturearray.cpp @@ -1,7 +1,7 @@ /* * Vulkan Example - Texture arrays and instanced rendering * -* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de +* Copyright (C) Sascha Willems - www.saschawillems.de * * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) */ @@ -23,7 +23,6 @@ #include "VulkanTexture.hpp" #include "VulkanBuffer.hpp" -#define VERTEX_BUFFER_BIND_ID 0 #define ENABLE_VALIDATION false // Vertex layout for this example @@ -40,12 +39,6 @@ public: uint32_t layerCount; vks::Texture textureArray; - struct { - VkPipelineVertexInputStateCreateInfo inputState; - std::vector bindingDescriptions; - std::vector attributeDescriptions; - } vertices; - vks::Buffer vertexBuffer; vks::Buffer indexBuffer; uint32_t indexCount; @@ -78,11 +71,12 @@ public: VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) { - zoom = -15.0f; - rotationSpeed = 0.25f; - rotation = { -15.0f, 35.0f, 0.0f }; title = "Texture arrays"; settings.overlay = true; + camera.type = Camera::CameraType::lookat; + camera.setPosition(glm::vec3(0.0f, 0.0f, -7.5f)); + camera.setRotation(glm::vec3(-35.0f, 0.0f, 0.0f)); + camera.setPerspective(45.0f, (float)width / (float)height, 0.1f, 256.0f); } ~VulkanExample() @@ -90,7 +84,6 @@ public: // Clean up used Vulkan resources // Note : Inherited destructor cleans up resources stored in base class - // Clean up texture resources vkDestroyImageView(device, textureArray.view, nullptr); vkDestroyImage(device, textureArray.image, nullptr); vkDestroySampler(device, textureArray.sampler, nullptr); @@ -340,7 +333,7 @@ public: vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); VkDeviceSize offsets[1] = { 0 }; - vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &vertexBuffer.buffer, offsets); + vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &vertexBuffer.buffer, offsets); vkCmdBindIndexBuffer(drawCmdBuffers[i], indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdDrawIndexed(drawCmdBuffers[i], indexCount, layerCount, 0, 0, 0); @@ -353,31 +346,53 @@ public: } } - void generateQuad() + void generateCube() { - // Setup vertices for a single uv-mapped quad made from two triangles - std::vector vertices = - { - { { 2.5f, 2.5f, 0.0f }, { 1.0f, 1.0f } }, - { { -2.5f, 2.5f, 0.0f }, { 0.0f, 1.0f } }, - { { -2.5f, -2.5f, 0.0f }, { 0.0f, 0.0f } }, - { { 2.5f, -2.5f, 0.0f }, { 1.0f, 0.0f } } + std::vector vertices = { + { { -1.0f, -1.0f, 1.0f }, { 0.0f, 0.0f } }, + { { 1.0f, -1.0f, 1.0f }, { 1.0f, 0.0f } }, + { { 1.0f, 1.0f, 1.0f }, { 1.0f, 1.0f } }, + { { -1.0f, 1.0f, 1.0f }, { 0.0f, 1.0f } }, + + { { 1.0f, 1.0f, 1.0f }, { 0.0f, 0.0f } }, + { { 1.0f, 1.0f, -1.0f }, { 1.0f, 0.0f } }, + { { 1.0f, -1.0f, -1.0f }, { 1.0f, 1.0f } }, + { { 1.0f, -1.0f, 1.0f }, { 0.0f, 1.0f } }, + + { { -1.0f, -1.0f, -1.0f }, { 0.0f, 0.0f } }, + { { 1.0f, -1.0f, -1.0f }, { 1.0f, 0.0f } }, + { { 1.0f, 1.0f, -1.0f }, { 1.0f, 1.0f } }, + { { -1.0f, 1.0f, -1.0f }, { 0.0f, 1.0f } }, + + { { -1.0f, -1.0f, -1.0f }, { 0.0f, 0.0f } }, + { { -1.0f, -1.0f, 1.0f }, { 1.0f, 0.0f } }, + { { -1.0f, 1.0f, 1.0f }, { 1.0f, 1.0f } }, + { { -1.0f, 1.0f, -1.0f }, { 0.0f, 1.0f } }, + + { { 1.0f, 1.0f, 1.0f }, { 0.0f, 0.0f } }, + { { -1.0f, 1.0f, 1.0f }, { 1.0f, 0.0f } }, + { { -1.0f, 1.0f, -1.0f }, { 1.0f, 1.0f } }, + { { 1.0f, 1.0f, -1.0f }, { 0.0f, 1.0f } }, + + { { -1.0f, -1.0f, -1.0f }, { 0.0f, 0.0f } }, + { { 1.0f, -1.0f, -1.0f }, { 1.0f, 0.0f } }, + { { 1.0f, -1.0f, 1.0f }, { 1.0f, 1.0f } }, + { { -1.0f, -1.0f, 1.0f }, { 0.0f, 1.0f } }, + }; + std::vector indices = { + 0,1,2, 0,2,3, 4,5,6, 4,6,7, 8,9,10, 8,10,11, 12,13,14, 12,14,15, 16,17,18, 16,18,19, 20,21,22, 20,22,23 }; - // Setup indices - 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, @@ -386,97 +401,34 @@ public: indices.data())); } - void setupVertexDescriptions() - { - // Binding description - vertices.bindingDescriptions.resize(1); - vertices.bindingDescriptions[0] = - vks::initializers::vertexInputBindingDescription( - VERTEX_BUFFER_BIND_ID, - sizeof(Vertex), - VK_VERTEX_INPUT_RATE_VERTEX); - - // Attribute descriptions - // Describes memory layout and shader positions - vertices.attributeDescriptions.resize(2); - // Location 0 : Position - vertices.attributeDescriptions[0] = - vks::initializers::vertexInputAttributeDescription( - VERTEX_BUFFER_BIND_ID, - 0, - VK_FORMAT_R32G32B32_SFLOAT, - 0); - // Location 1 : Texture coordinates - vertices.attributeDescriptions[1] = - vks::initializers::vertexInputAttributeDescription( - VERTEX_BUFFER_BIND_ID, - 1, - VK_FORMAT_R32G32_SFLOAT, - sizeof(float) * 3); - - vertices.inputState = vks::initializers::pipelineVertexInputStateCreateInfo(); - vertices.inputState.vertexBindingDescriptionCount = vertices.bindingDescriptions.size(); - vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data(); - vertices.inputState.vertexAttributeDescriptionCount = vertices.attributeDescriptions.size(); - vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data(); - } - void setupDescriptorPool() { - std::vector poolSizes = - { + 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.size(), - poolSizes.data(), - 2); - + VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes.size(), poolSizes.data(), 2); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); } void setupDescriptorSetLayout() { - std::vector setLayoutBindings = - { + 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 (texture array) - 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(), - setLayoutBindings.size()); - + VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings.data(), setLayoutBindings.size()); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); - VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = - vks::initializers::pipelineLayoutCreateInfo( - &descriptorSetLayout, - 1); - - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout)); + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); } void setupDescriptorSet() { - VkDescriptorSetAllocateInfo allocInfo = - vks::initializers::descriptorSetAllocateInfo( - descriptorPool, - &descriptorSetLayout, - 1); - + VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); // Image descriptor for the texture array @@ -486,99 +438,58 @@ public: textureArray.view, textureArray.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, &uniformBufferVS.descriptor), // Binding 1 : Fragment shader cubemap sampler - vks::initializers::writeDescriptorSet( - descriptorSet, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - 1, - &textureDescriptor) + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &textureDescriptor) }; - vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); } void preparePipelines() { - VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = - vks::initializers::pipelineInputAssemblyStateCreateInfo( - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, - 0, - VK_FALSE); + 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); + VkPipelineColorBlendStateCreateInfo colorBlendStateCI = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState); + VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL); + VkPipelineViewportStateCreateInfo viewportStateCI = vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); + VkPipelineMultisampleStateCreateInfo multisampleStateCI = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT, 0); + std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + VkPipelineDynamicStateCreateInfo dynamicStateCI = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables.data(), dynamicStateEnables.size(), 0); - 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 + // Vertex bindings and attributes + VkVertexInputBindingDescription vertexInputBinding = { 0, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX }; + std::vector vertexInputAttributes = { + { 0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, pos) }, + { 1, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, uv) }, }; - VkPipelineDynamicStateCreateInfo dynamicState = - vks::initializers::pipelineDynamicStateCreateInfo( - dynamicStateEnables.data(), - dynamicStateEnables.size(), - 0); + VkPipelineVertexInputStateCreateInfo vertexInputStateCI = vks::initializers::pipelineVertexInputStateCreateInfo(); + vertexInputStateCI.vertexBindingDescriptionCount = 1; + vertexInputStateCI.pVertexBindingDescriptions = &vertexInputBinding; + vertexInputStateCI.vertexAttributeDescriptionCount = static_cast(vertexInputAttributes.size()); + vertexInputStateCI.pVertexAttributeDescriptions = vertexInputAttributes.data(); // Instacing pipeline - // Load shaders std::array shaderStages; shaderStages[0] = loadShader(getAssetPath() + "shaders/texturearray/instancing.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[1] = loadShader(getAssetPath() + "shaders/texturearray/instancing.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - VkGraphicsPipelineCreateInfo pipelineCreateInfo = - vks::initializers::pipelineCreateInfo( - pipelineLayout, - renderPass, - 0); + VkGraphicsPipelineCreateInfo pipelineCI = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0); + pipelineCI.pVertexInputState = &vertexInputStateCI; + pipelineCI.pInputAssemblyState = &inputAssemblyStateCI; + pipelineCI.pRasterizationState = &rasterizationStateCI; + pipelineCI.pColorBlendState = &colorBlendStateCI; + pipelineCI.pMultisampleState = &multisampleStateCI; + pipelineCI.pViewportState = &viewportStateCI; + pipelineCI.pDepthStencilState = &depthStencilStateCI; + pipelineCI.pDynamicState = &dynamicStateCI; + pipelineCI.stageCount = shaderStages.size(); + pipelineCI.pStages = shaderStages.data(); - pipelineCreateInfo.pVertexInputState = &vertices.inputState; - pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; - pipelineCreateInfo.pRasterizationState = &rasterizationState; - pipelineCreateInfo.pColorBlendState = &colorBlendState; - pipelineCreateInfo.pMultisampleState = &multisampleState; - pipelineCreateInfo.pViewportState = &viewportState; - pipelineCreateInfo.pDepthStencilState = &depthStencilState; - pipelineCreateInfo.pDynamicState = &dynamicState; - pipelineCreateInfo.stageCount = shaderStages.size(); - pipelineCreateInfo.pStages = shaderStages.data(); - - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline)); + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); } void prepareUniformBuffers() @@ -596,14 +507,13 @@ public: // Array indices and model matrices are fixed float offset = -1.5f; - float center = (layerCount*offset) / 2; - for (int32_t i = 0; i < layerCount; i++) - { + 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(0.0f, i * offset - center, 0.0f)); - uboVS.instance[i].model = glm::rotate(uboVS.instance[i].model, glm::radians(60.0f), glm::vec3(1.0f, 0.0f, 0.0f)); + 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)); // Instance texture array index - uboVS.instance[i].arrayIndex.x = i; + uboVS.instance[i].arrayIndex.x = (float)i; } // Update instanced part of the uniform buffer @@ -617,23 +527,13 @@ public: // Map persistent VK_CHECK_RESULT(uniformBufferVS.map()); - updateUniformBufferMatrices(); + updateUniformBuffersCamera(); } - void updateUniformBufferMatrices() + void updateUniformBuffersCamera() { - // Only updates the uniform buffer block part containing the global matrices - - // Projection - uboVS.matrices.projection = glm::perspective(glm::radians(60.0f), (float)width / (float)height, 0.001f, 256.0f); - - // View - uboVS.matrices.view = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, -1.0f, zoom)); - uboVS.matrices.view = glm::rotate(uboVS.matrices.view, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)); - uboVS.matrices.view = glm::rotate(uboVS.matrices.view, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); - uboVS.matrices.view = glm::rotate(uboVS.matrices.view, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); - - // Only update the matrices part of the uniform buffer + uboVS.matrices.projection = camera.matrices.perspective; + uboVS.matrices.view = camera.matrices.view; memcpy(uniformBufferVS.mapped, &uboVS.matrices, sizeof(uboVS.matrices)); } @@ -652,8 +552,7 @@ public: { VulkanExampleBase::prepare(); loadTextures(); - setupVertexDescriptions(); - generateQuad(); + generateCube(); prepareUniformBuffers(); setupDescriptorSetLayout(); preparePipelines(); @@ -668,12 +567,10 @@ public: if (!prepared) return; draw(); + if (camera.updated) + updateUniformBuffersCamera(); } - virtual void viewChanged() - { - updateUniformBufferMatrices(); - } }; VULKAN_EXAMPLE_MAIN() \ No newline at end of file