Sample 코드의 다음 단계

AMD의 GPU에서 레이 트랙킹을 하고 싶고, GW에서 블칸의 레이 트랙킹을 배우고 있다.찾아봤지만 Qita도 별다른 기사가 없어 Hello World의 다음 단계를 노트로 남기고 싶었다.
ray tracking의 Hello World(hello triangle) 코드는 공식khronos에서 공개한 Sample 코드를 참고하면 될 것 같습니다.
https://github.com/KhronosGroup/Vulkan-Samples/tree/master/samples/extensions/raytracing_basic

레이 트랙의 차이점.


전제는 어느 정도 블랑칸에 적응했지만 순조롭게 구축되면 삼각형이 나타난다.놀랍게도, shader의 출력 결과는 완전히 다르다.일반적인vert/frag의 음영으로 출력되기를 기대하는 것은 각 정점의 벡터이지만raytraacing에서raygen shader가 계산한 결과는image로 출력됩니다.그림% 1개의 캡션을 편집했습니다.

다음 단계


Sample code는 2차원 삼각형만 출력하기 때문에 실제 쓰기 효과가 없습니다.다음 단계로 다음 사이트를 참고하게 해 주세요.
https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/#accelerationstructure/bottom-levelaccelerationstructure
여기에 입방체의 출력과raygen/miss/rchiit의 각종shader의 응용을 기술하였다.
아까 Sample code를 참고할 때 필요한 변경점은 다음과 같습니다.

bottom level acceleration structure 변경 사항


primitive count


Sample 코드는 삼각형만 출력하기 때문에 Geometry 정보는 직접 입력합니다.이곳을 수정하다.
uint32_t primitiveCount = indicesCount / 3;
//build range info
VkAccelerationStructureBuildRangeInfoKHR mRangeInfo = {};
mRangeInfo.primitiveCount = primitiveCount;
mRangeInfo.primitiveOffset = 0;
mRangeInfo.firstVertex = 0;
mRangeInfo.transformOffset = 0;

update flag


Sample 코드에서transform 행렬의 변경을 통해 화면을 업데이트하는 것을 고려하지 않았습니다.먼저 AS(Acceleration Structure)의 정보는 처음 빌드할 때와 마찬가지로 빌드 명령으로 업데이트됩니다.
pfnCmdBuildAccelerationStructuresKHR(
    commandBuffer, 1, &mBuildCommandGeometryInfo, rangeInfos.data());
pfn은 기능 지침이다.vulkan에서 extension에서 제공하는 함수를 사용하면 프로그램에 함수를 바늘로 전달해야 합니다.
pfnCmdBuildAccelerationStructuresKHR = 
    reinterpret_cast<PFN_vkCmdBuildAccelerationStructuresKHR>(
        vkGetDeviceProcAddr(device,"vkCmdBuildAccelerationStructuresKHR"));
AS의 정보를 업데이트한 후 다시 이 함수를 사용하여 AS를 업데이트하지만 AS를 구축할 때 미리 로고를 설정해야 한다.
//build geometry info
mBuildCommandGeometryInfo = {};
mBuildCommandGeometryInfo.sType = 
    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
mBuildCommandGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
mBuildCommandGeometryInfo.flags =
    VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR |
    VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR;
mBuildCommandGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
mBuildCommandGeometryInfo.dstAccelerationStructure = mAS;
mBuildCommandGeometryInfo.geometryCount = 1;
mBuildCommandGeometryInfo.pGeometries = &mGeometry;
mBuildCommandGeometryInfo.scratchData.deviceAddress =
    scratchBufferDeviceAddress.deviceAddress;
gflags의 멤버 VKBUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR를 미리 설정하지 않으면 업데이트 후 프로그램이 다운돼 PC 자체로 작동할 수 없기 때문에 주의가 필요하다.

push constants


light의 위치와 같은 정보는 모든shader에서 같은 데이터를 처리하기 때문에push constants에서 제공됩니다.
VkPushConstantRange pushConstant{};
pushConstant.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR |
                          VK_SHADER_STAGE_MISS_BIT_KHR |
                          VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
pushConstant.offset = 0;
pushConstant.size = size;/*constantsのサイズ*/
std::vector<VkPushConstantRange> pushConstants = {pushConstant};
//pipelinelayoutinfoに追加
pipelineLayoutInfo.pushConstantRangeCount = pushConstants->size();
pipelineLayoutInfo.pPushConstantRanges = pushConstants->data();
if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &mPipelineLayout) !=
    VK_SUCCESS)
        std::runtime_error("failed to create pipeline layout");

rchiit 면도기의 변경


Sample 코드에서, 모든 정점의 색깔은 rchiit 음영으로 계산됩니다.다음 단계의 예에 따라 이것을 변경합니다.다음은main 함수만 추출합니다.
closesthit.rchit
void main()
{
  ivec3 ind = ivec3(indices[0].i[3 * gl_PrimitiveID + 0],   //
                    indices[0].i[3 * gl_PrimitiveID + 1],   //
                    indices[0].i[3 * gl_PrimitiveID + 2]);  //
  Vertex3D v0 = vertices[0].v[ind.x];
  Vertex3D v1 = vertices[0].v[ind.y];
  Vertex3D v2 = vertices[0].v[ind.z]; /*Vertrex3Dはユーザ定義しているstruct*/
  const vec3 barycentricCoords = vec3(1.0f - attribs.x - attribs.y, attribs.x, attribs.y);
  vec3 normal = v0.normal * barycentricCoords.x + 
                v1.normal * barycentricCoords.y +
                v2.normal * barycentricCoords.z;
  // camはuniform bufferで渡しているstruct
  vec4 normalP = normalize(cam.modelViewProj * vec4(normal, 0.0));
  vec3 worldPos = v0.pos * barycentricCoords.x +
                  v1.pos * barycentricCoords.y +
                  v2.pos * barycentricCoords.z;
  vec4 worldP = cam.modelViewProj * vec4(worldPos, 0.0);
  vec3 L;
  float lightIntensity = pushC.lightIntensity;
  float lightDistance = 10000.0;
  vec3 lDir = pushC.lightPosition - worldP.xyz;
  lightDistance = length(lDir);
  lightIntensity = lightIntensity / (lightDistance * lightDistance);
  L = normalize(lDir);
  float dotNL = min(lightIntensity * max(dot(normalP.xyz, L), 0.02), 1.0);
  hitValue = vec3(dotNL);
}
실행하면 다음과 같은 예시를 얻을 수 있다. 빛이 입방체를 비춘다. (보기에 장방체만 있다.)

끝맺다


이 글에서, 나는 블랭크의 코드를 바탕으로 Sample 코드에서 다음 단계로 어떻게 전진하는지 보도해 보았다.여기에는 c++ 코드만 말하고 vulkan API에서ray tracking의 구조도 알아야 하기 때문에khronos 공식 홈페이지를 찾아보는 것이 좋습니다.
https://www.khronos.org/blog/ray-tracing-in-vulkan
연휴에는 외출 시간을 극력 줄였지만, 그동안 얻은 지식을 성과물로 남기고 싶어 수출한 것을 여기에 두고 싶다는 동기에서 이번에 투고하기로 했다.욕심이라면 더 어려운 모델이 되고 싶고 배경과 빛이 비치는 상황도 예뻐지고 싶지만 구조와 코딩이 생각보다 어려워 연휴 동안 할 수 있는 건 여기까지다.같은 곳에서 넘어진 사람에게 도움이 되길 바란다.

좋은 웹페이지 즐겨찾기