Simplified text overlay example, code cleanup, better text blending

This commit is contained in:
saschawillems 2018-03-24 11:35:02 +01:00
parent 0c2720efc3
commit 3c230c7ff5
18 changed files with 119 additions and 408 deletions

View file

@ -6,14 +6,6 @@
"assets": { "assets": {
"models": [ "models": [
"cube.dae" "cube.dae"
],
"textures": [
"skysphere_bc3_unorm.ktx",
"skysphere_astc_8x8_unorm.ktx",
"skysphere_etc2_unorm.ktx",
"round_window_bc3_unorm.ktx",
"round_window_astc_8x8_unorm.ktx",
"round_window_etc2_unorm.ktx"
] ]
} }
} }

View file

@ -1,15 +0,0 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (binding = 1) uniform sampler2D samplerColorMap;
layout (location = 0) in vec2 inUV;
layout (location = 0) out vec4 outFragColor;
void main()
{
outFragColor = texture(samplerColorMap, inUV);
}

View file

@ -1,17 +0,0 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (location = 0) out vec2 outUV;
out gl_PerVertex
{
vec4 gl_Position;
};
void main()
{
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
gl_Position = vec4(outUV * vec2(2.0f, 2.0f) + vec2(-1.0f, -1.0f), 0.0f, 1.0f);
}

View file

@ -1,6 +0,0 @@
glslangvalidator -V text.vert -o text.vert.spv
glslangvalidator -V text.frag -o text.frag.spv
glslangvalidator -V mesh.vert -o mesh.vert.spv
glslangvalidator -V mesh.frag -o mesh.frag.spv
glslangvalidator -V background.vert -o background.vert.spv
glslangvalidator -V background.frag -o background.frag.spv

View file

@ -3,8 +3,6 @@
#extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable #extension GL_ARB_shading_language_420pack : enable
layout (binding = 1) uniform sampler2D samplerColorMap;
layout (location = 0) in vec3 inNormal; layout (location = 0) in vec3 inNormal;
layout (location = 1) in vec2 inUV; layout (location = 1) in vec2 inUV;
layout (location = 2) in vec3 inViewVec; layout (location = 2) in vec3 inViewVec;
@ -14,13 +12,11 @@ layout (location = 0) out vec4 outFragColor;
void main() void main()
{ {
vec4 color = texture(samplerColorMap, inUV);
vec3 N = normalize(inNormal); vec3 N = normalize(inNormal);
vec3 L = normalize(inLightVec); vec3 L = normalize(inLightVec);
vec3 V = normalize(inViewVec); vec3 V = normalize(inViewVec);
vec3 R = reflect(-L, N); vec3 R = reflect(-L, N);
vec3 diffuse = max(dot(N, L), 0.0) * color.rgb; float diffuse = max(dot(N, L), 0.0);
vec3 specular = pow(max(dot(R, V), 0.0), 1.0) * vec3(color.a); float specular = pow(max(dot(R, V), 0.0), 1.0);
outFragColor = vec4(diffuse + specular, 1.0); outFragColor = vec4(vec3(diffuse + specular) * vec3(0.25), 1.0);
} }

View file

@ -21,7 +21,7 @@ layout (location = 3) out vec3 outLightVec;
out gl_PerVertex out gl_PerVertex
{ {
vec4 gl_Position; vec4 gl_Position;
}; };
void main() void main()
@ -30,9 +30,9 @@ void main()
outUV = inUV; outUV = inUV;
gl_Position = ubo.projection * ubo.model * vec4(inPos.xyz, 1.0); gl_Position = ubo.projection * ubo.model * vec4(inPos.xyz, 1.0);
vec4 pos = ubo.model * vec4(inPos, 1.0); vec4 pos = ubo.model * vec4(inPos, 1.0);
outNormal = mat3(transpose(inverse(ubo.model))) * normalize(inNormal); outNormal = mat3(transpose(inverse(ubo.model))) * normalize(inNormal);
vec3 lPos = mat3(ubo.model) * ubo.lightPos.xyz; vec3 lPos = mat3(ubo.model) * ubo.lightPos.xyz;
outLightVec = lPos - pos.xyz; outLightVec = lPos - pos.xyz;
outViewVec = -pos.xyz; outViewVec = -pos.xyz;
} }

