We have updated our WebGPU HZB tester and introduced several improvements and new tools.
The tester now supports working with custom buffers and enables occlusion testing using HZB for local storage.
Key changes:
- Optimized the BitSet class.
- Separated storage logic for AABB centers and half-extents — see the AABBStore class.
- Added the IndirectDataBuffer class, which supports batched data updates with configurable maximum batch size in bytes.
- Improved overall system performance.
- Added new debugging tools.
Feedback and suggestions are welcome.
Версия для русскоязычных:
Мы обновили наш тестер HZB для WebGPU и добавили ряд улучшений и новых инструментов.
Теперь тестер поддерживает работу с пользовательскими буферами, а также позволяет выполнять тесты окклюзии с использованием HZB для локального хранилища
Основные изменения:
- Оптимизирован класс BitSet.
- Разделена логика хранения центров AABB и половинных размеров — подробности см. в классе AABBStore.
- Добавлен класс IndirectDataBuffer, который поддерживает обновление данных батчами с возможностью задавать максимальный размер батча в байтах.
- Улучшена общая производительность системы.
- Добавлены новые инструменты для отладки.
Будем рады обратной связи и предложениям.
function setIndirect(meshInstance: pc.MeshInstance, tester: IGPUIndirectDrawOcclusionCullingTester, drawData: DrawData[]) {
const numSlots = drawData.length;
const firstSlot = meshInstance.mesh.device.getIndirectDrawSlot(numSlots);
for (let i = 0; i < numSlots; i++) {
const slot = firstSlot + i;
const queueItem = drawData[i];
const id = queueItem.id;
const primitive = queueItem.primitive;
const instanceCount = 1;
const firstInstance = 0;
tester.enqueue(id, slot, primitive, instanceCount, firstInstance);
}
meshInstance.setIndirect(null, firstSlot, numSlots);
}
...
// Fill aabb store
const aabbStore: IAABBStore;
const indirectDataBuffer: IndirectDataBuffer;
const queue: GPUIndexQueue;
...
function testOcclusionCulling(meshInstance: pc.MeshInstance, tester: IGPUIndirectDrawOcclusionCullingTester, drawData: DrawData[]) {
const numSlots = drawData.length;
const drawCommands = meshInstance.setMultiDraw(null, numSlots);
queue.clear();
for (let slot = 0; slot < numSlots; slot++) {
const queueItem = drawData[slot];
const id = queueItem.id;
const primitive = queueItem.primitive;
const instanceCount = 1;
const firstInstance = 0;
// or take from drawCommands
indirectDataBuffer.tryEnqueueUpdate(id, primitive, instanceCount, firstInstance);
queue.enqueue(id, slot);
}
// Update buffers
indirectDataBuffer.update();
queue.update();
// Run HZB test and write new indirect data to drawCommands buffer
tester.test(numSlots, viewProjection, cameraPosition, aabbStore, queue.buffer, indirectDataBuffer, drawCommands.impl.storage);
}