Reworked conditional rendering example, using complex glTF model

This commit is contained in:
saschawillems 2018-09-03 21:57:26 +02:00
parent 34148d5dc9
commit 0dd76f4ce3

View file

@ -3,8 +3,8 @@
* *
* Note: Requires a device that supports the VK_EXT_conditional_rendering extension * Note: Requires a device that supports the VK_EXT_conditional_rendering extension
* *
* With conditional rendering it's possible to execute certain rendering commands based * With conditional rendering it's possible to execute certain rendering commands based on a buffer value instead of having to rebuild the command buffers.
* on a buffer value instead of having to rebuild the command buffers. * This example sets up a conditonal buffer with one value per glTF part, that is used to toggle visibility of single model parts.
* *
* Copyright (C) 2018 by Sascha Willems - www.saschawillems.de * Copyright (C) 2018 by Sascha Willems - www.saschawillems.de
* *
@ -24,26 +24,17 @@
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include "vulkanexamplebase.h" #include "vulkanexamplebase.h"
#include "VulkanModel.hpp" #include "VulkanglTFModel.hpp"
#define ENABLE_VALIDATION false #define ENABLE_VALIDATION false
#define MODEL_ROWS 3
class VulkanExample : public VulkanExampleBase class VulkanExample : public VulkanExampleBase
{ {
public: public:
PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT; PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT;
PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT; PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT;
VkPhysicalDeviceConditionalRenderingFeaturesEXT conditionalRenderingFeatures{};
// Vertex layout for the models vkglTF::Model scene;
vks::VertexLayout vertexLayout = vks::VertexLayout({
vks::VERTEX_COMPONENT_POSITION,
vks::VERTEX_COMPONENT_NORMAL,
vks::VERTEX_COMPONENT_COLOR,
});
vks::Model model;
struct { struct {
glm::mat4 projection; glm::mat4 projection;
@ -52,7 +43,7 @@ public:
vks::Buffer uniformBuffer; vks::Buffer uniformBuffer;
std::array<int32_t, MODEL_ROWS> conditionalVisibility{}; std::vector<int32_t> conditionalVisibility;
vks::Buffer conditionalBuffer; vks::Buffer conditionalBuffer;
VkPipelineLayout pipelineLayout; VkPipelineLayout pipelineLayout;
@ -65,47 +56,75 @@ public:
title = "Conditional rendering"; title = "Conditional rendering";
settings.overlay = true; settings.overlay = true;
camera.type = Camera::CameraType::lookat; camera.type = Camera::CameraType::lookat;
camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 512.0f); camera.setPerspective(45.0f, (float)width / (float)height, 0.1f, 512.0f);
camera.setRotation(glm::vec3(0.0f, 0.0f, 0.0f)); camera.setRotation(glm::vec3(-9.0f, -55.0f, 0.0f));
camera.setTranslation(glm::vec3(0.0f, 0.0f, -15.0f)); camera.setTranslation(glm::vec3(3.45f, 3.15f, -22.0f));
rotationSpeed *= 0.25f; camera.rotationSpeed *= 0.25f;
// Enable extension required for conditional rendering /*
[POI] Enable extension required for conditional rendering
*/
enabledDeviceExtensions.push_back(VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME); enabledDeviceExtensions.push_back(VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME);
// Enable extension required to get conditional rendering supported features
enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
} }
~VulkanExample() ~VulkanExample()
{ {
// Clean up used Vulkan resources
// Note : Inherited destructor cleans up resources stored in base class
vkDestroyPipeline(device, pipeline, nullptr); vkDestroyPipeline(device, pipeline, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
model.destroy();
uniformBuffer.destroy(); uniformBuffer.destroy();
conditionalBuffer.destroy(); conditionalBuffer.destroy();
} }
// Enable physical device features required for this example void renderNode(vkglTF::Node *node, VkCommandBuffer commandBuffer) {
virtual void getEnabledFeatures() if (node->mesh) {
{ for (vkglTF::Primitive * primitive : node->mesh->primitives) {
// Geometry shader support is required for this example const std::vector<VkDescriptorSet> descriptorsets = {
if (deviceFeatures.geometryShader) { descriptorSet,
enabledFeatures.geometryShader = VK_TRUE; node->mesh->uniformBuffer.descriptorSet
};
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast<uint32_t>(descriptorsets.size()), descriptorsets.data(), 0, NULL);
struct PushBlock {
glm::vec4 baseColorFactor;
} pushBlock;
pushBlock.baseColorFactor = primitive->material.baseColorFactor;
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushBlock), &pushBlock);
/*
[POI] Setup the conditional rendering
*/
VkConditionalRenderingBeginInfoEXT conditionalRenderingBeginInfo{};
conditionalRenderingBeginInfo.sType = VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT;
conditionalRenderingBeginInfo.buffer = conditionalBuffer.buffer;
conditionalRenderingBeginInfo.offset = sizeof(int32_t) * node->index;
/*
[POI] Begin conditionally rendered section
If the value from the conditional rendering buffer at the given offset is != 0, the draw commands will be executed
*/
vkCmdBeginConditionalRenderingEXT(commandBuffer, &conditionalRenderingBeginInfo);
vkCmdDrawIndexed(commandBuffer, primitive->indexCount, 1, primitive->firstIndex, 0, 0);
vkCmdEndConditionalRenderingEXT(commandBuffer);
} }
else {
vks::tools::exitFatal("Selected GPU does not support geometry shaders!", VK_ERROR_FEATURE_NOT_PRESENT); };
for (auto child : node->children) {
renderNode(child, commandBuffer);
} }
} }
void buildCommandBuffers() void buildCommandBuffers()
{ {
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
VkClearValue clearValues[2]; VkClearValue clearValues[2];
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 0.0f } }; clearValues[0].color = { { 1.0f, 1.0f, 1.0f, 1.0f } };
clearValues[1].depthStencil = { 1.0f, 0 }; clearValues[1].depthStencil = { 1.0f, 0 };
VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
@ -117,9 +136,7 @@ public:
renderPassBeginInfo.clearValueCount = 2; renderPassBeginInfo.clearValueCount = 2;
renderPassBeginInfo.pClearValues = clearValues; renderPassBeginInfo.pClearValues = clearValues;
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) {
{
// Set target frame buffer
renderPassBeginInfo.framebuffer = frameBuffers[i]; renderPassBeginInfo.framebuffer = frameBuffers[i];
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
@ -133,49 +150,13 @@ public:
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL); vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL);
VkDeviceSize offsets[1] = { 0 };
vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &model.vertices.buffer, offsets);
vkCmdBindIndexBuffer(drawCmdBuffers[i], model.indices.buffer, 0, VK_INDEX_TYPE_UINT32);
struct PushBlock {
glm::vec4 offset;
glm::vec4 color;
} pushBlock;
const std::array<glm::vec3, 3> colors = {
glm::vec3(1.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f),
glm::vec3(0.0f, 0.0f, 1.0f),
};
/*
[POI] Setup the conditional rendering structure that decides on wether the commands are rendered or discarded
*/
VkConditionalRenderingBeginInfoEXT conditionalRenderingBeginInfo{};
conditionalRenderingBeginInfo.sType = VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT;
// If the value in this buffer at the given offset is zero, commands are discadrd
conditionalRenderingBeginInfo.buffer = conditionalBuffer.buffer;
// Offset will be changed in the loop below to toggle visibility of whole rows
conditionalRenderingBeginInfo.offset = 0;
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
for (int32_t x = -1; x < MODEL_ROWS - 1; x++) {
for (int32_t y = -2; y < 3; y++) {
pushBlock.offset = glm::vec4((float)x * 3.0f, (float)y * 2.5f, 0.0f, 1.0f);
pushBlock.color = glm::vec4(colors[x+1], 1.0f);
/* const VkDeviceSize offsets[1] = { 0 };
[POI] Start the conditionally rendered part (for this row) vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &scene.vertices.buffer, offsets);
*/ vkCmdBindIndexBuffer(drawCmdBuffers[i], scene.indices.buffer, 0, VK_INDEX_TYPE_UINT32);
for (auto node : scene.nodes) {
conditionalRenderingBeginInfo.offset = sizeof(uint32_t) * (x + 1); renderNode(node, drawCmdBuffers[i]);
vkCmdBeginConditionalRenderingEXT(drawCmdBuffers[i], &conditionalRenderingBeginInfo);
vkCmdPushConstants(drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(pushBlock), &pushBlock);
vkCmdDrawIndexed(drawCmdBuffers[i], model.indexCount, 1, 0, 0, 0);
vkCmdEndConditionalRenderingEXT(drawCmdBuffers[i]);
}
} }
vkCmdEndRenderPass(drawCmdBuffers[i]); vkCmdEndRenderPass(drawCmdBuffers[i]);
@ -186,7 +167,7 @@ public:
void loadAssets() void loadAssets()
{ {
model.loadFromFile(getAssetPath() + "models/suzanne.obj", vertexLayout, 0.1f, vulkanDevice, queue); scene.loadFromFile(getAssetPath() + "models/Buggy.gltf", vulkanDevice, queue);
} }
void setupDescriptorSets() void setupDescriptorSets()
@ -206,7 +187,10 @@ public:
descriptorLayoutCI.pBindings = setLayoutBindings.data(); descriptorLayoutCI.pBindings = setLayoutBindings.data();
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, nullptr, &descriptorSetLayout)); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, nullptr, &descriptorSetLayout));
VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); std::array<VkDescriptorSetLayout, 2> setLayouts = {
descriptorSetLayout, scene.descriptorSetLayout
};
VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), 2);
VkPushConstantRange pushConstantRange = vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, sizeof(glm::vec4) * 2, 0); VkPushConstantRange pushConstantRange = vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, sizeof(glm::vec4) * 2, 0);
pipelineLayoutCI.pushConstantRangeCount = 1; pipelineLayoutCI.pushConstantRangeCount = 1;
pipelineLayoutCI.pPushConstantRanges = &pushConstantRange; pipelineLayoutCI.pPushConstantRanges = &pushConstantRange;
@ -225,7 +209,7 @@ public:
const std::vector<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; const std::vector<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = 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_BACK_BIT, VK_FRONT_FACE_CLOCKWISE, 0); VkPipelineRasterizationStateCreateInfo rasterizationStateCI = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0);
VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE);
VkPipelineColorBlendStateCreateInfo colorBlendStateCI = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState); VkPipelineColorBlendStateCreateInfo colorBlendStateCI = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState);
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL); VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL);
@ -235,12 +219,12 @@ public:
// Vertex bindings and attributes // Vertex bindings and attributes
const std::vector<VkVertexInputBindingDescription> vertexInputBindings = { const std::vector<VkVertexInputBindingDescription> vertexInputBindings = {
vks::initializers::vertexInputBindingDescription(0, vertexLayout.stride(), VK_VERTEX_INPUT_RATE_VERTEX), vks::initializers::vertexInputBindingDescription(0, sizeof(vkglTF::Model::Vertex), VK_VERTEX_INPUT_RATE_VERTEX),
}; };
const std::vector<VkVertexInputAttributeDescription> vertexInputAttributes = { const std::vector<VkVertexInputAttributeDescription> vertexInputAttributes = {
vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0), // Location 0: Position vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0), // Location 0: Position
vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3), // Location 1: Normal vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3), // Location 1: Normal
vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 6), // Location 3: Color vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 6), // Location 2: UV
}; };
VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo(); VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo();
vertexInputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertexInputBindings.size()); vertexInputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertexInputBindings.size());
@ -283,41 +267,25 @@ public:
void updateUniformBuffers() void updateUniformBuffers()
{ {
uboVS.projection = camera.matrices.perspective; uboVS.projection = camera.matrices.perspective;
uboVS.modelview = camera.matrices.view; uboVS.modelview = glm::scale(camera.matrices.view, glm::vec3(0.1f , -0.1f, 0.1f));
memcpy(uniformBuffer.mapped, &uboVS, sizeof(uboVS)); memcpy(uniformBuffer.mapped, &uboVS, sizeof(uboVS));
} }
void updateConditionalBuffer() void updateConditionalBuffer()
{ {
memcpy(conditionalBuffer.mapped, &conditionalVisibility, sizeof(conditionalVisibility)); memcpy(conditionalBuffer.mapped, conditionalVisibility.data(), sizeof(int32_t) * conditionalVisibility.size());
} }
void draw()
{
VulkanExampleBase::prepareFrame();
// Command buffer to be sumitted to the queue
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
// Submit to queue
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
VulkanExampleBase::submitFrame();
}
void prepare()
{
VulkanExampleBase::prepare();
/* /*
Extension specific functions [POI] Extension specific setup
Gets the function pointers required for conditonal rendering
Sets up a dedicated conditional buffer that is used to determine visibility at draw time
*/ */
void prepareConditionalRendering()
{
/* /*
Get the function pointer The conditional rendering functions are part of an extension so they have to be loaded manually
The conditional rendering functions are part of an extension so they have to be manually loaded
*/ */
vkCmdBeginConditionalRenderingEXT = (PFN_vkCmdBeginConditionalRenderingEXT)vkGetDeviceProcAddr(device, "vkCmdBeginConditionalRenderingEXT"); vkCmdBeginConditionalRenderingEXT = (PFN_vkCmdBeginConditionalRenderingEXT)vkGetDeviceProcAddr(device, "vkCmdBeginConditionalRenderingEXT");
if (!vkCmdBeginConditionalRenderingEXT) { if (!vkCmdBeginConditionalRenderingEXT) {
@ -329,45 +297,46 @@ public:
vks::tools::exitFatal("Could not get a valid function pointer for vkCmdEndConditionalRenderingEXT", -1); vks::tools::exitFatal("Could not get a valid function pointer for vkCmdEndConditionalRenderingEXT", -1);
} }
/*
Get conditional rendering features
*/
PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"));
if (!vkGetPhysicalDeviceFeatures2KHR) {
vks::tools::exitFatal("Could not get a valid function pointer for vkGetPhysicalDeviceFeatures2KHR", -1);
}
VkPhysicalDeviceFeatures2KHR deviceFeatures2{};
conditionalRenderingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT;
deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
deviceFeatures2.pNext = &conditionalRenderingFeatures;
vkGetPhysicalDeviceFeatures2KHR(physicalDevice, &deviceFeatures2);
/* /*
Create the buffer that contains the conditional rendering information Create the buffer that contains the conditional rendering information
A single conditional value is 32 bits and if it's zero the rendering commands are discarded A single conditional value is 32 bits and if it's zero the rendering commands are discarded
This sample renders multiple rows of objects conditionally, so we setup a buffer with one value per row This sample renders multiple rows of objects conditionally, so we setup a buffer with one value per row
*/ */
conditionalVisibility.resize(scene.linearNodes.size());
VK_CHECK_RESULT(vulkanDevice->createBuffer( VK_CHECK_RESULT(vulkanDevice->createBuffer(
VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT, VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&conditionalBuffer, &conditionalBuffer,
sizeof(uint32_t) * MODEL_ROWS)); sizeof(int32_t) *conditionalVisibility.size(),
conditionalVisibility.data()));
VK_CHECK_RESULT(conditionalBuffer.map());
// By default, all parts of the glTF are visible
for (auto i = 0; i < conditionalVisibility.size(); i++) {
conditionalVisibility[i] = 1;
}
/* /*
Copy visibility data Copy visibility data
*/ */
for (auto i = 0; i < conditionalVisibility.size(); i++) { updateConditionalBuffer();
conditionalVisibility[i] = 1;
} }
VK_CHECK_RESULT(conditionalBuffer.map());
memcpy(conditionalBuffer.mapped, &conditionalVisibility, sizeof(conditionalVisibility));
/* void draw()
End of extension specific functions {
*/ VulkanExampleBase::prepareFrame();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
VulkanExampleBase::submitFrame();
}
void prepare()
{
VulkanExampleBase::prepare();
loadAssets(); loadAssets();
prepareConditionalRendering();
prepareUniformBuffers(); prepareUniformBuffers();
setupDescriptorSets(); setupDescriptorSets();
preparePipelines(); preparePipelines();
@ -380,29 +349,41 @@ public:
if (!prepared) if (!prepared)
return; return;
draw(); draw();
} if (camera.updated) {
virtual void viewChanged()
{
updateUniformBuffers(); updateUniformBuffers();
} }
}
virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay)
{ {
if (overlay->header("Visibility")) { if (overlay->header("Visibility")) {
for (uint32_t i = 0; i < MODEL_ROWS; i++) {
if (overlay->checkBox(std::to_string(i).c_str(), &conditionalVisibility[i])) { if (overlay->button("All")) {
for (auto i = 0; i < conditionalVisibility.size(); i++) {
conditionalVisibility[i] = 1;
}
updateConditionalBuffer();
}
ImGui::SameLine();
if (overlay->button("None")) {
for (auto i = 0; i < conditionalVisibility.size(); i++) {
conditionalVisibility[i] = 0;
}
updateConditionalBuffer();
}
ImGui::NewLine();
for (auto node : scene.linearNodes) {
// Add visibility toggle checkboxes for all model nodes with a mesh
if (node->mesh) {
if (overlay->checkBox(("[" + std::to_string(node->index) + "] " + node->mesh->name).c_str(), &conditionalVisibility[node->index])) {
updateConditionalBuffer(); updateConditionalBuffer();
};
if (i < MODEL_ROWS - 1) { ImGui::SameLine(); };
} }
} }
if (overlay->header("Device properties")) {
overlay->text("conditional rendering: %s", conditionalRenderingFeatures.conditionalRendering ? "true" : "false");
overlay->text("inherited conditional rendering: %s", conditionalRenderingFeatures.inheritedConditionalRendering ? "true" : "false");
} }
} }
}
}; };