VK_KHR_ray_query ile fragment shader'da ray tracing nasıl yapılır

Post 66. VK_KHR_ray_tracing_pipeline yepyeni bir dispatch modeli — shader binding table’lar, vkCmdTraceRaysKHR, ray-gen/miss/hit shader’lar. Gölgeler, ambient occlusion veya picking için bu abartı. VK_KHR_ray_query, BVH gezintisini var olan herhangi bir shader’ın içine koyar: bir acceleration structure kur, texture gibi bind et, birkaç GLSL çağrısıyla gez — fragment shader’dan.

example.sh
$ ./app --headless out.ppm
device: AMD Radeon RX 7800 XT (RADV NAVI32)
wrote out.ppm

Mükemmel sert bir üçgen gölgeli dama tahtası zemin düzlemi — her piksel ışığa doğru donanım hızlandırmalı bir ray gönderdi.

Example: VulkanExamples/p66_rayquery

Üç etkinleştirme özelliği

Ray query üç-struct’lı bir feature chain ister — buffer device address (AS buffer’ları descriptor ile değil GPU adresiyle referans edilir), accelerationStructure ve rayQuery‘nin kendisi:

main.cpp
vk::PhysicalDeviceBufferDeviceAddressFeatures bda{};
bda.setBufferDeviceAddress(true);
vk::PhysicalDeviceAccelerationStructureFeaturesKHR asf{};
asf.setAccelerationStructure(true).setPNext(&bda);
vk::PhysicalDeviceRayQueryFeaturesKHR rqf{};
rqf.setRayQuery(true).setPNext(&asf);
createDevice({VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME,
              VK_KHR_RAY_QUERY_EXTENSION_NAME,
              VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME}, &rqf);

VK_KHR_deferred_host_operations, AS uzantısının bir bağımlılığı — hiçbir deferred op kullanılmıyor, sadece listelenmesi gerekiyor.

BLAS + TLAS

Bottom-level AS geometri tutar; top-level AS BLAS’lara işaret eden instance’lar tutar. Üçgen BLAS için dans:

  1. eAccelerationStructureBuildInputReadOnlyKHR | eShaderDeviceAddress‘lı vertex buffer — GPU-adresli.
  2. vkGetAccelerationStructureBuildSizesKHR → AS storage + scratch boyutları.
  3. Storage buffer üzerinde vkCreateAccelerationStructureKHR, kurmak için vkCmdBuildAccelerationStructuresKHR.
  4. Bir VkAccelerationStructureInstanceKHR (identity transform, accelerationStructureReference = vkGetAccelerationStructureDeviceAddressKHR(blas)) → TLAS, instances buffer üzerinde aynı şekilde kurulur.

RADV’de karşılaştığım iki tuzak:

  • maxVertex sayı değil en yüksek vertex indeksidir. 3 vertex → maxVertex = 2. 3 vermek sürücüye çöp bir dördüncü vertex okutur — gölge deterministik olmayan gürültüye dönüşür.
  • BLAS’ı değil TLAS’ı bind et. BLAS’ı doğrudan bind etmek kağıt üstünde legal ama RADV’de rastgele titreyen hit’ler üretti. Instance’lı TLAS yolu bit-identical frame’ler render eder.

Shader tarafı

GLSL #extension GL_EXT_ray_query ve SPIR-V 1.4+ hedefi ister (shaderc’te shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_3). O zaman bir shadow ray beş çağrıdır:

s.frag
layout(set = 0, binding = 0) uniform accelerationStructureEXT scene;
rayQueryEXT q;
rayQueryInitializeEXT(q, scene, gl_RayFlagsTerminateOnFirstHitEXT,
                      0xFF, origin + dir * 0.02, 0.0, dir, tmax - 0.04);
while (rayQueryProceedEXT(q)) {}
bool shadow = rayQueryGetIntersectionTypeEXT(q, true)
            != gl_RayQueryCommittedIntersectionNoneEXT;

TerminateOnFirstHit shadow-ray optimizasyonudur — gezinti en yakını bulmak yerine ilk opak hit’te durur. 0.02 origin offset’i ve tmax - 0.04 klasik ray-tracing epsilon’udur: ray’i yüzeyden uzaklaştır ve ışığa değmeden hemen önce durdur ki kendine çarpmasın.

AS, eAccelerationStructureKHR tipinde normal bir descriptor ile bind edilir — write, pImageInfo/pBufferInfo yerine pNext‘e zincirlenmiş bir VkWriteDescriptorSetAccelerationStructureKHR ister.

Ray query ne zaman kazanır

  • Rasterizer’da gölgeler / AO / picking — SBT yok, yeni pipeline tipi yok, tek descriptor.
  • Her stage’de çalışır — fragment, compute, hatta vertex.
  • Maliyet: BLAS/TLAS ömrünü ve güncellemelerini kendin yönetirsin ve her ray shader içinde BVH gezintisi öder (tek shadow ray için uygun; tam path tracing yine RT pipeline ister).

Check out similar posts by category: C++ Vulkan