I'm some problems getting multiple mesh looking right on the same blas/tlas using Vulkan Ray-Tracing

I’m trying to load multiple mesh using the same blas/tlas, but it doesn’t seem to be looking right. It loads fine when it’s only mesh, but I try multiple mesh it looks like this. I’m not sure if there’s something wrong with the way working with the settings in the blas and tlas or if having multiple meshs are changing the way I have to unpack the vertices in the shader.

I’ve also tried taking a look though the nvidia ray tracing tutorial and sacha williams ray tracing code, looks like they are both only using one mesh per blas/tlas loading in the scene as one mesh. Which seems fine for a sample, but won’t that cause a problem when trying to manipulate each mesh individuality by transform, rotation or scale?

This is the blas and tlas code:

void RayTraceRenderer::createBottomLevelAccelerationStructure(VulkanEngine& engine)
{
std::shared_ptr<TextureManager> manager = std::make_shared<TextureManager>(engine);
std::shared_ptr<Texture> texture = std::make_shared<Texture>();

model = Model(engine, manager, "C:/Users/dotha/source/repos/VulkanGraphics/Models/vulkanscene_shadow.obj", RayTraceDescriptorSetLayout, 1, texture);


texture2D = Texture2D(engine, VK_FORMAT_R8G8B8A8_UNORM, "C:/Users/dotha/source/repos/VulkanGraphics/texture/Brick_diffuseOriginal.bmp", 1);
NormalMap = Texture2D(engine, VK_FORMAT_R8G8B8A8_UNORM, "C:/Users/dotha/source/repos/VulkanGraphics/texture/Brick_normal.bmp", 1);

std::vector<VkAccelerationStructureGeometryKHR> GeometryAccelerationStructureList;


for (int x = 0; x < 11; x++)
{
    auto mesh = model.SubMeshList[x];

    glm::mat4 transformMatrix = glm::mat4(1.0f);
    transformMatrix = glm::rotate(transformMatrix, glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f));

    vertexBuffer.CreateBuffer(engine, mesh.VertexList.size() * sizeof(Vertex), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, mesh.VertexList.data());
    indexBuffer.CreateBuffer(engine, mesh.IndexList.size() * sizeof(uint32_t), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, mesh.IndexList.data());
    transformBuffer.CreateBuffer(engine, sizeof(glm::mat4), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &transformMatrix);

    VkDeviceOrHostAddressConstKHR vertexBufferDeviceAddress = engine.BufferToDeviceAddress(vertexBuffer.Buffer);
    VkDeviceOrHostAddressConstKHR indexBufferDeviceAddress = engine.BufferToDeviceAddress(indexBuffer.Buffer);
    VkDeviceOrHostAddressConstKHR transformBufferDeviceAddress = engine.BufferToDeviceAddress(transformBuffer.Buffer);

    VkAccelerationStructureGeometryKHR GeometryAccelerationStructure = {};
    GeometryAccelerationStructure.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
    GeometryAccelerationStructure.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
    GeometryAccelerationStructure.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
    GeometryAccelerationStructure.geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR;
    GeometryAccelerationStructure.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
    GeometryAccelerationStructure.geometry.triangles.vertexData = vertexBufferDeviceAddress;
    GeometryAccelerationStructure.geometry.triangles.maxVertex = mesh.VertexList.size() * sizeof(Vertex);
    GeometryAccelerationStructure.geometry.triangles.vertexStride = sizeof(Vertex);
    GeometryAccelerationStructure.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
    GeometryAccelerationStructure.geometry.triangles.indexData = indexBufferDeviceAddress;
    GeometryAccelerationStructure.geometry.triangles.transformData.deviceAddress = 0;
    GeometryAccelerationStructure.geometry.triangles.transformData.hostAddress = nullptr;
    GeometryAccelerationStructure.geometry.triangles.transformData = transformBufferDeviceAddress;
    GeometryAccelerationStructureList.emplace_back(GeometryAccelerationStructure);

    VkAccelerationStructureBuildRangeInfoKHR AcclerationBuildRange = {};
    AcclerationBuildRange.primitiveCount = static_cast<uint32_t>(mesh.IndexList.size()) / 3;
    AcclerationBuildRange.primitiveOffset = x;
    AcclerationBuildRange.firstVertex = 0;
    AcclerationBuildRange.transformOffset = 0;
    AcclerationBuildRangeList.emplace_back(AcclerationBuildRange);
}

