【学習用】Vulkan OpenCV VideoCapture

もう生成AIちゃんはハルシネーション起こしてばかりいないでちゃんと学習して!
// main.cpp #include <vulkan/vulkan.h> #include <GLFW/glfw3.h> #include <opencv2/opencv.hpp> #include <iostream> #include <vector> #include <stdexcept> #include <fstream> #include <cstring> #include <array> //#define ENABLE_VALIDATION_LAYERS // バリデーションレイヤーを使用する場合は有効にする // ---------- グローバル変数 ---------- GLFWwindow* window = nullptr; VkInstance instance = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VkDevice device = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE; VkSwapchainKHR swapChain = VK_NULL_HANDLE; VkQueue graphicsQueue = VK_NULL_HANDLE; VkCommandPool commandPool = VK_NULL_HANDLE; std::vector<VkCommandBuffer> commandBuffers; std::vector<VkFramebuffer> swapChainFramebuffers; VkRenderPass renderPass = VK_NULL_HANDLE; VkExtent2D swapChainExtent = {800, 600}; std::vector<VkImage> swapChainImages; std::vector<VkImageView> swapChainImageViews; uint32_t graphicsQueueFamilyIndex = 0; // テクスチャ用変数 VkImage textureImage = VK_NULL_HANDLE; VkDeviceMemory textureImageMemory = VK_NULL_HANDLE; VkImageView textureImageView = VK_NULL_HANDLE; VkSampler textureSampler = VK_NULL_HANDLE; // ---- パイプライン関連のグローバル変数 ---- VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE; VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; VkPipeline graphicsPipeline = VK_NULL_HANDLE; VkBuffer vertexBuffer = VK_NULL_HANDLE; VkDeviceMemory vertexBufferMemory = VK_NULL_HANDLE; VkBuffer indexBuffer = VK_NULL_HANDLE; VkDeviceMemory indexBufferMemory = VK_NULL_HANDLE; VkDescriptorPool descriptorPool = VK_NULL_HANDLE; VkDescriptorSet descriptorSet = VK_NULL_HANDLE; // ---- 頂点データ(位置とUV) ---- struct Vertex { float pos[2]; float uv[2]; }; std::vector<Vertex> vertices = { { {-1.0f, -1.0f}, {0.0f, 1.0f} }, { { 1.0f, -1.0f}, {1.0f, 1.0f} }, { { 1.0f, 1.0f}, {1.0f, 0.0f} }, { {-1.0f, 1.0f}, {0.0f, 0.0f} } }; std::vector<uint16_t> indices = { 0, 1, 2, 2, 3, 0 }; // ---------- forward declarations ---------- void cleanup(); bool initVulkanInstance(); bool initVulkanDevice(); bool createSwapChain(VkSurfaceKHR surface); bool createSwapChainImageViews(); bool createRenderPass(); bool createFramebuffers(); bool createCommandPool(); bool createCommandBuffers(); void drawFrame(); uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory); VkCommandBuffer beginSingleTimeCommands(); void endSingleTimeCommands(VkCommandBuffer commandBuffer); void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout); void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height); void createTextureImage(int width, int height); void updateVulkanTexture(void* pixels, int width, int height); // ---- シェーダーファイルを読み込むヘルパー ---- std::vector<char> readFile(const std::string &filename) { std::ifstream file(filename, std::ios::ate | std::ios::binary); if (!file.is_open()) { throw std::runtime_error("failed to open file: " + filename); } size_t fileSize = (size_t) file.tellg(); std::vector<char> buffer(fileSize); file.seekg(0); file.read(buffer.data(), fileSize); file.close(); return buffer; } // ---- シェーダーモジュール作成 ---- VkShaderModule createShaderModule(const std::vector<char>& code) { VkShaderModuleCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data()); VkShaderModule shaderModule; if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } return shaderModule; } // ---- DescriptorSetLayoutの作成 ---- void createDescriptorSetLayout() { VkDescriptorSetLayoutBinding samplerLayoutBinding{}; samplerLayoutBinding.binding = 0; samplerLayoutBinding.descriptorCount = 1; samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; samplerLayoutBinding.pImmutableSamplers = nullptr; samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; VkDescriptorSetLayoutCreateInfo layoutInfo{}; layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; layoutInfo.bindingCount = 1; layoutInfo.pBindings = &samplerLayoutBinding; if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor set layout!"); } } // ---- グラフィックスパイプラインの作成 ---- void createGraphicsPipeline() { // シェーダーの読み込み(-S オプションでシェーダーステージを明示するか、ファイル名に .vert/.frag を使用) auto vertShaderCode = readFile("vert.spv"); auto fragShaderCode = readFile("frag.spv"); VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo{}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; vertShaderStageInfo.module = vertShaderModule; vertShaderStageInfo.pName = "main"; VkPipelineShaderStageCreateInfo fragShaderStageInfo{}; fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; fragShaderStageInfo.module = fragShaderModule; fragShaderStageInfo.pName = "main"; VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo }; // 頂点入力設定 VkVertexInputBindingDescription bindingDescription{}; bindingDescription.binding = 0; bindingDescription.stride = sizeof(Vertex); bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; std::array<VkVertexInputAttributeDescription, 2> attributeDescriptions{}; attributeDescriptions[0].binding = 0; attributeDescriptions[0].location = 0; attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT; attributeDescriptions[0].offset = offsetof(Vertex, pos); attributeDescriptions[1].binding = 0; attributeDescriptions[1].location = 1; attributeDescriptions[1].format = VK_FORMAT_R32G32_SFLOAT; attributeDescriptions[1].offset = offsetof(Vertex, uv); VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertexInputInfo.vertexBindingDescriptionCount = 1; vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size()); vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); // 入力アセンブリ設定 VkPipelineInputAssemblyStateCreateInfo inputAssembly{}; inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; inputAssembly.primitiveRestartEnable = VK_FALSE; // ビューポートとシザー設定 VkViewport viewport{}; viewport.x = 0.0f; viewport.y = 0.0f; viewport.width = static_cast<float>(swapChainExtent.width); viewport.height = static_cast<float>(swapChainExtent.height); viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; VkRect2D scissor{{0, 0}, swapChainExtent}; VkPipelineViewportStateCreateInfo viewportState{}; viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; viewportState.viewportCount = 1; viewportState.pViewports = &viewport; viewportState.scissorCount = 1; viewportState.pScissors = &scissor; // ラスターライザ設定 VkPipelineRasterizationStateCreateInfo rasterizer{}; rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rasterizer.depthClampEnable = VK_FALSE; rasterizer.rasterizerDiscardEnable = VK_FALSE; rasterizer.polygonMode = VK_POLYGON_MODE_FILL; rasterizer.lineWidth = 1.0f; rasterizer.cullMode = VK_CULL_MODE_NONE; // カリング無効 rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; rasterizer.depthBiasEnable = VK_FALSE; // マルチサンプリング VkPipelineMultisampleStateCreateInfo multisampling{}; multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling.sampleShadingEnable = VK_FALSE; multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; // カラーブレンド設定 VkPipelineColorBlendAttachmentState colorBlendAttachment{}; colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; colorBlendAttachment.blendEnable = VK_FALSE; VkPipelineColorBlendStateCreateInfo colorBlending{}; colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; colorBlending.logicOpEnable = VK_FALSE; colorBlending.attachmentCount = 1; colorBlending.pAttachments = &colorBlendAttachment; // パイプラインレイアウト(descriptor set layout を利用) VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 1; pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create pipeline layout!"); } // グラフィックスパイプライン作成 VkGraphicsPipelineCreateInfo pipelineInfo{}; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipelineInfo.stageCount = 2; pipelineInfo.pStages = shaderStages; pipelineInfo.pVertexInputState = &vertexInputInfo; pipelineInfo.pInputAssemblyState = &inputAssembly; pipelineInfo.pViewportState = &viewportState; pipelineInfo.pRasterizationState = &rasterizer; pipelineInfo.pMultisampleState = &multisampling; pipelineInfo.pColorBlendState = &colorBlending; pipelineInfo.layout = pipelineLayout; pipelineInfo.renderPass = renderPass; pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) { throw std::runtime_error("failed to create graphics pipeline!"); } // 不要になったシェーダーモジュールの破棄 vkDestroyShaderModule(device, vertShaderModule, nullptr); vkDestroyShaderModule(device, fragShaderModule, nullptr); } // ---- 頂点バッファ, インデックスバッファの作成 ---- void createVertexBuffer() { VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); createBuffer(bufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, vertexBuffer, vertexBufferMemory); void* data; vkMapMemory(device, vertexBufferMemory, 0, bufferSize, 0, &data); memcpy(data, vertices.data(), (size_t)bufferSize); vkUnmapMemory(device, vertexBufferMemory); } void createIndexBuffer() { VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size(); createBuffer(bufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, indexBuffer, indexBufferMemory); void* data; vkMapMemory(device, indexBufferMemory, 0, bufferSize, 0, &data); memcpy(data, indices.data(), (size_t)bufferSize); vkUnmapMemory(device, indexBufferMemory); } // ---- Descriptor Pool と Descriptor Set の作成 ---- void createDescriptorPool() { VkDescriptorPoolSize poolSize{}; poolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; poolSize.descriptorCount = 1; VkDescriptorPoolCreateInfo poolInfo{}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; poolInfo.poolSizeCount = 1; poolInfo.pPoolSizes = &poolSize; poolInfo.maxSets = 1; if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor pool!"); } } void createDescriptorSet() { VkDescriptorSetAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; allocInfo.descriptorPool = descriptorPool; allocInfo.descriptorSetCount = 1; allocInfo.pSetLayouts = &descriptorSetLayout; if (vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet) != VK_SUCCESS) { throw std::runtime_error("failed to allocate descriptor set!"); } VkDescriptorImageInfo imageInfo{}; imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo.imageView = textureImageView; imageInfo.sampler = textureSampler; VkWriteDescriptorSet descriptorWrite{}; descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrite.dstSet = descriptorSet; descriptorWrite.dstBinding = 0; descriptorWrite.dstArrayElement = 0; descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptorWrite.descriptorCount = 1; descriptorWrite.pImageInfo = &imageInfo; vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr); } // ---- テクスチャ用 ImageView, Sampler の作成 ---- void createTextureImageView() { VkImageViewCreateInfo viewInfo{}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = textureImage; viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; viewInfo.format = VK_FORMAT_R8G8B8A8_UNORM; viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; viewInfo.subresourceRange.baseMipLevel = 0; viewInfo.subresourceRange.levelCount = 1; viewInfo.subresourceRange.baseArrayLayer = 0; viewInfo.subresourceRange.layerCount = 1; if (vkCreateImageView(device, &viewInfo, nullptr, &textureImageView) != VK_SUCCESS) { throw std::runtime_error("failed to create texture image view!"); } } void createTextureSampler() { VkSamplerCreateInfo samplerInfo{}; samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; samplerInfo.magFilter = VK_FILTER_LINEAR; samplerInfo.minFilter = VK_FILTER_LINEAR; samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerInfo.anisotropyEnable = VK_FALSE; samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; samplerInfo.unnormalizedCoordinates = VK_FALSE; samplerInfo.compareEnable = VK_FALSE; samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; if (vkCreateSampler(device, &samplerInfo, nullptr, &textureSampler) != VK_SUCCESS) { throw std::runtime_error("failed to create texture sampler!"); } } // ---- Vulkan インスタンスの初期化 ---- bool initVulkanInstance() { // 利用可能なレイヤーを列挙 uint32_t layerCount; vkEnumerateInstanceLayerProperties(&layerCount, nullptr); std::vector<VkLayerProperties> availableLayers(layerCount); vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); std::cout << "Available Vulkan layers:\n"; for (const auto& layer : availableLayers) { std::cout << "\t" << layer.layerName << "\n"; } #ifdef ENABLE_VALIDATION_LAYERS const std::vector<const char*> validationLayers = { "VK_LAYER_KHRONOS_validation" }; // レイヤーチェック for (const char* layerName : validationLayers) { bool layerFound = false; for (const auto& layerProperties : availableLayers) { if (strcmp(layerName, layerProperties.layerName) == 0) { layerFound = true; break; } } if (!layerFound) { throw std::runtime_error(std::string("Validation layer not found: ") + layerName); } } #else const std::vector<const char*> validationLayers = {}; #endif uint32_t glfwExtensionCount = 0; const char** glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); if (!glfwExtensions) { std::cerr << "Failed to get required GLFW Vulkan extensions.\n"; return false; } std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount); #ifdef ENABLE_VALIDATION_LAYERS extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); #endif VkApplicationInfo appInfo{}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pApplicationName = "Vulkan OpenCV Sample"; appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); appInfo.pEngineName = "No Engine"; appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); appInfo.apiVersion = VK_API_VERSION_1_0; VkInstanceCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.pApplicationInfo = &appInfo; createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); VkResult result = vkCreateInstance(&createInfo, nullptr, &instance); if (result != VK_SUCCESS) { std::cerr << "Failed to create Vulkan instance: " << result << "\n"; return false; } return true; } // ---- 物理デバイス、論理デバイスの初期化 ---- bool initVulkanDevice() { uint32_t deviceCount = 0; vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); if (deviceCount == 0) { std::cerr << "Failed to find a GPU with Vulkan support.\n"; return false; } std::vector<VkPhysicalDevice> devices(deviceCount); vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); physicalDevice = devices[0]; uint32_t queueFamilyCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr); if (queueFamilyCount == 0) { std::cerr << "No queue families found.\n"; return false; } std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount); vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies.data()); bool found = false; for (uint32_t i = 0; i < queueFamilyCount; i++) { if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { graphicsQueueFamilyIndex = i; found = true; break; } } if (!found) { std::cerr << "Failed to find a graphics queue family.\n"; return false; } float queuePriority = 1.0f; VkDeviceQueueCreateInfo queueCreateInfo{}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = graphicsQueueFamilyIndex; queueCreateInfo.queueCount = 1; queueCreateInfo.pQueuePriorities = &queuePriority; std::vector<const char*> deviceExtensions = { "VK_KHR_swapchain" }; VkDeviceCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.queueCreateInfoCount = 1; createInfo.pQueueCreateInfos = &queueCreateInfo; createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); VkResult resultDev = vkCreateDevice(physicalDevice, &createInfo, nullptr, &device); if (resultDev != VK_SUCCESS) { std::cerr << "Failed to create logical device: " << resultDev << "\n"; return false; } vkGetDeviceQueue(device, graphicsQueueFamilyIndex, 0, &graphicsQueue); return true; } // ---- スワップチェーンの作成 ---- bool createSwapChain(VkSurfaceKHR surface) { VkSwapchainCreateInfoKHR swapChainCreateInfo{}; swapChainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapChainCreateInfo.surface = surface; swapChainCreateInfo.minImageCount = 2; swapChainCreateInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; swapChainCreateInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; swapChainCreateInfo.imageExtent = swapChainExtent; swapChainCreateInfo.imageArrayLayers = 1; swapChainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapChainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; swapChainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapChainCreateInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; swapChainCreateInfo.clipped = VK_TRUE; swapChainCreateInfo.oldSwapchain = VK_NULL_HANDLE; VkResult result = vkCreateSwapchainKHR(device, &swapChainCreateInfo, nullptr, &swapChain); if (result != VK_SUCCESS) { std::cerr << "Failed to create swap chain: " << result << "\n"; return false; } uint32_t imageCount = 0; vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); if (imageCount == 0) { std::cerr << "No swap chain images found.\n"; return false; } swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); return true; } // ---- スワップチェーンイメージビューの作成 ---- bool createSwapChainImageViews() { swapChainImageViews.resize(swapChainImages.size()); for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo viewInfo{}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = swapChainImages[i]; viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; viewInfo.format = VK_FORMAT_B8G8R8A8_SRGB; viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; viewInfo.subresourceRange.baseMipLevel = 0; viewInfo.subresourceRange.levelCount = 1; viewInfo.subresourceRange.baseArrayLayer = 0; viewInfo.subresourceRange.layerCount = 1; if (vkCreateImageView(device, &viewInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) { std::cerr << "Failed to create image view for swap chain image " << i << "\n"; return false; } } return true; } // ---- レンダーパスの作成 ---- bool createRenderPass() { VkAttachmentDescription colorAttachment{}; colorAttachment.format = VK_FORMAT_B8G8R8A8_SRGB; colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; VkAttachmentReference colorAttachmentRef{}; colorAttachmentRef.attachment = 0; colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkSubpassDescription subpass{}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &colorAttachmentRef; VkRenderPassCreateInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; renderPassInfo.attachmentCount = 1; renderPassInfo.pAttachments = &colorAttachment; renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) { std::cerr << "Failed to create render pass.\n"; return false; } return true; } // ---- フレームバッファの作成 ---- bool createFramebuffers() { swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { VkImageView attachments[] = { swapChainImageViews[i] }; VkFramebufferCreateInfo framebufferInfo{}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = renderPass; framebufferInfo.attachmentCount = 1; framebufferInfo.pAttachments = attachments; framebufferInfo.width = swapChainExtent.width; framebufferInfo.height = swapChainExtent.height; framebufferInfo.layers = 1; if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) { std::cerr << "Failed to create framebuffer " << i << "\n"; return false; } } return true; } // ---- コマンドプールの作成 ---- bool createCommandPool() { VkCommandPoolCreateInfo poolInfo{}; poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = graphicsQueueFamilyIndex; if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) { std::cerr << "Failed to create command pool.\n"; return false; } return true; } // ---- コマンドバッファの作成 ---- bool createCommandBuffers() { size_t commandBufferCount = swapChainFramebuffers.size(); if (commandBufferCount == 0) { std::cerr << "No framebuffers available to create command buffers.\n"; return false; } commandBuffers.resize(commandBufferCount); VkCommandBufferAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.commandPool = commandPool; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.commandBufferCount = static_cast<uint32_t>(commandBufferCount); if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) { std::cerr << "Failed to allocate command buffers.\n"; return false; } for (size_t i = 0; i < commandBufferCount; ++i) { VkCommandBufferBeginInfo beginInfo{}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; if (vkBeginCommandBuffer(commandBuffers[i], &beginInfo) != VK_SUCCESS) { std::cerr << "Failed to begin recording command buffer " << i << "\n"; return false; } VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; VkRenderPassBeginInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassInfo.renderPass = renderPass; renderPassInfo.framebuffer = swapChainFramebuffers[i]; renderPassInfo.renderArea.offset = {0, 0}; renderPassInfo.renderArea.extent = swapChainExtent; renderPassInfo.clearValueCount = 1; renderPassInfo.pClearValues = &clearColor; vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline); VkBuffer vertexBuffers[] = { vertexBuffer }; VkDeviceSize offsets[] = { 0 }; vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets); vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer, 0, VK_INDEX_TYPE_UINT16); vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0); vkCmdEndRenderPass(commandBuffers[i]); if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS) { std::cerr << "Failed to record command buffer " << i << "\n"; return false; } } return true; } // ---- 描画 ---- void drawFrame() { uint32_t imageIndex; VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, VK_NULL_HANDLE, VK_NULL_HANDLE, &imageIndex); if (result != VK_SUCCESS) { std::cerr << "Failed to acquire swap chain image: " << result << "\n"; return; } VkSubmitInfo submitInfo{}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &commandBuffers[imageIndex]; if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) { std::cerr << "Failed to submit draw command buffer.\n"; return; } VkPresentInfoKHR presentInfo{}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.waitSemaphoreCount = 0; presentInfo.pWaitSemaphores = nullptr; presentInfo.swapchainCount = 1; presentInfo.pSwapchains = &swapChain; presentInfo.pImageIndices = &imageIndex; vkQueuePresentKHR(graphicsQueue, &presentInfo); vkQueueWaitIdle(graphicsQueue); } // ---- ヘルパー関数群 ---- uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) { VkPhysicalDeviceMemoryProperties memProperties; vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties); for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) { if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) { return i; } } throw std::runtime_error("Failed to find suitable memory type!"); } void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory) { VkBufferCreateInfo bufferInfo{}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = size; bufferInfo.usage = usage; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { throw std::runtime_error("Failed to create buffer!"); } VkMemoryRequirements memRequirements; vkGetBufferMemoryRequirements(device, buffer, &memRequirements); VkMemoryAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) { throw std::runtime_error("Failed to allocate buffer memory!"); } vkBindBufferMemory(device, buffer, bufferMemory, 0); } VkCommandBuffer beginSingleTimeCommands() { VkCommandBufferAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.commandPool = commandPool; allocInfo.commandBufferCount = 1; VkCommandBuffer commandBuffer; vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer); VkCommandBufferBeginInfo beginInfo{}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; vkBeginCommandBuffer(commandBuffer, &beginInfo); return commandBuffer; } void endSingleTimeCommands(VkCommandBuffer commandBuffer) { vkEndCommandBuffer(commandBuffer); VkSubmitInfo submitInfo{}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &commandBuffer; vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); vkQueueWaitIdle(graphicsQueue); vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); } void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout) { VkCommandBuffer commandBuffer = beginSingleTimeCommands(); VkImageMemoryBarrier barrier{}; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; barrier.oldLayout = oldLayout; barrier.newLayout = newLayout; barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.image = image; barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; barrier.subresourceRange.baseMipLevel = 0; barrier.subresourceRange.levelCount = 1; barrier.subresourceRange.baseArrayLayer = 0; barrier.subresourceRange.layerCount = 1; VkPipelineStageFlags sourceStage; VkPipelineStageFlags destinationStage; if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { barrier.srcAccessMask = 0; barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; } // 追加: シェーダー読み取り状態から転送先状態への遷移 else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; } else { throw std::invalid_argument("Unsupported layout transition!"); } vkCmdPipelineBarrier( commandBuffer, sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier ); endSingleTimeCommands(commandBuffer); } void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height) { VkCommandBuffer commandBuffer = beginSingleTimeCommands(); VkBufferImageCopy region{}; region.bufferOffset = 0; region.bufferRowLength = 0; region.bufferImageHeight = 0; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.mipLevel = 0; region.imageSubresource.baseArrayLayer = 0; region.imageSubresource.layerCount = 1; region.imageOffset = {0, 0, 0}; region.imageExtent = { width, height, 1 }; vkCmdCopyBufferToImage( commandBuffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion ); endSingleTimeCommands(commandBuffer); } // ---- テクスチャ画像の作成と更新 ---- void createTextureImage(int width, int height) { VkImageCreateInfo imageInfo{}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.imageType = VK_IMAGE_TYPE_2D; imageInfo.extent.width = width; imageInfo.extent.height = height; imageInfo.extent.depth = 1; imageInfo.mipLevels = 1; imageInfo.arrayLayers = 1; imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; if (vkCreateImage(device, &imageInfo, nullptr, &textureImage) != VK_SUCCESS) { throw std::runtime_error("Failed to create texture image!"); } VkMemoryRequirements memRequirements; vkGetImageMemoryRequirements(device, textureImage, &memRequirements); VkMemoryAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex= findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); if (vkAllocateMemory(device, &allocInfo, nullptr, &textureImageMemory) != VK_SUCCESS) { throw std::runtime_error("Failed to allocate texture image memory!"); } vkBindImageMemory(device, textureImage, textureImageMemory, 0); } void updateVulkanTexture(void* pixels, int width, int height) { if (textureImage == VK_NULL_HANDLE) { createTextureImage(width, height); transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } else { transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } VkDeviceSize imageSize = static_cast<VkDeviceSize>(width * height * 4); VkBuffer stagingBuffer; VkDeviceMemory stagingBufferMemory; createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; vkMapMemory(device, stagingBufferMemory, 0, imageSize, 0, &data); std::memcpy(data, pixels, static_cast<size_t>(imageSize)); vkUnmapMemory(device, stagingBufferMemory); copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(width), static_cast<uint32_t>(height)); transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); vkDestroyBuffer(device, stagingBuffer, nullptr); vkFreeMemory(device, stagingBufferMemory, nullptr); if (textureImageView == VK_NULL_HANDLE) { createTextureImageView(); createTextureSampler(); createDescriptorPool(); createDescriptorSet(); } } // ---- main() ---- int main() { if (!glfwInit()) { std::cerr << "Failed to initialize GLFW.\n"; return -1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); window = glfwCreateWindow(800, 600, "Vulkan OpenCV Window", nullptr, nullptr); if (!window) { std::cerr << "Failed to create GLFW window.\n"; glfwTerminate(); return -1; } if (!initVulkanInstance()) { return -1; } if (!initVulkanDevice()) { return -1; } if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) { std::cerr << "Failed to create window surface.\n"; return -1; } if (!createSwapChain(surface)) { return -1; } if (!createSwapChainImageViews()) { return -1; } if (!createRenderPass()) { return -1; } if (!createFramebuffers()) { return -1; } if (!createCommandPool()) { return -1; } // 初期化:パイプライン、バッファ等の作成 createDescriptorSetLayout(); createGraphicsPipeline(); createVertexBuffer(); createIndexBuffer(); if (!createCommandBuffers()) { return -1; } cv::VideoCapture cap("/dev/video0", cv::CAP_V4L2); if (!cap.isOpened()) { std::cerr << "Error: Cannot open /dev/video0.\n"; return -1; } while (!glfwWindowShouldClose(window)) { glfwPollEvents(); cv::Mat frame; if (!cap.read(frame)) { std::cerr << "Failed to read frame from video capture.\n"; break; } cv::Mat frameRGBA; cv::cvtColor(frame, frameRGBA, cv::COLOR_BGR2RGBA); updateVulkanTexture(frameRGBA.data, frameRGBA.cols, frameRGBA.rows); // コマンドバッファを更新(テクスチャ更新後の情報を反映) if (!createCommandBuffers()) { break; } drawFrame(); } cap.release(); cleanup(); return 0; } // ---- リソース解放 ---- void cleanup() { vkDestroySampler(device, textureSampler, nullptr); vkDestroyImageView(device, textureImageView, nullptr); vkDestroyImage(device, textureImage, nullptr); vkFreeMemory(device, textureImageMemory, nullptr); vkDestroyBuffer(device, indexBuffer, nullptr); vkFreeMemory(device, indexBufferMemory, nullptr); vkDestroyBuffer(device, vertexBuffer, nullptr); vkFreeMemory(device, vertexBufferMemory, nullptr); vkDestroyDescriptorPool(device, descriptorPool, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); vkDestroyPipeline(device, graphicsPipeline, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr); for (auto framebuffer : swapChainFramebuffers) { vkDestroyFramebuffer(device, framebuffer, nullptr); } for (auto imageView : swapChainImageViews) { vkDestroyImageView(device, imageView, nullptr); } vkDestroySwapchainKHR(device, swapChain, nullptr); vkDestroyCommandPool(device, commandPool, nullptr); vkDestroyRenderPass(device, renderPass, nullptr); vkDestroyDevice(device, nullptr); vkDestroySurfaceKHR(instance, surface, nullptr); vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); glfwTerminate(); }
#version 450
layout(location = 0) in vec2 fragUV;
layout(location = 0) out vec4 outColor;
layout(set = 0, binding = 0) uniform sampler2D texSampler;
void main() {
outColor = texture(texSampler, fragUV);
}
#version 450
layout(location = 0) in vec2 inPos;
layout(location = 1) in vec2 inUV;
layout(location = 0) out vec2 fragUV;
void main() {
gl_Position = vec4(inPos, 0.0, 1.0);
fragUV = inUV;
}
Vulkanを触ってみる

