webgpu sponza

This commit is contained in:
Jorijn van der Graaf 2026-05-19 00:27:09 +02:00
commit b5d0f52da0
21 changed files with 1426 additions and 58 deletions

View file

@ -19,6 +19,7 @@ module Crafter.Graphics:Mesh_implWebGPU;
import :Mesh;
import :WebGPU;
import Crafter.Asset;
import Crafter.Math;
import std;
@ -215,26 +216,59 @@ namespace {
};
}
namespace {
// Shared between the positions-only and the compressed-asset Build paths.
// attribsBytes is empty for positions-only meshes; the JS bridge skips
// the attribs-heap append in that case.
void BuildBVHAndRegister(Mesh& mesh,
std::span<const Vector<float, 3, 3>> vertices,
std::span<const std::uint32_t> indices,
std::span<const std::byte> attribsBytes) {
mesh.triangleCount = static_cast<std::uint32_t>(indices.size()) / 3;
Builder builder;
builder.Build(vertices, indices);
std::vector<std::uint32_t> primRemap(mesh.triangleCount);
for (std::uint32_t i = 0; i < mesh.triangleCount; ++i) {
primRemap[i] = builder.prims[i].triIndex;
}
const BVHNode& root = builder.nodes[0];
mesh.blasAddr = WebGPU::wgpuRegisterMeshBLAS(
root.aabbMin[0], root.aabbMin[1], root.aabbMin[2],
root.aabbMax[0], root.aabbMax[1], root.aabbMax[2],
vertices.data(), static_cast<std::int32_t>(vertices.size()),
indices.data(), static_cast<std::int32_t>(indices.size()),
builder.nodes.data(), static_cast<std::int32_t>(builder.nodes.size()),
primRemap.data(), static_cast<std::int32_t>(primRemap.size()),
attribsBytes.data(), static_cast<std::int32_t>(attribsBytes.size()));
}
}
void Mesh::Build(std::span<Vector<float, 3, 3>> vertices,
std::span<std::uint32_t> indices,
WebGPUCommandEncoderRef /*cmd*/) {
triangleCount = static_cast<std::uint32_t>(indices.size()) / 3;
BuildBVHAndRegister(*this, vertices, indices, {});
}
Builder builder;
builder.Build(vertices, indices);
void Mesh::Build(const CompressedMeshAsset& asset,
WebGPUCommandEncoderRef /*cmd*/) {
std::vector<Vector<float, 3, 3>> vertices(asset.vertexCount);
std::vector<std::uint32_t> indices(asset.indexCount);
std::vector<std::byte> dataBytes(
static_cast<std::size_t>(asset.dataCount) * asset.dataStride);
std::vector<std::uint32_t> primRemap(triangleCount);
for (std::uint32_t i = 0; i < triangleCount; ++i) {
primRemap[i] = builder.prims[i].triIndex;
}
// CompressedBlob always carries 3 regions for MeshAsset (the data region
// can have decompressedSize=0). DecompressCPU validates output sizes
// against region sizes, so the empty-data path needs the empty span.
std::array<std::span<std::byte>, 3> outputs = {
std::as_writable_bytes(std::span(vertices)),
std::as_writable_bytes(std::span(indices)),
std::span<std::byte>(dataBytes),
};
Compression::DecompressCPU(asset.blob,
std::span(outputs).first(asset.blob.regions.size()));
const BVHNode& root = builder.nodes[0];
std::uint32_t h = WebGPU::wgpuRegisterMeshBLAS(
root.aabbMin[0], root.aabbMin[1], root.aabbMin[2],
root.aabbMax[0], root.aabbMax[1], root.aabbMax[2],
vertices.data(), static_cast<std::int32_t>(vertices.size()),
indices.data(), static_cast<std::int32_t>(indices.size()),
builder.nodes.data(), static_cast<std::int32_t>(builder.nodes.size()),
primRemap.data(), static_cast<std::int32_t>(primRemap.size()));
blasAddr = h;
BuildBVHAndRegister(*this, vertices, indices, std::span(dataBytes));
}