bvle-voxels/src/voxel/VoxelTypes.h
Samuel Bouchet 5f346bb14a Phase 2: GPU-driven voxel rendering pipeline
Mega-buffer architecture replacing per-chunk GPU buffers:
- Single StructuredBuffer<PackedQuad> for all chunks (2M quads, 16 MB)
- StructuredBuffer<GPUChunkInfo> with per-chunk metadata (position, quad offsets, face groups)
- VS reads chunk info via push constants (b999) for driver-safe chunk indexing
- CPU frustum culling with wi::primitive::Frustum + AABB per chunk
- Quads sorted by face direction in greedy mesher (faceOffsets/faceCounts)
- GPU frustum + backface cull compute shader (voxelCullCS.hlsl)
- GPU binary mesher compute shader baseline (voxelMeshCS.hlsl)
- Indirect draw buffers and timestamp query infrastructure
- README with build instructions and project architecture
2026-03-25 14:24:05 +01:00

118 lines
4.3 KiB
C++

#pragma once
#include <cstdint>
#include <functional>
namespace voxel {
// ── Voxel Data (16 bits per voxel, as per spec) ─────────────────
// Layout: 8 bits material ID | 4 bits flags | 4 bits metadata
struct VoxelData {
uint16_t packed = 0;
VoxelData() = default;
explicit VoxelData(uint8_t materialID, uint8_t flags = 0, uint8_t meta = 0) {
packed = (uint16_t(materialID) << 8) | (uint16_t(flags & 0xF) << 4) | (meta & 0xF);
}
uint8_t getMaterialID() const { return uint8_t(packed >> 8); }
uint8_t getFlags() const { return uint8_t((packed >> 4) & 0xF); }
uint8_t getMetadata() const { return uint8_t(packed & 0xF); }
bool isEmpty() const { return packed == 0; }
bool isSmooth() const { return (getFlags() & FLAG_SMOOTH) != 0; }
bool isTransparent() const { return (getFlags() & FLAG_TRANSPARENT) != 0; }
bool isEmissive() const { return (getFlags() & FLAG_EMISSIVE) != 0; }
static constexpr uint8_t FLAG_SMOOTH = 0x1;
static constexpr uint8_t FLAG_TRANSPARENT = 0x2;
static constexpr uint8_t FLAG_EMISSIVE = 0x4;
static constexpr uint8_t FLAG_CUSTOM = 0x8;
};
// ── Chunk Constants ─────────────────────────────────────────────
static constexpr int CHUNK_SIZE = 32;
static constexpr int CHUNK_VOLUME = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
// ── Packed Vertex for Greedy Mesh Quads (8 bytes per quad) ──────
// Layout per spec:
// 6 bits posX | 6 bits posY | 6 bits posZ |
// 6 bits width | 6 bits height | 3 bits face |
// 8 bits materialID | 8 bits AO | 15 bits flags
struct PackedQuad {
uint64_t data;
static PackedQuad create(
uint8_t x, uint8_t y, uint8_t z,
uint8_t w, uint8_t h, uint8_t face,
uint8_t materialID, uint8_t ao = 0, uint16_t flags = 0
) {
PackedQuad q;
q.data =
(uint64_t(x & 0x3F)) |
(uint64_t(y & 0x3F) << 6) |
(uint64_t(z & 0x3F) << 12) |
(uint64_t(w & 0x3F) << 18) |
(uint64_t(h & 0x3F) << 24) |
(uint64_t(face & 0x7) << 30) |
(uint64_t(materialID) << 33) |
(uint64_t(ao) << 41) |
(uint64_t(flags & 0x7FFF) << 49);
return q;
}
uint8_t getX() const { return uint8_t(data & 0x3F); }
uint8_t getY() const { return uint8_t((data >> 6) & 0x3F); }
uint8_t getZ() const { return uint8_t((data >> 12) & 0x3F); }
uint8_t getWidth() const { return uint8_t((data >> 18) & 0x3F); }
uint8_t getHeight() const { return uint8_t((data >> 24) & 0x3F); }
uint8_t getFace() const { return uint8_t((data >> 30) & 0x7); }
uint8_t getMaterialID() const { return uint8_t((data >> 33) & 0xFF); }
uint8_t getAO() const { return uint8_t((data >> 41) & 0xFF); }
uint16_t getFlags() const { return uint16_t((data >> 49) & 0x7FFF); }
};
// Face directions: +X, -X, +Y, -Y, +Z, -Z
enum Face : uint8_t {
FACE_POS_X = 0,
FACE_NEG_X = 1,
FACE_POS_Y = 2,
FACE_NEG_Y = 3,
FACE_POS_Z = 4,
FACE_NEG_Z = 5,
FACE_COUNT = 6
};
// ── Material Descriptor ─────────────────────────────────────────
struct MaterialDesc {
uint16_t albedoTextureIndex = 0;
uint16_t normalTextureIndex = 0;
uint16_t heightmapTextureIndex = 0;
uint8_t roughness = 128; // 0-255 mapped to 0.0-1.0
uint8_t metallic = 0;
uint8_t flags = 0; // triplanar, blend mode, etc.
uint8_t _pad = 0;
static constexpr uint8_t FLAG_TRIPLANAR = 0x1;
};
// ── Chunk Position Hash ─────────────────────────────────────────
struct ChunkPos {
int32_t x, y, z;
bool operator==(const ChunkPos& other) const {
return x == other.x && y == other.y && z == other.z;
}
};
struct ChunkPosHash {
size_t operator()(const ChunkPos& p) const {
// FNV-1a inspired hash
size_t h = 0x811c9dc5;
h ^= size_t(p.x); h *= 0x01000193;
h ^= size_t(p.y); h *= 0x01000193;
h ^= size_t(p.z); h *= 0x01000193;
return h;
}
};
} // namespace voxel