载入中...
搜索中...
未找到
GraphicsPbr.cpp
浏览该文件的文档.
1#include <cstdint>
2#include <map>
3#include <tuple>
5#include "graphics/shaders/pbr_surface_frag_spv.inc"
6#include "graphics/shaders/pbr_surface_vert_spv.inc"
9
10namespace eve::graphics::vulkan {
11namespace {
12using detail::PbrUniformGpu;
13vk::SamplerAddressMode addressMode(uint32_t value) {
14 return value == 33071 ? vk::SamplerAddressMode::eClampToEdge
15 : value == 33648 ? vk::SamplerAddressMode::eMirroredRepeat
16 : vk::SamplerAddressMode::eRepeat;
17}
18vk::Pipeline createPbrPipeline(vkb::Device& device, vk::PipelineLayout layout, const vkb::BuiltRenderPass& pass,
19 vk::SampleCountFlagBits samples, BlendMode blend, bool depthWrite, PbrCullMode cullMode,
20 bool alphaToCoverage) {
21 ShaderModulePair shaders(device, embeddedSpirv(pbr_surface_vert_spv), embeddedSpirv(pbr_surface_frag_spv));
22 auto input = vkb::VertexInputStateBuilder();
23 input.addInputBinding<MeshVertex>();
24 // The dedicated PBR shader reserves locations 5..15 for its eleven material
25 // UV streams. MeshVertex gained a color attribute at location 5 for the
26 // regular mesh pipelines, so describe only the five attributes consumed by
27 // pbr_surface.vert here instead of importing the shared six-attribute list.
28 input.input_attributes.emplace_back(0, 0, vk::Format::eR32G32B32Sfloat,
29 uint32_t(offsetof(MeshVertex, pos)));
30 input.input_attributes.emplace_back(1, 0, vk::Format::eR32G32B32Sfloat,
31 uint32_t(offsetof(MeshVertex, normal)));
32 input.input_attributes.emplace_back(2, 0, vk::Format::eR32G32Sfloat,
33 uint32_t(offsetof(MeshVertex, uv)));
34 input.input_attributes.emplace_back(3, 0, vk::Format::eR16G16B16A16Uint,
35 uint32_t(offsetof(MeshVertex, joints)));
36 input.input_attributes.emplace_back(4, 0, vk::Format::eR32G32B32A32Sfloat,
37 uint32_t(offsetof(MeshVertex, weights)));
38 // Five mesh attributes plus eleven material UV streams fit Vulkan's minimum
39 // sixteen vertex attributes. Each role can select any canonical mesh UV set.
40 for (uint32_t i = 0; i < 11; ++i) {
41 input.input_bindings.emplace_back(i + 1, uint32_t(2 * sizeof(float)), vk::VertexInputRate::eVertex);
42 input.input_attributes.emplace_back(i + 5, i + 1, vk::Format::eR32G32Sfloat, 0);
43 }
44 auto attachment = makeBlendAttachment(blend);
45 attachment.blendEnable = blend != BlendMode::Opaque;
46 vk::PipelineColorBlendStateCreateInfo color{};
47 color.attachmentCount = 1;
48 color.pAttachments = &attachment;
49 vk::PipelineMultisampleStateCreateInfo multisampling{};
50 multisampling.rasterizationSamples = samples;
51 multisampling.alphaToCoverageEnable = alphaToCoverage && samples != vk::SampleCountFlagBits::e1;
52 return device.createPipeline()
53 .useClassicPipeline(shaders.vert, shaders.frag)
54 .setPipelineLayout(layout)
55 .setVertexInputState(input)
56 .setDynamicStatesViewportScissor()
57 .setRasterizer(vk::PolygonMode::eFill, false, false, 1.0f,
58 cullMode == PbrCullMode::None ? vk::CullModeFlagBits::eNone
59 : (cullMode == PbrCullMode::Front ? vk::CullModeFlagBits::eFront
60 : vk::CullModeFlagBits::eBack),
61 vk::FrontFace::eCounterClockwise)
62 .setMultisampler(multisampling)
63 .setDepthStencil(true, depthWrite, vk::CompareOp::eLess)
64 .setColorBlending(color)
65 .build(pass);
66}
67} // namespace
69 struct Draw {
70 vkb::GenericBuffer uniform, uv, skin, shadow;
71 vk::DescriptorPool pool{};
72 vk::DescriptorSet set{};
73 };
74 vk::Device device{};
75 vk::DescriptorSetLayout setLayout{};
76 vk::PipelineLayout layout{};
77 std::map<std::tuple<VkRenderPass, uint32_t, size_t>, vk::Pipeline> pipelines;
78 std::map<std::array<uint32_t, 4>, vk::Sampler> samplers;
79 std::vector<std::vector<std::unique_ptr<Draw>>> frames;
81 for (auto& frame : frames)
82 for (auto& draw : frame)
83 if (draw->pool) device.destroyDescriptorPool(draw->pool);
84 for (auto& [key, pipeline] : pipelines) device.destroyPipeline(pipeline);
85 for (auto& [key, sampler] : samplers) device.destroySampler(sampler);
86 if (layout) device.destroyPipelineLayout(layout);
87 if (setLayout) device.destroyDescriptorSetLayout(setLayout);
88 }
89};
90void Graphics::deletePbrResources(PbrResources* resources) { delete resources; }
91void Graphics::destroyPbrResources() { pbrResources_.reset(); }
93 if (!surface) {
94 pbrSurface_.reset();
95 return Result<void>::success();
96 }
97 auto result = validatePbrSurface(*surface);
98 if (!result) return result;
99 for (const auto& binding : surface->textures)
100 if (binding.texture && !binding.texture->gpuHandle)
102 Diagnostic::error(DiagnosticCode::InvalidArgument, "PBR texture has no GPU resource"));
103 for (const auto& binding : surface->vegetationDetail.textures)
104 if (binding.texture && !binding.texture->gpuHandle)
106 Diagnostic::error(DiagnosticCode::InvalidArgument, "PBR detail texture has no GPU resource"));
107 if (surface->vegetationExtras.texture && !surface->vegetationExtras.texture->gpuHandle)
109 Diagnostic::error(DiagnosticCode::InvalidArgument, "PBR Extras texture has no GPU resource"));
110 if (surface->vegetationColors.texture && !surface->vegetationColors.texture->gpuHandle)
112 Diagnostic::error(DiagnosticCode::InvalidArgument, "PBR Colors texture has no GPU resource"));
113 if (surface->vegetationVertex.texture && !surface->vegetationVertex.texture->gpuHandle)
115 Diagnostic::error(DiagnosticCode::InvalidArgument, "PBR Vertex texture has no GPU resource"));
116 if (surface->vegetationMotion.texture && !surface->vegetationMotion.texture->gpuHandle)
118 Diagnostic::error(DiagnosticCode::InvalidArgument, "PBR Motion texture has no GPU resource"));
119 if (surface->vegetationMotion.noise && !surface->vegetationMotion.noise->gpuHandle)
121 Diagnostic::error(DiagnosticCode::InvalidArgument, "PBR motion noise has no GPU resource"));
122 if (surface->vegetationAlpha.noise && !surface->vegetationAlpha.noise->gpuHandle)
124 Diagnostic::error(DiagnosticCode::InvalidArgument, "PBR vegetation fade noise has no GPU resource"));
125 const auto requireKind = [](Texture* texture, const char* role, bool array, bool volume,
126 std::uint32_t minimumLayers = 1u) -> Result<void> {
127 if (!texture) return Result<void>::success();
128 const auto* gpu = static_cast<const GpuTexture*>(texture->gpuHandle);
129 if (!gpu || gpu->isCube || gpu->isVolume != volume || (!volume && gpu->isArray != array) ||
130 (array && std::uint32_t(texture->layers) < minimumLayers))
132 DiagnosticCode::InvalidArgument, std::string(role) + " has an incompatible texture dimension"));
133 return Result<void>::success();
134 };
135 for (const auto& binding : surface->textures) {
136 auto ready = requireKind(binding.texture, "PBR texture", false, false);
137 if (!ready) return ready;
138 }
139 for (const auto& binding : surface->vegetationDetail.textures) {
140 auto ready = requireKind(binding.texture, "PBR detail texture", false, false);
141 if (!ready) return ready;
142 }
143 for (auto [texture, role, layer] :
144 std::array<std::tuple<Texture*, const char*, std::uint32_t>, 4>{
145 {{surface->vegetationExtras.texture, "PBR Extras texture", surface->vegetationExtras.layer},
146 {surface->vegetationColors.texture, "PBR Colors texture", surface->vegetationColors.layer},
147 {surface->vegetationVertex.texture, "PBR Vertex texture", surface->vegetationVertex.layer},
148 {surface->vegetationMotion.texture, "PBR Motion texture", surface->vegetationMotion.layer}}}) {
149 auto ready = requireKind(texture, role, true, false, layer + 1u);
150 if (!ready) return ready;
151 }
152 auto ready = requireKind(surface->vegetationMotion.noise, "PBR motion noise", false, false);
153 if (!ready) return ready;
154 ready = requireKind(surface->vegetationAlpha.noise, "PBR fade noise", false, true);
155 if (!ready) return ready;
156 pbrSurface_ = *surface;
157 return Result<void>::success();
158}
159void Graphics::drawPbrMesh(Mesh* mesh, const glm::mat4& model, const Color& tint) {
160 if (!pbrResources_) {
161 pbrResources_.reset(new PbrResources());
162 auto& r = *pbrResources_;
163 r.device = device.instance;
164 const auto both = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment;
165 const auto fragment = vk::ShaderStageFlagBits::eFragment;
166 const auto vertex = vk::ShaderStageFlagBits::eVertex;
167 std::array<vk::DescriptorSetLayoutBinding, 14> bindings{
168 {{0, vk::DescriptorType::eUniformBuffer, 1, both},
169 {1, vk::DescriptorType::eCombinedImageSampler, 11, fragment},
170 {3, vk::DescriptorType::eStorageBuffer, 1, vertex},
171 {4, vk::DescriptorType::eCombinedImageSampler, 1, fragment},
172 {5, vk::DescriptorType::eUniformBuffer, 1, fragment},
173 {6, vk::DescriptorType::eCombinedImageSampler, 1, fragment},
174 {7, vk::DescriptorType::eCombinedImageSampler, 3, fragment},
175 {8, vk::DescriptorType::eCombinedImageSampler, 1, fragment},
176 {9, vk::DescriptorType::eCombinedImageSampler, 1, fragment},
177 {10, vk::DescriptorType::eCombinedImageSampler, 1, vertex},
178 {11, vk::DescriptorType::eCombinedImageSampler, 1, vertex},
179 {12, vk::DescriptorType::eCombinedImageSampler, 1, vertex},
180 {13, vk::DescriptorType::eCombinedImageSampler, 1, fragment},
181 {2, vk::DescriptorType::eStorageBuffer, 1, vertex}}};
182 vk::DescriptorSetLayoutCreateInfo info{};
183 info.bindingCount = uint32_t(bindings.size());
184 info.pBindings = bindings.data();
185 r.setLayout = device->createDescriptorSetLayout(info);
186 r.layout = createPipelineLayout(device, r.setLayout);
187 }
188 auto& r = *pbrResources_;
189 auto& fslots = currentMesh3dFrameSlots();
190 // All snapshots belong to this fenced frame slot and unique draw index.
191 auto frame = currentFrameSlot();
192 if (r.frames.size() <= frame) r.frames.resize(frame + 1);
193 auto& draws = r.frames[frame];
194 const auto index = fslots.drawIndex++;
195 while (draws.size() <= index) draws.emplace_back(std::make_unique<PbrResources::Draw>());
196 auto& draw = *draws[index];
197 if (!draw.pool) {
198 std::array<vk::DescriptorPoolSize, 3> sizes{{{vk::DescriptorType::eUniformBuffer, 2},
199 {vk::DescriptorType::eStorageBuffer, 2},
200 {vk::DescriptorType::eCombinedImageSampler, 22}}};
201 vk::DescriptorPoolCreateInfo info{};
202 info.maxSets = 1;
203 info.poolSizeCount = 3;
204 info.pPoolSizes = sizes.data();
205 draw.pool = device->createDescriptorPool(info);
206 vk::DescriptorSetAllocateInfo alloc{};
207 alloc.descriptorPool = draw.pool;
208 alloc.descriptorSetCount = 1;
209 alloc.pSetLayouts = &r.setLayout;
210 draw.set = device->allocateDescriptorSets(alloc).front();
211 }
212 const auto& s = *pbrSurface_;
213 PbrUniformGpu u;
214 u.model = model;
215 u.mvp = mesh3dFrameUbo.mvp * model;
216 u.view = mesh3dFrameUbo.view;
217 u.camera = glm::vec4(glm::vec3(mesh3dFrameUbo.cameraPos), s.anisotropyRotation);
218 u.tint = {tint.r, tint.g, tint.b, tint.a};
219 u.ambient = glm::vec4(glm::vec3(mesh3dLighting.ambient), s.anisotropyStrength);
220 u.material = {mesh3dMetallic, mesh3dRoughness, float(int(mesh3dSurfaceMode)),
221 std::clamp(mesh3dAlphaCutoff + s.vegetationColor.globalAlphaThresholdOffset, 0.f, 1.f)};
222 if (mesh3dSurfaceMode == SurfaceMode::Transparent && mesh3dSurfaceBlend == BlendMode::Premultiplied)
223 u.material.z = 3;
224 u.emissive = {s.emissive[0], s.emissive[1], s.emissive[2], s.emissiveStrength};
225 u.specular = {s.specularColor[0], s.specularColor[1], s.specularColor[2], s.specularFactor};
226 u.coat = {s.clearcoatFactor, s.clearcoatRoughness, s.clearcoatNormalScale, s.ior};
227 u.colorMaskSecondary = {s.colorMaskSecondary[0], s.colorMaskSecondary[1], s.colorMaskSecondary[2],
228 float(s.normalMode)};
229 u.colorMaskParams = {s.colorMaskEnabled ? 1.f : 0.f, s.colorMaskMin, s.colorMaskMax, s.albedoTextureStrength};
230 const auto& trans = s.translucency;
231 u.translucencyColor = {trans.color[0], trans.color[1], trans.color[2], trans.intensity};
232 u.translucencyParams = {trans.strength, trans.normalDistortion, trans.scattering, trans.direct};
233 u.translucencyLighting = {trans.ambient, trans.shadow, trans.maskAmount, trans.globalIntensity * trans.overlay};
234 u.translucencyMask = {trans.maskMinimum, trans.maskMaximum, 0, 0};
235 u.motionHighlightColor = {s.motionHighlightColor[0], s.motionHighlightColor[1], s.motionHighlightColor[2],
236 s.vegetationColor.overlaySubsurface};
237 u.vegetationOverlay = {s.vegetationColor.overlayColor[0], s.vegetationColor.overlayColor[1],
238 s.vegetationColor.overlayColor[2], s.vegetationColor.overlay};
239 u.vegetationWetness = {s.vegetationColor.wetness, s.vegetationColor.overlayNormalScale,
240 s.vegetationColor.wetnessNormalScale, s.vegetationColor.overlaySmoothness};
241 u.vegetationStageParams = {s.vegetationColor.overlayVariation, s.vegetationColor.overlayProjection,
242 s.vegetationColor.vertexOcclusionAlpha, s.vegetationColor.wetnessContrast};
243 u.vegetationFieldColor = {s.vegetationColor.fieldColor[0], s.vegetationColor.fieldColor[1],
244 s.vegetationColor.fieldColor[2], s.vegetationColor.fieldColor[3]};
245 u.vegetationColorParams = {s.vegetationColor.colorsCoverage, s.vegetationColor.colorsIntensity,
246 s.vegetationColor.colorsMask, s.vegetationColor.colorsVariation};
247 u.vegetationOcclusionParams = {s.vegetationColor.vertexOcclusionMinimum, s.vegetationColor.vertexOcclusionMaximum,
248 0, 0};
249 u.vegetationOcclusionColor = {s.vegetationColor.vertexOcclusionColor[0], s.vegetationColor.vertexOcclusionColor[1],
250 s.vegetationColor.vertexOcclusionColor[2],
251 float(s.vegetationColor.backfaceNormalMode)};
252 u.vegetationGlobalMasks = {s.vegetationColor.globalColorMaskMinimum, s.vegetationColor.globalColorMaskMaximum,
253 s.vegetationColor.globalOverlayMaskMinimum, s.vegetationColor.globalOverlayMaskMaximum};
254 const auto& d = s.vegetationDetail;
255 u.detailUv = {d.uvScale[0], d.uvScale[1], d.uvOffset[0], d.uvOffset[1]};
256 u.detailColor = {d.color[0], d.color[1], d.color[2], d.normalBlendValue};
257 u.detailColorTwo = {d.colorTwo[0], d.colorTwo[1], d.colorTwo[2], d.colorTwo[3]};
258 u.detailValues = {d.value, d.normalValue, d.albedoValue, d.metallicValue};
259 u.detailMaterial = {d.occlusionValue, d.smoothnessValue, d.blendMinimum, d.blendMaximum};
260 u.detailMasks = {d.maskMinimum, d.maskMaximum, d.meshMinimum, d.meshMaximum};
261 u.detailInfo = {d.uvMode, d.colorMode, d.blendMode, d.alphaMode};
262 uint32_t detailPresent = 0;
263 for (size_t i = 0; i < d.textures.size(); ++i)
264 if (d.textures[i].texture) detailPresent |= 1u << i;
265 u.detailInfo2 = {d.maskMode, d.meshMode, d.inverseUvScale ? 1u : 0u, detailPresent};
266 const auto& extras = s.vegetationExtras;
267 u.extrasCoords = {extras.coords[0], extras.coords[1], extras.coords[2], extras.coords[3]};
268 u.extrasFallback = {extras.fallback[0], extras.fallback[1], extras.fallback[2], extras.fallback[3]};
269 u.extrasUsage0 = {extras.usage[0], extras.usage[1], extras.usage[2], extras.usage[3]};
270 u.extrasUsage1 = {extras.usage[4], extras.usage[5], extras.usage[6], extras.usage[7]};
271 u.extrasUsage2 = {extras.usage[8], 0, 0, 0};
272 u.extrasInfo = {extras.layer, extras.usePivotPosition ? 1u : 0u, extras.texture ? 1u : 0u,
273 s.vegetationAlpha.enabled ? 1u : 0u};
274 u.extrasUsage2.y = s.vegetationAlpha.global;
275 u.extrasUsage2.z = s.vegetationAlpha.variation;
276 u.extrasUsage2.w = s.vegetationAlpha.detailFade ? 1.f : 0.f;
277 u.vegetationAlphaFade = {s.vegetationAlpha.glancing, s.vegetationAlpha.camera, s.vegetationAlpha.constant,
278 s.vegetationAlpha.noiseTiling};
279 u.vegetationAlphaCamera = {s.vegetationAlpha.cameraFadeMin, s.vegetationAlpha.cameraFadeMax, 0, 0};
280 u.vegetationEmission = {s.vegetationEmission.minimum, s.vegetationEmission.maximum, s.vegetationEmission.phase,
281 s.vegetationEmission.enabled ? s.vegetationEmission.global : -1.f};
282 u.vegetationGradientOne = {s.vegetationGradient.colorOne[0], s.vegetationGradient.colorOne[1],
283 s.vegetationGradient.colorOne[2],
284 s.vegetationGradient.enabled ? s.vegetationGradient.minimum : -1.f};
285 u.vegetationGradientTwo = {s.vegetationGradient.colorTwo[0], s.vegetationGradient.colorTwo[1],
286 s.vegetationGradient.colorTwo[2], s.vegetationGradient.maximum};
287 const auto& colors = s.vegetationColors;
288 u.colorsCoords = {colors.coords[0], colors.coords[1], colors.coords[2], colors.coords[3]};
289 u.colorsFallback = {colors.fallback[0], colors.fallback[1], colors.fallback[2], colors.fallback[3]};
290 u.colorsUsage0 = {colors.usage[0], colors.usage[1], colors.usage[2], colors.usage[3]};
291 u.colorsUsage1 = {colors.usage[4], colors.usage[5], colors.usage[6], colors.usage[7]};
292 u.colorsUsage2 = {colors.usage[8], 0, 0, 0};
293 u.colorsInfo = {colors.layer, colors.usePivotPosition ? 1u : 0u, colors.texture ? 1u : 0u, 0u};
294 const auto& vertex = s.vegetationVertex;
295 u.vertexCoords = {vertex.coords[0], vertex.coords[1], vertex.coords[2], vertex.coords[3]};
296 u.vertexFallback = {vertex.fallback[0], vertex.fallback[1], vertex.fallback[2], vertex.fallback[3]};
297 u.vertexUsage0 = {vertex.usage[0], vertex.usage[1], vertex.usage[2], vertex.usage[3]};
298 u.vertexUsage1 = {vertex.usage[4], vertex.usage[5], vertex.usage[6], vertex.usage[7]};
299 u.vertexUsage2 = {vertex.usage[8], 0, 0, 0};
300 u.vertexSize = {vertex.globalSize, vertex.sizeFadeStart, vertex.sizeFadeEnd, vertex.distanceFadeBias};
301 u.vertexInfo = {vertex.layer, uint32_t(vertex.source), 0u, 0u};
302 const auto& motion = s.vegetationMotion;
303 u.motionCoords = {motion.coords[0], motion.coords[1], motion.coords[2], motion.coords[3]};
304 u.motionFallback = {motion.fallback[0], motion.fallback[1], motion.fallback[2], motion.fallback[3]};
305 u.motionUsage0 = {motion.usage[0], motion.usage[1], motion.usage[2], motion.usage[3]};
306 u.motionUsage1 = {motion.usage[4], motion.usage[5], motion.usage[6], motion.usage[7]};
307 u.motionUsage2 = {motion.usage[8], 0, 0, 0};
308 u.motionGlobal0 = {motion.globalDirection[0], motion.globalDirection[1], motion.worldOrigin[0],
309 motion.worldOrigin[1]};
310 u.motionGlobal1 = {motion.worldOrigin[2], motion.dynamicMode, motion.rigidity, motion.facing};
311 u.motionTime = {float(motion.time), 0, 0, 0};
312 u.motionBending = {motion.bending, motion.bendingSpeed, motion.bendingScale, motion.bendingVariation};
313 u.motionBranch = {motion.branch, motion.rolling, motion.branchSpeed, motion.branchScale};
314 u.motionBranch2 = {motion.branchVariation, motion.globalBending, motion.globalBranch, motion.globalFlutter};
315 u.motionFlutter = {motion.flutter, motion.flutterSpeed, motion.flutterScale, motion.flutterVariation};
316 u.motionControl = {motion.noiseTiling, motion.interaction, motion.interactionMask, motion.fadeDistance};
317 u.motionPerspective = {motion.perspectivePush, motion.perspectiveNoise, motion.perspectiveAngle, 0};
318 u.motionInfo = {motion.layer, uint32_t(motion.mode), 0u, 0u};
319 const bool skinned = mesh->hasGpuSkinning() && mesh->getSkinPaletteCount() > 0;
320 u.misc = {s.normalScale, s.occlusionStrength, s.unlit ? 1.f : 0.f,
321 skinned ? float(mesh->getSkinPaletteCount()) : 0.f};
322 for (int i = 0; i < std::min(mesh3dLighting.count, 8); ++i) u.lights[i] = mesh3dLighting.lights[i];
323 u.lights[0].color.w = mesh3dEnvTexture ? mesh3dEnvIntensity : 0;
324 std::map<uint32_t, size_t> offsets;
325 // Binding a valid dummy stream also covers roles using the mesh vertex UV0.
326 std::vector<float> coordinates(size_t(mesh->getVertexCount()) * 2, 0.f);
327 std::array<vk::DescriptorImageInfo, 11> images;
328 std::array<vk::DescriptorImageInfo, 3> detailImages;
329 for (size_t i = 0; i < 11; ++i) {
330 const auto& b = s.textures[i];
331 uint32_t offset = UINT32_MAX;
332 if (b.texture) {
333 auto values = mesh->texcoordSet(b.texcoord);
334 if (values.empty() && b.texcoord != 0) throw Exception("PBR texture references missing mesh UV channel");
335 if (!values.empty()) {
336 auto found = offsets.find(b.texcoord);
337 if (found == offsets.end()) {
338 size_t start = coordinates.size() / 2;
339 offsets.emplace(b.texcoord, start);
340 coordinates.insert(coordinates.end(), values.begin(), values.end());
341 offset = uint32_t(start);
342 } else
343 offset = uint32_t(found->second);
344 }
345 }
346 u.uvTransform[i] = {b.offset[0], b.offset[1], b.scale[0], b.scale[1]};
347 u.uvInfo[i] = {b.rotation, offset, b.texture ? 1.f : 0.f, b.srgbDecode ? 1.f : 0.f};
348 auto* tex = static_cast<GpuTexture*>((b.texture ? b.texture : whiteTexture)->gpuHandle);
349 if (tex->isCube) throw Exception("PBR material texture must be two-dimensional");
350 const std::array<uint32_t, 4> key{b.wrapS, b.wrapT, b.minFilter, b.magFilter};
351 auto found = r.samplers.find(key);
352 if (found == r.samplers.end()) {
353 vk::SamplerCreateInfo info{};
354 info.magFilter = b.magFilter == 9728 ? vk::Filter::eNearest : vk::Filter::eLinear;
355 info.minFilter = (b.minFilter == 9728 || b.minFilter == 9984 || b.minFilter == 9986) ? vk::Filter::eNearest
356 : vk::Filter::eLinear;
357 info.mipmapMode = b.minFilter >= 9986 ? vk::SamplerMipmapMode::eLinear : vk::SamplerMipmapMode::eNearest;
358 info.addressModeU = addressMode(b.wrapS);
359 info.addressModeV = addressMode(b.wrapT);
360 info.addressModeW = vk::SamplerAddressMode::eRepeat;
361 info.maxLod = b.minFilter >= 9984 ? VK_LOD_CLAMP_NONE : 0;
362 found = r.samplers.emplace(key, device->createSampler(info)).first;
363 }
364 images[i] = {found->second, tex->imageView(), vk::ImageLayout::eShaderReadOnlyOptimal};
365 }
366 for (size_t i = 0; i < d.textures.size(); ++i) {
367 const auto& b = d.textures[i];
368 auto* tex = static_cast<GpuTexture*>((b.texture ? b.texture : whiteTexture)->gpuHandle);
369 if (tex->isCube) throw Exception("PBR detail texture must be two-dimensional");
370 const std::array<uint32_t, 4> key{b.wrapS, b.wrapT, b.minFilter, b.magFilter};
371 auto found = r.samplers.find(key);
372 if (found == r.samplers.end()) {
373 vk::SamplerCreateInfo info{};
374 info.magFilter = b.magFilter == 9728 ? vk::Filter::eNearest : vk::Filter::eLinear;
375 info.minFilter = (b.minFilter == 9728 || b.minFilter == 9984 || b.minFilter == 9986) ? vk::Filter::eNearest
376 : vk::Filter::eLinear;
377 info.mipmapMode = b.minFilter >= 9986 ? vk::SamplerMipmapMode::eLinear : vk::SamplerMipmapMode::eNearest;
378 info.addressModeU = addressMode(b.wrapS);
379 info.addressModeV = addressMode(b.wrapT);
380 info.addressModeW = vk::SamplerAddressMode::eRepeat;
381 info.maxLod = b.minFilter >= 9984 ? VK_LOD_CLAMP_NONE : 0;
382 found = r.samplers.emplace(key, device->createSampler(info)).first;
383 }
384 detailImages[i] = {found->second, tex->imageView(), vk::ImageLayout::eShaderReadOnlyOptimal};
385 }
386 if (!extras.texture && !defaultExtrasArray) {
387 const std::array<uint16_t, 4> neutral{0x3c00u, 0u, 0u, 0x3c00u};
388 auto created = newTextureArrayRgba16f(1, 1, 1, neutral);
389 if (!created.ok()) throw Exception("PBR could not create its neutral Extras array");
390 defaultExtrasArray = created.value();
391 }
392 Texture* extrasTexture = extras.texture ? extras.texture : defaultExtrasArray;
393 auto* extrasGpu = static_cast<GpuTexture*>(extrasTexture->gpuHandle);
394 if (!extrasGpu->isArray || (extras.texture && extrasTexture->layers < 9))
395 throw Exception("PBR Extras texture must be a nine-layer 2D array");
396 vk::DescriptorImageInfo extrasImage{extrasGpu->sampler, extrasGpu->imageView(),
397 vk::ImageLayout::eShaderReadOnlyOptimal};
398 if (!colors.texture && !defaultColorsArray) {
399 const std::array<uint16_t, 4> neutral{0x3c00u, 0x3c00u, 0x3c00u, 0u};
400 auto created = newTextureArrayRgba16f(1, 1, 1, neutral);
401 if (!created.ok()) throw Exception("PBR could not create its neutral Colors array");
402 defaultColorsArray = created.value();
403 }
404 Texture* colorsTexture = colors.texture ? colors.texture : defaultColorsArray;
405 auto* colorsGpu = static_cast<GpuTexture*>(colorsTexture->gpuHandle);
406 if (!colorsGpu->isArray || (colors.texture && colorsTexture->layers < 9))
407 throw Exception("PBR Colors texture must be a nine-layer 2D array");
408 vk::DescriptorImageInfo colorsImage{colorsGpu->sampler, colorsGpu->imageView(),
409 vk::ImageLayout::eShaderReadOnlyOptimal};
410 if (!vertex.texture && !defaultVertexArray) {
411 const std::array<uint16_t, 4> neutral{0u, 0u, 0u, 0x3c00u};
412 auto created = newTextureArrayRgba16f(1, 1, 1, neutral);
413 if (!created.ok()) throw Exception("PBR could not create its neutral Vertex array");
414 defaultVertexArray = created.value();
415 }
416 Texture* vertexTexture = vertex.texture ? vertex.texture : defaultVertexArray;
417 auto* vertexGpu = static_cast<GpuTexture*>(vertexTexture->gpuHandle);
418 if (!vertexGpu->isArray || (vertex.texture && vertexTexture->layers < 9))
419 throw Exception("PBR Vertex texture must be a nine-layer 2D array");
420 if ((vertex.source == PbrVegetationDeformationSource::GpuFields ||
421 motion.mode != PbrVegetationMotionMode::Disabled) &&
422 skinned)
423 throw Exception("PBR GPU vegetation deformation requires an unskinned object-mode mesh");
424 vk::DescriptorImageInfo vertexImage{vertexGpu->sampler, vertexGpu->imageView(),
425 vk::ImageLayout::eShaderReadOnlyOptimal};
426 if (!motion.texture && !defaultMotionArray) {
427 const std::array<uint16_t, 4> neutral{0x3c00u, 0u, 0x3800u, 0u};
428 auto created = newTextureArrayRgba16f(1, 1, 1, neutral);
429 if (!created.ok()) throw Exception("PBR could not create its neutral Motion array");
430 defaultMotionArray = created.value();
431 }
432 Texture* motionTexture = motion.texture ? motion.texture : defaultMotionArray;
433 auto* motionGpu = static_cast<GpuTexture*>(motionTexture->gpuHandle);
434 if (!motionGpu->isArray || (motion.texture && motionTexture->layers < 9))
435 throw Exception("PBR Motion texture must be a nine-layer 2D array");
436 vk::DescriptorImageInfo motionImage{motionGpu->sampler, motionGpu->imageView(),
437 vk::ImageLayout::eShaderReadOnlyOptimal};
438 Texture* noiseTexture = motion.noise ? motion.noise : whiteTexture;
439 auto* noiseGpu = static_cast<GpuTexture*>(noiseTexture->gpuHandle);
440 if (noiseGpu->isArray || noiseGpu->isCube) throw Exception("PBR motion noise must be two-dimensional");
441 vk::DescriptorImageInfo noiseImage{noiseGpu->sampler, noiseGpu->imageView(),
442 vk::ImageLayout::eShaderReadOnlyOptimal};
443 if (!defaultVegetationFadeNoise) {
444 const std::array<uint8_t, 4> zero{0, 0, 0, 255};
445 auto created = newTexture3DRgba8(1, 1, 1, zero);
446 if (!created.ok()) throw Exception("PBR could not create its neutral vegetation fade volume");
447 defaultVegetationFadeNoise = created.value();
448 }
449 Texture* fadeNoiseTexture = s.vegetationAlpha.noise ? s.vegetationAlpha.noise : defaultVegetationFadeNoise;
450 auto* fadeNoiseGpu = static_cast<GpuTexture*>(fadeNoiseTexture->gpuHandle);
451 if (!fadeNoiseGpu->isVolume) throw Exception("PBR vegetation fade noise must be three-dimensional");
452 vk::DescriptorImageInfo fadeNoiseImage{fadeNoiseGpu->sampler, fadeNoiseGpu->imageView(),
453 vk::ImageLayout::eShaderReadOnlyOptimal};
454 if (coordinates.empty()) coordinates.resize(2);
455 if (s.normalMode != PbrNormalMode::TangentXYZ && mesh->hasImportedTangents()) {
456 const auto& tangents = mesh->importedTangents();
457 const auto& bitangents = mesh->importedBitangents();
458 if (tangents.size() != size_t(mesh->getVertexCount()) * 3 || bitangents.size() != tangents.size())
459 throw Exception("PBR authored tangent frame does not match mesh vertices");
460 if (coordinates.size() > UINT32_MAX || tangents.size() > (UINT32_MAX - coordinates.size()) / 2)
461 throw Exception("PBR tangent stream exceeds addressable range");
462 u.tangentInfo = {uint32_t(coordinates.size()), 1, 0, 0};
463 for (size_t i = 0; i < tangents.size(); i += 3) {
464 coordinates.insert(coordinates.end(), tangents.begin() + i, tangents.begin() + i + 3);
465 coordinates.insert(coordinates.end(), bitangents.begin() + i, bitangents.begin() + i + 3);
466 }
467 }
468 const auto highlights = mesh->motionHighlights();
469 if (!highlights.empty()) {
470 auto valid = mesh->validateMotionHighlights(highlights);
471 if (!valid) throw Exception("PBR motion highlights do not match mesh vertices");
472 if (coordinates.size() > UINT32_MAX || highlights.size() > UINT32_MAX - coordinates.size())
473 throw Exception("PBR highlight stream exceeds addressable range");
474 u.tangentInfo.z = uint32_t(coordinates.size());
475 u.tangentInfo.w = 1;
476 coordinates.insert(coordinates.end(), highlights.begin(), highlights.end());
477 }
478 const auto vegetationFactors = mesh->vegetationFactors();
479 if (!vegetationFactors.empty()) {
480 auto valid = mesh->validateVegetationFactors(vegetationFactors);
481 if (!valid) throw Exception("PBR vegetation factors do not match mesh vertices");
482 if (coordinates.size() > UINT32_MAX || vegetationFactors.size() > UINT32_MAX - coordinates.size())
483 throw Exception("PBR vegetation factor stream exceeds addressable range");
484 u.vegetationInfo = {uint32_t(coordinates.size()), 1, s.vegetationColor.invertVertexOcclusion ? 1u : 0u,
485 s.vegetationColor.invertVertexOcclusionColors ? 1u : 0u};
486 coordinates.insert(coordinates.end(), vegetationFactors.begin(), vegetationFactors.end());
487 }
488 const auto deformationFactors = mesh->vegetationDeformationFactors();
489 if (!deformationFactors.empty()) {
490 auto valid = mesh->validateVegetationDeformationFactors(deformationFactors);
491 if (!valid) throw Exception("PBR vegetation deformation factors do not match mesh vertices");
492 if (coordinates.size() > UINT32_MAX || deformationFactors.size() > UINT32_MAX - coordinates.size())
493 throw Exception("PBR vegetation deformation stream exceeds addressable range");
494 u.vertexInfo.z = uint32_t(coordinates.size());
495 u.vertexInfo.w = 1;
496 coordinates.insert(coordinates.end(), deformationFactors.begin(), deformationFactors.end());
497 }
498 if (motion.mode == PbrVegetationMotionMode::Object && deformationFactors.empty())
499 throw Exception("PBR GPU vegetation motion requires a nine-float rest-deformation stream");
500 const auto upload = [&](vkb::GenericBuffer& buffer, vk::BufferUsageFlags usage, const void* data, size_t bytes) {
501 if ((usage & vk::BufferUsageFlagBits::eStorageBuffer) &&
502 bytes > device.physical_device.properties.limits.maxStorageBufferRange)
503 throw Exception("PBR mesh storage exceeds device maxStorageBufferRange");
504 buffer.allocate(frameToken(), device, usage, bytes, kHostVisibleCoherent);
505 updateRingLocal(buffer, 0, data, bytes);
506 };
507 upload(draw.uniform, vk::BufferUsageFlagBits::eUniformBuffer, &u, sizeof(u));
508 upload(draw.uv, vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eStorageBuffer,
509 coordinates.data(), coordinates.size() * sizeof(float));
510 const glm::mat4 identity(1);
511 upload(draw.skin, vk::BufferUsageFlagBits::eStorageBuffer, skinned ? mesh->skinPalette().data() : &identity[0][0],
512 skinned ? mesh->skinPalette().size() * sizeof(float) : sizeof(identity));
513 auto shadow = mesh3dShadows.ubo;
514 if (!mesh3dShadows.active) {
515 shadow.bias.y = 0;
516 shadow.splits.w = 0;
517 }
518 shadow.bias.z = mesh3dShadowReceive ? 1.f : 0.f;
519 upload(draw.shadow, vk::BufferUsageFlagBits::eUniformBuffer, &shadow, sizeof(shadow));
520 ensureDefaultEnvCubemap();
521 auto* env = static_cast<GpuTexture*>((mesh3dEnvTexture ? mesh3dEnvTexture : defaultEnvCubemap)->gpuHandle);
522 if (!env->isCube) throw Exception("PBR environment must be a cubemap");
523 vk::DescriptorImageInfo envInfo{env->sampler, env->imageView(), vk::ImageLayout::eShaderReadOnlyOptimal};
524 vk::DescriptorImageInfo shadowInfo{shadowSampler, currentShadowArrayView(),
525 currentShadowMap().image.currentLayout()};
526 std::array<vk::DescriptorBufferInfo, 4> buffers{{{draw.uniform.buffer, 0, sizeof(u)},
527 {draw.skin.buffer, 0, draw.skin.size},
528 {draw.shadow.buffer, 0, sizeof(shadow)},
529 {draw.uv.buffer, 0, draw.uv.size}}};
530 std::array<vk::WriteDescriptorSet, 14> writes{};
531 const std::array<uint32_t, 14> bindings{0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 2};
532 for (size_t i = 0; i < writes.size(); ++i) {
533 writes[i].dstSet = draw.set;
534 writes[i].dstBinding = bindings[i];
535 writes[i].descriptorCount = 1;
536 }
537 for (auto [write, buffer] : std::array<std::pair<int, int>, 4>{{{0, 0}, {2, 1}, {4, 2}, {13, 3}}}) {
538 writes[write].descriptorType =
539 (write == 2 || write == 13) ? vk::DescriptorType::eStorageBuffer : vk::DescriptorType::eUniformBuffer;
540 writes[write].pBufferInfo = &buffers[buffer];
541 }
542 writes[1].descriptorType = writes[3].descriptorType = writes[5].descriptorType = writes[6].descriptorType =
543 writes[7].descriptorType = writes[8].descriptorType = writes[9].descriptorType = writes[10].descriptorType =
544 writes[11].descriptorType = writes[12].descriptorType = vk::DescriptorType::eCombinedImageSampler;
545 writes[1].descriptorCount = 11;
546 writes[1].pImageInfo = images.data();
547 writes[3].pImageInfo = &envInfo;
548 writes[5].pImageInfo = &shadowInfo;
549 writes[6].descriptorCount = 3;
550 writes[6].pImageInfo = detailImages.data();
551 writes[7].pImageInfo = &extrasImage;
552 writes[8].pImageInfo = &colorsImage;
553 writes[9].pImageInfo = &vertexImage;
554 writes[10].pImageInfo = &motionImage;
555 writes[11].pImageInfo = &noiseImage;
556 writes[12].pImageInfo = &fadeNoiseImage;
557 device->updateDescriptorSets(writes, {});
558 const auto& rp = offscreen3DPassOpen ? (offscreen3DHDRActive ? hdrOffscreen3DRenderPass : offscreen3DRenderPass)
559 : activeScenePass();
560 const auto samples = offscreen3DPassOpen ? vk::SampleCountFlagBits::e1 : activeSceneSamples();
561 const bool transparent = mesh3dSurfaceMode == SurfaceMode::Transparent;
562 const auto blend = transparent ? mesh3dSurfaceBlend : BlendMode::Opaque;
563 const bool depthWrite = !transparent || mesh3dSurfaceDepthWrite;
564 const auto resolvedCull = s.cullMode == PbrCullMode::Inherit
565 ? (mesh3dSurfaceDoubleSided ? PbrCullMode::None : PbrCullMode::Back)
566 : s.cullMode;
567 const bool alphaToCoverage = s.alphaToCoverage && mesh3dSurfaceMode == SurfaceMode::Masked;
568 const size_t pipelineVariant =
569 size_t(blend) * 12u + (depthWrite ? 6u : 0u) + (alphaToCoverage ? 3u : 0u) + size_t(resolvedCull) - 1u;
570 auto key = std::make_tuple(VkRenderPass(rp.handle), uint32_t(samples), pipelineVariant);
571 auto found = r.pipelines.find(key);
572 if (found == r.pipelines.end())
573 found = r.pipelines
574 .emplace(key, createPbrPipeline(device, r.layout, rp, samples, blend, depthWrite, resolvedCull,
575 alphaToCoverage))
576 .first;
577 auto& cb = currentPresentCb();
578 cb.bindPipeline(vk::PipelineBindPoint::eGraphics, found->second);
579 cb.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, r.layout, 0, 1, &draw.set, 0, nullptr);
580 std::array<vk::Buffer, 11> uvBuffers;
581 uvBuffers.fill(draw.uv.buffer);
582 std::array<vk::DeviceSize, 11> uvOffsets{};
583 for (size_t i = 0; i < uvOffsets.size(); ++i)
584 if (u.uvInfo[i].offset != UINT32_MAX) uvOffsets[i] = vk::DeviceSize(u.uvInfo[i].offset) * 2 * sizeof(float);
585 cb.bindVertexBuffers(1, uvBuffers, uvOffsets);
586 drawIndexedMesh(cb, *static_cast<GpuMesh*>(mesh->gpuHandle));
587 lastMesh3dPipeline = vk::Pipeline{};
588 lastMesh3dClusteredPipeline = vk::Pipeline{};
589}
590} // namespace eve::graphics::vulkan
double value
Duration start
std::string usage
double volume
const std::string & s
float uv
std::map< std::string, Var > values
EvpackChunkInput input
Definition Evpack.cpp:170
std::string layout
vkb::Device & device
std::uint32_t key
vk::UniqueSampler sampler
glm::vec4 tint
float u
Definition Grass.cpp:233
double r
float blend
size_t offset
std::uint64_t bytes
bool valid
MeleePoint3 b
Definition MeleeHit.cpp:41
MeshVfxBatchedDraw draw
Texture * normal
std::vector< std::weak_ptr< DeviceBytes > > resources
Definition OnnxGpgpu.cpp:55
std::vector< std::shared_ptr< DeviceBytes > > bindings
Definition OnnxGpgpu.cpp:38
std::unique_ptr< gpgpu::GpuBuffer > buffer
Definition OnnxGpgpu.cpp:26
std::unordered_map< std::string, ShaderEntry > shaders
Definition OnnxGpgpu.cpp:44
eve::action::ActionVfxBinding binding
TileLayer * layer
float d
Mesh * mesh
glm::mat4 model
std::vector< float > colors
bool found
int created
float weights[3]
float size
Definition TreeMesh.cpp:156
uint32_t index
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
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 mesh handle (+ optional CPU morph targets).
Definition Mesh.h:25
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
Definition Texture.h:18
Result< void > setMesh3DPbrSurface(const PbrSurface *surface) override
Sets the mesh 3 d pbr surface.
Result< Texture * > newTextureArrayRgba16f(uint32_t width, uint32_t height, uint32_t layers, std::span< const uint16_t > rgbaHalf) override
Creates a texture array rgba 16 f. @ownership Caller deletes unless documented otherwise.
Result< Texture * > newTexture3DRgba8(uint32_t width, uint32_t height, uint32_t depth, std::span< const uint8_t > rgba) override
Creates a texture 3 d rgba 8. @ownership Caller deletes unless documented otherwise.
PbrCullMode
Raster face culling requested by a PBR material.
Definition PbrSurface.h:20
eve::Color Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...
Definition Color.h:13
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
CompareOp
CompareOp public API.
Definition NpcAi.h:27
Light3DGpu lights[kMaxLights]
Definition Light.h:175
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
GpuTexture public API.
Definition Graphics.h:257
std::map< std::array< uint32_t, 4 >, vk::Sampler > samplers
std::vector< std::vector< std::unique_ptr< Draw > > > frames
std::map< std::tuple< VkRenderPass, uint32_t, size_t >, vk::Pipeline > pipelines
glm::uvec4 info
glm::vec4 color