モデルのレンダリング完成(Android + Vulkan + Ray Tracing)
完成図
モデルのレンダリングだけでなく、キューブに反射するモデルも描けているところがray tracingポイントです。
前回からの変更点
調べてみると、Android 11からはandroid ndkが提供する画像デコーダライブラリが使える模様。
pngやjpegで描かれるテクスチャを読み込んで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];としてはダメ。