View file

@ -9,5 +9,5 @@ layout (location = 0) out vec4 outFragColor;
void main(void) void main(void)
{ {
float color = texture(samplerFont, inUV).r; float color = texture(samplerFont, inUV).r;
outFragColor = vec4(vec3(color), 1.0); outFragColor = vec4(color);
} }

View file

@ -7,7 +7,7 @@ layout (location = 0) out vec2 outUV;
out gl_PerVertex out gl_PerVertex
{ {
vec4 gl_Position; vec4 gl_Position;
}; };
void main(void) void main(void)

View file

@ -26,25 +26,18 @@
#include "VulkanDevice.hpp" #include "VulkanDevice.hpp"
#include "VulkanBuffer.hpp" #include "VulkanBuffer.hpp"
#include "VulkanModel.hpp" #include "VulkanModel.hpp"
#include "VulkanTexture.hpp"
#include "../external/stb/stb_font_consolas_24_latin1.inl" #include "../external/stb/stb_font_consolas_24_latin1.inl"
#define VERTEX_BUFFER_BIND_ID 0 #define VERTEX_BUFFER_BIND_ID 0
#define ENABLE_VALIDATION false #define ENABLE_VALIDATION false
// Defines for the STB font used
// STB font files can be found at http://nothings.org/stb/font/
#define STB_FONT_NAME stb_font_consolas_24_latin1
#define STB_FONT_WIDTH STB_FONT_consolas_24_latin1_BITMAP_WIDTH
#define STB_FONT_HEIGHT STB_FONT_consolas_24_latin1_BITMAP_HEIGHT
#define STB_FIRST_CHAR STB_FONT_consolas_24_latin1_FIRST_CHAR
#define STB_NUM_CHARS STB_FONT_consolas_24_latin1_NUM_CHARS
// Max. number of chars the text overlay buffer can hold // Max. number of chars the text overlay buffer can hold
#define TEXTOVERLAY_MAX_CHAR_COUNT 2048 #define TEXTOVERLAY_MAX_CHAR_COUNT 2048
// Mostly self-contained text overlay class /*
Mostly self-contained text overlay class
*/
class TextOverlay class TextOverlay
{ {
private: private:
@ -78,7 +71,7 @@ private:
// Pointer to mapped vertex buffer // Pointer to mapped vertex buffer
glm::vec4 *mapped = nullptr; glm::vec4 *mapped = nullptr;
stb_fontchar stbFontData[STB_NUM_CHARS]; stb_fontchar stbFontData[STB_FONT_consolas_24_latin1_NUM_CHARS];
uint32_t numLetters; uint32_t numLetters;
public: public:
@ -140,8 +133,11 @@ public:
// The text overlay uses separate resources for descriptors (pool, sets, layouts), pipelines and command buffers // The text overlay uses separate resources for descriptors (pool, sets, layouts), pipelines and command buffers
void prepareResources() void prepareResources()
{ {
static unsigned char font24pixels[STB_FONT_HEIGHT][STB_FONT_WIDTH]; const uint32_t fontWidth = STB_FONT_consolas_24_latin1_BITMAP_WIDTH;
STB_FONT_NAME(stbFontData, font24pixels, STB_FONT_HEIGHT); const uint32_t fontHeight = STB_FONT_consolas_24_latin1_BITMAP_WIDTH;
static unsigned char font24pixels[fontWidth][fontHeight];
stb_font_consolas_24_latin1(stbFontData, font24pixels, fontHeight);
// Command buffer // Command buffer
@ -180,8 +176,8 @@ public:
VkImageCreateInfo imageInfo = vks::initializers::imageCreateInfo(); VkImageCreateInfo imageInfo = vks::initializers::imageCreateInfo();
imageInfo.imageType = VK_IMAGE_TYPE_2D; imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.format = VK_FORMAT_R8_UNORM; imageInfo.format = VK_FORMAT_R8_UNORM;
imageInfo.extent.width = STB_FONT_WIDTH; imageInfo.extent.width = fontWidth;
imageInfo.extent.height = STB_FONT_HEIGHT; imageInfo.extent.height = fontHeight;
imageInfo.extent.depth = 1; imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1; imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1; imageInfo.arrayLayers = 1;
@ -227,7 +223,7 @@ public:
uint8_t *data; uint8_t *data;
VK_CHECK_RESULT(vkMapMemory(vulkanDevice->logicalDevice, stagingBuffer.memory, 0, allocInfo.allocationSize, 0, (void **)&data)); VK_CHECK_RESULT(vkMapMemory(vulkanDevice->logicalDevice, stagingBuffer.memory, 0, allocInfo.allocationSize, 0, (void **)&data));
// Size of the font texture is WIDTH * HEIGHT * 1 byte (only one channel) // Size of the font texture is WIDTH * HEIGHT * 1 byte (only one channel)
memcpy(data, &font24pixels[0][0], STB_FONT_WIDTH * STB_FONT_HEIGHT); memcpy(data, &font24pixels[0][0], fontWidth * fontHeight);
vkUnmapMemory(vulkanDevice->logicalDevice, stagingBuffer.memory); vkUnmapMemory(vulkanDevice->logicalDevice, stagingBuffer.memory);
// Copy to image // Copy to image
@ -251,8 +247,8 @@ public:
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
bufferCopyRegion.imageSubresource.mipLevel = 0; bufferCopyRegion.imageSubresource.mipLevel = 0;
bufferCopyRegion.imageSubresource.layerCount = 1; bufferCopyRegion.imageSubresource.layerCount = 1;
bufferCopyRegion.imageExtent.width = STB_FONT_WIDTH; bufferCopyRegion.imageExtent.width = fontWidth;
bufferCopyRegion.imageExtent.height = STB_FONT_HEIGHT; bufferCopyRegion.imageExtent.height = fontHeight;
bufferCopyRegion.imageExtent.depth = 1; bufferCopyRegion.imageExtent.depth = 1;
vkCmdCopyBufferToImage( vkCmdCopyBufferToImage(
@ -366,84 +362,43 @@ public:
// Prepare a separate pipeline for the font rendering decoupled from the main application // Prepare a separate pipeline for the font rendering decoupled from the main application
void preparePipeline() void preparePipeline()
{ {
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = // Enable blending, using alpha from red channel of the font texture (see text.frag)
vks::initializers::pipelineInputAssemblyStateCreateInfo( VkPipelineColorBlendAttachmentState blendAttachmentState{};
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, blendAttachmentState.blendEnable = VK_TRUE;
0,
VK_FALSE);
VkPipelineRasterizationStateCreateInfo rasterizationState =
vks::initializers::pipelineRasterizationStateCreateInfo(
VK_POLYGON_MODE_FILL,
VK_CULL_MODE_BACK_BIT,
VK_FRONT_FACE_CLOCKWISE,
0);
// Enable blending
VkPipelineColorBlendAttachmentState blendAttachmentState =
vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_TRUE);
blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
VkPipelineColorBlendStateCreateInfo colorBlendState = VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0, VK_FALSE);
vks::initializers::pipelineColorBlendStateCreateInfo( VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_CLOCKWISE, 0);
1, VkPipelineColorBlendStateCreateInfo colorBlendState = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState);
&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<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables);
VkPipelineDepthStencilStateCreateInfo depthStencilState = std::array<VkVertexInputBindingDescription, 2> vertexInputBindings = {
vks::initializers::pipelineDepthStencilStateCreateInfo( vks::initializers::vertexInputBindingDescription(0, sizeof(glm::vec4), VK_VERTEX_INPUT_RATE_VERTEX),
VK_TRUE, vks::initializers::vertexInputBindingDescription(1, sizeof(glm::vec4), VK_VERTEX_INPUT_RATE_VERTEX),
VK_TRUE, };
VK_COMPARE_OP_LESS_OR_EQUAL); std::array<VkVertexInputAttributeDescription, 2> vertexInputAttributes = {
vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32_SFLOAT, 0), // Location 0: Position
VkPipelineViewportStateCreateInfo viewportState = vks::initializers::vertexInputAttributeDescription(1, 1, VK_FORMAT_R32G32_SFLOAT, sizeof(glm::vec2)), // Location 1: UV
vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0);
VkPipelineMultisampleStateCreateInfo multisampleState =
vks::initializers::pipelineMultisampleStateCreateInfo(
VK_SAMPLE_COUNT_1_BIT,
0);
std::vector<VkDynamicState> dynamicStateEnables = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR
}; };
VkPipelineDynamicStateCreateInfo dynamicState = VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo();
vks::initializers::pipelineDynamicStateCreateInfo( vertexInputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertexInputBindings.size());
dynamicStateEnables.data(), vertexInputState.pVertexBindingDescriptions = vertexInputBindings.data();
static_cast<uint32_t>(dynamicStateEnables.size()), vertexInputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexInputAttributes.size());
0); vertexInputState.pVertexAttributeDescriptions = vertexInputAttributes.data();
std::array<VkVertexInputBindingDescription, 2> vertexBindings = {}; VkGraphicsPipelineCreateInfo pipelineCreateInfo = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0);
vertexBindings[0] = vks::initializers::vertexInputBindingDescription(0, sizeof(glm::vec4), VK_VERTEX_INPUT_RATE_VERTEX); pipelineCreateInfo.pVertexInputState = &vertexInputState;
vertexBindings[1] = vks::initializers::vertexInputBindingDescription(1, sizeof(glm::vec4), VK_VERTEX_INPUT_RATE_VERTEX);
std::array<VkVertexInputAttributeDescription, 2> vertexAttribs = {};
// Position
vertexAttribs[0] = vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32_SFLOAT, 0);
// UV
vertexAttribs[1] = vks::initializers::vertexInputAttributeDescription(1, 1, VK_FORMAT_R32G32_SFLOAT, sizeof(glm::vec2));
VkPipelineVertexInputStateCreateInfo inputState = vks::initializers::pipelineVertexInputStateCreateInfo();
inputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertexBindings.size());
inputState.pVertexBindingDescriptions = vertexBindings.data();
inputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexAttribs.size());
inputState.pVertexAttributeDescriptions = vertexAttribs.data();
VkGraphicsPipelineCreateInfo pipelineCreateInfo =
vks::initializers::pipelineCreateInfo(
pipelineLayout,
renderPass,
0);
pipelineCreateInfo.pVertexInputState = &inputState;
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
pipelineCreateInfo.pRasterizationState = &rasterizationState; pipelineCreateInfo.pRasterizationState = &rasterizationState;
pipelineCreateInfo.pColorBlendState = &colorBlendState; pipelineCreateInfo.pColorBlendState = &colorBlendState;
@ -548,6 +503,8 @@ public:
// todo : drop shadow? color attribute? // todo : drop shadow? color attribute?
void addText(std::string text, float x, float y, TextAlign align) void addText(std::string text, float x, float y, TextAlign align)
{ {
const uint32_t firstChar = STB_FONT_consolas_24_latin1_FIRST_CHAR;
assert(mapped != nullptr); assert(mapped != nullptr);
const float charW = 1.5f / *frameBufferWidth; const float charW = 1.5f / *frameBufferWidth;
@ -562,7 +519,7 @@ public:
float textWidth = 0; float textWidth = 0;
for (auto letter : text) for (auto letter : text)
{ {
stb_fontchar *charData = &stbFontData[(uint32_t)letter - STB_FIRST_CHAR]; stb_fontchar *charData = &stbFontData[(uint32_t)letter - firstChar];
textWidth += charData->advance * charW; textWidth += charData->advance * charW;
} }
@ -579,7 +536,7 @@ public:
// Generate a uv mapped quad per char in the new text // Generate a uv mapped quad per char in the new text
for (auto letter : text) for (auto letter : text)
{ {
stb_fontchar *charData = &stbFontData[(uint32_t)letter - STB_FIRST_CHAR]; stb_fontchar *charData = &stbFontData[(uint32_t)letter - firstChar];
mapped->x = (x + (float)charData->x0 * charW); mapped->x = (x + (float)charData->x0 * charW);
mapped->y = (y + (float)charData->y0 * charH); mapped->y = (y + (float)charData->y0 * charH);
@ -685,6 +642,9 @@ public:
}; };
/*
Vulkan example main class
*/
class VulkanExample : public VulkanExampleBase class VulkanExample : public VulkanExampleBase
{ {
public: public:
@ -698,21 +658,10 @@ public:
vks::VERTEX_COMPONENT_COLOR, vks::VERTEX_COMPONENT_COLOR,
}); });
struct {
vks::Texture2D background;
vks::Texture2D cube;
} textures;
struct { struct {
vks::Model cube; vks::Model cube;
} models; } models;
struct {
VkPipelineVertexInputStateCreateInfo inputState;
std::vector<VkVertexInputBindingDescription> bindingDescriptions;
std::vector<VkVertexInputAttributeDescription> attributeDescriptions;
} vertices;
vks::Buffer uniformBuffer; vks::Buffer uniformBuffer;
struct UBOVS { struct UBOVS {
@ -721,38 +670,28 @@ public:
glm::vec4 lightPos = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); glm::vec4 lightPos = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
} uboVS; } uboVS;
struct {
VkPipeline solid;
VkPipeline background;
} pipelines;
VkPipelineLayout pipelineLayout; VkPipelineLayout pipelineLayout;
VkPipeline pipeline;
VkDescriptorSetLayout descriptorSetLayout; VkDescriptorSetLayout descriptorSetLayout;
VkDescriptorSet descriptorSet;
struct {
VkDescriptorSet background;
VkDescriptorSet cube;
} descriptorSets;
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
{ {
zoom = -4.5f;
zoomSpeed = 2.5f;
rotation = { -25.0f, 0.0f, 0.0f };
title = "Vulkan Example - Text overlay"; title = "Vulkan Example - Text overlay";
settings.overlay = false; settings.overlay = false;
camera.type = Camera::CameraType::lookat;
camera.setPosition(glm::vec3(0.0f, 0.0f, -4.5f));
camera.setRotation(glm::vec3(-25.0f, -0.0f, 0.0f));
camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f);
} }
~VulkanExample() ~VulkanExample()
{ {
vkDestroyPipeline(device, pipelines.solid, nullptr); vkDestroyPipeline(device, pipeline, nullptr);
vkDestroyPipeline(device, pipelines.background, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
models.cube.destroy(); models.cube.destroy();
textures.background.destroy();
textures.cube.destroy();
uniformBuffer.destroy(); uniformBuffer.destroy();
delete(textOverlay); delete(textOverlay);
} }
@ -763,7 +702,7 @@ public:
VkClearValue clearValues[3]; VkClearValue clearValues[3];
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } }; clearValues[0].color = { { 0.0f, 0.0f, 0.2f, 1.0f } };
clearValues[1].depthStencil = { 1.0f, 0 }; clearValues[1].depthStencil = { 1.0f, 0 };
VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
@ -788,20 +727,13 @@ public:
VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0); VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0);
vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets.background, 0, NULL);
VkDeviceSize offsets[1] = { 0 }; VkDeviceSize offsets[1] = { 0 };
vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &models.cube.vertices.buffer, offsets); vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &models.cube.vertices.buffer, offsets);
vkCmdBindIndexBuffer(drawCmdBuffers[i], models.cube.indices.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(drawCmdBuffers[i], models.cube.indices.buffer, 0, VK_INDEX_TYPE_UINT32);
// Background
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.background);
// Vertices are generated by the vertex shader
vkCmdDraw(drawCmdBuffers[i], 4, 1, 0, 0);
// Cube // Cube
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.solid); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets.cube, 0, NULL); vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL);
vkCmdDrawIndexed(drawCmdBuffers[i], models.cube.indexCount, 1, 0, 0, 0); vkCmdDrawIndexed(drawCmdBuffers[i], models.cube.indexCount, 1, 0, 0, 0);
vkCmdEndRenderPass(drawCmdBuffers[i]); vkCmdEndRenderPass(drawCmdBuffers[i]);
@ -866,235 +798,81 @@ public:
void loadAssets() void loadAssets()
{ {
models.cube.loadFromFile(getAssetPath() + "models/cube.dae", vertexLayout, 1.0f, vulkanDevice, queue); models.cube.loadFromFile(getAssetPath() + "models/cube.dae", vertexLayout, 1.0f, vulkanDevice, queue);
// Textures
std::string texFormatSuffix;
VkFormat texFormat;
// Get supported compressed texture format
if (vulkanDevice->features.textureCompressionBC) {
texFormatSuffix = "_bc3_unorm";
texFormat = VK_FORMAT_BC3_UNORM_BLOCK;
}
else if (vulkanDevice->features.textureCompressionASTC_LDR) {
texFormatSuffix = "_astc_8x8_unorm";
texFormat = VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
}
else if (vulkanDevice->features.textureCompressionETC2) {
texFormatSuffix = "_etc2_unorm";
texFormat = VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
}
else {
vks::tools::exitFatal("Device does not support any compressed texture format!", VK_ERROR_FEATURE_NOT_PRESENT);
}
textures.background.loadFromFile(getAssetPath() + "textures/skysphere" + texFormatSuffix + ".ktx", texFormat, vulkanDevice, queue);
textures.cube.loadFromFile(getAssetPath() + "textures/round_window" + texFormatSuffix + ".ktx", texFormat, vulkanDevice, queue);
}
void setupVertexDescriptions()
{
// Binding description
vertices.bindingDescriptions.resize(1);
vertices.bindingDescriptions[0] =
vks::initializers::vertexInputBindingDescription(
VERTEX_BUFFER_BIND_ID,
vertexLayout.stride(),
VK_VERTEX_INPUT_RATE_VERTEX);
// Attribute descriptions
vertices.attributeDescriptions.resize(4);
// Location 0 : Position
vertices.attributeDescriptions[0] =
vks::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
0,
VK_FORMAT_R32G32B32_SFLOAT,
0);
// Location 1 : Normal
vertices.attributeDescriptions[1] =
vks::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
1,
VK_FORMAT_R32G32B32_SFLOAT,
sizeof(float) * 3);
// Location 2 : Texture coordinates
vertices.attributeDescriptions[2] =
vks::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
2,
VK_FORMAT_R32G32_SFLOAT,
sizeof(float) * 6);
// Location 3 : Color
vertices.attributeDescriptions[3] =
vks::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
3,
VK_FORMAT_R32G32B32_SFLOAT,
sizeof(float) * 8);
vertices.inputState = vks::initializers::pipelineVertexInputStateCreateInfo();
vertices.inputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertices.bindingDescriptions.size());
vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data();
vertices.inputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertices.attributeDescriptions.size());
vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data();
} }
void setupDescriptorPool() void setupDescriptorPool()
{ {
std::vector<VkDescriptorPoolSize> poolSizes = std::vector<VkDescriptorPoolSize> poolSizes = {
{
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2), vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2),
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2),
}; };
VkDescriptorPoolCreateInfo descriptorPoolInfo = VkDescriptorPoolCreateInfo descriptorPoolInfo =
vks::initializers::descriptorPoolCreateInfo( vks::initializers::descriptorPoolCreateInfo(poolSizes, 2);
static_cast<uint32_t>(poolSizes.size()),
poolSizes.data(),
2);
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));
} }
void setupDescriptorSetLayout() void setupDescriptorSetLayout()
{ {
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
{ // Binding 0: Vertex shader uniform buffer
// 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 combined sampler
vks::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_SHADER_STAGE_FRAGMENT_BIT,
1),
}; };
VkDescriptorSetLayoutCreateInfo descriptorLayout = VkDescriptorSetLayoutCreateInfo descriptorLayout =
vks::initializers::descriptorSetLayoutCreateInfo( vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings);
setLayoutBindings.data(),
static_cast<uint32_t>(setLayoutBindings.size()));
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout));
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo =
vks::initializers::pipelineLayoutCreateInfo( vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1);
&descriptorSetLayout,
1);
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout)); VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout));
} }
void setupDescriptorSet() void setupDescriptorSet()
{ {
VkDescriptorSetAllocateInfo allocInfo = VkDescriptorSetAllocateInfo allocInfo =
vks::initializers::descriptorSetAllocateInfo( vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
descriptorPool, VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
&descriptorSetLayout, std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
1); // Binding 0: Vertex shader uniform buffer
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor),
// Background };
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.background));
VkDescriptorImageInfo texDescriptor =
vks::initializers::descriptorImageInfo(
textures.background.sampler,
textures.background.view,
VK_IMAGE_LAYOUT_GENERAL);
std::vector<VkWriteDescriptorSet> writeDescriptorSets;
// Binding 0 : Vertex shader uniform buffer
writeDescriptorSets.push_back(
vks::initializers::writeDescriptorSet(
descriptorSets.background,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0,
&uniformBuffer.descriptor));
// Binding 1 : Color map
writeDescriptorSets.push_back(
vks::initializers::writeDescriptorSet(
descriptorSets.background,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1,
&texDescriptor));
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
// Cube
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.cube));
texDescriptor.sampler = textures.cube.sampler;
texDescriptor.imageView = textures.cube.view;
writeDescriptorSets[0].dstSet = descriptorSets.cube;
writeDescriptorSets[1].dstSet = descriptorSets.cube;
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
} }
void preparePipelines() void preparePipelines()
{ {
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE);
vks::initializers::pipelineInputAssemblyStateCreateInfo( VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_CLOCKWISE, 0);
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE);
0, VkPipelineColorBlendStateCreateInfo colorBlendState = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState);
VK_FALSE); 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<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables);
VkPipelineRasterizationStateCreateInfo rasterizationState = // Vertex bindings and attributes
vks::initializers::pipelineRasterizationStateCreateInfo( std::vector<VkVertexInputBindingDescription> vertexInputBindings = {
VK_POLYGON_MODE_FILL, vks::initializers::vertexInputBindingDescription(0, vertexLayout.stride(), VK_VERTEX_INPUT_RATE_VERTEX),
VK_CULL_MODE_BACK_BIT,
VK_FRONT_FACE_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<VkDynamicState> dynamicStateEnables = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR
}; };
VkPipelineDynamicStateCreateInfo dynamicState = std::vector<VkVertexInputAttributeDescription> vertexInputAttributes = {
vks::initializers::pipelineDynamicStateCreateInfo( vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0), // Location 0: Position
dynamicStateEnables.data(), vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3), // Location 1: Normal
static_cast<uint32_t>(dynamicStateEnables.size()), vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 6), // Location 2: Texture coordinates
0); vks::initializers::vertexInputAttributeDescription(0, 3, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 8), // Location 3: Color
};
VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo();
vertexInputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertexInputBindings.size());
vertexInputState.pVertexBindingDescriptions = vertexInputBindings.data();
vertexInputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexInputAttributes.size());
vertexInputState.pVertexAttributeDescriptions = vertexInputAttributes.data();
// Wire frame rendering pipeline // Shaders
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages; std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
shaderStages[0] = loadShader(getAssetPath() + "shaders/textoverlay/mesh.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[0] = loadShader(getAssetPath() + "shaders/textoverlay/mesh.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getAssetPath() + "shaders/textoverlay/mesh.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); shaderStages[1] = loadShader(getAssetPath() + "shaders/textoverlay/mesh.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
VkGraphicsPipelineCreateInfo pipelineCreateInfo = VkGraphicsPipelineCreateInfo pipelineCreateInfo = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0);
vks::initializers::pipelineCreateInfo( pipelineCreateInfo.pVertexInputState = &vertexInputState;
pipelineLayout,
renderPass,
0);
pipelineCreateInfo.pVertexInputState = &vertices.inputState;
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
pipelineCreateInfo.pRasterizationState = &rasterizationState; pipelineCreateInfo.pRasterizationState = &rasterizationState;
pipelineCreateInfo.pColorBlendState = &colorBlendState; pipelineCreateInfo.pColorBlendState = &colorBlendState;
@ -1102,21 +880,10 @@ public:
pipelineCreateInfo.pViewportState = &viewportState; pipelineCreateInfo.pViewportState = &viewportState;
pipelineCreateInfo.pDepthStencilState = &depthStencilState; pipelineCreateInfo.pDepthStencilState = &depthStencilState;
pipelineCreateInfo.pDynamicState = &dynamicState; pipelineCreateInfo.pDynamicState = &dynamicState;
pipelineCreateInfo.stageCount = static_cast<uint32_t>(shaderStages.size()); pipelineCreateInfo.stageCount = 2;
pipelineCreateInfo.pStages = shaderStages.data(); 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));
// Background rendering pipeline
depthStencilState.depthTestEnable = VK_FALSE;
depthStencilState.depthWriteEnable = VK_FALSE;
rasterizationState.polygonMode = VK_POLYGON_MODE_FILL;
shaderStages[0] = loadShader(getAssetPath() + "shaders/textoverlay/background.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getAssetPath() + "shaders/textoverlay/background.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.background));
} }
// Prepare and initialize uniform buffer containing shader uniforms // Prepare and initialize uniform buffer containing shader uniforms
@ -1137,16 +904,11 @@ public:
void updateUniformBuffers() void updateUniformBuffers()
{ {
// Vertex shader uboVS.projection = camera.matrices.perspective;
uboVS.projection = glm::perspective(glm::radians(60.0f), (float)width / (float)height, 0.1f, 256.0f); uboVS.model = glm::rotate(glm::mat4(1.0f), glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
glm::mat4 viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, zoom));
uboVS.model = viewMatrix * glm::translate(glm::mat4(1.0f), cameraPos);
uboVS.model = glm::rotate(uboVS.model, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
uboVS.model = glm::rotate(uboVS.model, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); uboVS.model = glm::rotate(uboVS.model, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
uboVS.model = glm::rotate(uboVS.model, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); uboVS.model = glm::rotate(uboVS.model, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
uboVS.model = camera.matrices.view * uboVS.model;
memcpy(uniformBuffer.mapped, &uboVS, sizeof(uboVS)); memcpy(uniformBuffer.mapped, &uboVS, sizeof(uboVS));
} }
@ -1191,7 +953,6 @@ public:
{ {
VulkanExampleBase::prepare(); VulkanExampleBase::prepare();
loadAssets(); loadAssets();
setupVertexDescriptions();
prepareUniformBuffers(); prepareUniformBuffers();
setupDescriptorSetLayout(); setupDescriptorSetLayout();
preparePipelines(); preparePipelines();