Removed offscreen texture (and copy), sample from depth attachment directly instead
This commit is contained in:
parent
e7b79bec31
commit
82a57c8ce9
1 changed files with 132 additions and 238 deletions
|
|
@ -1,9 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Vulkan Example - Offscreen rendering using a separate framebuffer
|
* Vulkan Example - Shadow mapping for directional light sources
|
||||||
*
|
|
||||||
* p - Toggle light source animation
|
|
||||||
* l - Toggle between scene and light's POV
|
|
||||||
* s - Toggle shadowmap display
|
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
|
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
|
||||||
*
|
*
|
||||||
|
|
@ -31,12 +27,16 @@
|
||||||
// 16 bits of depth is enough for such a small scene
|
// 16 bits of depth is enough for such a small scene
|
||||||
#define DEPTH_FORMAT VK_FORMAT_D16_UNORM
|
#define DEPTH_FORMAT VK_FORMAT_D16_UNORM
|
||||||
|
|
||||||
// Texture properties
|
// Shadowmap properties
|
||||||
#define TEX_DIM 2048
|
#if defined(__ANDROID__)
|
||||||
#define TEX_FILTER VK_FILTER_LINEAR
|
#define SHADOWMAP_DIM 1024
|
||||||
|
#else
|
||||||
|
#define SHADOWMAP_DIM 2048
|
||||||
|
#endif
|
||||||
|
#define SHADOWMAP_FILTER VK_FILTER_LINEAR
|
||||||
|
|
||||||
// Offscreen frame buffer properties
|
// Offscreen frame buffer properties
|
||||||
#define FB_DIM TEX_DIM
|
#define FB_DIM SHADOWMAP_DIM
|
||||||
#define FB_COLOR_FORMAT VK_FORMAT_R8G8B8A8_UNORM
|
#define FB_COLOR_FORMAT VK_FORMAT_R8G8B8A8_UNORM
|
||||||
|
|
||||||
// Vertex layout for this example
|
// Vertex layout for this example
|
||||||
|
|
@ -59,6 +59,7 @@ public:
|
||||||
float zNear = 1.0f;
|
float zNear = 1.0f;
|
||||||
float zFar = 96.0f;
|
float zFar = 96.0f;
|
||||||
|
|
||||||
|
// Depth bias (and slope) are used to avoid shadowing artefacts
|
||||||
// Constant depth bias factor (always applied)
|
// Constant depth bias factor (always applied)
|
||||||
float depthBiasConstant = 1.25f;
|
float depthBiasConstant = 1.25f;
|
||||||
// Slope depth bias factor, applied depending on polygon's slope
|
// Slope depth bias factor, applied depending on polygon's slope
|
||||||
|
|
@ -78,10 +79,11 @@ public:
|
||||||
std::vector<VkVertexInputAttributeDescription> attributeDescriptions;
|
std::vector<VkVertexInputAttributeDescription> attributeDescriptions;
|
||||||
} vertices;
|
} vertices;
|
||||||
|
|
||||||
vkTools::UniformData uniformDataVS, uniformDataOffscreenVS;
|
vkTools::UniformData uniformDataVS;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
vkTools::UniformData scene;
|
vkTools::UniformData scene;
|
||||||
|
vkTools::UniformData offscreen;
|
||||||
} uniformData;
|
} uniformData;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
@ -131,7 +133,7 @@ public:
|
||||||
VkFramebuffer frameBuffer;
|
VkFramebuffer frameBuffer;
|
||||||
FrameBufferAttachment color, depth;
|
FrameBufferAttachment color, depth;
|
||||||
VkRenderPass renderPass;
|
VkRenderPass renderPass;
|
||||||
vkTools::VulkanTexture textureTarget;
|
VkSampler depthSampler;
|
||||||
} offScreenFrameBuf;
|
} offScreenFrameBuf;
|
||||||
|
|
||||||
VkCommandBuffer offScreenCmdBuffer = VK_NULL_HANDLE;
|
VkCommandBuffer offScreenCmdBuffer = VK_NULL_HANDLE;
|
||||||
|
|
@ -143,6 +145,7 @@ public:
|
||||||
{
|
{
|
||||||
zoom = -20.0f;
|
zoom = -20.0f;
|
||||||
rotation = { -15.0f, -390.0f, 0.0f };
|
rotation = { -15.0f, -390.0f, 0.0f };
|
||||||
|
enableTextOverlay = true;
|
||||||
title = "Vulkan Example - Projected shadow mapping";
|
title = "Vulkan Example - Projected shadow mapping";
|
||||||
timerSpeed *= 0.5f;
|
timerSpeed *= 0.5f;
|
||||||
}
|
}
|
||||||
|
|
@ -152,9 +155,6 @@ public:
|
||||||
// Clean up used Vulkan resources
|
// Clean up used Vulkan resources
|
||||||
// Note : Inherited destructor cleans up resources stored in base class
|
// Note : Inherited destructor cleans up resources stored in base class
|
||||||
|
|
||||||
// Texture target
|
|
||||||
textureLoader->destroyTexture(offScreenFrameBuf.textureTarget);
|
|
||||||
|
|
||||||
// Frame buffer
|
// Frame buffer
|
||||||
|
|
||||||
// Color attachment
|
// Color attachment
|
||||||
|
|
@ -186,91 +186,18 @@ public:
|
||||||
|
|
||||||
// Uniform buffers
|
// Uniform buffers
|
||||||
vkTools::destroyUniformData(device, &uniformDataVS);
|
vkTools::destroyUniformData(device, &uniformDataVS);
|
||||||
vkTools::destroyUniformData(device, &uniformDataOffscreenVS);
|
vkTools::destroyUniformData(device, &uniformData.offscreen);
|
||||||
|
vkTools::destroyUniformData(device, &uniformData.scene);
|
||||||
|
|
||||||
vkFreeCommandBuffers(device, cmdPool, 1, &offScreenCmdBuffer);
|
vkFreeCommandBuffers(device, cmdPool, 1, &offScreenCmdBuffer);
|
||||||
vkDestroySemaphore(device, offscreenSemaphore, nullptr);
|
vkDestroySemaphore(device, offscreenSemaphore, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preapre an empty texture as the blit target from
|
|
||||||
// the offscreen framebuffer
|
|
||||||
void prepareTextureTarget(uint32_t width, uint32_t height, VkFormat format)
|
|
||||||
{
|
|
||||||
// Get device properites for the requested texture format
|
|
||||||
VkFormatProperties formatProperties;
|
|
||||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties);
|
|
||||||
// Check if format is supported for optimal tiling
|
|
||||||
assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
|
||||||
|
|
||||||
// Prepare blit target texture
|
|
||||||
offScreenFrameBuf.textureTarget.width = width;
|
|
||||||
offScreenFrameBuf.textureTarget.height = height;
|
|
||||||
|
|
||||||
VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo();
|
|
||||||
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
|
||||||
imageCreateInfo.format = format;
|
|
||||||
imageCreateInfo.extent = { width, height, 1 };
|
|
||||||
imageCreateInfo.mipLevels = 1;
|
|
||||||
imageCreateInfo.arrayLayers = 1;
|
|
||||||
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
||||||
imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
||||||
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
|
||||||
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
|
||||||
|
|
||||||
VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo();
|
|
||||||
VkMemoryRequirements memReqs;
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkCreateImage(device, &imageCreateInfo, nullptr, &offScreenFrameBuf.textureTarget.image));
|
|
||||||
vkGetImageMemoryRequirements(device, offScreenFrameBuf.textureTarget.image, &memReqs);
|
|
||||||
memAllocInfo.allocationSize = memReqs.size;
|
|
||||||
memAllocInfo.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
||||||
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &offScreenFrameBuf.textureTarget.deviceMemory));
|
|
||||||
VK_CHECK_RESULT(vkBindImageMemory(device, offScreenFrameBuf.textureTarget.image, offScreenFrameBuf.textureTarget.deviceMemory, 0));
|
|
||||||
|
|
||||||
VkCommandBuffer layoutCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
|
||||||
|
|
||||||
offScreenFrameBuf.textureTarget.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
||||||
vkTools::setImageLayout(
|
|
||||||
layoutCmd,
|
|
||||||
offScreenFrameBuf.textureTarget.image,
|
|
||||||
VK_IMAGE_ASPECT_DEPTH_BIT,
|
|
||||||
VK_IMAGE_LAYOUT_PREINITIALIZED,
|
|
||||||
offScreenFrameBuf.textureTarget.imageLayout);
|
|
||||||
|
|
||||||
VulkanExampleBase::flushCommandBuffer(layoutCmd, queue, true);
|
|
||||||
|
|
||||||
// Create sampler
|
|
||||||
VkSamplerCreateInfo sampler = vkTools::initializers::samplerCreateInfo();
|
|
||||||
sampler.magFilter = TEX_FILTER;
|
|
||||||
sampler.minFilter = TEX_FILTER;
|
|
||||||
sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
sampler.addressModeV = sampler.addressModeU;
|
|
||||||
sampler.addressModeW = sampler.addressModeU;
|
|
||||||
sampler.mipLodBias = 0.0f;
|
|
||||||
sampler.maxAnisotropy = 0;
|
|
||||||
sampler.minLod = 0.0f;
|
|
||||||
sampler.maxLod = 1.0f;
|
|
||||||
sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
|
||||||
VK_CHECK_RESULT(vkCreateSampler(device, &sampler, nullptr, &offScreenFrameBuf.textureTarget.sampler));
|
|
||||||
|
|
||||||
// Create image view
|
|
||||||
VkImageViewCreateInfo view = vkTools::initializers::imageViewCreateInfo();
|
|
||||||
view.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
||||||
view.format = format;
|
|
||||||
view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
|
|
||||||
view.subresourceRange = { VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1 };
|
|
||||||
view.image = offScreenFrameBuf.textureTarget.image;
|
|
||||||
VK_CHECK_RESULT(vkCreateImageView(device, &view, nullptr, &offScreenFrameBuf.textureTarget.view));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up a separate render pass for the offscreen frame buffer
|
// Set up a separate render pass for the offscreen frame buffer
|
||||||
// This is necessary as the offscreen frame buffer attachments
|
// This is necessary as the offscreen frame buffer attachments
|
||||||
// use formats different to the ones from the visible frame buffer
|
// use formats different to the ones from the visible frame buffer
|
||||||
// and at least the depth one may not be compatible
|
// and at least the depth one may not be compatible
|
||||||
void setupOffScreenRenderPass()
|
void prepareOffscreenRenderpass()
|
||||||
{
|
{
|
||||||
VkAttachmentDescription attDesc[2];
|
VkAttachmentDescription attDesc[2];
|
||||||
attDesc[0].format = FB_COLOR_FORMAT;
|
attDesc[0].format = FB_COLOR_FORMAT;
|
||||||
|
|
@ -333,13 +260,13 @@ public:
|
||||||
image.format = fbColorFormat;
|
image.format = fbColorFormat;
|
||||||
image.extent.width = offScreenFrameBuf.width;
|
image.extent.width = offScreenFrameBuf.width;
|
||||||
image.extent.height = offScreenFrameBuf.height;
|
image.extent.height = offScreenFrameBuf.height;
|
||||||
|
image.extent.depth = 1;
|
||||||
image.mipLevels = 1;
|
image.mipLevels = 1;
|
||||||
image.arrayLayers = 1;
|
image.arrayLayers = 1;
|
||||||
image.samples = VK_SAMPLE_COUNT_1_BIT;
|
image.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
image.tiling = VK_IMAGE_TILING_OPTIMAL;
|
image.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||||
// Image of the framebuffer is blit source
|
// Image of the framebuffer is blit source
|
||||||
image.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
image.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
image.flags = 0;
|
|
||||||
|
|
||||||
VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo();
|
VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo();
|
||||||
VkMemoryRequirements memReqs;
|
VkMemoryRequirements memReqs;
|
||||||
|
|
@ -376,12 +303,12 @@ public:
|
||||||
|
|
||||||
// Depth stencil attachment
|
// Depth stencil attachment
|
||||||
image.format = DEPTH_FORMAT;
|
image.format = DEPTH_FORMAT;
|
||||||
image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
// We will sample directly from the depth attachment for the shadow mapping
|
||||||
|
image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||||
|
|
||||||
VkImageViewCreateInfo depthStencilView = vkTools::initializers::imageViewCreateInfo();
|
VkImageViewCreateInfo depthStencilView = vkTools::initializers::imageViewCreateInfo();
|
||||||
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
depthStencilView.format = DEPTH_FORMAT;
|
depthStencilView.format = DEPTH_FORMAT;
|
||||||
depthStencilView.flags = 0;
|
|
||||||
depthStencilView.subresourceRange = {};
|
depthStencilView.subresourceRange = {};
|
||||||
depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
depthStencilView.subresourceRange.baseMipLevel = 0;
|
depthStencilView.subresourceRange.baseMipLevel = 0;
|
||||||
|
|
@ -396,6 +323,8 @@ public:
|
||||||
VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &offScreenFrameBuf.depth.mem));
|
VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &offScreenFrameBuf.depth.mem));
|
||||||
VK_CHECK_RESULT(vkBindImageMemory(device, offScreenFrameBuf.depth.image, offScreenFrameBuf.depth.mem, 0));
|
VK_CHECK_RESULT(vkBindImageMemory(device, offScreenFrameBuf.depth.image, offScreenFrameBuf.depth.mem, 0));
|
||||||
|
|
||||||
|
// Set the initial layout to shader read instead of attachment
|
||||||
|
// This is done as teh render loop does the actualy image layout transitions
|
||||||
vkTools::setImageLayout(
|
vkTools::setImageLayout(
|
||||||
layoutCmd,
|
layoutCmd,
|
||||||
offScreenFrameBuf.depth.image,
|
offScreenFrameBuf.depth.image,
|
||||||
|
|
@ -408,11 +337,27 @@ public:
|
||||||
depthStencilView.image = offScreenFrameBuf.depth.image;
|
depthStencilView.image = offScreenFrameBuf.depth.image;
|
||||||
VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &offScreenFrameBuf.depth.view));
|
VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &offScreenFrameBuf.depth.view));
|
||||||
|
|
||||||
|
// Create sampler used to sample from depth attachment
|
||||||
|
// in shadowing fragment shader
|
||||||
|
VkSamplerCreateInfo sampler = vkTools::initializers::samplerCreateInfo();
|
||||||
|
sampler.magFilter = SHADOWMAP_FILTER;
|
||||||
|
sampler.minFilter = SHADOWMAP_FILTER;
|
||||||
|
sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
sampler.addressModeV = sampler.addressModeU;
|
||||||
|
sampler.addressModeW = sampler.addressModeU;
|
||||||
|
sampler.mipLodBias = 0.0f;
|
||||||
|
sampler.maxAnisotropy = 0;
|
||||||
|
sampler.minLod = 0.0f;
|
||||||
|
sampler.maxLod = 1.0f;
|
||||||
|
sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
||||||
|
VK_CHECK_RESULT(vkCreateSampler(device, &sampler, nullptr, &offScreenFrameBuf.depthSampler));
|
||||||
|
|
||||||
VkImageView attachments[2];
|
VkImageView attachments[2];
|
||||||
attachments[0] = offScreenFrameBuf.color.view;
|
attachments[0] = offScreenFrameBuf.color.view;
|
||||||
attachments[1] = offScreenFrameBuf.depth.view;
|
attachments[1] = offScreenFrameBuf.depth.view;
|
||||||
|
|
||||||
setupOffScreenRenderPass();
|
prepareOffscreenRenderpass();
|
||||||
|
|
||||||
// Create frame buffer
|
// Create frame buffer
|
||||||
VkFramebufferCreateInfo fbufCreateInfo = vkTools::initializers::framebufferCreateInfo();
|
VkFramebufferCreateInfo fbufCreateInfo = vkTools::initializers::framebufferCreateInfo();
|
||||||
|
|
@ -428,15 +373,9 @@ public:
|
||||||
|
|
||||||
void buildOffscreenCommandBuffer()
|
void buildOffscreenCommandBuffer()
|
||||||
{
|
{
|
||||||
// Create separate command buffer for offscreen
|
|
||||||
// rendering
|
|
||||||
if (offScreenCmdBuffer == VK_NULL_HANDLE)
|
if (offScreenCmdBuffer == VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
VkCommandBufferAllocateInfo cmd = vkTools::initializers::commandBufferAllocateInfo(
|
offScreenCmdBuffer = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, false);
|
||||||
cmdPool,
|
|
||||||
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
|
||||||
1);
|
|
||||||
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmd, &offScreenCmdBuffer));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a semaphore used to synchronize offscreen rendering and usage
|
// Create a semaphore used to synchronize offscreen rendering and usage
|
||||||
|
|
@ -461,6 +400,14 @@ public:
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkBeginCommandBuffer(offScreenCmdBuffer, &cmdBufInfo));
|
VK_CHECK_RESULT(vkBeginCommandBuffer(offScreenCmdBuffer, &cmdBufInfo));
|
||||||
|
|
||||||
|
// Change back layout of the depth attachment after sampling in the fragment shader
|
||||||
|
vkTools::setImageLayout(
|
||||||
|
offScreenCmdBuffer,
|
||||||
|
offScreenFrameBuf.depth.image,
|
||||||
|
VK_IMAGE_ASPECT_DEPTH_BIT,
|
||||||
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||||
|
|
||||||
VkViewport viewport = vkTools::initializers::viewport((float)offScreenFrameBuf.width, (float)offScreenFrameBuf.height, 0.0f, 1.0f);
|
VkViewport viewport = vkTools::initializers::viewport((float)offScreenFrameBuf.width, (float)offScreenFrameBuf.height, 0.0f, 1.0f);
|
||||||
vkCmdSetViewport(offScreenCmdBuffer, 0, 1, &viewport);
|
vkCmdSetViewport(offScreenCmdBuffer, 0, 1, &viewport);
|
||||||
|
|
||||||
|
|
@ -468,6 +415,7 @@ public:
|
||||||
vkCmdSetScissor(offScreenCmdBuffer, 0, 1, &scissor);
|
vkCmdSetScissor(offScreenCmdBuffer, 0, 1, &scissor);
|
||||||
|
|
||||||
// Set depth bias (aka "Polygon offset")
|
// Set depth bias (aka "Polygon offset")
|
||||||
|
// Required to avoid shadow mapping artefacts
|
||||||
vkCmdSetDepthBias(
|
vkCmdSetDepthBias(
|
||||||
offScreenCmdBuffer,
|
offScreenCmdBuffer,
|
||||||
depthBiasConstant,
|
depthBiasConstant,
|
||||||
|
|
@ -486,7 +434,13 @@ public:
|
||||||
|
|
||||||
vkCmdEndRenderPass(offScreenCmdBuffer);
|
vkCmdEndRenderPass(offScreenCmdBuffer);
|
||||||
|
|
||||||
updateTexture();
|
// Change back layout of the depth attachment after sampling in the fragment shader
|
||||||
|
vkTools::setImageLayout(
|
||||||
|
offScreenCmdBuffer,
|
||||||
|
offScreenFrameBuf.depth.image,
|
||||||
|
VK_IMAGE_ASPECT_DEPTH_BIT,
|
||||||
|
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkEndCommandBuffer(offScreenCmdBuffer));
|
VK_CHECK_RESULT(vkEndCommandBuffer(offScreenCmdBuffer));
|
||||||
}
|
}
|
||||||
|
|
@ -550,47 +504,6 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw()
|
|
||||||
{
|
|
||||||
// Get next image in the swap chain (back/front buffer)
|
|
||||||
VK_CHECK_RESULT(swapChain.acquireNextImage(semaphores.presentComplete, ¤tBuffer));
|
|
||||||
|
|
||||||
submitPostPresentBarrier(swapChain.buffers[currentBuffer].image);
|
|
||||||
|
|
||||||
// Submit offscreen command buffer for rendering depth buffer from light's pov
|
|
||||||
|
|
||||||
// Wait for swap chain presentation to finish
|
|
||||||
submitInfo.waitSemaphoreCount = 1;
|
|
||||||
submitInfo.pWaitSemaphores = &semaphores.presentComplete;
|
|
||||||
// Signal ready with offscreen semaphore
|
|
||||||
submitInfo.signalSemaphoreCount = 1;
|
|
||||||
submitInfo.pSignalSemaphores = &offscreenSemaphore;
|
|
||||||
|
|
||||||
submitInfo.commandBufferCount = 1;
|
|
||||||
submitInfo.pCommandBuffers = &offScreenCmdBuffer;
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
|
|
||||||
|
|
||||||
// Submit current render command buffer
|
|
||||||
|
|
||||||
submitInfo.commandBufferCount = 1;
|
|
||||||
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
|
|
||||||
|
|
||||||
// Wait for offscreen semaphore
|
|
||||||
submitInfo.waitSemaphoreCount = 1;
|
|
||||||
submitInfo.pWaitSemaphores = &offscreenSemaphore;
|
|
||||||
// Signal ready with render complete semaphpre
|
|
||||||
submitInfo.signalSemaphoreCount = 1;
|
|
||||||
submitInfo.pSignalSemaphores = &semaphores.renderComplete;
|
|
||||||
|
|
||||||
// Submit to queue
|
|
||||||
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
|
|
||||||
|
|
||||||
submitPrePresentBarrier(swapChain.buffers[currentBuffer].image);
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete));
|
|
||||||
}
|
|
||||||
|
|
||||||
void loadMeshes()
|
void loadMeshes()
|
||||||
{
|
{
|
||||||
loadMesh(getAssetPath() + "models/vulkanscene_shadow.dae", &meshes.scene, vertexLayout, 4.0f);
|
loadMesh(getAssetPath() + "models/vulkanscene_shadow.dae", &meshes.scene, vertexLayout, 4.0f);
|
||||||
|
|
@ -747,11 +660,11 @@ public:
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
|
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
|
||||||
|
|
||||||
// Image descriptor for the shadow map texture
|
// Image descriptor for the shadow map attachment
|
||||||
VkDescriptorImageInfo texDescriptor =
|
VkDescriptorImageInfo texDescriptor =
|
||||||
vkTools::initializers::descriptorImageInfo(
|
vkTools::initializers::descriptorImageInfo(
|
||||||
offScreenFrameBuf.textureTarget.sampler,
|
offScreenFrameBuf.depthSampler,
|
||||||
offScreenFrameBuf.textureTarget.view,
|
offScreenFrameBuf.depth.view,
|
||||||
VK_IMAGE_LAYOUT_GENERAL);
|
VK_IMAGE_LAYOUT_GENERAL);
|
||||||
|
|
||||||
std::vector<VkWriteDescriptorSet> writeDescriptorSets =
|
std::vector<VkWriteDescriptorSet> writeDescriptorSets =
|
||||||
|
|
@ -782,16 +695,16 @@ public:
|
||||||
descriptorSets.offscreen,
|
descriptorSets.offscreen,
|
||||||
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
0,
|
0,
|
||||||
&uniformDataOffscreenVS.descriptor),
|
&uniformData.offscreen.descriptor),
|
||||||
};
|
};
|
||||||
vkUpdateDescriptorSets(device, offScreenWriteDescriptorSets.size(), offScreenWriteDescriptorSets.data(), 0, NULL);
|
vkUpdateDescriptorSets(device, offScreenWriteDescriptorSets.size(), offScreenWriteDescriptorSets.data(), 0, NULL);
|
||||||
|
|
||||||
// 3D scene
|
// 3D scene
|
||||||
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.scene));
|
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.scene));
|
||||||
|
|
||||||
// Image descriptor for the shadow map texture
|
// Image descriptor for the shadow map attachment
|
||||||
texDescriptor.sampler = offScreenFrameBuf.textureTarget.sampler;
|
texDescriptor.sampler = offScreenFrameBuf.depthSampler;
|
||||||
texDescriptor.imageView = offScreenFrameBuf.textureTarget.view;
|
texDescriptor.imageView = offScreenFrameBuf.depth.view;
|
||||||
|
|
||||||
std::vector<VkWriteDescriptorSet> sceneDescriptorSets =
|
std::vector<VkWriteDescriptorSet> sceneDescriptorSets =
|
||||||
{
|
{
|
||||||
|
|
@ -823,7 +736,7 @@ public:
|
||||||
VkPipelineRasterizationStateCreateInfo rasterizationState =
|
VkPipelineRasterizationStateCreateInfo rasterizationState =
|
||||||
vkTools::initializers::pipelineRasterizationStateCreateInfo(
|
vkTools::initializers::pipelineRasterizationStateCreateInfo(
|
||||||
VK_POLYGON_MODE_FILL,
|
VK_POLYGON_MODE_FILL,
|
||||||
VK_CULL_MODE_FRONT_BIT,
|
VK_CULL_MODE_NONE,
|
||||||
VK_FRONT_FACE_CLOCKWISE,
|
VK_FRONT_FACE_CLOCKWISE,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
|
|
@ -874,8 +787,6 @@ public:
|
||||||
renderPass,
|
renderPass,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
rasterizationState.cullMode = VK_CULL_MODE_NONE;
|
|
||||||
|
|
||||||
pipelineCreateInfo.pVertexInputState = &vertices.inputState;
|
pipelineCreateInfo.pVertexInputState = &vertices.inputState;
|
||||||
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
|
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
|
||||||
pipelineCreateInfo.pRasterizationState = &rasterizationState;
|
pipelineCreateInfo.pRasterizationState = &rasterizationState;
|
||||||
|
|
@ -892,13 +803,12 @@ public:
|
||||||
// 3D scene
|
// 3D scene
|
||||||
shaderStages[0] = loadShader(getAssetPath() + "shaders/shadowmapping/scene.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
|
shaderStages[0] = loadShader(getAssetPath() + "shaders/shadowmapping/scene.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
shaderStages[1] = loadShader(getAssetPath() + "shaders/shadowmapping/scene.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
|
shaderStages[1] = loadShader(getAssetPath() + "shaders/shadowmapping/scene.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
rasterizationState.cullMode = VK_CULL_MODE_NONE;
|
rasterizationState.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||||
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.scene));
|
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.scene));
|
||||||
|
|
||||||
// Offscreen pipeline
|
// Offscreen pipeline
|
||||||
shaderStages[0] = loadShader(getAssetPath() + "shaders/shadowmapping/offscreen.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
|
shaderStages[0] = loadShader(getAssetPath() + "shaders/shadowmapping/offscreen.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
shaderStages[1] = loadShader(getAssetPath() + "shaders/shadowmapping/offscreen.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
|
shaderStages[1] = loadShader(getAssetPath() + "shaders/shadowmapping/offscreen.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
pipelineCreateInfo.layout = pipelineLayouts.offscreen;
|
|
||||||
// Cull front faces
|
// Cull front faces
|
||||||
depthStencilState.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
|
depthStencilState.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
|
||||||
// Enable depth bias
|
// Enable depth bias
|
||||||
|
|
@ -911,6 +821,8 @@ public:
|
||||||
dynamicStateEnables.size(),
|
dynamicStateEnables.size(),
|
||||||
0);
|
0);
|
||||||
|
|
||||||
|
pipelineCreateInfo.layout = pipelineLayouts.offscreen;
|
||||||
|
pipelineCreateInfo.renderPass = offScreenFrameBuf.renderPass;
|
||||||
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.offscreen));
|
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.offscreen));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -920,6 +832,7 @@ public:
|
||||||
// Debug quad vertex shader uniform buffer block
|
// Debug quad vertex shader uniform buffer block
|
||||||
createBuffer(
|
createBuffer(
|
||||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
sizeof(uboVSscene),
|
sizeof(uboVSscene),
|
||||||
nullptr,
|
nullptr,
|
||||||
&uniformDataVS.buffer,
|
&uniformDataVS.buffer,
|
||||||
|
|
@ -929,15 +842,17 @@ public:
|
||||||
// Offsvreen vertex shader uniform buffer block
|
// Offsvreen vertex shader uniform buffer block
|
||||||
createBuffer(
|
createBuffer(
|
||||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
sizeof(uboOffscreenVS),
|
sizeof(uboOffscreenVS),
|
||||||
nullptr,
|
nullptr,
|
||||||
&uniformDataOffscreenVS.buffer,
|
&uniformData.offscreen.buffer,
|
||||||
&uniformDataOffscreenVS.memory,
|
&uniformData.offscreen.memory,
|
||||||
&uniformDataOffscreenVS.descriptor);
|
&uniformData.offscreen.descriptor);
|
||||||
|
|
||||||
// Scene vertex shader uniform buffer block
|
// Scene vertex shader uniform buffer block
|
||||||
createBuffer(
|
createBuffer(
|
||||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
sizeof(uboVSscene),
|
sizeof(uboVSscene),
|
||||||
nullptr,
|
nullptr,
|
||||||
&uniformData.scene.buffer,
|
&uniformData.scene.buffer,
|
||||||
|
|
@ -962,7 +877,7 @@ public:
|
||||||
// Shadow map debug quad
|
// Shadow map debug quad
|
||||||
float AR = (float)height / (float)width;
|
float AR = (float)height / (float)width;
|
||||||
|
|
||||||
uboVSquad.projection = glm::ortho(0.0f, 2.5f / AR, 0.0f, 2.5f, -1.0f, 1.0f);
|
uboVSquad.projection = glm::ortho(2.5f / AR, 0.0f, 0.0f, 2.5f, -1.0f, 1.0f);
|
||||||
uboVSquad.model = glm::mat4();
|
uboVSquad.model = glm::mat4();
|
||||||
|
|
||||||
uint8_t *pData;
|
uint8_t *pData;
|
||||||
|
|
@ -986,9 +901,8 @@ public:
|
||||||
if (lightPOV)
|
if (lightPOV)
|
||||||
{
|
{
|
||||||
uboVSscene.projection = glm::perspective(glm::radians(lightFOV), (float)width / (float)height, zNear, zFar);
|
uboVSscene.projection = glm::perspective(glm::radians(lightFOV), (float)width / (float)height, zNear, zFar);
|
||||||
uboVSscene.view = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0, 1, 0));
|
uboVSscene.view = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uboVSscene.depthBiasMVP = uboOffscreenVS.depthMVP;
|
uboVSscene.depthBiasMVP = uboOffscreenVS.depthMVP;
|
||||||
|
|
||||||
|
|
@ -1001,82 +915,50 @@ public:
|
||||||
{
|
{
|
||||||
// Matrix from light's point of view
|
// Matrix from light's point of view
|
||||||
glm::mat4 depthProjectionMatrix = glm::perspective(glm::radians(lightFOV), 1.0f, zNear, zFar);
|
glm::mat4 depthProjectionMatrix = glm::perspective(glm::radians(lightFOV), 1.0f, zNear, zFar);
|
||||||
glm::mat4 depthViewMatrix = glm::lookAt(lightPos, glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
|
glm::mat4 depthViewMatrix = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0, 1, 0));
|
||||||
glm::mat4 depthModelMatrix = glm::mat4();
|
glm::mat4 depthModelMatrix = glm::mat4();
|
||||||
|
|
||||||
uboOffscreenVS.depthMVP = depthProjectionMatrix * depthViewMatrix * depthModelMatrix;
|
uboOffscreenVS.depthMVP = depthProjectionMatrix * depthViewMatrix * depthModelMatrix;
|
||||||
|
|
||||||
uint8_t *pData;
|
uint8_t *pData;
|
||||||
VK_CHECK_RESULT(vkMapMemory(device, uniformDataOffscreenVS.memory, 0, sizeof(uboOffscreenVS), 0, (void **)&pData));
|
VK_CHECK_RESULT(vkMapMemory(device, uniformData.offscreen.memory, 0, sizeof(uboOffscreenVS), 0, (void **)&pData));
|
||||||
memcpy(pData, &uboOffscreenVS, sizeof(uboOffscreenVS));
|
memcpy(pData, &uboOffscreenVS, sizeof(uboOffscreenVS));
|
||||||
vkUnmapMemory(device, uniformDataOffscreenVS.memory);
|
vkUnmapMemory(device, uniformData.offscreen.memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy offscreen depth frame buffer contents to the depth texture
|
void draw()
|
||||||
void updateTexture()
|
|
||||||
{
|
{
|
||||||
// Make sure color writes to the framebuffer are finished before using it as transfer source
|
VulkanExampleBase::prepareFrame();
|
||||||
vkTools::setImageLayout(
|
|
||||||
offScreenCmdBuffer,
|
// The scene render command buffer has to wait for the offscreen
|
||||||
offScreenFrameBuf.depth.image,
|
// rendering (and transfer) to be finished before using
|
||||||
VK_IMAGE_ASPECT_DEPTH_BIT,
|
// the shadow map, so we need to synchronize
|
||||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
// We use an additional semaphore for this
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
|
||||||
|
|
||||||
// Transform texture target to transfer source
|
// Offscreen rendering
|
||||||
vkTools::setImageLayout(
|
|
||||||
offScreenCmdBuffer,
|
|
||||||
offScreenFrameBuf.textureTarget.image,
|
|
||||||
VK_IMAGE_ASPECT_DEPTH_BIT,
|
|
||||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
|
||||||
|
|
||||||
VkImageCopy imgCopy = {};
|
// Wait for swap chain presentation to finish
|
||||||
|
submitInfo.pWaitSemaphores = &semaphores.presentComplete;
|
||||||
|
// Signal ready with offscreen semaphore
|
||||||
|
submitInfo.pSignalSemaphores = &offscreenSemaphore;
|
||||||
|
|
||||||
imgCopy.srcSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
// Submit work
|
||||||
imgCopy.srcSubresource.mipLevel = 0;
|
submitInfo.commandBufferCount = 1;
|
||||||
imgCopy.srcSubresource.baseArrayLayer = 0;
|
submitInfo.pCommandBuffers = &offScreenCmdBuffer;
|
||||||
imgCopy.srcSubresource.layerCount = 1;
|
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
|
||||||
|
|
||||||
imgCopy.srcOffset = { 0, 0, 0 };
|
// Scene rendering
|
||||||
|
|
||||||
imgCopy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
// Wait for offscreen semaphore
|
||||||
imgCopy.dstSubresource.mipLevel = 0;
|
submitInfo.pWaitSemaphores = &offscreenSemaphore;
|
||||||
imgCopy.dstSubresource.baseArrayLayer = 0;
|
// Signal ready with render complete semaphpre
|
||||||
imgCopy.dstSubresource.layerCount = 1;
|
submitInfo.pSignalSemaphores = &semaphores.renderComplete;
|
||||||
|
|
||||||
imgCopy.dstOffset = { 0, 0, 0 };
|
// Submit work
|
||||||
|
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
|
||||||
|
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
|
||||||
|
|
||||||
imgCopy.extent.width = TEX_DIM;
|
VulkanExampleBase::submitFrame();
|
||||||
imgCopy.extent.height = TEX_DIM;
|
|
||||||
imgCopy.extent.depth = 1;
|
|
||||||
|
|
||||||
vkCmdCopyImage(
|
|
||||||
offScreenCmdBuffer,
|
|
||||||
offScreenFrameBuf.depth.image,
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
||||||
offScreenFrameBuf.textureTarget.image,
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
||||||
1,
|
|
||||||
&imgCopy);
|
|
||||||
|
|
||||||
// Transform framebuffer color attachment back
|
|
||||||
vkTools::setImageLayout(
|
|
||||||
offScreenCmdBuffer,
|
|
||||||
offScreenFrameBuf.depth.image,
|
|
||||||
VK_IMAGE_ASPECT_DEPTH_BIT,
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
||||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
|
||||||
|
|
||||||
// Transform texture target back to shader read
|
|
||||||
// Makes sure that writes to the textuer are finished before
|
|
||||||
// it's accessed in the shader
|
|
||||||
vkTools::setImageLayout(
|
|
||||||
offScreenCmdBuffer,
|
|
||||||
offScreenFrameBuf.textureTarget.image,
|
|
||||||
VK_IMAGE_ASPECT_DEPTH_BIT,
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
||||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void prepare()
|
void prepare()
|
||||||
|
|
@ -1084,14 +966,13 @@ public:
|
||||||
VulkanExampleBase::prepare();
|
VulkanExampleBase::prepare();
|
||||||
generateQuad();
|
generateQuad();
|
||||||
loadMeshes();
|
loadMeshes();
|
||||||
|
prepareOffscreenFramebuffer();
|
||||||
setupVertexDescriptions();
|
setupVertexDescriptions();
|
||||||
prepareUniformBuffers();
|
prepareUniformBuffers();
|
||||||
prepareTextureTarget(TEX_DIM, TEX_DIM, DEPTH_FORMAT);
|
|
||||||
setupDescriptorSetLayout();
|
setupDescriptorSetLayout();
|
||||||
preparePipelines();
|
preparePipelines();
|
||||||
setupDescriptorPool();
|
setupDescriptorPool();
|
||||||
setupDescriptorSets();
|
setupDescriptorSets();
|
||||||
prepareOffscreenFramebuffer();
|
|
||||||
buildCommandBuffers();
|
buildCommandBuffers();
|
||||||
buildOffscreenCommandBuffer();
|
buildOffscreenCommandBuffer();
|
||||||
prepared = true;
|
prepared = true;
|
||||||
|
|
@ -1104,7 +985,6 @@ public:
|
||||||
draw();
|
draw();
|
||||||
if (!paused)
|
if (!paused)
|
||||||
{
|
{
|
||||||
vkDeviceWaitIdle(device);
|
|
||||||
updateLight();
|
updateLight();
|
||||||
updateUniformBufferOffscreen();
|
updateUniformBufferOffscreen();
|
||||||
updateUniformBuffers();
|
updateUniformBuffers();
|
||||||
|
|
@ -1113,7 +993,6 @@ public:
|
||||||
|
|
||||||
virtual void viewChanged()
|
virtual void viewChanged()
|
||||||
{
|
{
|
||||||
vkDeviceWaitIdle(device);
|
|
||||||
updateUniformBufferOffscreen();
|
updateUniformBufferOffscreen();
|
||||||
updateUniformBuffers();
|
updateUniformBuffers();
|
||||||
}
|
}
|
||||||
|
|
@ -1129,6 +1008,33 @@ public:
|
||||||
lightPOV = !lightPOV;
|
lightPOV = !lightPOV;
|
||||||
viewChanged();
|
viewChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void keyPressed(uint32_t keyCode)
|
||||||
|
{
|
||||||
|
switch (keyCode)
|
||||||
|
{
|
||||||
|
case 0x53:
|
||||||
|
case GAMEPAD_BUTTON_A:
|
||||||
|
toggleShadowMapDisplay();
|
||||||
|
break;
|
||||||
|
case 0x4C:
|
||||||
|
case GAMEPAD_BUTTON_X:
|
||||||
|
toogleLightPOV();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void getOverlayText(VulkanTextOverlay *textOverlay)
|
||||||
|
{
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
textOverlay->addText("Press \"Button A\" to toggle shadow map", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
|
||||||
|
textOverlay->addText("Press \"Button X\" to toggle light's pov", 5.0f, 100.0f, VulkanTextOverlay::alignLeft);
|
||||||
|
#else
|
||||||
|
textOverlay->addText("Press \"s\" to toggle shadow map", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
|
||||||
|
textOverlay->addText("Press \"l\" to toggle light's pov", 5.0f, 100.0f, VulkanTextOverlay::alignLeft);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
VulkanExample *vulkanExample;
|
VulkanExample *vulkanExample;
|
||||||
|
|
@ -1139,18 +1045,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
if (vulkanExample != NULL)
|
if (vulkanExample != NULL)
|
||||||
{
|
{
|
||||||
vulkanExample->handleMessages(hWnd, uMsg, wParam, lParam);
|
vulkanExample->handleMessages(hWnd, uMsg, wParam, lParam);
|
||||||
if (uMsg == WM_KEYDOWN)
|
|
||||||
{
|
|
||||||
switch (wParam)
|
|
||||||
{
|
|
||||||
case 0x53:
|
|
||||||
vulkanExample->toggleShadowMapDisplay();
|
|
||||||
break;
|
|
||||||
case 0x4C:
|
|
||||||
vulkanExample->toogleLightPOV();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return (DefWindowProc(hWnd, uMsg, wParam, lParam));
|
return (DefWindowProc(hWnd, uMsg, wParam, lParam));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue