Aqoole_Hateenaの技術日記

vulkan+raytraceで色々描いてます

モデルのレンダリング完成(Android + Vulkan + Ray Tracing)

完成図

モデルのレンダリングだけでなく、キューブに反射するモデルも描けているところがray tracingポイントです。

1
2
3

前回からの変更点

調べてみると、Android 11からはandroid ndkが提供する画像デコーダライブラリが使える模様。
pngjpegで描かれるテクスチャを読み込んでvulkanにimage bufferとして渡すときに使用する。
画像デコーダー  |  Android NDK  |  Android Developers
上記で行えることはpng/jpegイメージを読み込んでvoid*に書き込むところまでなので、そのデータをvulkan bufferに渡すところは自分で用意する必要がある。

    AAsset* file = AAssetManager_open(app->activity->assetManager,
                                      imagePath, AASSET_MODE_STREAMING);
    AImageDecoder *decoder;
    if(AImageDecoder_createFromAAsset(file, &decoder) != ANDROID_IMAGE_DECODER_SUCCESS)
        __android_log_print(ANDROID_LOG_DEBUG, "aqoole error", "error in decode image %d", 0);
    const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
    int32_t width = AImageDecoderHeaderInfo_getWidth(info);
    int32_t height = AImageDecoderHeaderInfo_getHeight(info);
    AndroidBitmapFormat format =
            (AndroidBitmapFormat) AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
    size_t stride = AImageDecoder_getMinimumStride(decoder);  // Image decoder does not use padding by default
    size_t size = height * stride;
    void* pixels = malloc(size);
    if(AImageDecoder_decodeImage(decoder, pixels, stride, size) != ANDROID_IMAGE_DECODER_SUCCESS)
        __android_log_print(ANDROID_LOG_DEBUG, "aqoole error", "error in decode image %d", 0);
    AImageDecoder_delete(decoder);
    AAsset_close(file);
    //copy data to tmp buffer
    VkDeviceSize imageSize = size;
    int texWidth = width;
    int texHeight = height;
    VkBuffer stagingBuffer;
    VkDeviceMemory stagingBufferMemory;
    AEBuffer::CreateBuffer(mDevice, imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
                           VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer,
                           stagingBufferMemory);
    AEBuffer::CopyData(mDevice, stagingBufferMemory, imageSize, (void*)pixels);
    //create image
    AEImage::CreateImage2D(mDevice, (uint32_t)texWidth, (uint32_t)texHeight, VK_FORMAT_B8G8R8A8_UNORM,
                           VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_USAGE_TRANSFER_DST_BIT |
                                                                               VK_IMAGE_USAGE_SAMPLED_BIT, VK_SHARING_MODE_EXCLUSIVE, VK_SAMPLE_COUNT_1_BIT, &mImage);
    //bind image to memory
    AEImage::BindImageMemory(mDevice, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
                             &mImage, &mImageMemory);
    //command buffer create
    AECommandBuffer singleTimeCommandBuffer(mDevice, commandPool);
    //begin single time command
    AECommand::BeginSingleTimeCommands(&singleTimeCommandBuffer);
    AEImage::TransitionImageLayout(mDevice, &singleTimeCommandBuffer, VK_IMAGE_LAYOUT_UNDEFINED,
                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &mImage);
    //copy buffer to image memory
    AEImage::CopyBufferToImage(mDevice, &singleTimeCommandBuffer, (uint32_t)texWidth, (uint32_t)texHeight,
                               &mImage, &stagingBuffer);
    AEImage::TransitionImageLayout(mDevice, &singleTimeCommandBuffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                                   VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, &mImage);
    //end command
    AECommand::EndSingleTimeCommands(&singleTimeCommandBuffer, queue);
    //create image view
    AEImage::CreateImageView2D(mDevice, &mImage, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT,
                               &mImageView, 1);
    //clean buffer
    vkFreeMemory(*mDevice->GetDevice(), stagingBufferMemory, nullptr);
    vkDestroyBuffer(*mDevice->GetDevice(), stagingBuffer, nullptr);
    free(pixels);

ただ上記は読み込み方法をstb_imageから変更しただけで、根本解決ではなかった。

rchitシェーダ

根本原因は配列の読み込みミスだった。
vertices[nonuniformEXT(objId)]とすることでrayが衝突したオブジェクトごとのvertexデータを取ってこれるが、今回はtextureデータを使用する関係で別のbufferにデータを格納していた。

layout(binding = 3, set = 0, scalar) buffer Vertices {Vertex3D v[];} vertices[];
layout(binding = 5, set = 0, scalar) buffer Verticesobj {Vertex3DObj vobj[];} verticesobj[];

今回の場合ではVerticesobj のブロックはモデルしか使わないので、アクセスはverticesobj[0].vobj[ind.x];などとすれば解決した。
オブジェクト番号と配列の番号が一致しないときはverticesobj[nonuniformEXT(objId)].vobj[ind.x];としてはダメ。