10void Graphics::createVoxelPipelines() {
11 voxelSetLayout = makeVoxelBindGroupLayout();
12 voxelPipelineLayout = makeVoxelPipelineLayout();
14 WGPUVertexAttribute
attrs[1] = {};
15 attrs[0].format = WGPUVertexFormat_Float32x2;
17 attrs[0].shaderLocation = 0;
18 WGPUVertexBufferLayout cornerVb{};
19 cornerVb.arrayStride = 8;
20 cornerVb.stepMode = WGPUVertexStepMode_Vertex;
21 cornerVb.attributeCount = 1;
22 cornerVb.attributes =
attrs;
24 WGPUVertexAttribute packedAttr{};
25 packedAttr.format = WGPUVertexFormat_Uint32;
26 packedAttr.offset = 0;
27 packedAttr.shaderLocation = 1;
28 WGPUVertexBufferLayout packedVb{};
29 packedVb.arrayStride = 4;
30 packedVb.stepMode = WGPUVertexStepMode_Instance;
31 packedVb.attributeCount = 1;
32 packedVb.attributes = &packedAttr;
34 WGPUVertexAttribute aoAttr{};
35 aoAttr.format = WGPUVertexFormat_Uint32;
37 aoAttr.shaderLocation = 2;
38 WGPUVertexBufferLayout aoVb{};
40 aoVb.stepMode = WGPUVertexStepMode_Instance;
41 aoVb.attributeCount = 1;
42 aoVb.attributes = &aoAttr;
44 WGPUVertexBufferLayout vbs[3] = {cornerVb, packedVb, aoVb};
46 WGPUDepthStencilState ds{};
47 ds.format = WGPUTextureFormat_Depth32Float;
48 ds.depthWriteEnabled = WGPUOptionalBool_True;
49 ds.depthCompare = WGPUCompareFunction_Less;
50 ds.stencilReadMask = 0;
51 ds.stencilWriteMask = 0;
53 WGPUColorTargetState
target{};
54 target.format = sceneColorFormat;
56 target.writeMask = WGPUColorWriteMask_All;
58 WGPURenderPipelineDescriptor pd{};
59 pd.label =
sv(
"eve_voxel");
60 pd.layout = voxelPipelineLayout.Get();
63 pd.vertex.module = vertModule.Get();
64 pd.vertex.entryPoint =
sv(
"vs_main");
65 pd.vertex.bufferCount = 3;
66 pd.vertex.buffers = vbs;
67 WGPUFragmentState fs{};
68 fs.module = fragModule.Get();
69 fs.entryPoint =
sv(
"fs_main");
73 pd.primitive.topology = WGPUPrimitiveTopology_TriangleList;
74 pd.primitive.frontFace = WGPUFrontFace_CCW;
75 pd.primitive.cullMode = WGPUCullMode_None;
76 pd.primitive.stripIndexFormat = WGPUIndexFormat_Undefined;
77 pd.depthStencil = &ds;
78 pd.multisample.count = sceneColorSamples;
81 pd.multisample.mask = 0xFFFFFFFFu;
82 voxelRectPipeline = device.CreateRenderPipeline(
reinterpret_cast<const wgpu::RenderPipelineDescriptor *
>(&pd));
85 float quad[8] = {0, 0, 1, 0, 1, 1, 0, 1};
86 WGPUBufferDescriptor bd{};
87 bd.label =
sv(
"eve_voxel_quad");
88 bd.size =
sizeof(quad);
89 bd.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex;
90 bd.mappedAtCreation =
false;
91 voxelUnitQuadVerts = device.CreateBuffer(
reinterpret_cast<const wgpu::BufferDescriptor *
>(&bd));
92 queue.WriteBuffer(voxelUnitQuadVerts, 0, quad,
sizeof(quad));
94 uint32_t
indices[6] = {0, 1, 2, 2, 3, 0};
95 WGPUBufferDescriptor ibd{};
96 ibd.label =
sv(
"eve_voxel_quad_idx");
98 ibd.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index;
99 ibd.mappedAtCreation =
false;
100 voxelUnitQuadIndices = device.CreateBuffer(
reinterpret_cast<const wgpu::BufferDescriptor *
>(&ibd));
101 queue.WriteBuffer(voxelUnitQuadIndices, 0,
indices,
sizeof(
indices));
105 const std::string &faceDir,
Texture *atlas,
int tilesPerRow,
const uint32_t *ao) {
106 if (!device || !frame3DStarted ||
count <= 0 || !packed)
return;
107 frameHad3DThisFrame =
true;
111 if (faceDir ==
"posX" || faceDir ==
"+x")
113 else if (faceDir ==
"negX" || faceDir ==
"-x")
115 else if (faceDir ==
"posY" || faceDir ==
"+y")
117 else if (faceDir ==
"negY" || faceDir ==
"-y")
119 else if (faceDir ==
"posZ" || faceDir ==
"+z")
121 else if (faceDir ==
"negZ" || faceDir ==
"-z")
124 throw Exception(
"drawVoxelFaceInstances: unknown faceDir '%s'", faceDir.c_str());
127 d.count = uint32_t(
count);
128 d.atlas = gpuForTextureOrWhite(atlas);
129 d.viewProj = mesh3dViewProj;
130 d.chunkOrigin = glm::vec4(originX, originY, originZ,
float(face));
131 d.atlasInfo = glm::vec4(
float(std::max(1, tilesPerRow)), 0.f, 0.f, 0.f);
132 d.tint = glm::vec4(1.f);
133 d.instanceBufferOffset = 0;
138 auto &arena = voxelInstanceArena;
139 auto &aoArena = voxelAoArena;
140 auto ensureArena = [&](VertexArena &
a) {
142 WGPUBufferDescriptor bd{};
143 bd.label =
sv(
"eve_voxel_instances");
145 bd.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex;
146 bd.mappedAtCreation =
false;
147 a.buffer = device.CreateBuffer(
reinterpret_cast<const wgpu::BufferDescriptor *
>(&bd));
148 a.capacity = 1u << 20;
150 uint64_t need = uint64_t(
count) * 4;
151 if (
a.used + need >
a.capacity) {
152 uint64_t cap =
a.capacity * 2;
153 WGPUBufferDescriptor bd{};
154 bd.label =
sv(
"eve_voxel_instances");
156 bd.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex;
157 bd.mappedAtCreation =
false;
158 a.buffer = device.CreateBuffer(
reinterpret_cast<const wgpu::BufferDescriptor *
>(&bd));
164 ensureArena(aoArena);
165 const uint32_t defaultAO = 0xFFu;
166 std::vector<uint32_t> aoDefaults;
168 aoDefaults.assign(
size_t(
count), defaultAO);
169 ao = aoDefaults.data();
171 const uint64_t need = uint64_t(
count) * 4;
172 d.instanceBufferOffset =
static_cast<uint32_t
>(arena.used);
173 queue.WriteBuffer(arena.buffer, arena.used, packed, need);
175 d.aoBufferOffset =
static_cast<uint32_t
>(aoArena.used);
176 queue.WriteBuffer(aoArena.buffer, aoArena.used, ao, need);
177 aoArena.used += need;
178 voxelDraws.push_back(
d);
181void Graphics::flushVoxelDraws(wgpu::RenderPassEncoder pass, WGPUTextureFormat format) {
182 if (voxelDraws.empty())
return;
183 if (!voxelRectPipeline) createVoxelPipelines();
184 auto &uboArena = currentUboArena();
185 ensureUboArena(uboArena, uboArena.used + voxelDraws.size() * 512);
186 pass.SetPipeline(voxelRectPipeline);
188 for (
auto &
d : voxelDraws) {
189 uint32_t
offset = uboArena.alloc(256, 256);
192 glm::vec4 chunkOrigin;
196 pc.viewProj =
d.viewProj;
197 pc.chunkOrigin =
d.chunkOrigin;
198 pc.atlasInfo =
d.atlasInfo;
200 queue.WriteBuffer(uboArena.buffer,
offset, &pc,
sizeof(pc));
202 WGPUBindGroupEntry
entries[3]{};
204 entries[0].buffer = uboArena.buffer.Get();
207 entries[1].textureView =
d.atlas->view.Get();
209 entries[2].sampler =
d.atlas->sampler.Get();
210 WGPUBindGroupDescriptor bgd{};
211 bgd.layout = voxelSetLayout.Get();
214 wgpu::BindGroup bg = device.CreateBindGroup(
reinterpret_cast<const wgpu::BindGroupDescriptor *
>(&bgd));
215 uint32_t offsets[1] = {
offset};
216 pass.SetBindGroup(0, bg, 1, offsets);
218 pass.SetVertexBuffer(0, voxelUnitQuadVerts, 0, 32);
219 pass.SetVertexBuffer(1, voxelInstanceArena.buffer,
d.instanceBufferOffset, uint64_t(
d.count) * 4);
220 pass.SetVertexBuffer(2, voxelAoArena.buffer,
d.aoBufferOffset, uint64_t(
d.count) * 4);
221 pass.SetIndexBuffer(voxelUnitQuadIndices, wgpu::IndexFormat::Uint32, 0, 24);
222 pass.DrawIndexed(6,
d.count, 0, 0, 0);
std::unordered_map< std::string, QuestRuntime > entries
std::vector< std::uint32_t > indices
EVENGINE_API_FOUNDATION public API.
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
void drawVoxelFaceInstances(const uint32_t *packed, int count, float originX, float originY, float originZ, const std::string &faceDir, Texture *atlas, int tilesPerRow=16, const uint32_t *ao=nullptr) override
Draws voxel face instances.
WGPUStringView sv(const char *s)
Build a WGPUStringView from a C string (null-safe, length auto-computed).
const char * kVoxelRectVertWgsl
wgpu::ShaderModule makeWgslModule(wgpu::Device &dev, const char *wgsl)
Create an owning shader module; retain it until pipeline creation completes.
const char * kVoxelRectFragWgsl
std::vector< int64_t > attrs(const Node &n, const char *key, std::vector< int64_t > fallback)
Attrs.