1120 lines
44 KiB
C++
1120 lines
44 KiB
C++
/* Copyright (c) 2023-2025, Mobica Limited
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 the "License";
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "extended_dynamic_state2.h"
|
|
|
|
#include "gltf_loader.h"
|
|
#include "scene_graph/components/mesh.h"
|
|
#include "scene_graph/components/sub_mesh.h"
|
|
|
|
ExtendedDynamicState2::ExtendedDynamicState2()
|
|
{
|
|
title = "Extended Dynamic State2";
|
|
|
|
add_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
|
add_device_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
|
|
add_device_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
|
|
add_device_extension(VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME);
|
|
}
|
|
|
|
ExtendedDynamicState2::~ExtendedDynamicState2()
|
|
{
|
|
if (has_device())
|
|
{
|
|
uniform_buffers.common.reset();
|
|
uniform_buffers.baseline.reset();
|
|
uniform_buffers.tesselation.reset();
|
|
|
|
vkDestroySampler(get_device().get_handle(), textures.envmap.sampler, VK_NULL_HANDLE);
|
|
textures = {};
|
|
|
|
vkDestroyPipeline(get_device().get_handle(), pipeline.tesselation, VK_NULL_HANDLE);
|
|
vkDestroyPipeline(get_device().get_handle(), pipeline.baseline, VK_NULL_HANDLE);
|
|
vkDestroyPipeline(get_device().get_handle(), pipeline.background, VK_NULL_HANDLE);
|
|
vkDestroyPipelineLayout(get_device().get_handle(), pipeline_layouts.tesselation, VK_NULL_HANDLE);
|
|
vkDestroyPipelineLayout(get_device().get_handle(), pipeline_layouts.baseline, VK_NULL_HANDLE);
|
|
vkDestroyPipelineLayout(get_device().get_handle(), pipeline_layouts.background, VK_NULL_HANDLE);
|
|
vkDestroyDescriptorSetLayout(get_device().get_handle(), descriptor_set_layouts.tesselation, VK_NULL_HANDLE);
|
|
vkDestroyDescriptorSetLayout(get_device().get_handle(), descriptor_set_layouts.baseline, VK_NULL_HANDLE);
|
|
vkDestroyDescriptorSetLayout(get_device().get_handle(), descriptor_set_layouts.background, VK_NULL_HANDLE);
|
|
vkDestroyDescriptorPool(get_device().get_handle(), descriptor_pool, VK_NULL_HANDLE);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fn bool ExtendedDynamicState2::prepare(const vkb::ApplicationOptions &options)
|
|
* @brief Configuring all sample specific settings, creating descriptor sets/pool, pipelines, generating or loading models etc.
|
|
*/
|
|
bool ExtendedDynamicState2::prepare(const vkb::ApplicationOptions &options)
|
|
{
|
|
if (!ApiVulkanSample::prepare(options))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
camera.type = vkb::CameraType::LookAt;
|
|
camera.set_position({2.0f, -4.0f, -10.0f});
|
|
camera.set_rotation({-15.0f, 190.0f, 0.0f});
|
|
camera.set_perspective(60.0f, static_cast<float>(width) / static_cast<float>(height), 256.0f, 0.1f);
|
|
|
|
load_assets();
|
|
model_data_creation();
|
|
prepare_uniform_buffers();
|
|
create_descriptor_pool();
|
|
setup_descriptor_set_layout();
|
|
create_descriptor_sets();
|
|
create_pipelines();
|
|
build_command_buffers();
|
|
prepared = true;
|
|
|
|
return true;
|
|
}
|
|
/**
|
|
* @fn void ExtendedDynamicState2::load_assets()
|
|
* @brief Loading extra models, textures from assets
|
|
*/
|
|
void ExtendedDynamicState2::load_assets()
|
|
{
|
|
load_scene("scenes/primitives/primitives.gltf");
|
|
|
|
std::vector<SceneNode> scene_elements;
|
|
std::vector<vkb::sg::Node *> node_scene_list = {&(get_scene().get_root_node())};
|
|
vkb::sg::Node *node = nullptr;
|
|
|
|
for (size_t list_it = 0; node_scene_list.size() > list_it; ++list_it)
|
|
{
|
|
node = node_scene_list[list_it];
|
|
|
|
// Add node children to vector if they exist
|
|
if (!node->get_children().empty())
|
|
{
|
|
node_scene_list.insert(
|
|
node_scene_list.end(),
|
|
node->get_children().begin(),
|
|
node->get_children().end());
|
|
}
|
|
|
|
// If current node have mesh add it to scene_elements
|
|
if (node->has_component<vkb::sg::Mesh>())
|
|
{
|
|
vkb::sg::Mesh &mesh = node->get_component<vkb::sg::Mesh>();
|
|
|
|
ModelDynamicParam object_param{};
|
|
gui_settings.objects.push_back(object_param);
|
|
|
|
for (auto &sub_mesh : mesh.get_submeshes())
|
|
{
|
|
scene_elements.push_back({mesh.get_name(), node, sub_mesh});
|
|
}
|
|
}
|
|
}
|
|
/* Split scene */
|
|
scene_pipeline_divide(scene_elements);
|
|
|
|
background_model = load_model("scenes/cube.gltf");
|
|
/* Load HDR cube map */
|
|
textures.envmap = load_texture_cubemap("textures/uffizi_rgba16f_cube.ktx", vkb::sg::Image::Color);
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::draw()
|
|
* @brief Preparing frame and submitting it to the present queue
|
|
*/
|
|
void ExtendedDynamicState2::draw()
|
|
{
|
|
ApiVulkanSample::prepare_frame();
|
|
submit_info.commandBufferCount = 1;
|
|
submit_info.pCommandBuffers = &draw_cmd_buffers[current_buffer];
|
|
VK_CHECK(vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE));
|
|
ApiVulkanSample::submit_frame();
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::render(float delta_time)
|
|
* @brief Drawing frames and/or updating uniform buffers when camera position/rotation was changed
|
|
*/
|
|
void ExtendedDynamicState2::render(float delta_time)
|
|
{
|
|
if (!prepared)
|
|
{
|
|
return;
|
|
}
|
|
draw();
|
|
if (camera.updated)
|
|
{
|
|
update_uniform_buffers();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::prepare_uniform_buffers()
|
|
* @brief Preparing uniform buffer (setting bits) and updating UB data
|
|
*/
|
|
void ExtendedDynamicState2::prepare_uniform_buffers()
|
|
{
|
|
uniform_buffers.common =
|
|
std::make_unique<vkb::core::BufferC>(get_device(), sizeof(ubo_common), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
|
|
uniform_buffers.baseline =
|
|
std::make_unique<vkb::core::BufferC>(get_device(), sizeof(ubo_baseline), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
|
|
uniform_buffers.tesselation =
|
|
std::make_unique<vkb::core::BufferC>(get_device(), sizeof(ubo_tess), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
|
|
update_uniform_buffers();
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::update_uniform_buffers()
|
|
* @brief Updating data from application to GPU uniform buffer
|
|
*/
|
|
void ExtendedDynamicState2::update_uniform_buffers()
|
|
{
|
|
/* Common uniform buffer */
|
|
ubo_common.projection = camera.matrices.perspective;
|
|
ubo_common.view = camera.matrices.view;
|
|
uniform_buffers.common->convert_and_update(ubo_common);
|
|
|
|
/* Baseline uniform buffer */
|
|
uniform_buffers.baseline->convert_and_update(ubo_baseline);
|
|
|
|
/* Tessellation uniform buffer */
|
|
ubo_tess.tessellation_factor = gui_settings.tess_factor;
|
|
|
|
if (!gui_settings.tessellation)
|
|
{
|
|
// Setting this to zero sets all tessellation factors to 1.0 in the shader
|
|
ubo_tess.tessellation_factor = 0.0f;
|
|
}
|
|
uniform_buffers.tesselation->convert_and_update(ubo_tess);
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::create_pipelines()
|
|
* @brief Creating graphical pipelines: baseline, background, tessellation.
|
|
*/
|
|
void ExtendedDynamicState2::create_pipelines()
|
|
{
|
|
/* Setup for first pipeline */
|
|
VkPipelineInputAssemblyStateCreateInfo input_assembly_state =
|
|
vkb::initializers::pipeline_input_assembly_state_create_info(
|
|
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
|
0,
|
|
VK_FALSE);
|
|
|
|
VkPipelineRasterizationStateCreateInfo rasterization_state =
|
|
vkb::initializers::pipeline_rasterization_state_create_info(
|
|
VK_POLYGON_MODE_FILL,
|
|
VK_CULL_MODE_BACK_BIT,
|
|
VK_FRONT_FACE_CLOCKWISE,
|
|
0);
|
|
|
|
rasterization_state.depthBiasConstantFactor = 1.0f;
|
|
rasterization_state.depthBiasSlopeFactor = 1.0f;
|
|
|
|
VkPipelineColorBlendAttachmentState blend_attachment_state =
|
|
vkb::initializers::pipeline_color_blend_attachment_state(
|
|
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
|
VK_TRUE);
|
|
|
|
blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD;
|
|
blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD;
|
|
blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
|
|
|
VkPipelineColorBlendStateCreateInfo color_blend_state =
|
|
vkb::initializers::pipeline_color_blend_state_create_info(
|
|
1,
|
|
&blend_attachment_state);
|
|
|
|
/* Note: Using reversed depth-buffer for increased precision, so Greater depth values are kept */
|
|
VkPipelineDepthStencilStateCreateInfo depth_stencil_state =
|
|
vkb::initializers::pipeline_depth_stencil_state_create_info(
|
|
VK_TRUE,
|
|
VK_TRUE,
|
|
VK_COMPARE_OP_GREATER);
|
|
|
|
VkPipelineViewportStateCreateInfo viewport_state =
|
|
vkb::initializers::pipeline_viewport_state_create_info(1, 1, 0);
|
|
|
|
VkPipelineMultisampleStateCreateInfo multisample_state =
|
|
vkb::initializers::pipeline_multisample_state_create_info(
|
|
VK_SAMPLE_COUNT_1_BIT,
|
|
0);
|
|
|
|
VkPipelineTessellationStateCreateInfo tessellation_state =
|
|
vkb::initializers::pipeline_tessellation_state_create_info(3);
|
|
|
|
std::vector<VkDynamicState> dynamic_state_enables = {
|
|
VK_DYNAMIC_STATE_VIEWPORT,
|
|
VK_DYNAMIC_STATE_SCISSOR,
|
|
VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT,
|
|
VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT,
|
|
VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT,
|
|
VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT,
|
|
};
|
|
VkPipelineDynamicStateCreateInfo dynamic_state =
|
|
vkb::initializers::pipeline_dynamic_state_create_info(
|
|
dynamic_state_enables.data(),
|
|
static_cast<uint32_t>(dynamic_state_enables.size()),
|
|
0);
|
|
|
|
/* Vertex bindings and attributes for model rendering */
|
|
/* Binding description */
|
|
std::vector<VkVertexInputBindingDescription> vertex_input_bindings = {
|
|
vkb::initializers::vertex_input_binding_description(0, sizeof(glm::vec3), VK_VERTEX_INPUT_RATE_VERTEX),
|
|
vkb::initializers::vertex_input_binding_description(1, sizeof(glm::vec3), VK_VERTEX_INPUT_RATE_VERTEX),
|
|
};
|
|
|
|
/* Attribute descriptions */
|
|
std::vector<VkVertexInputAttributeDescription> vertex_input_attributes = {
|
|
vkb::initializers::vertex_input_attribute_description(0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0), // Position
|
|
vkb::initializers::vertex_input_attribute_description(1, 1, VK_FORMAT_R32G32B32_SFLOAT, 0), // Normal
|
|
};
|
|
|
|
VkPipelineVertexInputStateCreateInfo vertex_input_state = vkb::initializers::pipeline_vertex_input_state_create_info();
|
|
vertex_input_state.vertexBindingDescriptionCount = static_cast<uint32_t>(vertex_input_bindings.size());
|
|
vertex_input_state.pVertexBindingDescriptions = vertex_input_bindings.data();
|
|
vertex_input_state.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertex_input_attributes.size());
|
|
vertex_input_state.pVertexAttributeDescriptions = vertex_input_attributes.data();
|
|
|
|
std::array<VkPipelineShaderStageCreateInfo, 4> shader_stages{};
|
|
shader_stages[0] = load_shader("extended_dynamic_state2/baseline.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
|
|
shader_stages[1] = load_shader("extended_dynamic_state2/baseline.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
|
|
/* Use the pNext to point to the rendering create struct */
|
|
VkGraphicsPipelineCreateInfo graphics_create{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO};
|
|
graphics_create.pNext = VK_NULL_HANDLE;
|
|
graphics_create.renderPass = VK_NULL_HANDLE;
|
|
graphics_create.pInputAssemblyState = &input_assembly_state;
|
|
graphics_create.pRasterizationState = &rasterization_state;
|
|
graphics_create.pColorBlendState = &color_blend_state;
|
|
graphics_create.pMultisampleState = &multisample_state;
|
|
graphics_create.pViewportState = &viewport_state;
|
|
graphics_create.pDepthStencilState = &depth_stencil_state;
|
|
graphics_create.pDynamicState = &dynamic_state;
|
|
graphics_create.pVertexInputState = &vertex_input_state;
|
|
graphics_create.pTessellationState = VK_NULL_HANDLE;
|
|
graphics_create.stageCount = 2;
|
|
graphics_create.pStages = shader_stages.data();
|
|
graphics_create.layout = pipeline_layouts.baseline;
|
|
|
|
graphics_create.pNext = VK_NULL_HANDLE;
|
|
graphics_create.renderPass = render_pass;
|
|
|
|
VK_CHECK(vkCreateGraphicsPipelines(get_device().get_handle(),
|
|
pipeline_cache,
|
|
1,
|
|
&graphics_create,
|
|
VK_NULL_HANDLE,
|
|
&pipeline.baseline));
|
|
|
|
/* Setup for second pipeline */
|
|
graphics_create.layout = pipeline_layouts.background;
|
|
|
|
std::vector<VkDynamicState> dynamic_state_enables_background = {
|
|
VK_DYNAMIC_STATE_VIEWPORT,
|
|
VK_DYNAMIC_STATE_SCISSOR,
|
|
};
|
|
dynamic_state.pDynamicStates = dynamic_state_enables_background.data();
|
|
dynamic_state.dynamicStateCount = static_cast<uint32_t>(dynamic_state_enables_background.size());
|
|
|
|
/* Binding description */
|
|
std::vector<VkVertexInputBindingDescription> vertex_input_bindings_background = {
|
|
vkb::initializers::vertex_input_binding_description(0, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX),
|
|
};
|
|
|
|
/* Attribute descriptions */
|
|
std::vector<VkVertexInputAttributeDescription> vertex_input_attributes_background = {
|
|
vkb::initializers::vertex_input_attribute_description(0,
|
|
0,
|
|
VK_FORMAT_R32G32B32_SFLOAT,
|
|
0), // Position
|
|
vkb::initializers::vertex_input_attribute_description(0,
|
|
1,
|
|
VK_FORMAT_R32G32B32_SFLOAT,
|
|
offsetof(Vertex, normal)), // Normal
|
|
};
|
|
|
|
vertex_input_state.vertexBindingDescriptionCount = static_cast<uint32_t>(vertex_input_bindings_background.size());
|
|
vertex_input_state.pVertexBindingDescriptions = vertex_input_bindings_background.data();
|
|
vertex_input_state.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertex_input_attributes_background.size());
|
|
vertex_input_state.pVertexAttributeDescriptions = vertex_input_attributes_background.data();
|
|
|
|
rasterization_state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
|
|
|
shader_stages[0] = load_shader("extended_dynamic_state2/background.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
|
|
shader_stages[1] = load_shader("extended_dynamic_state2/background.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
|
|
VK_CHECK(vkCreateGraphicsPipelines(get_device().get_handle(),
|
|
pipeline_cache,
|
|
1,
|
|
&graphics_create,
|
|
VK_NULL_HANDLE,
|
|
&pipeline.background));
|
|
|
|
/* Setup for third pipeline */
|
|
graphics_create.pTessellationState = &tessellation_state;
|
|
graphics_create.layout = pipeline_layouts.tesselation;
|
|
input_assembly_state.topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
|
|
|
|
dynamic_state_enables.push_back(VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT);
|
|
dynamic_state.pDynamicStates = dynamic_state_enables.data();
|
|
dynamic_state.dynamicStateCount = static_cast<uint32_t>(dynamic_state_enables.size());
|
|
|
|
vertex_input_state.vertexBindingDescriptionCount = static_cast<uint32_t>(vertex_input_bindings.size());
|
|
vertex_input_state.pVertexBindingDescriptions = vertex_input_bindings.data();
|
|
vertex_input_state.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertex_input_attributes.size());
|
|
vertex_input_state.pVertexAttributeDescriptions = vertex_input_attributes.data();
|
|
|
|
/* Wireframe mode */
|
|
if (get_device().get_gpu().get_features().fillModeNonSolid)
|
|
{
|
|
rasterization_state.polygonMode = VK_POLYGON_MODE_LINE;
|
|
}
|
|
|
|
shader_stages[0] = load_shader("extended_dynamic_state2/tess.vert.spv",
|
|
VK_SHADER_STAGE_VERTEX_BIT);
|
|
shader_stages[1] = load_shader("extended_dynamic_state2/tess.frag.spv",
|
|
VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
shader_stages[2] = load_shader("extended_dynamic_state2/tess.tesc.spv",
|
|
VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
|
|
shader_stages[3] = load_shader("extended_dynamic_state2/tess.tese.spv",
|
|
VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
|
|
graphics_create.stageCount = static_cast<uint32_t>(shader_stages.size());
|
|
graphics_create.pStages = shader_stages.data();
|
|
/* Enable depth test and write */
|
|
depth_stencil_state.depthWriteEnable = VK_TRUE;
|
|
depth_stencil_state.depthTestEnable = VK_TRUE;
|
|
/* Flip cull mode */
|
|
rasterization_state.cullMode = VK_CULL_MODE_FRONT_BIT;
|
|
VK_CHECK(vkCreateGraphicsPipelines(get_device().get_handle(),
|
|
pipeline_cache,
|
|
1,
|
|
&graphics_create,
|
|
VK_NULL_HANDLE,
|
|
&pipeline.tesselation));
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::build_command_buffers()
|
|
* @brief Creating command buffers and drawing particular elements on window.
|
|
* @details Drawing object list:
|
|
* - models from baseline scene
|
|
* - model from tessellation scene
|
|
* - background model
|
|
* - primitive restart model
|
|
*/
|
|
void ExtendedDynamicState2::build_command_buffers()
|
|
{
|
|
std::array<VkClearValue, 2> clear_values{};
|
|
clear_values[0].color = {{0.0f, 0.0f, 0.0f, 0.0f}};
|
|
clear_values[1].depthStencil = {0.0f, 0};
|
|
|
|
constexpr uint32_t patch_control_points_triangle = 3; /* Geosphere model is based on triangle patches */
|
|
|
|
int i = -1; /* Required for accessing element in framebuffers vector */
|
|
for (auto &draw_cmd_buffer : draw_cmd_buffers)
|
|
{
|
|
++i;
|
|
auto command_begin = vkb::initializers::command_buffer_begin_info();
|
|
VK_CHECK(vkBeginCommandBuffer(draw_cmd_buffer, &command_begin));
|
|
|
|
VkRenderPassBeginInfo render_pass_begin_info = vkb::initializers::render_pass_begin_info();
|
|
render_pass_begin_info.renderPass = render_pass;
|
|
render_pass_begin_info.framebuffer = framebuffers[i];
|
|
render_pass_begin_info.renderArea.extent.width = width;
|
|
render_pass_begin_info.renderArea.extent.height = height;
|
|
render_pass_begin_info.clearValueCount = static_cast<uint32_t>(clear_values.size());
|
|
render_pass_begin_info.pClearValues = clear_values.data();
|
|
|
|
vkCmdBeginRenderPass(draw_cmd_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
|
|
|
|
VkViewport viewport = vkb::initializers::viewport(static_cast<float>(width), static_cast<float>(height), 0.0f, 1.0f);
|
|
vkCmdSetViewport(draw_cmd_buffer, 0, 1, &viewport);
|
|
|
|
VkRect2D scissor = vkb::initializers::rect2D(static_cast<int>(width), static_cast<int>(height), 0, 0);
|
|
vkCmdSetScissor(draw_cmd_buffer, 0, 1, &scissor);
|
|
|
|
/* Binding background pipeline and descriptor sets */
|
|
vkCmdBindDescriptorSets(draw_cmd_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
pipeline_layouts.background,
|
|
0,
|
|
1,
|
|
&descriptor_sets.background,
|
|
0,
|
|
nullptr);
|
|
vkCmdBindPipeline(draw_cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.background);
|
|
|
|
/* Drawing background */
|
|
draw_model(background_model, draw_cmd_buffer);
|
|
|
|
/* Changing bindings to baseline pipeline and descriptor sets */
|
|
vkCmdBindDescriptorSets(draw_cmd_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
pipeline_layouts.baseline,
|
|
0,
|
|
1,
|
|
&descriptor_sets.baseline,
|
|
0,
|
|
nullptr);
|
|
vkCmdBindPipeline(draw_cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.baseline);
|
|
|
|
/* Setting topology to triangle list and disabling primitive restart functionality */
|
|
vkCmdSetPrimitiveTopologyEXT(draw_cmd_buffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
|
|
vkCmdSetPrimitiveRestartEnableEXT(draw_cmd_buffer, VK_FALSE);
|
|
|
|
/* Drawing objects from baseline scene (with rasterizer discard and depth bias functionality) */
|
|
draw_from_scene(draw_cmd_buffer, scene_elements_baseline);
|
|
|
|
/* Changing topology to triangle strip with using primitive restart feature */
|
|
vkCmdSetPrimitiveTopologyEXT(draw_cmd_buffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
|
|
vkCmdSetPrimitiveRestartEnableEXT(draw_cmd_buffer, VK_TRUE);
|
|
|
|
/* Draw model with primitive restart functionality */
|
|
draw_created_model(draw_cmd_buffer);
|
|
|
|
/* Changing bindings to tessellation pipeline */
|
|
vkCmdBindDescriptorSets(draw_cmd_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
pipeline_layouts.tesselation,
|
|
0,
|
|
1,
|
|
&descriptor_sets.tesselation,
|
|
0,
|
|
nullptr);
|
|
vkCmdBindPipeline(draw_cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.tesselation);
|
|
|
|
/* Change topology to patch list and setting patch control points value */
|
|
vkCmdSetPrimitiveTopologyEXT(draw_cmd_buffer, VK_PRIMITIVE_TOPOLOGY_PATCH_LIST);
|
|
vkCmdSetPatchControlPointsEXT(draw_cmd_buffer, patch_control_points_triangle);
|
|
|
|
/* Drawing scene with objects using tessellation feature */
|
|
draw_from_scene(draw_cmd_buffer, scene_elements_tess);
|
|
|
|
/* UI */
|
|
draw_ui(draw_cmd_buffer);
|
|
|
|
vkCmdEndRenderPass(draw_cmd_buffer);
|
|
|
|
VK_CHECK(vkEndCommandBuffer(draw_cmd_buffer));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::create_descriptor_pool()
|
|
* @brief Creating descriptor pool with size adjusted to use uniform buffer and image sampler
|
|
*/
|
|
void ExtendedDynamicState2::create_descriptor_pool()
|
|
{
|
|
std::vector<VkDescriptorPoolSize> pool_sizes = {
|
|
vkb::initializers::descriptor_pool_size(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 5),
|
|
vkb::initializers::descriptor_pool_size(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1),
|
|
};
|
|
|
|
VkDescriptorPoolCreateInfo descriptor_pool_create_info =
|
|
vkb::initializers::descriptor_pool_create_info(
|
|
static_cast<uint32_t>(pool_sizes.size()),
|
|
pool_sizes.data(),
|
|
3);
|
|
|
|
VK_CHECK(vkCreateDescriptorPool(get_device().get_handle(), &descriptor_pool_create_info, nullptr, &descriptor_pool));
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::setup_descriptor_set_layout()
|
|
* @brief Creating layout for descriptor sets
|
|
*/
|
|
void ExtendedDynamicState2::setup_descriptor_set_layout()
|
|
{
|
|
/* First descriptor set */
|
|
std::vector<VkDescriptorSetLayoutBinding> set_layout_bindings = {
|
|
vkb::initializers::descriptor_set_layout_binding(
|
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
VK_SHADER_STAGE_VERTEX_BIT,
|
|
0),
|
|
vkb::initializers::descriptor_set_layout_binding(
|
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
VK_SHADER_STAGE_VERTEX_BIT,
|
|
1),
|
|
};
|
|
|
|
VkDescriptorSetLayoutCreateInfo descriptor_layout_create_info =
|
|
vkb::initializers::descriptor_set_layout_create_info(set_layout_bindings.data(),
|
|
static_cast<uint32_t>(set_layout_bindings.size()));
|
|
|
|
VK_CHECK(vkCreateDescriptorSetLayout(get_device().get_handle(),
|
|
&descriptor_layout_create_info,
|
|
nullptr,
|
|
&descriptor_set_layouts.baseline));
|
|
|
|
VkPipelineLayoutCreateInfo pipeline_layout_create_info =
|
|
vkb::initializers::pipeline_layout_create_info(
|
|
&descriptor_set_layouts.baseline,
|
|
1);
|
|
|
|
/* Pass scene node information via push constants */
|
|
VkPushConstantRange push_constant_range = vkb::initializers::push_constant_range(VK_SHADER_STAGE_VERTEX_BIT,
|
|
sizeof(push_const_block),
|
|
0);
|
|
pipeline_layout_create_info.pushConstantRangeCount = 1;
|
|
pipeline_layout_create_info.pPushConstantRanges = &push_constant_range;
|
|
|
|
VK_CHECK(vkCreatePipelineLayout(get_device().get_handle(),
|
|
&pipeline_layout_create_info,
|
|
nullptr,
|
|
&pipeline_layouts.baseline));
|
|
|
|
/* Second descriptor set */
|
|
set_layout_bindings = {
|
|
vkb::initializers::descriptor_set_layout_binding(
|
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT | VK_SHADER_STAGE_VERTEX_BIT,
|
|
0),
|
|
vkb::initializers::descriptor_set_layout_binding(
|
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
|
|
1),
|
|
};
|
|
|
|
descriptor_layout_create_info.pBindings = set_layout_bindings.data();
|
|
descriptor_layout_create_info.bindingCount = static_cast<uint32_t>(set_layout_bindings.size());
|
|
VK_CHECK(vkCreateDescriptorSetLayout(get_device().get_handle(),
|
|
&descriptor_layout_create_info,
|
|
nullptr,
|
|
&descriptor_set_layouts.tesselation));
|
|
|
|
pipeline_layout_create_info.pSetLayouts = &descriptor_set_layouts.tesselation;
|
|
pipeline_layout_create_info.setLayoutCount = 1;
|
|
push_constant_range.stageFlags = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
|
|
VK_CHECK(vkCreatePipelineLayout(get_device().get_handle(),
|
|
&pipeline_layout_create_info,
|
|
nullptr,
|
|
&pipeline_layouts.tesselation));
|
|
|
|
/* Third descriptor set */
|
|
set_layout_bindings = {
|
|
vkb::initializers::descriptor_set_layout_binding(
|
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
VK_SHADER_STAGE_VERTEX_BIT,
|
|
0),
|
|
vkb::initializers::descriptor_set_layout_binding(
|
|
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
1),
|
|
};
|
|
|
|
descriptor_layout_create_info.pBindings = set_layout_bindings.data();
|
|
descriptor_layout_create_info.bindingCount = static_cast<uint32_t>(set_layout_bindings.size());
|
|
VK_CHECK(vkCreateDescriptorSetLayout(get_device().get_handle(),
|
|
&descriptor_layout_create_info,
|
|
nullptr,
|
|
&descriptor_set_layouts.background));
|
|
|
|
pipeline_layout_create_info.pSetLayouts = &descriptor_set_layouts.background;
|
|
pipeline_layout_create_info.setLayoutCount = 1;
|
|
pipeline_layout_create_info.pushConstantRangeCount = 0;
|
|
pipeline_layout_create_info.pPushConstantRanges = VK_NULL_HANDLE;
|
|
VK_CHECK(vkCreatePipelineLayout(get_device().get_handle(),
|
|
&pipeline_layout_create_info,
|
|
nullptr,
|
|
&pipeline_layouts.background));
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::create_descriptor_sets()
|
|
* @brief Creating descriptor sets for 3 separate pipelines.
|
|
*/
|
|
void ExtendedDynamicState2::create_descriptor_sets()
|
|
{
|
|
/* First descriptor set */
|
|
VkDescriptorSetAllocateInfo alloc_info =
|
|
vkb::initializers::descriptor_set_allocate_info(
|
|
descriptor_pool,
|
|
&descriptor_set_layouts.baseline,
|
|
1);
|
|
|
|
VK_CHECK(vkAllocateDescriptorSets(get_device().get_handle(), &alloc_info, &descriptor_sets.baseline));
|
|
|
|
VkDescriptorBufferInfo matrix_common_buffer_descriptor = create_descriptor(*uniform_buffers.common);
|
|
VkDescriptorBufferInfo matrix_baseline_buffer_descriptor = create_descriptor(*uniform_buffers.baseline);
|
|
|
|
std::vector<VkWriteDescriptorSet> write_descriptor_sets = {
|
|
vkb::initializers::write_descriptor_set(
|
|
descriptor_sets.baseline,
|
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
0,
|
|
&matrix_common_buffer_descriptor),
|
|
vkb::initializers::write_descriptor_set(
|
|
descriptor_sets.baseline,
|
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
1,
|
|
&matrix_baseline_buffer_descriptor)};
|
|
|
|
vkUpdateDescriptorSets(get_device().get_handle(), static_cast<uint32_t>(write_descriptor_sets.size()),
|
|
write_descriptor_sets.data(), 0, VK_NULL_HANDLE);
|
|
|
|
/* Second descriptor set */
|
|
alloc_info =
|
|
vkb::initializers::descriptor_set_allocate_info(
|
|
descriptor_pool,
|
|
&descriptor_set_layouts.tesselation,
|
|
1);
|
|
|
|
VK_CHECK(vkAllocateDescriptorSets(get_device().get_handle(), &alloc_info, &descriptor_sets.tesselation));
|
|
|
|
VkDescriptorBufferInfo matrix_tess_buffer_descriptor = create_descriptor(*uniform_buffers.tesselation);
|
|
|
|
write_descriptor_sets = {
|
|
vkb::initializers::write_descriptor_set(
|
|
descriptor_sets.tesselation,
|
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
0,
|
|
&matrix_common_buffer_descriptor),
|
|
vkb::initializers::write_descriptor_set(
|
|
descriptor_sets.tesselation,
|
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
1,
|
|
&matrix_tess_buffer_descriptor)};
|
|
|
|
vkUpdateDescriptorSets(get_device().get_handle(), static_cast<uint32_t>(write_descriptor_sets.size()),
|
|
write_descriptor_sets.data(), 0, VK_NULL_HANDLE);
|
|
|
|
/* Third descriptor set */
|
|
alloc_info =
|
|
vkb::initializers::descriptor_set_allocate_info(
|
|
descriptor_pool,
|
|
&descriptor_set_layouts.background,
|
|
1);
|
|
|
|
VK_CHECK(vkAllocateDescriptorSets(get_device().get_handle(), &alloc_info, &descriptor_sets.background));
|
|
|
|
VkDescriptorImageInfo background_image_descriptor = create_descriptor(textures.envmap);
|
|
|
|
write_descriptor_sets = {
|
|
vkb::initializers::write_descriptor_set(
|
|
descriptor_sets.background,
|
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
0,
|
|
&matrix_common_buffer_descriptor),
|
|
vkb::initializers::write_descriptor_set(
|
|
descriptor_sets.background,
|
|
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
1,
|
|
&background_image_descriptor)};
|
|
|
|
vkUpdateDescriptorSets(get_device().get_handle(), static_cast<uint32_t>(write_descriptor_sets.size()),
|
|
write_descriptor_sets.data(), 0, VK_NULL_HANDLE);
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::request_gpu_features(vkb::PhysicalDevice &gpu)
|
|
* @brief Enabling features related to Vulkan extensions
|
|
*/
|
|
void ExtendedDynamicState2::request_gpu_features(vkb::PhysicalDevice &gpu)
|
|
{
|
|
/* Enable extension features required by this sample
|
|
These are passed to device creation via a pNext structure chain */
|
|
REQUEST_REQUIRED_FEATURE(
|
|
gpu, VkPhysicalDeviceExtendedDynamicState2FeaturesEXT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT, extendedDynamicState2);
|
|
REQUEST_REQUIRED_FEATURE(gpu,
|
|
VkPhysicalDeviceExtendedDynamicState2FeaturesEXT,
|
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT,
|
|
extendedDynamicState2PatchControlPoints);
|
|
|
|
REQUEST_REQUIRED_FEATURE(
|
|
gpu, VkPhysicalDeviceExtendedDynamicStateFeaturesEXT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT, extendedDynamicState);
|
|
|
|
REQUEST_REQUIRED_FEATURE(gpu,
|
|
VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT,
|
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT,
|
|
primitiveTopologyListRestart);
|
|
|
|
// Tessellation shader support is required for this example
|
|
auto &requested_features = gpu.get_mutable_requested_features();
|
|
if (gpu.get_features().tessellationShader)
|
|
{
|
|
requested_features.tessellationShader = VK_TRUE;
|
|
}
|
|
else
|
|
{
|
|
throw vkb::VulkanException(VK_ERROR_FEATURE_NOT_PRESENT, "Selected GPU does not support tessellation shaders!");
|
|
}
|
|
|
|
if (gpu.get_features().fillModeNonSolid)
|
|
{
|
|
requested_features.fillModeNonSolid = VK_TRUE;
|
|
}
|
|
|
|
if (gpu.get_features().samplerAnisotropy)
|
|
{
|
|
gpu.get_mutable_requested_features().samplerAnisotropy = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::on_update_ui_overlay(vkb::Drawer &drawer)
|
|
* @brief Projecting GUI and transferring data between GUI and app
|
|
*/
|
|
void ExtendedDynamicState2::on_update_ui_overlay(vkb::Drawer &drawer)
|
|
{
|
|
if (drawer.header("Settings"))
|
|
{
|
|
if (drawer.checkbox("Tessellation Enable", &gui_settings.tessellation))
|
|
{
|
|
update_uniform_buffers();
|
|
}
|
|
|
|
/* Maximum tessellation factor is set to 4.0 */
|
|
if (drawer.slider_float("Tessellation Factor", &gui_settings.tess_factor, 1.0f, 4.0f))
|
|
{
|
|
update_uniform_buffers();
|
|
}
|
|
}
|
|
if (drawer.header("Models"))
|
|
{
|
|
drawer.checkbox("Selection effect active", &gui_settings.selection_active);
|
|
const int obj_cnt = static_cast<int>(scene_elements_baseline.size());
|
|
std::vector<std::string> obj_names;
|
|
|
|
for (int i = 0; i < obj_cnt; ++i)
|
|
{
|
|
obj_names.push_back((scene_elements_baseline[i].name).c_str());
|
|
}
|
|
drawer.combo_box("Name", &gui_settings.selected_obj, obj_names);
|
|
drawer.checkbox("Depth Bias Enable", &gui_settings.objects[gui_settings.selected_obj].depth_bias);
|
|
drawer.checkbox("Rasterizer Discard", &gui_settings.objects[gui_settings.selected_obj].rasterizer_discard);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::update(float delta_time)
|
|
* @brief Function which was called in every frame.
|
|
* @details For presenting z-fighting, a small animation was implemented (cube_animation)
|
|
*/
|
|
void ExtendedDynamicState2::update(float delta_time)
|
|
{
|
|
cube_animation(delta_time);
|
|
ApiVulkanSample::update(delta_time);
|
|
}
|
|
|
|
/**
|
|
* @fn glm::vec4 ExtendedDynamicState2::get_changed_alpha(const vkb::sg::PBRMaterial *original_mat)
|
|
* @brief Changing alpha value to create blinking effect on selected model
|
|
* @returns Color of original_mat with changed alpha value
|
|
*/
|
|
glm::vec4 ExtendedDynamicState2::get_changed_alpha(const vkb::sg::PBRMaterial *original_mat)
|
|
{
|
|
static bool rise = false;
|
|
static int previous_obj_id = gui_settings.selected_obj;
|
|
static float accumulated_diff = 0.0f;
|
|
constexpr float alpha_step = 0.075f;
|
|
constexpr float alpha_max = 0.98f;
|
|
constexpr float alpha_min = 0.3f;
|
|
glm::vec4 color = original_mat->base_color_factor;
|
|
|
|
/* Change alpha value */
|
|
if (gui_settings.time_tick == true)
|
|
{
|
|
accumulated_diff += rise ? alpha_step : -alpha_step;
|
|
gui_settings.time_tick = false;
|
|
}
|
|
color.w += accumulated_diff;
|
|
|
|
/* Detecting change of selected object */
|
|
if (previous_obj_id != gui_settings.selected_obj)
|
|
{
|
|
accumulated_diff = 0.0f;
|
|
previous_obj_id = gui_settings.selected_obj;
|
|
}
|
|
/* Determine if alpha need to increase or decrease */
|
|
if (color.w < alpha_min)
|
|
{
|
|
rise = true;
|
|
}
|
|
else if (color.w > alpha_max)
|
|
{
|
|
rise = false;
|
|
}
|
|
|
|
return color;
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::scene_pipeline_divide(std::vector<SceneNode> const &scene_node)
|
|
* @brief Spliting main scene into two separate.
|
|
* @details This operation is required to use same "draw_from_scene" function to draw models that are using different
|
|
* pipelines (baseline and tessellation)
|
|
*/
|
|
void ExtendedDynamicState2::scene_pipeline_divide(std::vector<SceneNode> const &scene_node)
|
|
{
|
|
/* Divide main scene to two (baseline and tessellation) */
|
|
for (int i = 0; i < scene_node.size(); ++i)
|
|
{
|
|
if (scene_node[i].name == "Geosphere")
|
|
{
|
|
scene_elements_tess.push_back(scene_node[i]);
|
|
}
|
|
else
|
|
{
|
|
scene_elements_baseline.push_back(scene_node[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::draw_from_scene(VkCommandBuffer command_buffer, std::vector<SceneNode> const &scene_node)
|
|
* @brief Drawing all objects included to scene that is passed as argument of this function
|
|
*/
|
|
void ExtendedDynamicState2::draw_from_scene(VkCommandBuffer command_buffer, std::vector<SceneNode> const &scene_node)
|
|
{
|
|
for (int i = 0; i < scene_node.size(); ++i)
|
|
{
|
|
const auto &vertex_buffer_pos = scene_node[i].sub_mesh->vertex_buffers.at("position");
|
|
const auto &vertex_buffer_normal = scene_node[i].sub_mesh->vertex_buffers.at("normal");
|
|
auto &index_buffer = scene_node[i].sub_mesh->index_buffer;
|
|
|
|
if (scene_node[i].name != "Geosphere")
|
|
{
|
|
vkCmdSetDepthBiasEnableEXT(command_buffer, gui_settings.objects[i].depth_bias);
|
|
vkCmdSetRasterizerDiscardEnableEXT(command_buffer, gui_settings.objects[i].rasterizer_discard);
|
|
}
|
|
|
|
/* Pass data for the current node via push commands */
|
|
auto node_material = dynamic_cast<const vkb::sg::PBRMaterial *>(scene_node[i].sub_mesh->get_material());
|
|
push_const_block.model_matrix = scene_node[i].node->get_transform().get_world_matrix();
|
|
if (gui_settings.selection_active && i == gui_settings.selected_obj)
|
|
{
|
|
push_const_block.color = get_changed_alpha(node_material);
|
|
}
|
|
else
|
|
{
|
|
push_const_block.color = node_material->base_color_factor;
|
|
}
|
|
vkCmdPushConstants(command_buffer,
|
|
pipeline_layouts.baseline,
|
|
VK_SHADER_STAGE_VERTEX_BIT,
|
|
0,
|
|
sizeof(push_const_block),
|
|
&push_const_block);
|
|
|
|
VkDeviceSize offsets[1] = {0};
|
|
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffer_pos.get(), offsets);
|
|
vkCmdBindVertexBuffers(command_buffer, 1, 1, vertex_buffer_normal.get(), offsets);
|
|
vkCmdBindIndexBuffer(command_buffer, index_buffer->get_handle(), 0, scene_node[i].sub_mesh->index_type);
|
|
|
|
vkCmdDrawIndexed(command_buffer, scene_node[i].sub_mesh->vertex_indices, 1, 0, 0, 0);
|
|
}
|
|
vkCmdSetDepthBiasEnableEXT(command_buffer, VK_FALSE);
|
|
vkCmdSetRasterizerDiscardEnableEXT(command_buffer, VK_FALSE);
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::draw_created_model(VkCommandBuffer commandBuffer)
|
|
* @brief Drawing model created in function "model_data_creation"
|
|
*/
|
|
void ExtendedDynamicState2::draw_created_model(VkCommandBuffer commandBuffer)
|
|
{
|
|
VkDeviceSize offsets[1] = {0};
|
|
push_const_block.color = glm::vec4{0.5f, 1.0f, 1.0f, 1.0f};
|
|
vkCmdPushConstants(commandBuffer,
|
|
pipeline_layouts.baseline,
|
|
VK_SHADER_STAGE_VERTEX_BIT,
|
|
0,
|
|
sizeof(push_const_block),
|
|
&push_const_block);
|
|
vkCmdBindVertexBuffers(commandBuffer, 0, 1, cube.vertices_pos->get(), offsets);
|
|
vkCmdBindVertexBuffers(commandBuffer, 1, 1, cube.vertices_norm->get(), offsets);
|
|
vkCmdBindIndexBuffer(commandBuffer, cube.indices->get_handle(), 0, VK_INDEX_TYPE_UINT32);
|
|
vkCmdDrawIndexed(commandBuffer, cube.index_count, 1, 0, 0, 0);
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::model_data_creation()
|
|
* @brief Creating model (basic cube) vertex data
|
|
*/
|
|
void ExtendedDynamicState2::model_data_creation()
|
|
{
|
|
constexpr uint32_t vertex_count = 8;
|
|
|
|
std::array<glm::vec3, vertex_count> vertices_pos;
|
|
std::array<glm::vec3, vertex_count> vertices_norm;
|
|
|
|
vertices_pos[0] = {0.0f, 0.0f, 0.0f};
|
|
vertices_pos[1] = {1.0f, 0.0f, 0.0f};
|
|
vertices_pos[2] = {1.0f, 1.0f, 0.0f};
|
|
vertices_pos[3] = {0.0f, 1.0f, 0.0f};
|
|
vertices_pos[4] = {0.0f, 0.0f, 1.0f};
|
|
vertices_pos[5] = {1.0f, 0.0f, 1.0f};
|
|
vertices_pos[6] = {1.0f, 1.0f, 1.0f};
|
|
vertices_pos[7] = {0.0f, 1.0f, 1.0f};
|
|
|
|
/* Normalized normal vectors for each face of cube */
|
|
glm::vec3 Xp = {1.0, 0.0, 0.0};
|
|
glm::vec3 Xm = {-1.0, 0.0, 0.0};
|
|
glm::vec3 Yp = {0.0, 1.0, 0.0};
|
|
glm::vec3 Ym = {0.0, -1.0, 0.0};
|
|
glm::vec3 Zp = {0.0, 0.0, 1.0};
|
|
glm::vec3 Zm = {0.0, 0.0, -1.0};
|
|
|
|
/* Normalized normal vectors for each vertex (created by sum of corresponding faces) */
|
|
vertices_norm[0] = glm::normalize(Xm + Ym + Zm);
|
|
vertices_norm[1] = glm::normalize(Xp + Ym + Zm);
|
|
vertices_norm[2] = glm::normalize(Xp + Yp + Zm);
|
|
vertices_norm[3] = glm::normalize(Xm + Yp + Zm);
|
|
vertices_norm[4] = glm::normalize(Xm + Ym + Zp);
|
|
vertices_norm[5] = glm::normalize(Xp + Ym + Zp);
|
|
vertices_norm[6] = glm::normalize(Xp + Yp + Zp);
|
|
vertices_norm[7] = glm::normalize(Xm + Yp + Zp);
|
|
|
|
/* Scaling and position transform */
|
|
for (int i = 0; i < vertex_count; ++i)
|
|
{
|
|
vertices_pos[i] *= glm::vec3(4.0f, 4.0f, 4.0f);
|
|
vertices_pos[i] += glm::vec3(15.0f, 2.0f, 0.0f);
|
|
}
|
|
|
|
constexpr uint32_t index_count = 29;
|
|
uint32_t vertex_buffer_size = vertex_count * sizeof(glm::vec3);
|
|
uint32_t index_buffer_size = index_count * sizeof(uint32_t);
|
|
cube.index_count = index_count;
|
|
|
|
/* Array with vertices indexes for corresponding triangles */
|
|
std::array<uint32_t, index_count> indices{0, 4, 3, 7,
|
|
UINT32_MAX,
|
|
1, 0, 2, 3,
|
|
UINT32_MAX,
|
|
2, 6, 1, 5,
|
|
UINT32_MAX,
|
|
1, 5, 0, 4,
|
|
UINT32_MAX,
|
|
4, 5, 7, 6,
|
|
UINT32_MAX,
|
|
2, 3, 6, 7};
|
|
|
|
vkb::core::BufferC vertex_pos_staging = vkb::core::BufferC::create_staging_buffer(get_device(), vertices_pos);
|
|
vkb::core::BufferC vertex_norm_staging = vkb::core::BufferC::create_staging_buffer(get_device(), vertices_norm);
|
|
vkb::core::BufferC index_staging = vkb::core::BufferC::create_staging_buffer(get_device(), indices);
|
|
|
|
cube.vertices_pos = std::make_unique<vkb::core::BufferC>(get_device(),
|
|
vertex_buffer_size,
|
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
|
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
VMA_MEMORY_USAGE_GPU_ONLY);
|
|
|
|
cube.vertices_norm = std::make_unique<vkb::core::BufferC>(get_device(),
|
|
vertex_buffer_size,
|
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
|
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
VMA_MEMORY_USAGE_GPU_ONLY);
|
|
|
|
cube.indices = std::make_unique<vkb::core::BufferC>(get_device(),
|
|
index_buffer_size,
|
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
VMA_MEMORY_USAGE_GPU_ONLY);
|
|
|
|
/* Copy from staging buffers */
|
|
VkCommandBuffer copy_command = get_device().create_command_buffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
|
|
|
VkBufferCopy copy_region = {};
|
|
|
|
copy_region.size = vertex_buffer_size;
|
|
vkCmdCopyBuffer(
|
|
copy_command,
|
|
vertex_pos_staging.get_handle(),
|
|
cube.vertices_pos->get_handle(),
|
|
1,
|
|
©_region);
|
|
|
|
vkCmdCopyBuffer(
|
|
copy_command,
|
|
vertex_norm_staging.get_handle(),
|
|
cube.vertices_norm->get_handle(),
|
|
1,
|
|
©_region);
|
|
|
|
copy_region.size = index_buffer_size;
|
|
vkCmdCopyBuffer(
|
|
copy_command,
|
|
index_staging.get_handle(),
|
|
cube.indices->get_handle(),
|
|
1,
|
|
©_region);
|
|
|
|
get_device().flush_command_buffer(copy_command, queue, true);
|
|
}
|
|
|
|
/**
|
|
* @fn void ExtendedDynamicState2::cube_animation(float delta_time)
|
|
* @brief Changing position of one z-fighting cube (visualize negative phenomenon z-fighting)
|
|
*/
|
|
void ExtendedDynamicState2::cube_animation(float delta_time)
|
|
{
|
|
constexpr float tick_limit = 0.05f;
|
|
constexpr float delta = 0.05f;
|
|
constexpr float move_step = 0.0005f;
|
|
static float time_pass = 0.0f;
|
|
time_pass += delta_time;
|
|
static auto &transform =
|
|
std::ranges::find_if(scene_elements_baseline, [](SceneNode const &scene_node) { return scene_node.node->get_name() == "Cube_1"; })
|
|
->node->get_transform();
|
|
static auto translation = transform.get_translation();
|
|
static float difference = 0.0f;
|
|
static bool rising = true;
|
|
|
|
/* Checking if tick time passed away */
|
|
if (time_pass > tick_limit)
|
|
{
|
|
/* Determine direction of x axis */
|
|
if (difference < -delta)
|
|
{
|
|
rising = true;
|
|
}
|
|
else if (difference > delta)
|
|
{
|
|
rising = false;
|
|
}
|
|
|
|
/* Move object by step value */
|
|
if (rising == true)
|
|
{
|
|
translation.x += move_step;
|
|
difference += move_step;
|
|
}
|
|
else
|
|
{
|
|
translation.x -= move_step;
|
|
difference -= move_step;
|
|
}
|
|
time_pass = 0;
|
|
|
|
/* Write new position to object */
|
|
transform.set_translation(translation);
|
|
gui_settings.time_tick = true;
|
|
rebuild_command_buffers();
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<vkb::VulkanSampleC> create_extended_dynamic_state2()
|
|
{
|
|
return std::make_unique<ExtendedDynamicState2>();
|
|
}
|