载入中...
搜索中...
未找到
GraphicsVoxel.cpp
浏览该文件的文档.
1#include <algorithm>
2#include <cstring>
3#include "common/Exception.h"
8
9namespace eve::graphics::webgpu {
10void Graphics::createVoxelPipelines() {
11 voxelSetLayout = makeVoxelBindGroupLayout();
12 voxelPipelineLayout = makeVoxelPipelineLayout();
13
14 WGPUVertexAttribute attrs[1] = {};
15 attrs[0].format = WGPUVertexFormat_Float32x2; // corner
16 attrs[0].offset = 0;
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;
23
24 WGPUVertexAttribute packedAttr{};
25 packedAttr.format = WGPUVertexFormat_Uint32; // packed rect word
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;
33
34 WGPUVertexAttribute aoAttr{};
35 aoAttr.format = WGPUVertexFormat_Uint32; // 2 bits per corner
36 aoAttr.offset = 0;
37 aoAttr.shaderLocation = 2;
38 WGPUVertexBufferLayout aoVb{};
39 aoVb.arrayStride = 4;
40 aoVb.stepMode = WGPUVertexStepMode_Instance;
41 aoVb.attributeCount = 1;
42 aoVb.attributes = &aoAttr;
43
44 WGPUVertexBufferLayout vbs[3] = {cornerVb, packedVb, aoVb};
45
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;
52
53 WGPUColorTargetState target{};
54 target.format = sceneColorFormat;
55 target.blend = nullptr;
56 target.writeMask = WGPUColorWriteMask_All;
57
58 WGPURenderPipelineDescriptor pd{};
59 pd.label = sv("eve_voxel");
60 pd.layout = voxelPipelineLayout.Get();
61 wgpu::ShaderModule vertModule = makeWgslModule(device, kVoxelRectVertWgsl);
62 wgpu::ShaderModule fragModule = makeWgslModule(device, kVoxelRectFragWgsl);
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");
70 fs.targetCount = 1;
71 fs.targets = &target;
72 pd.fragment = &fs;
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;
79 // Zero-init would leave mask=0, which discards every fragment
80 // (sampleMask=0). The WebGPU default is 0xFFFFFFFF (all samples).
81 pd.multisample.mask = 0xFFFFFFFFu;
82 voxelRectPipeline = device.CreateRenderPipeline(reinterpret_cast<const wgpu::RenderPipelineDescriptor *>(&pd));
83
84 // Unit quad for instanced voxel faces (2 triangles, corner + packed uv slot).
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));
93
94 uint32_t indices[6] = {0, 1, 2, 2, 3, 0};
95 WGPUBufferDescriptor ibd{};
96 ibd.label = sv("eve_voxel_quad_idx");
97 ibd.size = sizeof(indices);
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));
102}
103
104void Graphics::drawVoxelFaceInstances(const uint32_t *packed, int count, float originX, float originY, float originZ,
105 const std::string &faceDir, Texture *atlas, int tilesPerRow, const uint32_t *ao) {
106 if (!device || !frame3DStarted || count <= 0 || !packed) return;
107 frameHad3DThisFrame = true;
108 frameHad3D = true;
109
110 int face = -1;
111 if (faceDir == "posX" || faceDir == "+x")
112 face = 0;
113 else if (faceDir == "negX" || faceDir == "-x")
114 face = 1;
115 else if (faceDir == "posY" || faceDir == "+y")
116 face = 2;
117 else if (faceDir == "negY" || faceDir == "-y")
118 face = 3;
119 else if (faceDir == "posZ" || faceDir == "+z")
120 face = 4;
121 else if (faceDir == "negZ" || faceDir == "-z")
122 face = 5;
123 else
124 throw Exception("drawVoxelFaceInstances: unknown faceDir '%s'", faceDir.c_str());
125
126 VoxelDraw d;
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;
134 d.pushUboOffset = 0;
135
136 // Upload packed instances + the parallel AO word (2 bits per corner) into
137 // the per-frame instance arenas.
138 auto &arena = voxelInstanceArena;
139 auto &aoArena = voxelAoArena;
140 auto ensureArena = [&](VertexArena &a) {
141 if (!a.buffer) {
142 WGPUBufferDescriptor bd{};
143 bd.label = sv("eve_voxel_instances");
144 bd.size = 1u << 20;
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;
149 }
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");
155 bd.size = cap;
156 bd.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex;
157 bd.mappedAtCreation = false;
158 a.buffer = device.CreateBuffer(reinterpret_cast<const wgpu::BufferDescriptor *>(&bd));
159 a.capacity = cap;
160 a.used = 0;
161 }
162 };
163 ensureArena(arena);
164 ensureArena(aoArena);
165 const uint32_t defaultAO = 0xFFu; // all four corners AO=3 (full bright)
166 std::vector<uint32_t> aoDefaults;
167 if (!ao) {
168 aoDefaults.assign(size_t(count), defaultAO);
169 ao = aoDefaults.data();
170 }
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);
174 arena.used += 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);
179}
180
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);
187
188 for (auto &d : voxelDraws) {
189 uint32_t offset = uboArena.alloc(256, 256);
190 struct VoxelPC {
191 glm::mat4 viewProj;
192 glm::vec4 chunkOrigin;
193 glm::vec4 atlasInfo;
194 glm::vec4 tint;
195 } pc;
196 pc.viewProj = d.viewProj;
197 pc.chunkOrigin = d.chunkOrigin;
198 pc.atlasInfo = d.atlasInfo;
199 pc.tint = d.tint;
200 queue.WriteBuffer(uboArena.buffer, offset, &pc, sizeof(pc));
201
202 WGPUBindGroupEntry entries[3]{};
203 entries[0].binding = 0;
204 entries[0].buffer = uboArena.buffer.Get();
205 entries[0].size = sizeof(pc);
206 entries[1].binding = 1;
207 entries[1].textureView = d.atlas->view.Get();
208 entries[2].binding = 2;
209 entries[2].sampler = d.atlas->sampler.Get();
210 WGPUBindGroupDescriptor bgd{};
211 bgd.layout = voxelSetLayout.Get();
212 bgd.entryCount = 3;
213 bgd.entries = entries;
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);
217
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);
223 }
224 voxelDraws.clear();
225}
226
227} // namespace eve::graphics::webgpu
LogicalId target
std::unordered_map< std::string, QuestRuntime > entries
glm::vec4 tint
std::vector< std::uint32_t > indices
size_t offset
MeleePoint3 a
Definition MeleeHit.cpp:40
float d
glm::mat4 viewProj
std::uint32_t count
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
Definition Texture.h:18
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).
Definition wgpu_types.h:20
const char * kVoxelRectVertWgsl
wgpu::ShaderModule makeWgslModule(wgpu::Device &dev, const char *wgsl)
Create an owning shader module; retain it until pipeline creation completes.
Definition wgpu_types.h:34
const char * kVoxelRectFragWgsl
std::vector< int64_t > attrs(const Node &n, const char *key, std::vector< int64_t > fallback)
Attrs.