载入中...
搜索中...
未找到
GraphicsPbr.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <array>
5#include <map>
6#include <tuple>
7
8#include "common/Exception.h"
13
14namespace eve::graphics::webgpu {
15namespace {
16using SamplerKey = std::array<std::uint32_t, 4>;
17
18wgpu::AddressMode addressMode(std::uint32_t value) {
19 return value == 33071 ? wgpu::AddressMode::ClampToEdge
20 : value == 33648 ? wgpu::AddressMode::MirrorRepeat
21 : wgpu::AddressMode::Repeat;
22}
23
24wgpu::Sampler makePbrSampler(const wgpu::Device& device, const PbrTextureBinding& binding) {
25 const auto nearestMin = binding.minFilter == 9728 || binding.minFilter == 9984 || binding.minFilter == 9986;
26 return SamplerBuilder()
27 .address(addressMode(binding.wrapS), addressMode(binding.wrapT), wgpu::AddressMode::Repeat)
28 .filter(binding.magFilter == 9728 ? wgpu::FilterMode::Nearest : wgpu::FilterMode::Linear,
29 nearestMin ? wgpu::FilterMode::Nearest : wgpu::FilterMode::Linear)
30 .mipmap(binding.minFilter >= 9986 ? wgpu::MipmapFilterMode::Linear : wgpu::MipmapFilterMode::Nearest,
31 0.f, binding.minFilter >= 9984 ? 1000.f : 0.f)
32 .build(device);
33}
34
35std::size_t rasterKey(BlendMode blend, bool depthWrite, PbrCullMode cull, bool alphaToCoverage) {
36 return std::size_t(blend) * 16u + (depthWrite ? 8u : 0u) + (alphaToCoverage ? 4u : 0u) +
37 std::size_t(cull);
38}
39} // namespace
40
42 struct Pipeline {
44 WGPUTextureFormat format = WGPUTextureFormat_Undefined;
45 std::uint32_t samples = 1;
46 std::size_t raster = 0;
47 wgpu::RenderPipeline pipeline;
48 wgpu::BindGroupLayout layout;
49 };
50 std::vector<Pipeline> pipelines;
51 std::map<SamplerKey, wgpu::Sampler> samplers;
52};
53
54void Graphics::deletePbrResources(PbrResources* resources) { delete resources; }
55
57 if (!surface) {
58 mesh3dPbrSurface.reset();
59 return Result<void>::success();
60 }
61 auto valid = validatePbrSurface(*surface);
62 if (!valid) return valid;
63 const auto requireGpu = [](Texture* texture, const char* role) -> Result<void> {
64 if (texture && !texture->gpuHandle)
66 Diagnostic::error(DiagnosticCode::InvalidArgument, std::string(role) + " has no GPU resource"));
67 return Result<void>::success();
68 };
69 const auto requireKind = [&](Texture* texture, const char* role, bool array, bool volume,
70 std::uint32_t minimumLayers = 1u) -> Result<void> {
71 if (!texture) return Result<void>::success();
72 auto* gpu = gpuForTexture(texture);
73 if (!gpu || gpu->isCube || gpu->isVolume != volume || (!volume && gpu->isArray != array) ||
74 (array && std::uint32_t(texture->layers) < minimumLayers))
76 DiagnosticCode::InvalidArgument, std::string(role) + " has an incompatible texture dimension"));
77 return Result<void>::success();
78 };
79 for (const auto& binding : surface->textures) {
80 auto ready = requireGpu(binding.texture, "PBR texture");
81 if (!ready) return ready;
82 ready = requireKind(binding.texture, "PBR texture", false, false);
83 if (!ready) return ready;
84 }
85 for (const auto& binding : surface->vegetationDetail.textures) {
86 auto ready = requireGpu(binding.texture, "PBR detail texture");
87 if (!ready) return ready;
88 ready = requireKind(binding.texture, "PBR detail texture", false, false);
89 if (!ready) return ready;
90 }
91 for (auto [texture, role] : std::array<std::pair<Texture*, const char*>, 6>{
92 {{surface->vegetationExtras.texture, "PBR Extras texture"},
93 {surface->vegetationColors.texture, "PBR Colors texture"},
94 {surface->vegetationVertex.texture, "PBR Vertex texture"},
95 {surface->vegetationMotion.texture, "PBR Motion texture"},
96 {surface->vegetationMotion.noise, "PBR motion noise"},
97 {surface->vegetationAlpha.noise, "PBR fade noise"}}}) {
98 auto ready = requireGpu(texture, role);
99 if (!ready) return ready;
100 }
101 for (auto [texture, role, layer] :
102 std::array<std::tuple<Texture*, const char*, std::uint32_t>, 4>{
103 {{surface->vegetationExtras.texture, "PBR Extras texture", surface->vegetationExtras.layer},
104 {surface->vegetationColors.texture, "PBR Colors texture", surface->vegetationColors.layer},
105 {surface->vegetationVertex.texture, "PBR Vertex texture", surface->vegetationVertex.layer},
106 {surface->vegetationMotion.texture, "PBR Motion texture", surface->vegetationMotion.layer}}}) {
107 auto ready = requireKind(texture, role, true, false, layer + 1u);
108 if (!ready) return ready;
109 }
110 auto ready = requireKind(surface->vegetationMotion.noise, "PBR motion noise", false, false);
111 if (!ready) return ready;
112 ready = requireKind(surface->vegetationAlpha.noise, "PBR fade noise", false, true);
113 if (!ready) return ready;
116 auto planned = planPbrVariant(*surface, false, false, limits);
117 if (!planned) return Result<void>::failure(planned.status());
118 mesh3dPbrSurface = *surface;
119 return Result<void>::success();
120}
121
122bool Graphics::drawPbrMesh(wgpu::RenderPassEncoder pass, WGPUTextureFormat format, bool canvasTarget,
123 Mesh3dDraw& draw, GpuMesh& mesh) {
124 const auto& surface = *draw.pbrSurface;
125 const bool environment = draw.environment && gpuForTexture(draw.environment) &&
126 gpuForTexture(draw.environment)->isCube;
127 const bool shadows = draw.shadows.active && draw.shadowReceive && shadowDepthArray;
130 auto planned = planPbrVariant(surface, environment, shadows, limits);
131 if (!planned) throw Exception("%s", planned.error()->message().c_str());
132 const auto& plan = planned.value();
133
134 if (!pbrResources_) pbrResources_.reset(new PbrResources());
135 auto& resources = *pbrResources_;
136 const bool transparent = draw.surfaceMode == SurfaceMode::Transparent;
137 const BlendMode blend = transparent ? draw.surfaceBlend : BlendMode::Opaque;
138 const bool depthWrite = !transparent || draw.depthWrite;
139 const auto cull = surface.cullMode == PbrCullMode::Inherit
140 ? (draw.doubleSided ? PbrCullMode::None : PbrCullMode::Back)
141 : surface.cullMode;
142 const bool alphaToCoverage = surface.alphaToCoverage && draw.surfaceMode == SurfaceMode::Masked;
143 const std::uint32_t samples = canvasTarget ? 1u : sceneColorSamples;
144 const auto raster = rasterKey(blend, depthWrite, cull, alphaToCoverage);
145 auto found = std::find_if(resources.pipelines.begin(), resources.pipelines.end(), [&](const auto& candidate) {
146 return candidate.plan == plan && candidate.format == format && candidate.samples == samples &&
147 candidate.raster == raster;
148 });
149 if (found == resources.pipelines.end()) {
151 wgpu::ShaderSourceWGSL vertexWgsl{};
152 vertexWgsl.code = source.vertex.c_str();
153 wgpu::ShaderModuleDescriptor vertexDescriptor{};
154 vertexDescriptor.nextInChain = &vertexWgsl;
155 auto vertex = device.CreateShaderModule(&vertexDescriptor);
156 wgpu::ShaderSourceWGSL fragmentWgsl{};
157 fragmentWgsl.code = source.fragment.c_str();
158 wgpu::ShaderModuleDescriptor fragmentDescriptor{};
159 fragmentDescriptor.nextInChain = &fragmentWgsl;
160 auto fragment = device.CreateShaderModule(&fragmentDescriptor);
161
162 std::array<wgpu::VertexAttribute, 16> attributes{};
163 auto attribute = [&](std::size_t index, wgpu::VertexFormat vertexFormat, std::uint64_t offset,
164 std::uint32_t location) {
165 attributes[index].format = vertexFormat;
166 attributes[index].offset = offset;
167 attributes[index].shaderLocation = location;
168 };
169 attribute(0, wgpu::VertexFormat::Float32x3, 0, 0);
170 attribute(1, wgpu::VertexFormat::Float32x3, 12, 1);
171 attribute(2, wgpu::VertexFormat::Float32x2, 24, 2);
172 attribute(3, wgpu::VertexFormat::Uint16x4, 32, 3);
173 attribute(4, wgpu::VertexFormat::Float32x4, 40, 4);
174 for (std::uint32_t index = 0; index < 11; ++index)
175 attribute(index + 5, wgpu::VertexFormat::Float32x2, std::uint64_t(index) * 8u, index + 5);
176 std::array<wgpu::VertexBufferLayout, 2> buffers{};
177 buffers[0].arrayStride = sizeof(MeshVertex);
178 buffers[0].attributeCount = 5;
179 buffers[0].attributes = attributes.data();
180 buffers[1].arrayStride = 11u * 2u * sizeof(float);
181 buffers[1].attributeCount = 11;
182 buffers[1].attributes = attributes.data() + 5;
183
184 wgpu::BlendState blendState{};
185 blendState.color.operation = wgpu::BlendOperation::Add;
186 blendState.alpha.operation = wgpu::BlendOperation::Add;
187 blendState.color.srcFactor = blend == BlendMode::Additive ? wgpu::BlendFactor::One
188 : blend == BlendMode::Premultiplied ? wgpu::BlendFactor::One
189 : wgpu::BlendFactor::SrcAlpha;
190 blendState.color.dstFactor = blend == BlendMode::Multiply ? wgpu::BlendFactor::Zero
191 : wgpu::BlendFactor::OneMinusSrcAlpha;
192 blendState.alpha.srcFactor = wgpu::BlendFactor::One;
193 blendState.alpha.dstFactor = wgpu::BlendFactor::OneMinusSrcAlpha;
194 if (blend == BlendMode::Multiply) {
195 blendState.color.srcFactor = wgpu::BlendFactor::Dst;
196 blendState.color.dstFactor = wgpu::BlendFactor::Zero;
197 }
198 wgpu::ColorTargetState target{};
199 target.format = wgpu::TextureFormat(format);
200 target.blend = blend == BlendMode::Opaque ? nullptr : &blendState;
201 target.writeMask = wgpu::ColorWriteMask::All;
202 wgpu::FragmentState fragmentState{};
203 fragmentState.module = fragment;
204 fragmentState.entryPoint = "main";
205 fragmentState.targetCount = 1;
206 fragmentState.targets = &target;
207 wgpu::DepthStencilState depth{};
208 depth.format = wgpu::TextureFormat::Depth32Float;
209 depth.depthWriteEnabled = depthWrite ? wgpu::OptionalBool::True : wgpu::OptionalBool::False;
210 depth.depthCompare = wgpu::CompareFunction::Less;
211 wgpu::RenderPipelineDescriptor descriptor{};
212 descriptor.vertex.module = vertex;
213 descriptor.vertex.entryPoint = "main";
214 descriptor.vertex.bufferCount = buffers.size();
215 descriptor.vertex.buffers = buffers.data();
216 descriptor.fragment = &fragmentState;
217 descriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
218 descriptor.primitive.frontFace = wgpu::FrontFace::CCW;
219 descriptor.primitive.cullMode = cull == PbrCullMode::None ? wgpu::CullMode::None
220 : cull == PbrCullMode::Front ? wgpu::CullMode::Front
221 : wgpu::CullMode::Back;
222 descriptor.depthStencil = &depth;
223 descriptor.multisample.count = samples;
224 descriptor.multisample.mask = 0xffffffffu;
225 descriptor.multisample.alphaToCoverageEnabled = alphaToCoverage;
226 PbrResources::Pipeline candidate{plan, format, samples, raster};
227 candidate.pipeline = device.CreateRenderPipeline(&descriptor);
228 candidate.layout = candidate.pipeline.GetBindGroupLayout(0);
229 resources.pipelines.push_back(std::move(candidate));
230 found = std::prev(resources.pipelines.end());
231 }
232
233 float surfaceCode = float(int(draw.surfaceMode));
234 if (draw.surfaceMode == SurfaceMode::Transparent && draw.surfaceBlend == BlendMode::Premultiplied)
235 surfaceCode = 3.f;
236 const std::uint32_t skinCount = draw.mesh->hasGpuSkinning() ? draw.mesh->getSkinPaletteCount() : 0;
237 detail::PbrUniformGpu uniform = detail::buildPbrUniformGpu(
238 {surface, draw.viewProj * draw.model, draw.model, draw.view, draw.cameraPos,
239 glm::vec4(draw.tint.r, draw.tint.g, draw.tint.b, draw.tint.a), draw.lighting.ambient,
240 draw.lighting, draw.metallic, draw.roughness, surfaceCode, draw.alphaCutoff,
241 environment ? draw.environmentIntensity : 0.f, skinCount});
242
243 const auto vertexCount = std::size_t(mesh.vertexCount);
244 std::vector<float> uv(vertexCount * 22u, 0.f);
245 for (std::size_t slot = 0; slot < surface.textures.size(); ++slot) {
246 const auto& binding = surface.textures[slot];
247 auto values = draw.mesh->texcoordSet(binding.texcoord);
248 if (binding.texture && values.empty() && binding.texcoord != 0)
249 throw Exception("PBR texture references missing mesh UV channel");
250 if (!values.empty()) uniform.uvInfo[slot].offset = 0u;
251 for (std::size_t vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex) {
252 const auto fallback = mesh.cpuVertices[vertexIndex].uv;
253 uv[vertexIndex * 22u + slot * 2u] = values.empty() ? fallback.x : values[vertexIndex * 2u];
254 uv[vertexIndex * 22u + slot * 2u + 1u] = values.empty() ? fallback.y : values[vertexIndex * 2u + 1u];
255 }
256 }
257
258 std::vector<float> attributes(2u, 0.f);
259 if (surface.normalMode != PbrNormalMode::TangentXYZ && draw.mesh->hasImportedTangents()) {
260 uniform.tangentInfo = {std::uint32_t(attributes.size()), 1u, 0u, 0u};
261 const auto& tangents = draw.mesh->importedTangents();
262 const auto& bitangents = draw.mesh->importedBitangents();
263 for (std::size_t index = 0; index < tangents.size(); index += 3u) {
264 attributes.insert(attributes.end(), tangents.begin() + index, tangents.begin() + index + 3u);
265 attributes.insert(attributes.end(), bitangents.begin() + index, bitangents.begin() + index + 3u);
266 }
267 }
268 const auto highlights = draw.mesh->motionHighlights();
269 if (!highlights.empty()) {
270 uniform.tangentInfo.z = std::uint32_t(attributes.size());
271 uniform.tangentInfo.w = 1u;
272 attributes.insert(attributes.end(), highlights.begin(), highlights.end());
273 }
274 const auto factors = draw.mesh->vegetationFactors();
275 if (!factors.empty()) {
276 uniform.vegetationInfo.x = std::uint32_t(attributes.size());
277 uniform.vegetationInfo.y = 1u;
278 attributes.insert(attributes.end(), factors.begin(), factors.end());
279 }
280 const auto deformation = draw.mesh->vegetationDeformationFactors();
281 if (!deformation.empty()) {
282 uniform.vertexInfo.z = std::uint32_t(attributes.size());
283 uniform.vertexInfo.w = 1u;
284 attributes.insert(attributes.end(), deformation.begin(), deformation.end());
285 }
286 if (surface.vegetationMotion.mode == PbrVegetationMotionMode::Object && deformation.empty())
287 throw Exception("PBR GPU vegetation motion requires a nine-float rest-deformation stream");
288
289 auto& arena = currentUboArena();
290 const auto uniformOffset = arena.alloc(sizeof(uniform), 256);
291 const auto shadowOffset = arena.alloc(sizeof(ShadowUBO), 256);
292 queue.WriteBuffer(arena.buffer, uniformOffset, &uniform, sizeof(uniform));
293 auto shadow = draw.shadows.ubo;
294 if (!shadows) {
295 shadow.bias.y = 0.f;
296 shadow.splits.w = 0.f;
297 }
298 shadow.bias.z = draw.shadowReceive ? 1.f : 0.f;
299 queue.WriteBuffer(arena.buffer, shadowOffset, &shadow, sizeof(shadow));
300
301 const auto allocateAux = [&](const void* data, std::uint64_t bytes) {
302 const auto index = arena.paletteIndex++;
303 if (arena.palettes.size() <= index) arena.palettes.resize(index + 1u);
304 auto& buffer = arena.palettes[index];
305 if (!buffer || buffer.GetSize() < bytes) {
306 wgpu::BufferDescriptor descriptor{};
307 descriptor.size = std::max<std::uint64_t>(bytes, 4u);
308 descriptor.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Storage | wgpu::BufferUsage::Vertex;
309 buffer = device.CreateBuffer(&descriptor);
310 }
311 queue.WriteBuffer(buffer, 0, data, bytes);
312 return buffer;
313 };
314 auto uvBuffer = allocateAux(uv.data(), uv.size() * sizeof(float));
315 auto attributeBuffer = allocateAux(attributes.data(), attributes.size() * sizeof(float));
316 auto skinBuffer = uploadSkinPalette(draw.mesh);
317
318 std::vector<wgpu::BindGroupEntry> entries;
319 const auto addBuffer = [&](std::uint32_t binding, const wgpu::Buffer& buffer, std::uint64_t offset,
320 std::uint64_t size) {
321 wgpu::BindGroupEntry entry{};
322 entry.binding = binding;
323 entry.buffer = buffer;
324 entry.offset = offset;
325 entry.size = size;
326 entries.push_back(entry);
327 };
328 const auto addTexture = [&](std::uint32_t binding, GpuTexture* texture) {
329 wgpu::BindGroupEntry entry{};
330 entry.binding = binding;
331 entry.textureView = texture->view;
332 entries.push_back(entry);
333 };
334 const auto addSampler = [&](std::uint32_t binding, const wgpu::Sampler& sampler) {
335 wgpu::BindGroupEntry entry{};
336 entry.binding = binding;
337 entry.sampler = sampler;
338 entries.push_back(entry);
339 };
340 addBuffer(0, arena.buffer, uniformOffset, sizeof(uniform));
341 addBuffer(2, attributeBuffer, 0, attributes.size() * sizeof(float));
342 addBuffer(3, skinBuffer, 0, skinBuffer.GetSize());
343 addBuffer(6, arena.buffer, shadowOffset, sizeof(shadow));
344
345 const auto samplerFor = [&](const PbrTextureBinding& binding) -> const wgpu::Sampler& {
346 const SamplerKey key{binding.wrapS, binding.wrapT, binding.minFilter, binding.magFilter};
347 auto sampler = resources.samplers.find(key);
348 if (sampler == resources.samplers.end())
349 sampler = resources.samplers.emplace(key, makePbrSampler(device, binding)).first;
350 return sampler->second;
351 };
352 for (std::uint32_t slot = 0; slot < std::uint32_t(surface.textures.size()); ++slot) {
353 if ((plan.canonicalTextureMask & (1u << slot)) == 0u) continue;
354 addTexture(20u + slot * 2u, gpuForTexture(surface.textures[slot].texture));
355 if (plan.canonicalSamplerRepresentatives[slot] == slot)
356 addSampler(21u + slot * 2u, samplerFor(surface.textures[slot]));
357 }
358 for (std::uint32_t slot = 0; slot < std::uint32_t(surface.vegetationDetail.textures.size()); ++slot) {
359 if ((plan.detailTextureMask & (1u << slot)) == 0u) continue;
360 addTexture(42u + slot * 2u, gpuForTexture(surface.vegetationDetail.textures[slot].texture));
361 if (plan.detailSamplerRepresentatives[slot] == std::uint32_t(PbrTextureSlot::Count) + slot)
362 addSampler(43u + slot * 2u, samplerFor(surface.vegetationDetail.textures[slot]));
363 }
364 if (plan.fragmentFlags & PbrEnvironment) {
365 auto* texture = gpuForTexture(draw.environment);
366 addTexture(4, texture);
367 addSampler(5, texture->sampler);
368 }
369 if (plan.fragmentFlags & PbrShadows) {
370 addTexture(7, shadowDepthArray);
371 addSampler(8, shadowDepthArray->sampler);
372 }
373 if (plan.fragmentFlags & PbrExtras) {
374 auto* texture = gpuForTexture(surface.vegetationExtras.texture);
375 addTexture(9, texture);
376 addSampler(10, texture->sampler);
377 }
378 if (plan.fragmentFlags & PbrColors) {
379 auto* texture = gpuForTexture(surface.vegetationColors.texture);
380 addTexture(11, texture);
381 addSampler(12, texture->sampler);
382 }
383 if (plan.fragmentFlags & PbrFadeNoise) {
384 auto* texture = gpuForTexture(surface.vegetationAlpha.noise);
385 addTexture(13, texture);
386 addSampler(14, texture->sampler);
387 }
388 if (plan.vertexFlags & PbrVertexField) {
389 auto* texture = gpuForTexture(surface.vegetationVertex.texture);
390 addTexture(50, texture);
391 addSampler(51, texture->sampler);
392 }
393 if (plan.vertexFlags & PbrMotionField) {
394 auto* texture = gpuForTexture(surface.vegetationMotion.texture);
395 addTexture(52, texture);
396 addSampler(53, texture->sampler);
397 }
398 if (plan.vertexFlags & PbrMotionNoise) {
399 auto* texture = gpuForTexture(surface.vegetationMotion.noise);
400 addTexture(54, texture);
401 addSampler(55, texture->sampler);
402 }
403
404 wgpu::BindGroupDescriptor bindDescriptor{};
405 bindDescriptor.layout = found->layout;
406 bindDescriptor.entryCount = entries.size();
407 bindDescriptor.entries = entries.data();
408 auto bindGroup = device.CreateBindGroup(&bindDescriptor);
409 pass.SetPipeline(found->pipeline);
410 pass.SetBindGroup(0, bindGroup);
411 pass.SetVertexBuffer(0, mesh.vertexBuffer, 0, std::uint64_t(mesh.vertexCount) * mesh.vertexStride);
412 pass.SetVertexBuffer(1, uvBuffer, 0, uv.size() * sizeof(float));
413 if (mesh.indexBuffer) {
414 const auto indexBytes = mesh.indexFormat == wgpu::IndexFormat::Uint16 ? 2u : 4u;
415 pass.SetIndexBuffer(mesh.indexBuffer, mesh.indexFormat, 0, std::uint64_t(mesh.indexCount) * indexBytes);
416 pass.DrawIndexed(mesh.indexCount, 1, 0, 0, 0);
417 } else {
418 pass.Draw(mesh.vertexCount, 1, 0, 0);
419 }
420 return true;
421}
422
423} // namespace eve::graphics::webgpu
LogicalId target
double value
std::string descriptor
double volume
std::unordered_map< std::string, QuestRuntime > entries
float uv
std::map< std::string, Var > values
std::uint32_t vertexCount
vkb::Device & device
std::uint32_t key
vk::UniqueSampler sampler
float u
Definition Grass.cpp:233
std::int32_t first
float blend
size_t offset
std::uint64_t bytes
bool valid
MeshVfxBatchedDraw draw
std::vector< std::weak_ptr< DeviceBytes > > resources
Definition OnnxGpgpu.cpp:55
std::unique_ptr< gpgpu::GpuBuffer > buffer
Definition OnnxGpgpu.cpp:26
eve::action::ActionVfxBinding binding
TileLayer * layer
Mesh * mesh
bool found
std::string mipmap
float size
Definition TreeMesh.cpp:156
uint32_t index
const UnitySourceAsset & source
std::uint32_t depth
const AssetImportLimits & limits
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
Definition Texture.h:18
uint32_t maxSamplersPerShaderStage() const
Maximum samplers visible to one shader stage.
uint32_t maxSampledTexturesPerShaderStage() const
Maximum sampled textures visible to one shader stage.
Result< void > setMesh3DPbrSurface(const PbrSurface *surface) override
Sets the mesh 3 d pbr surface.
PbrUniformGpu buildPbrUniformGpu(const PbrUniformBuildInputs &inputs)
Build all material and scene fields; mesh stream offsets remain disabled for the backend to fill.
Result< PbrVariantPlan > planPbrVariant(const PbrSurface &surface, bool environment, bool shadows, const PbrVariantLimits &limits)
Plan only resources reachable for an immutable PBR draw snapshot.
PbrSpecializedSources specializePbrVariantSources(const PbrVariantPlan &plan)
Specialize the generated WGSL for the resource reachability encoded by a checked plan.
FilterMode
Mag/min filter for texture sampling.
PbrCullMode
Raster face culling requested by a PBR material.
Definition PbrSurface.h:20
Result< void > validatePbrSurface(const PbrSurface &s)
Validate finite material factors and sampler enums without changing the input.
Definition PbrSurface.cpp:4
eve::BlendMode BlendMode
Compatibility alias for the shared 2D blend mode.
Definition BlendMode.h:8
BlendMode
Render-neutral 2D blend mode shared by graphics-facing modules.
Definition RenderTypes.h:11
Owning material parameter snapshot; texture pointers remain borrowed. Base color/metallic/roughness c...
Definition PbrSurface.h:218
PbrVegetationMotion vegetationMotion
Definition PbrSurface.h:259
PbrVegetationExtras vegetationExtras
Definition PbrSurface.h:256
std::array< PbrTextureBinding, std::size_t(PbrTextureSlot::Count)> textures
Definition PbrSurface.h:219
PbrVegetationVertex vegetationVertex
Definition PbrSurface.h:258
PbrVegetationColors vegetationColors
Definition PbrSurface.h:257
PbrVegetationDetail vegetationDetail
Definition PbrSurface.h:255
PbrVegetationAlpha vegetationAlpha
Definition PbrSurface.h:260
std::array< PbrTextureBinding, 3 > textures
Definition PbrSurface.h:104
Vertex/index buffers for one mesh.
Definition Graphics.h:153
std::map< SamplerKey, wgpu::Sampler > samplers
Device resource limits relevant to one extended PBR shader variant.
Stable resource-layout key and checked stage counts for a PBR snapshot.