VkAccelerationStructureBuildGeometryInfoKHR AccelerationBuildGeometry = {};
AccelerationBuildGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
AccelerationBuildGeometry.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
AccelerationBuildGeometry.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
AccelerationBuildGeometry.geometryCount = static_cast<uint32_t>(GeometryAccelerationStructureList.size());
AccelerationBuildGeometry.pGeometries = GeometryAccelerationStructureList.data();


maxPrimCount.resize(AcclerationBuildRangeList.size());
for (auto x = 0; x < AcclerationBuildRangeList.size(); x++)
{
    maxPrimCount[x] = AcclerationBuildRangeList[x].primitiveCount;
}

VkAccelerationStructureBuildSizesInfoKHR AccelerationBuildInfo = {};
AccelerationBuildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR;
vkGetAccelerationStructureBuildSizesKHR(engine.Device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &AccelerationBuildGeometry, maxPrimCount.data(), &AccelerationBuildInfo);

bottomLevelAS.CreateBuffer(engine, AccelerationBuildInfo.accelerationStructureSize, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

VkAccelerationStructureCreateInfoKHR AccelerationStructureInfo = {};
AccelerationStructureInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
AccelerationStructureInfo.buffer = bottomLevelAS.Buffer;
AccelerationStructureInfo.size = AccelerationBuildInfo.accelerationStructureSize;
AccelerationStructureInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
VkResult result = vkCreateAccelerationStructureKHR(engine.Device, &AccelerationStructureInfo, nullptr, &bottomLevelAS.BufferHandle);

VulkanBuffer ScratchBuffer = VulkanBuffer();
ScratchBuffer.CreateBuffer(engine, AccelerationBuildInfo.buildScratchSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkDeviceOrHostAddressConstKHR ScratchBufferDeviceAddress = engine.BufferToDeviceAddress(ScratchBuffer.GetBuffer());

VkAccelerationStructureBuildGeometryInfoKHR AccelerationBuildGeometryInfo = {};
AccelerationBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
AccelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
AccelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
AccelerationBuildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
AccelerationBuildGeometryInfo.dstAccelerationStructure = bottomLevelAS.BufferHandle;
AccelerationBuildGeometryInfo.geometryCount = static_cast<uint32_t>(GeometryAccelerationStructureList.size());
AccelerationBuildGeometryInfo.pGeometries = GeometryAccelerationStructureList.data();
AccelerationBuildGeometryInfo.scratchData.deviceAddress = ScratchBufferDeviceAddress.deviceAddress;

VkCommandBufferAllocateInfo commandBufferAllocateInfo{};
commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
commandBufferAllocateInfo.commandPool = engine.GetRenderCommandPool();
commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
commandBufferAllocateInfo.commandBufferCount = 1;

VkCommandBuffer cmdBuffer;
vkAllocateCommandBuffers(engine.Device, &commandBufferAllocateInfo, &cmdBuffer);

VkCommandBufferBeginInfo cmdBufferBeginInfo{};
cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;

auto asdf = AcclerationBuildRangeList.data();
vkBeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo);
vkCmdBuildAccelerationStructuresKHR(cmdBuffer, 1, &AccelerationBuildGeometryInfo, &asdf);
vkEndCommandBuffer(cmdBuffer);

VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &cmdBuffer;
VkFenceCreateInfo fenceCreateInfo{};
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceCreateInfo.flags = 0;

VkFence fence;
vkCreateFence(engine.Device, &fenceCreateInfo, nullptr, &fence);
vkQueueSubmit(engine.GraphicsQueue, 1, &submitInfo, fence);
vkWaitForFences(engine.Device, 1, &fence, VK_TRUE, 100000000000);
vkDestroyFence(engine.Device, fence, nullptr);
vkFreeCommandBuffers(engine.Device, engine.GetRenderCommandPool(), 1, &cmdBuffer);


VkAccelerationStructureDeviceAddressInfoKHR AccelerationDeviceAddressInfo{};
AccelerationDeviceAddressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
AccelerationDeviceAddressInfo.accelerationStructure = bottomLevelAS.BufferHandle;
bottomLevelAS.BufferDeviceAddress = vkGetAccelerationStructureDeviceAddressKHR(engine.Device, &AccelerationDeviceAddressInfo);

ScratchBuffer.DestoryBuffer(engine);
}
void RayTraceRenderer::createTopLevelAccelerationStructure(VulkanEngine& engine)
{
VkTransformMatrixKHR transformMatrix = {
        1.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 1.0f, 0.0f
};

VkAccelerationStructureInstanceKHR AccelerationInstance = {};
AccelerationInstance.transform = transformMatrix;
AccelerationInstance.instanceCustomIndex = 0;
AccelerationInstance.mask = 0xFF;
AccelerationInstance.instanceShaderBindingTableRecordOffset = 0;
AccelerationInstance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
AccelerationInstance.accelerationStructureReference = bottomLevelAS.BufferDeviceAddress;

VulkanBuffer instancesBuffer;
instancesBuffer.CreateBuffer(engine, sizeof(VkAccelerationStructureInstanceKHR), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &AccelerationInstance);

VkDeviceOrHostAddressConstKHR TopLevelAccelerationInstanceBufferDeviceAddress{};
TopLevelAccelerationInstanceBufferDeviceAddress.deviceAddress = engine.BufferToDeviceAddress(instancesBuffer.Buffer).deviceAddress;

VkAccelerationStructureGeometryKHR AccelerationGeometry = {};
AccelerationGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
AccelerationGeometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
AccelerationGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
AccelerationGeometry.geometry.instances.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR;
AccelerationGeometry.geometry.instances.arrayOfPointers = VK_FALSE;
AccelerationGeometry.geometry.instances.data = TopLevelAccelerationInstanceBufferDeviceAddress;

VkAccelerationStructureBuildGeometryInfoKHR AccelerationStructureBuildGeometry = {};
AccelerationStructureBuildGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
AccelerationStructureBuildGeometry.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
AccelerationStructureBuildGeometry.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
AccelerationStructureBuildGeometry.geometryCount = 1;
AccelerationStructureBuildGeometry.pGeometries = &AccelerationGeometry;


VkAccelerationStructureBuildSizesInfoKHR AccelerationBuildInfo = {};
AccelerationBuildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR;
vkGetAccelerationStructureBuildSizesKHR(engine.Device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &AccelerationStructureBuildGeometry, maxPrimCount.data(), &AccelerationBuildInfo);

topLevelAS.CreateBuffer(engine, AccelerationBuildInfo.accelerationStructureSize, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

VkAccelerationStructureCreateInfoKHR AccelerationStructureInfo = {};
AccelerationStructureInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
AccelerationStructureInfo.buffer = topLevelAS.Buffer;
AccelerationStructureInfo.size = AccelerationBuildInfo.accelerationStructureSize;
AccelerationStructureInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
VkResult result = vkCreateAccelerationStructureKHR(engine.Device, &AccelerationStructureInfo, nullptr, &topLevelAS.BufferHandle);

VulkanBuffer ScratchBuffer = VulkanBuffer();
ScratchBuffer.CreateBuffer(engine, AccelerationBuildInfo.buildScratchSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkDeviceOrHostAddressConstKHR ScratchBufferDeviceAddress = engine.BufferToDeviceAddress(ScratchBuffer.GetBuffer());

VkAccelerationStructureBuildGeometryInfoKHR AccelerationBuildGeometryInfo = {};
AccelerationBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
AccelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
AccelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
AccelerationBuildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
AccelerationBuildGeometryInfo.dstAccelerationStructure = topLevelAS.BufferHandle;
AccelerationBuildGeometryInfo.geometryCount = 1;
AccelerationBuildGeometryInfo.pGeometries = &AccelerationGeometry;
AccelerationBuildGeometryInfo.scratchData.deviceAddress = ScratchBufferDeviceAddress.deviceAddress;

std::vector<VkAccelerationStructureBuildRangeInfoKHR*> AcclerationBuildRangeList;
VkAccelerationStructureBuildRangeInfoKHR AcclerationBuildRange = {};
AcclerationBuildRange.primitiveCount = static_cast<uint32_t>(maxPrimCount.size());
AcclerationBuildRange.primitiveOffset = 0;
AcclerationBuildRange.firstVertex = 0;
AcclerationBuildRange.transformOffset = 0;
AcclerationBuildRangeList.emplace_back(&AcclerationBuildRange);

VkCommandBufferAllocateInfo commandBufferAllocateInfo{};
commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
commandBufferAllocateInfo.commandPool = engine.GetRenderCommandPool();
commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
commandBufferAllocateInfo.commandBufferCount = 1;

VkCommandBuffer cmdBuffer;
vkAllocateCommandBuffers(engine.Device, &commandBufferAllocateInfo, &cmdBuffer);

VkCommandBufferBeginInfo cmdBufferBeginInfo{};
cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;

vkBeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo);
vkCmdBuildAccelerationStructuresKHR(cmdBuffer, 1, &AccelerationBuildGeometryInfo, AcclerationBuildRangeList.data());
vkEndCommandBuffer(cmdBuffer);

VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &cmdBuffer;
VkFenceCreateInfo fenceCreateInfo{};
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceCreateInfo.flags = 0;

VkFence fence;
vkCreateFence(engine.Device, &fenceCreateInfo, nullptr, &fence);
vkQueueSubmit(engine.GraphicsQueue, 1, &submitInfo, fence);
vkWaitForFences(engine.Device, 1, &fence, VK_TRUE, 100000000000);
vkDestroyFence(engine.Device, fence, nullptr);
vkFreeCommandBuffers(engine.Device, engine.GetRenderCommandPool(), 1, &cmdBuffer);

VkAccelerationStructureDeviceAddressInfoKHR AccelerationDeviceAddressInfo{};
AccelerationDeviceAddressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
AccelerationDeviceAddressInfo.accelerationStructure = topLevelAS.BufferHandle;
topLevelAS.BufferDeviceAddress = vkGetAccelerationStructureDeviceAddressKHR(engine.Device, &AccelerationDeviceAddressInfo);

ScratchBuffer.DestoryBuffer(engine);
}

and the hit shader code:

        #version 460
        #extension GL_EXT_ray_tracing : require
        #extension GL_EXT_nonuniform_qualifier : enable

        layout(location = 0) rayPayloadInEXT vec3 hitValue;
        layout(location = 2) rayPayloadEXT bool shadowed;
        hitAttributeEXT vec3 attribs;

        layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS;
        layout(binding = 2, set = 0) uniform UBO 
        {
    	    mat4 viewInverse;
    	    mat4 projInverse;
    	    mat4 modelInverse;
    	    vec4 lightPos;
    	    vec4 viewPos;
    	    int vertexSize;
        } ubo;
        layout(binding = 3, set = 0) buffer Vertices { vec4 v[]; } vertices;
        layout(binding = 4, set = 0) buffer Indices { uint i[]; } indices;
        layout(binding = 5, set = 0) uniform sampler2D DiffuseMap;
        layout(binding = 6, set = 0) uniform sampler2D NormalMap;

        struct Vertex
        {
          vec3 pos;
          vec3 normal;
          vec2 uv;
          vec4 tangent;
          vec4 BiTangant;
          vec4 Color;
          vec4 BoneID;
          vec4 BoneWeights;
        };

        Vertex unpack(uint index)
        {
    	// Unpack the vertices from the SSBO using the glTF vertex structure
    	// The multiplier is the size of the vertex divided by four float components (=16 bytes)
    	const int m = ubo.vertexSize / 16;

    	vec4 d0 = vertices.v[m * index + 0];
    	vec4 d1 = vertices.v[m * index + 1];
    	vec4 d2 = vertices.v[m * index + 2];

    	Vertex v;
    	v.pos = d0.xyz;
    	v.normal = vec3(d0.w, d1.x, d1.y);
    	v.Color = vec4(d2.x, d2.y, d2.z, 1.0);
    	v.uv = vec2(d0.x, d0.y);
    	v.tangent = vec4(d0.w, d1.y, d1.y, 0.0f);

    	return v;
        }

        void main()
        {
    	ivec3 index = ivec3(indices.i[3 * gl_PrimitiveID], indices.i[3 * gl_PrimitiveID + 1], indices.i[3 * gl_PrimitiveID + 2]);

    	Vertex v0 = unpack(index.x);
    	Vertex v1 = unpack(index.y);
    	Vertex v2 = unpack(index.z);

    	const vec3 barycentricCoords = vec3(1.0f - attribs.x - attribs.y, attribs.x, attribs.y);
    	vec3 worldPos = v0.pos * barycentricCoords.x + v1.pos * barycentricCoords.y + v2.pos * barycentricCoords.z;
    	vec3 normal2 = normalize(v0.normal * barycentricCoords.x + v1.normal * barycentricCoords.y + v2.normal * barycentricCoords.z);
    	vec2 texCoord = v0.uv * barycentricCoords.x + v1.uv * barycentricCoords.y + v2.uv * barycentricCoords.z;
    	vec3 tangent = v0.tangent.xyz * barycentricCoords.x + v1.tangent.xyz * barycentricCoords.y + v2.tangent.xyz * barycentricCoords.z;

    	mat3 normalMatrix = transpose(inverse(mat3(ubo.modelInverse)));
        vec3 T = normalize(normalMatrix * tangent);
        vec3 N = normalize(normalMatrix * normal2);
        T = normalize(T - dot(T, N) * N);
        vec3 B = cross(N, T);
        
        mat3 TBN = transpose(mat3(T, B, N));    
        vec3 TangentLightPos = TBN * ubo.lightPos.xyz;
        vec3 TangentViewPos  = TBN * ubo.viewPos.xyz;
        vec3 TangentFragPos  = TBN * worldPos;

    	vec3 normal = texture(NormalMap, texCoord).rgb;
    	normal = normalize(normal * 2.0 - 1.0);  
      

    	vec3 color = texture(DiffuseMap, texCoord).rgb;
    	vec3 ambient = 0.1 * color;

    	vec3 lightDir = normalize(TangentLightPos - TangentFragPos);
        float diff = max(dot(lightDir, normal), 0.0);
        vec3 diffuse = diff * color;

    	//vec3 lightVector = normalize(ubo.lightPos.xyz);
    	//float dot_product = max(dot(lightVector, normal), 0.2);
    	hitValue = ambient + diffuse;

    	// Shadow casting
    	float tmin = 0.001;
    	float tmax = 10000.0;
    	vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT;
    	shadowed = true;  
    	// Trace shadow ray and offset indices to match shadow hit/miss shader group indices
    	traceRayEXT(topLevelAS, gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT, 0xFF, 1, 0, 1, origin, tmin, lightDir, tmax, 2);
    	if (shadowed) {
    		hitValue *= 0.3;
    	}
    	else
    	{
    		vec3 viewDir = normalize(TangentLightPos - TangentFragPos);
    		vec3 reflectDir = reflect(-lightDir, normal);
    		vec3 halfwayDir = normalize(lightDir + viewDir);  
    		float spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);

    		vec3 specular = vec3(0.2) * spec;

    		hitValue += specular;
    	}
    }

Cross-ref: