17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-28 09:57:30 +01:00

Vulkan ray tracing: include tracks and roads, build triangle strips and fans

This commit is contained in:
2026-10-25 15:35:26 +01:00
parent cdacb4110b
commit 08f4f6ed60
5 changed files with 46 additions and 13 deletions

View File

@@ -252,9 +252,9 @@ the environment map only.
| `gfx.raytracing yes/no` | `no` | Vulkan renderer only, on a graphics card with ray queries (`VK_KHR_ray_query`): what the screen space reflections don't find is traced through the scenery around the camera instead of reflecting the sky. Read at the start; with `gfx.ssr no` all the reflections of the scenery are traced |
| `gfx.raytracing.range` | `500` | 10..5000: the scenery within this distance from the camera takes part in the traced reflections, and the rays are this long, metres |
The traced reflections hold what the environment map held before, as `gfx.reflections.fidelity` says: the tracks and the
terrain (0), the models within `gfx.reflections.range_instances` (1) and the vehicles within
`gfx.reflections.range_vehicles` (2, the default now), except the vehicle of the cab. `gfx.reflections.fidelity` and the
The traced reflections hold what the environment map held before, as `gfx.reflections.fidelity` says: the terrain
and the large shapes of the scenery (0), the tracks, the roads and the models within `gfx.reflections.range_instances` (1)
and the vehicles within `gfx.reflections.range_vehicles` (2, the default now), except the vehicle of the cab. `gfx.reflections.fidelity` and the
two ranges have no other use now; `gfx.reflections.framerate` still says how often the environment map (the sky) is
drawn. The point hit is lit by the sky, by the sun where nothing stands between them (a ray of its own) and by its own light; the lamps and headlights don't light it. Each part of a model gets its structure
for the tracing the first time it's met (a few a frame, so a new place fills in over some frames), and loses it when it

View File

@@ -482,6 +482,8 @@ void scene_walk::Render(cell_sequence::iterator First, cell_sequence::iterator L
// opaque non-instanced shapes
for (auto const &shape : cell->m_shapesopaque)
Render(shape, false);
// tracks: the ray traced reflections (the one user of this mode) show the trackbed and the platforms made of roads
Render(std::begin(cell->m_paths), std::end(cell->m_paths));
// post-render cleanup
::glPopMatrix();

View File

@@ -1821,7 +1821,7 @@ void vulkan14_renderer::gather_ray_draw(gfx::geometry_handle const &Geometry)
return;
}
auto const &chunk{static_cast<vk14::vulkan14_geometrybank *>(m_banks[Geometry.bank - 1])->last()};
if ((chunk.topology != VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST) || (chunk.vertex_address == 0))
if (((chunk.topology != VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST) && (chunk.topology != VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP) && (chunk.topology != VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN)) || (chunk.vertex_address == 0))
{
return;
}

View File

@@ -205,7 +205,7 @@ void ray_tracing::clear(std::uint64_t const Value)
auto const handle{m_device->handle()};
for (auto &entry : m_bottoms)
{
m_deletions->push(Value, [handle, structure = entry.second.handle, storage = entry.second.storage]() { destroy_structure(handle, structure); });
m_deletions->push(Value, [handle, structure = entry.second.handle, storage = entry.second.storage, indices = entry.second.indices]() { destroy_structure(handle, structure); });
}
m_bottoms.clear();
m_bottombytes = 0;
@@ -440,11 +440,37 @@ void ray_tracing::build(command_stream *Commands, std::uint32_t const Slot, std:
}
auto const &source{draw.source};
auto const indexed{source.indices != VK_NULL_HANDLE};
auto const primitives{source.count / 3};
// the strips and the fans (the tracks and the roads are strips) get triangles of their own, as indices kept with the structure
auto const strip{source.topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP};
auto const fan{source.topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN};
if ((strip || fan) && indexed)
{
continue;
}
auto const primitives{(strip || fan) ? (source.count >= 3 ? source.count - 2 : 0) : source.count / 3};
if ((primitives == 0) || (source.vertex_address == 0) || (indexed && (source.index_address == 0)) || (source.vertexcount == 0))
{
continue;
}
std::shared_ptr<buffer> generated;
if (strip || fan)
{
auto const bytes{sizeof(std::uint32_t) * 3 * static_cast<VkDeviceSize>(primitives)};
generated = std::make_shared<buffer>();
if ((false == generated->create(*m_memory, bytes, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, memory_kind::upload, "ray tracing strip indices")) ||
(generated->mapped() == nullptr))
{
continue;
}
auto *indices{reinterpret_cast<std::uint32_t *>(generated->mapped())};
for (std::uint32_t triangle = 0; triangle < primitives; ++triangle)
{
indices[triangle * 3 + 0] = (strip ? triangle : 0);
indices[triangle * 3 + 1] = triangle + 1;
indices[triangle * 3 + 2] = triangle + 2;
}
generated->flush(0, bytes);
}
pending_build build{};
build.geometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
build.geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
@@ -454,8 +480,8 @@ void ray_tracing::build(command_stream *Commands, std::uint32_t const Slot, std:
triangles_data.vertexData.deviceAddress = source.vertex_address + vertex_stride * source.vertexfirst;
triangles_data.vertexStride = vertex_stride;
triangles_data.maxVertex = source.vertexcount - 1;
triangles_data.indexType = (indexed ? VK_INDEX_TYPE_UINT32 : VK_INDEX_TYPE_NONE_KHR);
triangles_data.indexData.deviceAddress = (indexed ? source.index_address + sizeof(std::uint32_t) * source.first : 0);
triangles_data.indexType = ((indexed || generated) ? VK_INDEX_TYPE_UINT32 : VK_INDEX_TYPE_NONE_KHR);
triangles_data.indexData.deviceAddress = (generated ? generated->address() : indexed ? source.index_address + sizeof(std::uint32_t) * source.first : 0);
build.range.primitiveCount = primitives;
build.info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
build.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
@@ -486,7 +512,7 @@ void ray_tracing::build(command_stream *Commands, std::uint32_t const Slot, std:
{
// the data of the chunk changed: the old structure goes once the frames which read it are done
m_bottombytes -= lookup->second.bytes;
m_deletions->push(Value, [handle, old = lookup->second.handle, oldstorage = lookup->second.storage]() { destroy_structure(handle, old); });
m_deletions->push(Value, [handle, old = lookup->second.handle, oldstorage = lookup->second.storage, oldindices = lookup->second.indices]() { destroy_structure(handle, old); });
}
VkAccelerationStructureDeviceAddressInfoKHR addressinfo{};
addressinfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
@@ -497,7 +523,9 @@ void ray_tracing::build(command_stream *Commands, std::uint32_t const Slot, std:
entry.address = vkGetAccelerationStructureDeviceAddressKHR(handle, &addressinfo);
entry.generation = source.generation;
entry.used = Frame;
entry.bytes = sizes.accelerationStructureSize;
entry.bytes = sizes.accelerationStructureSize + (generated ? generated->size() : 0);
entry.index_address = (generated ? generated->address() : 0);
entry.indices = std::move(generated);
m_bottombytes += entry.bytes;
build.info.dstAccelerationStructure = structure;
build.scratch = scratchsize;
@@ -520,7 +548,7 @@ void ray_tracing::build(command_stream *Commands, std::uint32_t const Slot, std:
if (it->second.handle == build.info.dstAccelerationStructure)
{
m_bottombytes -= it->second.bytes;
m_deletions->push(Value, [handle, old = it->second.handle, oldstorage = it->second.storage]() { destroy_structure(handle, old); });
m_deletions->push(Value, [handle, old = it->second.handle, oldstorage = it->second.storage, oldindices = it->second.indices]() { destroy_structure(handle, old); });
m_bottoms.erase(it);
break;
}
@@ -589,7 +617,7 @@ void ray_tracing::build(command_stream *Commands, std::uint32_t const Slot, std:
}
auto &entry{records[written]};
entry.vertices = source.vertex_address + vertex_stride * source.vertexfirst;
entry.indices = (source.indices != VK_NULL_HANDLE ? source.index_address + sizeof(std::uint32_t) * source.first : 0);
entry.indices = (lookup->second.index_address != 0 ? lookup->second.index_address : source.indices != VK_NULL_HANDLE ? source.index_address + sizeof(std::uint32_t) * source.first : 0);
entry.texture = texture;
auto const alpha{(texture != 0) && (draw.cutoff > 0.f)};
entry.flags = (alpha ? record_alpha : 0);
@@ -702,7 +730,7 @@ void ray_tracing::build(command_stream *Commands, std::uint32_t const Slot, std:
if (it->second.used + bottom_lifetime < Frame)
{
m_bottombytes -= it->second.bytes;
m_deletions->push(Value, [handle, old = it->second.handle, oldstorage = it->second.storage]() { destroy_structure(handle, old); });
m_deletions->push(Value, [handle, old = it->second.handle, oldstorage = it->second.storage, oldindices = it->second.indices]() { destroy_structure(handle, old); });
it = m_bottoms.erase(it);
}
else

View File

@@ -97,6 +97,9 @@ class ray_tracing
std::uint64_t generation{0}; // of the data of the chunk it was built from
std::uint64_t used{0}; // the frame it was last met in
VkDeviceSize bytes{0};
// the triangles of a strip or a fan, which the structure is built from and the shading reads
std::shared_ptr<buffer> indices;
VkDeviceAddress index_address{0};
};
struct frame_data
{