diff options
Diffstat (limited to 'src/vk/graphics_pipeline_3d_skeletal.cpp')
-rw-r--r-- | src/vk/graphics_pipeline_3d_skeletal.cpp | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/src/vk/graphics_pipeline_3d_skeletal.cpp b/src/vk/graphics_pipeline_3d_skeletal.cpp new file mode 100644 index 0000000..3e1db66 --- /dev/null +++ b/src/vk/graphics_pipeline_3d_skeletal.cpp @@ -0,0 +1,657 @@ +/* + * Copyright 2022-2023 Frederico de Oliveira Linhares + * + * 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 "graphics_pipeline_3d.hpp" + +#include <array> +#include <stdexcept> + +#include "../core.hpp" +#include "core.hpp" +#include "image.hpp" +#include "skeletal_mesh_vertex.hpp" +#include "uniform_data_object.hpp" + +namespace +{ + +void +load_world_vert_uniform_buffer(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + try + { + self->ub_world_vert.reserve(cg_core.vk_swapchain->images_count); + for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + self->ub_world_vert.emplace_back( + cg_core.vk_device_with_swapchain, sizeof(VK::ODOWorld3D_Vert)); + } + catch(const std::exception& e) + { + throw CommandError{e.what()}; + } +} + +void +unload_world_vert_uniform_buffer(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + self->ub_world_vert.clear(); +} + +void +load_world_frag_uniform_buffer(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + try + { + self->ub_world_frag.reserve(cg_core.vk_swapchain->images_count); + for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + self->ub_world_frag.emplace_back( + cg_core.vk_device_with_swapchain, sizeof(VK::ODOWorld3D_Frag)); + } + catch(const std::exception& e) + { + throw CommandError{e.what()}; + } +} + +void +unload_world_frag_uniform_buffer(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + self->ub_world_frag.clear(); +} + +void +load_descriptor_pool(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + uint32_t uniform_buffers_count = + self->ub_world_vert.size() + self->ub_world_vert.size(); + + VkDescriptorPoolSize descriptor_pool_size{}; + descriptor_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_pool_size.descriptorCount = uniform_buffers_count; + + VkDescriptorPoolCreateInfo pool_info{}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.pNext = nullptr; + pool_info.flags = 0; + pool_info.maxSets = uniform_buffers_count; + pool_info.poolSizeCount = 1; + pool_info.pPoolSizes = &descriptor_pool_size; + + if(vkCreateDescriptorPool( + cg_core.vk_device_with_swapchain->device, &pool_info, nullptr, + &self->descriptor_pool) != VK_SUCCESS) + throw CommandError{"Failed to create a Vulkan descriptor pool."}; +} + +void +unload_descriptor_pool(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + vkDestroyDescriptorPool( + cg_core.vk_device_with_swapchain->device, self->descriptor_pool, + nullptr); +} + +void +load_descriptor_sets_world(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + std::vector<VkDescriptorSetLayout> layouts( + cg_core.vk_swapchain->images_count, + cg_core.vk_graphics_pipeline_3d_layout->descriptor_set_world); + + VkDescriptorSetAllocateInfo alloc_info{}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = self->descriptor_pool; + alloc_info.descriptorSetCount = layouts.size(); + alloc_info.pSetLayouts = layouts.data(); + + self->descriptor_sets_world.resize(layouts.size()); + if(vkAllocateDescriptorSets( + cg_core.vk_device_with_swapchain->device, &alloc_info, + self->descriptor_sets_world.data()) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan world descriptor set."}; +} + +void +load_resources_to_descriptor_sets(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + { + VkDescriptorBufferInfo world_vert_info{}; + world_vert_info.buffer = self->ub_world_vert[i].buffer; + world_vert_info.offset = 0; + world_vert_info.range = sizeof(VK::ODOWorld3D_Vert); + + VkDescriptorBufferInfo world_frag_info{}; + world_frag_info.buffer = self->ub_world_frag[i].buffer; + world_frag_info.offset = 0; + world_frag_info.range = sizeof(VK::ODOWorld3D_Frag); + + std::array<VkWriteDescriptorSet, 2> write_descriptors{}; + write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptors[0].dstSet = self->descriptor_sets_world[i]; + write_descriptors[0].dstBinding = 0; + write_descriptors[0].dstArrayElement = 0; + write_descriptors[0].descriptorCount = 1; + write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write_descriptors[0].pBufferInfo = &world_vert_info; + write_descriptors[0].pImageInfo = nullptr; + write_descriptors[0].pTexelBufferView = nullptr; + + write_descriptors[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptors[1].dstSet = self->descriptor_sets_world[i]; + write_descriptors[1].dstBinding = 1; + write_descriptors[1].dstArrayElement = 0; + write_descriptors[1].descriptorCount = 1; + write_descriptors[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write_descriptors[1].pBufferInfo = &world_frag_info; + write_descriptors[1].pImageInfo = nullptr; + write_descriptors[1].pTexelBufferView = nullptr; + + vkUpdateDescriptorSets( + cg_core.vk_device_with_swapchain->device, write_descriptors.size(), + write_descriptors.data(), 0, nullptr); + } +} + +void +load_depth_image(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + VkExtent3D extent3d{}; + extent3d.width = cg_core.display_width; + extent3d.height = cg_core.display_height; + extent3d.depth = 1; + + try + { + VK::Image::create( + cg_core.vk_device_with_swapchain, + &self->depth_image, + &self->depth_image_memory, + VK_FORMAT_D32_SFLOAT, + extent3d, + 1, + VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT + ); + } + catch(VK::Image::Error error) + { + std::string error_message{"Failed to create depth image → "}; + error_message += error.what(); + throw CommandError{error_message}; + } +} + +void +unload_depth_image(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + vkDestroyImage( + cg_core.vk_device_with_swapchain->device, self->depth_image, + nullptr); + vkFreeMemory( + cg_core.vk_device_with_swapchain->device, + self->depth_image_memory, nullptr); +} + +void +load_depth_image_view(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + try + { + VK::Image::create_view( + cg_core.vk_device_with_swapchain, &self->depth_image_view, + self->depth_image, + VK_FORMAT_D32_SFLOAT, VK_IMAGE_ASPECT_DEPTH_BIT); + } + catch(VK::Image::Error error) + { + std::string error_message{"Failed to create depth image view → "}; + error_message += error.what(); + throw CommandError{error_message}; + } +} + +void +unload_depth_image_view(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + vkDestroyImageView( + cg_core.vk_device_with_swapchain->device, self->depth_image_view, nullptr); +} + +void +load_framebuffer(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + self->swapchain_framebuffers.resize(cg_core.vk_swapchain->images_count); + for (auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + { + std::array<VkImageView, 2> attachments = { + cg_core.vk_swapchain->image_views[i], + self->depth_image_view + }; + + VkFramebufferCreateInfo framebuffer_info{}; + framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebuffer_info.renderPass = + cg_core.vk_graphics_pipeline_3d_layout->render_pass; + framebuffer_info.attachmentCount = attachments.size(); + framebuffer_info.pAttachments = attachments.data(); + framebuffer_info.width = cg_core.display_width; + framebuffer_info.height = cg_core.display_height; + + framebuffer_info.layers = 1; + + if(vkCreateFramebuffer( + cg_core.vk_device_with_swapchain->device, &framebuffer_info, nullptr, + &self->swapchain_framebuffers[i]) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan Framebuffer."}; + } +} + +void +unload_framebuffer(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + for(auto framebuffer: self->swapchain_framebuffers) + vkDestroyFramebuffer( + cg_core.vk_device_with_swapchain->device, framebuffer, nullptr); +} + +void +load_pipeline(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + VkPipelineShaderStageCreateInfo vert_shader_stage_info = {}; + vert_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vert_shader_stage_info.pNext = nullptr; + vert_shader_stage_info.flags = 0; + vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; + vert_shader_stage_info.module = + cg_core.vk_device_with_swapchain->vert3d_shader_module; + vert_shader_stage_info.pName = "main"; + vert_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo frag_shader_stage_info = {}; + frag_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + frag_shader_stage_info.pNext = nullptr; + frag_shader_stage_info.flags = 0; + frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + frag_shader_stage_info.module = + cg_core.vk_device_with_swapchain->frag3d_shader_module; + frag_shader_stage_info.pName = "main"; + frag_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo shader_stages[] = { + vert_shader_stage_info, + frag_shader_stage_info + }; + + VkVertexInputBindingDescription vertex_input_binding{}; + vertex_input_binding.binding = 0; + vertex_input_binding.stride = sizeof(VK::SkeletalMeshVertex); + vertex_input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + std::array<VkVertexInputAttributeDescription, 5> vertex_attribute{}; + // Position. + vertex_attribute[0].location = 0; + vertex_attribute[0].binding = 0; + vertex_attribute[0].format = VK_FORMAT_R32G32B32_SFLOAT; + vertex_attribute[0].offset = offsetof(VK::SkeletalMeshVertex, position); + // Normal. + vertex_attribute[1].location = 1; + vertex_attribute[1].binding = 0; + vertex_attribute[1].format = VK_FORMAT_R32G32B32_SFLOAT; + vertex_attribute[1].offset = offsetof(VK::SkeletalMeshVertex, normal); + // Texture coordinate. + vertex_attribute[2].location = 2; + vertex_attribute[2].binding = 0; + vertex_attribute[2].format = VK_FORMAT_R32G32_SFLOAT; + vertex_attribute[2].offset = offsetof(VK::SkeletalMeshVertex, texture_coord); + // Bones ids. + vertex_attribute[3].location = 3; + vertex_attribute[3].binding = 0; + vertex_attribute[3].format = VK_FORMAT_R32G32B32A32_SINT; + vertex_attribute[3].offset = offsetof(VK::SkeletalMeshVertex, bone_ids); + // Bones weights. + vertex_attribute[4].location = 4; + vertex_attribute[4].binding = 0; + vertex_attribute[4].format = VK_FORMAT_R32G32B32A32_SFLOAT; + vertex_attribute[4].offset = offsetof(VK::SkeletalMeshVertex, bone_weights); + + VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; + vertex_input_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_input_info.pNext = nullptr; + vertex_input_info.flags = 0; + vertex_input_info.vertexBindingDescriptionCount = 1; + vertex_input_info.pVertexBindingDescriptions = &vertex_input_binding; + vertex_input_info.vertexAttributeDescriptionCount = + static_cast<uint32_t>(vertex_attribute.size()); + vertex_input_info.pVertexAttributeDescriptions = vertex_attribute.data(); + + VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; + input_assembly.sType = + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + input_assembly.pNext = nullptr; + input_assembly.flags = 0; + input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + input_assembly.primitiveRestartEnable = VK_FALSE; + + VkViewport viewport = {}; + viewport.x = 0; + viewport.y = 0; + viewport.width = cg_core.display_width; + viewport.height = cg_core.display_height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = {}; + scissor.offset = {0, 0}; + scissor.extent = {cg_core.display_width, cg_core.display_height}; + + VkPipelineViewportStateCreateInfo viewport_state = {}; + viewport_state.sType = + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_state.pNext = nullptr; + viewport_state.flags = 0; + viewport_state.viewportCount = 1; + viewport_state.pViewports = &viewport; + viewport_state.scissorCount = 1; + viewport_state.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.pNext = nullptr; + rasterizer.flags = 0; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.cullMode = VK_CULL_MODE_NONE; + rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + rasterizer.depthBiasConstantFactor = 0.0f; + rasterizer.depthBiasClamp = 0.0f; + rasterizer.depthBiasSlopeFactor = 0.0f; + rasterizer.lineWidth = 1.0f; + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.minSampleShading = 1.0f; + multisampling.pSampleMask = nullptr; + multisampling.alphaToCoverageEnable = VK_FALSE; + multisampling.alphaToOneEnable = VK_FALSE; + + VkPipelineDepthStencilStateCreateInfo depth_stencil = {}; + depth_stencil.sType = + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depth_stencil.depthTestEnable = VK_TRUE; + depth_stencil.depthWriteEnable = VK_TRUE; + depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; + depth_stencil.depthBoundsTestEnable = VK_FALSE; + depth_stencil.minDepthBounds = 0.0f; + depth_stencil.maxDepthBounds = 1.0f; + depth_stencil.stencilTestEnable = VK_FALSE; + depth_stencil.front = {}; + depth_stencil.back = {}; + + VkPipelineColorBlendAttachmentState color_blend_attachment = {}; + color_blend_attachment.blendEnable = VK_FALSE; + color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo color_blending = {}; + color_blending.sType = + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + color_blending.pNext = nullptr; + color_blending.flags = 0; + color_blending.logicOpEnable = VK_FALSE; + color_blending.logicOp = VK_LOGIC_OP_COPY; + color_blending.attachmentCount = 1; + color_blending.pAttachments = &color_blend_attachment; + color_blending.blendConstants[0] = 0.0f; + color_blending.blendConstants[1] = 0.0f; + color_blending.blendConstants[2] = 0.0f; + color_blending.blendConstants[3] = 0.0f; + + VkDynamicState dynamic_states[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_LINE_WIDTH + }; + + VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; + dynamic_state_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state_info.dynamicStateCount = 2; + dynamic_state_info.pDynamicStates = dynamic_states; + + VkGraphicsPipelineCreateInfo pipeline_info{}; + pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipeline_info.pNext = nullptr; + pipeline_info.flags = 0; + pipeline_info.stageCount = 2; + pipeline_info.pStages = shader_stages; + pipeline_info.pVertexInputState = &vertex_input_info; + pipeline_info.pInputAssemblyState = &input_assembly; + pipeline_info.pTessellationState = nullptr; + pipeline_info.pViewportState = &viewport_state; + pipeline_info.pRasterizationState = &rasterizer; + pipeline_info.pMultisampleState = &multisampling; + pipeline_info.pDepthStencilState = &depth_stencil; + pipeline_info.pColorBlendState = &color_blending; + pipeline_info.pDynamicState = &dynamic_state_info; + pipeline_info.layout = cg_core.vk_graphics_pipeline_3d_layout->pipeline; + pipeline_info.renderPass = + cg_core.vk_graphics_pipeline_3d_layout->render_pass; + pipeline_info.subpass = 0; + pipeline_info.basePipelineHandle = VK_NULL_HANDLE; + pipeline_info.basePipelineIndex = -1; + + if(vkCreateGraphicsPipelines( + cg_core.vk_device_with_swapchain->device, VK_NULL_HANDLE, 1, + &pipeline_info, nullptr, &self->graphic_pipeline) + != VK_SUCCESS) + throw CommandError{"Failed to create graphics pipeline."}; +} + +void +unload_pipeline(void *obj) +{ + auto self = static_cast<VK::GraphicsPipeline3DSkeletal*>(obj); + + vkDestroyPipeline( + cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr); +} + +const CommandChain loader{ + {&load_world_vert_uniform_buffer, &unload_world_vert_uniform_buffer}, + {&load_world_frag_uniform_buffer, &unload_world_frag_uniform_buffer}, + {&load_descriptor_pool, &unload_descriptor_pool}, + // By destroying the pool the sets are also destroyed. + {&load_descriptor_sets_world, nullptr}, + {&load_resources_to_descriptor_sets, nullptr}, + {&load_depth_image, &unload_depth_image}, + {&load_depth_image_view, &unload_depth_image_view}, + {&load_framebuffer, &unload_framebuffer}, + {&load_pipeline, &unload_pipeline} +}; + +} + +namespace VK +{ + +GraphicsPipeline3DSkeletal::GraphicsPipeline3DSkeletal() +{ + loader.execute(this); +} + +GraphicsPipeline3DSkeletal::~GraphicsPipeline3DSkeletal() +{ + loader.revert(this); +} + +void +GraphicsPipeline3DSkeletal::draw( + std::shared_ptr<View3D> view, const VkCommandBuffer draw_command_buffer, + const size_t current_frame, const uint32_t image_index) +{ + { // Set viewport + VkViewport vk_viewport{}; + vk_viewport.x = view->region.x; + vk_viewport.y = view->region.y; + vk_viewport.width = view->region.z; + vk_viewport.height = view->region.w; + vk_viewport.minDepth = 0.0f; + vk_viewport.maxDepth = 1.0f; + vkCmdSetViewport(draw_command_buffer, 0, 1, &vk_viewport); + + VkRect2D vk_scissor{}; + vk_scissor.offset.x = static_cast<int32_t>(view->region.x); + vk_scissor.offset.y = static_cast<int32_t>(view->region.y); + vk_scissor.extent.width = static_cast<uint32_t>(view->region.z); + vk_scissor.extent.height = static_cast<uint32_t>(view->region.w); + vkCmdSetScissor(draw_command_buffer, 0, 1, &vk_scissor); + } + + // Draw models + for(auto& [skeletal_mesh, instances]: + cg_core.vk_renderer->skeletal_models_to_draw[current_frame]) + { + VkBuffer vertex_buffers[]{skeletal_mesh->vertex_buffer->buffer}; + VkDeviceSize offsets[]{0}; + + vkCmdBindPipeline( + draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + this->graphic_pipeline); + vkCmdBindVertexBuffers( + draw_command_buffer, 0, 1, vertex_buffers, offsets); + vkCmdBindIndexBuffer( + draw_command_buffer, skeletal_mesh->index_buffer->buffer, 0, + VK_INDEX_TYPE_UINT32); + + for(auto &instance: instances) + { // Object matrix. + glm::mat4 base_matrix{1.0f}; + base_matrix = glm::translate(base_matrix, *instance->position); + base_matrix = glm::rotate( + base_matrix, instance->rotation->x, glm::vec3{1.0, 0.0, 0.0}); + base_matrix = glm::rotate( + base_matrix, instance->rotation->y, glm::vec3{0.0, 1.0, 0.0}); + base_matrix = glm::rotate( + base_matrix, instance->rotation->z, glm::vec3{0.0, 0.0, 1.0}); + + std::array<VkDescriptorSet, 3> vk_descriptor_sets{ + this->descriptor_sets_world[image_index], + view->descriptor_sets_3d[image_index], + instance->descriptor_sets[image_index]}; + + vkCmdBindDescriptorSets( + draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + cg_core.vk_graphics_pipeline_3d_layout->pipeline, 0, + vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr); + + vkCmdDrawIndexed( + draw_command_buffer, skeletal_mesh->index_count, 1, 0, 0, 0); + + VK::ODOSkeletalModel odo_skeletal_model{}; + instance->tick(cg_core.delta_time); + odo_skeletal_model.base_matrix = base_matrix; + std::copy(instance->bone_transforms.begin(), + instance->bone_transforms.end(), + odo_skeletal_model.bone_matrices); + instance->uniform_buffers[image_index].copy_data(&odo_skeletal_model); + } + } + + { // Update view uniform buffers + VK::ODOView3D ubo_view_3d{}; + + // View matrix. + ubo_view_3d.view = glm::mat4{1.0f}; + ubo_view_3d.view = glm::translate( + ubo_view_3d.view, *view->camera_position); + ubo_view_3d.view = glm::rotate( + ubo_view_3d.view, view->camera_rotation->y, glm::vec3{0.0, 1.0, 0.0}); + ubo_view_3d.view = glm::rotate( + ubo_view_3d.view, view->camera_rotation->x, glm::vec3{1.0, 0.0, 0.0}); + ubo_view_3d.view = glm::rotate( + ubo_view_3d.view, view->camera_rotation->z, glm::vec3{0.0, 0.0, 1.0}); + ubo_view_3d.view = glm::inverse(ubo_view_3d.view); + + // Projection matrix. + ubo_view_3d.proj = glm::perspective( + glm::radians(45.0f), + view->region.z / view->region.w, + 0.1f, 100.0f); + + view->ub_3d[image_index].copy_data(&ubo_view_3d); + } + + // TODO: Do not update this for each view. All views use the same data. + { // Update world uniform buffer + ODOWorld3D_Vert ubo_world_3d_vert{}; + ubo_world_3d_vert.ambient_light_color = glm::vec4{0.25, 0.25, 0.25, 1.0}; + this->ub_world_vert[image_index].copy_data(&ubo_world_3d_vert); + + ODOWorld3D_Frag ubo_world_3d_frag{}; + ubo_world_3d_frag.directional_light_direction = + glm::vec3{-0.57735, 0.57735, -0.57735}; + ubo_world_3d_frag.directional_light_color = glm::vec4{0.8, 0.8, 0.8, 1.0}; + this->ub_world_frag[image_index].copy_data(&ubo_world_3d_frag); + } +} + +} |