最近リアルタイムレンダリングしたいからVulkanを触ってみたのよ。
で、今ハマってるのがGaussian Splatting。
ガウス…?なんか数学っぽい響き…。
スプラッティングって、インク飛ばすの?
その例え、意外と悪くない!
Gaussian Splattingってのはね、3D空間に“点”じゃなくて“ぼんやりしたガウス分布”をばらまいて、
そこに色とか透明度とかを持たせて描画する手法なのよ。
えっ…3Dって、ポリゴンで描くんじゃないの?
それが今はね、ポリゴンじゃなくて“点の雲”で表現するNeRFとかGaussian系が流行ってるの。
で、ガウシアンスプラットはその中でもリアルタイム性に優れてて、
ちゃんとVulkanでGPUレンダリングできるのよ。
すごい…けど、それってどうやってモデル作るの?
そこで出てくるのが——SLAM。
スラム…?それも格ゲーの技じゃないの…?
違うわ(笑)
SLAMっていうのは、“Simultaneous Localization and Mapping”。
カメラとかセンサーで周囲を観察しながら、自分の位置とマップを同時に作っていく技術なの。
あ、ロボットがよくやってるやつ!
そうそう。私の構想では、リアルタイムにSLAMでカメラの位置と深度を取得して、
それを使ってGaussian Splatをリアルタイムで生成・更新して、Vulkanで即描画!
な、なんかめっちゃすごそう…!
それってARとかVRにも使える?
大正解!動きながら空間をスキャンして、
現実世界をふんわりした3Dで再構築して表示できる。ガチで未来感あるでしょ?
でも、それってすごい処理重そう…
そこをどう最適化するかが勝負よ。
シェーダーで並列化したり、Level-of-Detailで近くは細かく、遠くはボケっと表示したり。
なるほど~。それをVulkanで書いてるんだ…?
今はまだ、三角形の代わりに1万個のガウス玉を投げてるだけ。
でもいつか、SLAMと融合してリアルタイム3D再構築を自作したいのよ。
そのときは、私がそれを使ってゲーム作るね!
いいね。じゃあそのゲーム、“スプラット☆マッピング大戦”ってタイトルで。
…それだけ聞くとちょっと怪しいタイトル(笑)
でもさ…AIに聞きながらやれば、なんとかなるって思ってたんだけど…
わかる。私も最初はChatGPTに聞きながら進めてたんだけど、
ちょっと複雑になると平気でハルシネーション起こすのよね。
えっ、そんなに…?
じゃあ「これで動きます!」って言ってくるコードが…
大体コンパイルすら通らない(笑)
でも、それでも参考になる部分はあるし、ヒントにはなるのよ。
うーん、じゃあAIは“優秀なうっかりアシスタント”って感じ?
そんな感じ。でも最近、GitHubとかQiitaにもGaussian SplattingやSLAM関連のコード増えてきたし、
今後ネット上にちゃんと“動くコード”がもっと出回るようになれば、
AIの精度も良くなると思うのよ。
なるほど…未来に期待、だね!
文系はオワコン!!大規模言語モデルChatGPTは文系職を破壊する!!!!
文系に最も多い就職先のデスクワークはすでに人余り
ITで真っ先に仕事が減るのが 人気なホワイトデスクワーク。 本当はデスクワークをAI化で人員減らして 介護土木看護建築のような肉体労働に人員回すべきだが 簡単なAIでも出来る事務仕事をやりたがる日本人が多いので AI化が難しい肉体労働ばかり人手不足で AI化しやすい事務仕事に人手過剰だから最強にAI化しづらい環境になっている
ほとんどの文系は営業•販売•事務に就きます。
営業
営業は減少傾向で少数精鋭となっており、コミュニケーション能力がかなり高い人しかいません。
販売
販売は基本的にいらないものを売り付けることになります。また、コロナ禍で非対人販売に移行しました。
事務
事務は上記の通りDX•AI化の阻害要因となっています。事務職員を募集して人が集まらなくなった時、IT・AI化というインセンティブが働きます。手取り10万円台1名採用という募集に100名が応募してくるという異常な状態が続いています。募集したら即大量の応募が来る今の状況を変えなければなりません。
というわけで私立文系大学を廃止して、 肉体労働できるAIロボットを一丸となって開発するしかないのだが、なんだろうこの国のやる気のなさは...
もしくは、肉体労働を伴う公共事業をやめればいいと思うが、スーパーゼネコンが中抜きできなくなるんだろなー
今人手不足の現場仕事の問題はアレな人が多すぎることね
仕事が出来ても出来なくても理不尽な目に遭うから
結果的にアレな人が残ることになるわ
せめてコミュニケーションだけでもAIがやってくれればいいんだけれど...
安易に人手不足の業界に行くと
刑務所以下の奴隷労働をさせられるわ
奴隷労働はAIロボットがやるべきよ
そして人間らしく生きるためにはベーシックインカムしかないわ
ちなみに肉体労働・奴隷労働は人の気持ちがわからないサイコパスが出世します。
筆者の気持ちを考えていた文系の人は気をつけてください。
文系が足を引っ張っている
海外「事務作業は外注もしくはAI&ITを活用し自社で抱える事務職を必要最小限に圧縮! 浮いたお金は技術者や研究者のための研究開発費や現業職への待遇改善に使う!」
日本「生産職(技術者や現業職)から搾取して無駄な会議や資料作りをする事務職をいっぱい抱えるぞー!!おーい依存しているプログラムを全部調べて著作権を列挙しろ!文化庁が言ってたぞ!!」
こんなんで海外に勝てるわけないだろ
GPTの誕生
そしてついに、 大規模言語モデルのChatGPTも登場した。 政治家、経営者、弁護士、会計士、記者、経済学者、コンサルタント、学習アシスタント(教師、塾講師)、作家、翻訳者、病院事務、行政事務、金融事務、一般事務の 文系職を破壊する!!!!
ChatGPT4はかなりヤバい!! GPT5は2024年リリース予定!!
ChatGPTに権限を持たせなければならない
今週あったできごと
リモートサーバーにあるGitがエラーになってしまった... 助けてChatGPT
このようなエラーに対しては以下の解決方法があります
さすが!!ChatGPT!!
でも、そのコマンドはスーパーユーザーしか打てないわ
スーパーユーザーさん
コマンドを打ってください
何があったんですか?
.。○◯『さっさとコマンド打てよ』
(事情説明する)
そのようなことはなさらないでください
.。○◯『は?じゃあどうするの?ChatGPTは代替案も提示してくれるわ』
すみませんでした
対応しました
.。○◯『結局AIが提示した方法をやってるし!!余計な時間コストを支払ってしまったわ!!!』
ありがとうございます
GPT3.5でもすでに人間を超えている
やっぱこれからはAIの時代ね!!!
AIをスーパーユーザーにしなければならない
あ!さっき時間コストを支払ったけど
AI(GPT)で代替できるのに ものすごい金銭コストを支払ってる既得権益者(スーパーユーザー)・資格バリアしてる奴だらけだったわ!!
GPT(大規模言語モデル)で代替できそうな職種:
政治家、経営者、弁護士、会計士、記者、経済学者、コンサルタント、学習アシスタント(教師、塾講師)、作家、翻訳者、病院事務、行政事務、金融事務、一般事務
タイムイズマネー!!
グッバイ!!時間泥棒!!
