272 const QSSGRenderCamera &inCamera,
273 const QSSGRenderLight *inLight,
274 const int shadowMapResolution,
275 const float pcfRadius,
276 const float clipNear,
278 const QSSGBounds3 &castingObjectsBox,
279 const QSSGBounds3 &receivingObjectsBox,
280 bool lockShadowmapTexels,
281 QSSGDebugDrawSystem *debugDrawSystem,
283 bool drawSceneCascadeIntersection)
285 Q_ASSERT(inLight->type == QSSGRenderLight::Type::DirectionalLight);
286 QVarLengthArray<std::unique_ptr<QSSGRenderCamera>, 4> result;
288 if (clipNear >= clipFar || qFuzzyCompare(clipNear, clipFar))
291 const QMatrix4x4 lightGlobalTransform = data.getGlobalTransform(*inLight);
292 const QVector3D lightDir = inLight->getDirection(lightGlobalTransform);
293 const QVector3D lightPivot = inLight->pivot;
295 const QVector3D forward = lightDir.normalized();
296 const QVector3D right = qFuzzyCompare(qAbs(forward.y()), 1.0f)
297 ? QVector3D::crossProduct(forward, QVector3D(1, 0, 0)).normalized()
298 : QVector3D::crossProduct(forward, QVector3D(0, 1, 0)).normalized();
299 const QVector3D up = QVector3D::crossProduct(right, forward).normalized();
301 QMatrix4x4 lightMatrix;
302 lightMatrix.setRow(0, QVector4D(right, 0.0f));
303 lightMatrix.setRow(1, QVector4D(up, 0.0f));
304 lightMatrix.setRow(2, QVector4D(forward, 0.0f));
305 lightMatrix.setRow(3, QVector4D(0.0f, 0.0f, 0.0f, 1.0f));
306 QMatrix4x4 lightMatrixInverted = lightMatrix.inverted();
308 const float farScale = (clipFar - clipNear) / (inCamera.clipPlanes.clipFar() - inCamera.clipPlanes.clipNear());
310 const QMatrix4x4 cameraGlobalTransform = data.getGlobalTransform(inCamera);
311 QMatrix4x4 viewProjection(Qt::Uninitialized);
312 inCamera.calculateViewProjectionMatrix(cameraGlobalTransform, viewProjection);
313 const QSSGBoxPoints frustum = computeFrustumBounds(viewProjection);
314 const QSSGBoxPoints frustumUntransformed = lockShadowmapTexels ? computeFrustumBounds(inCamera.projection) : QSSGBoxPoints();
318 const auto calcFrustumRadius = [&](
float t0,
float t1) ->
float {
319 const QSSGBoxPoints pts = sliceFrustum(frustumUntransformed, t0 * farScale, t1 * farScale);
321 QVector3D center = QVector3D(0.f, 0.f, 0.f);
322 for (QVector3D point : pts) {
325 center = center * 0.125f;
327 float radiusSquared = 0;
328 for (QVector3D point : pts) {
329 radiusSquared = qMax(radiusSquared, (point - center).lengthSquared());
332 return std::sqrt(radiusSquared);
335 const auto computeSplitRanges = [inLight](
const QVarLengthArray<
float, 3> &splits) -> QVarLengthArray<QPair<
float,
float>, 4> {
336 QVarLengthArray<QPair<
float,
float>, 4> ranges;
337 const float csmBlendRatio = inLight->m_csmBlendRatio;
339 for (qsizetype i = 0; i < splits.length(); i++) {
340 const float tI = qBound(qMin(t0 + 0.01f, 1.0f), splits[i], 1.0f);
341 ranges.emplace_back(t0, qMin(1.0f, tI + csmBlendRatio));
344 ranges.emplace_back(t0, 1.0f);
348 const auto computeFrustums = [&](
const QVarLengthArray<
float, 3> &splits) {
349 for (
const auto &range : computeSplitRanges(splits)) {
350 const float frustumRadius = lockShadowmapTexels ? calcFrustumRadius(range.first, range.second) : 0.0f;
351 auto camera = computeShadowCameraFromFrustum(lightMatrix,
359 range.first * farScale,
360 range.second * farScale,
367 drawSceneCascadeIntersection);
368 result.emplace_back(std::move(camera));
372 switch (inLight->m_csmNumSplits) {
378 computeFrustums({ inLight->m_csmSplit1 });
382 computeFrustums({ inLight->m_csmSplit1, inLight->m_csmSplit2 });
386 computeFrustums({ inLight->m_csmSplit1, inLight->m_csmSplit2, inLight->m_csmSplit3 });
428 QSSGRhiShaderPipeline *shaderPipeline,
429 QSSGRenderableImage *renderableImage,
430 QSSGRhiShaderResourceBindingList &bindings,
431 bool isCustomMaterialMeshSubset =
false)
433 static const auto imageAffectsAlpha = [](QSSGRenderableImage::Type mapType) {
434 return mapType == QSSGRenderableImage::Type::BaseColor ||
435 mapType == QSSGRenderableImage::Type::Diffuse ||
436 mapType == QSSGRenderableImage::Type::Translucency ||
437 mapType == QSSGRenderableImage::Type::Opacity;
440 while (renderableImage) {
441 const auto mapType = renderableImage->m_mapType;
442 if (imageAffectsAlpha(mapType)) {
443 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(mapType);
444 const int samplerHint =
int(mapType);
445 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
446 if (samplerBinding >= 0) {
447 QRhiTexture *texture = renderableImage->m_texture.m_texture;
448 if (samplerBinding >= 0 && texture) {
449 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
450 QRhiSampler *sampler = rhiCtx->sampler({ QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
451 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
452 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
453 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
454 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
455 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
457 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
461 renderableImage = renderableImage->m_nextImage;
464 if (isCustomMaterialMeshSubset) {
465 QVector<QShaderDescription::InOutVariable> samplerVars =
466 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
467 for (
const QShaderDescription::InOutVariable &var : shaderPipeline->vertexStage()->shader().description().combinedImageSamplers()) {
468 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
469 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
470 if (it == samplerVars.cend())
471 samplerVars.append(var);
474 int maxSamplerBinding = -1;
475 for (
const QShaderDescription::InOutVariable &var : samplerVars)
476 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
485 QBitArray samplerBindingsSpecified(maxSamplerBinding + 1);
487 if (maxSamplerBinding >= 0) {
489 int customTexCount = shaderPipeline->extraTextureCount();
490 for (
int i = 0; i < customTexCount; ++i) {
491 const QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
492 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
493 if (samplerBinding >= 0) {
494 samplerBindingsSpecified.setBit(samplerBinding);
495 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
496 bindings.addTexture(samplerBinding,
497 RENDERER_VISIBILITY_ALL,
505 QRhiSampler *dummySampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
506 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
507 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
508 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
509 QRhiTexture *dummyCubeTexture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
510 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
512 for (
const QShaderDescription::InOutVariable &var : samplerVars) {
513 if (!samplerBindingsSpecified.testBit(var.binding)) {
514 QRhiTexture *t = var.type == QShaderDescription::SamplerCube ? dummyCubeTexture : dummyTexture;
515 bindings.addTexture(var.binding, RENDERER_VISIBILITY_ALL, t, dummySampler);
701 QSSGRhiGraphicsPipelineState *ps,
702 const QVector2D *depthAdjust,
703 const QSSGRenderableObjectList &sortedOpaqueObjects,
704 QSSGRenderCamera &inCamera,
706 QSSGRenderTextureCubeFace cubeFace,
707 quint32 cascadeIndex)
709 QSSGShaderFeatures featureSet;
711 featureSet.set(QSSGShaderFeatures::Feature::OrthoShadowPass,
true);
713 featureSet.set(QSSGShaderFeatures::Feature::PerspectiveShadowPass,
true);
719 featureSet.set(QSSGShaderFeatures::Feature::DisableMultiView,
true);
721 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
722 const auto &defaultMaterialShaderKeyProperties = inData.getDefaultMaterialPropertyTable();
723 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
725 for (
const auto &handle : sortedOpaqueObjects) {
726 QSSGRenderableObject *theObject = handle.obj;
727 QSSG_ASSERT(theObject->renderableFlags.castsShadows(),
continue);
729 QSSGShaderFeatures objectFeatureSet = featureSet;
730 const bool isOpaqueDepthPrePass = theObject->depthWriteMode == QSSGDepthDrawMode::OpaquePrePass;
731 if (isOpaqueDepthPrePass)
732 objectFeatureSet.set(QSSGShaderFeatures::Feature::OpaqueDepthPrePass,
true);
734 QSSGRhiDrawCallData *dcd =
nullptr;
735 QMatrix4x4 modelViewProjection;
736 QSSGSubsetRenderable &renderable(
static_cast<QSSGSubsetRenderable &>(*theObject));
737 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
738 const bool hasSkinning = defaultMaterialShaderKeyProperties.m_boneCount.getValue(renderable.shaderDescription) > 0;
739 modelViewProjection = hasSkinning ? pEntry->m_lightViewProjection[cascadeIndex]
740 : pEntry->m_lightViewProjection[cascadeIndex] * renderable.modelContext.globalTransform;
744 const quintptr entryIdx = cascadeIndex + cubeFaceIdx + (quintptr(renderable.subset.offset) << 3);
745 dcd = &rhiCtxD->drawCallData({ passKey, &renderable.modelContext.model, pEntry, entryIdx });
748 QSSGRhiShaderResourceBindingList bindings;
749 QSSGRhiShaderPipelinePtr shaderPipeline;
750 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*theObject));
751 if (theObject->type == QSSGSubsetRenderable::Type::DefaultMaterialMeshSubset) {
752 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
753 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
754 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(subsetRenderable.shaderDescription);
756 shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, objectFeatureSet);
759 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
760 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
762 QSSGRenderCameraList cameras({ &inCamera });
763 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, cameras, depthAdjust, &modelViewProjection);
765 QSSGParticleRenderer::updateUniformsForParticleModel(*shaderPipeline, ubufData, &subsetRenderable.modelContext.model, subsetRenderable.subset.offset);
766 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
768 QSSGParticleRenderer::prepareParticlesForModel(*shaderPipeline, rhiCtx, bindings, &subsetRenderable.modelContext.model);
769 }
else if (theObject->type == QSSGSubsetRenderable::Type::CustomMaterialMeshSubset) {
770 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
771 ps->cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
773 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
774 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(ps, material, subsetRenderable, inData.getDefaultMaterialPropertyTable(), objectFeatureSet);
777 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
778 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
780 QSSGRenderCameraList cameras({ &inCamera });
781 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, material, subsetRenderable,
782 cameras, depthAdjust, &modelViewProjection);
783 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
786 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
788 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, shaderPipeline.get());
789 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
790 ia = subsetRenderable.subset.rhi.ia;
791 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
792 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
793 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
796 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
799 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
801 addNormalTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
803 if (isOpaqueDepthPrePass) {
804 addOpaqueDepthPrePassBindings(rhiCtx,
805 shaderPipeline.get(),
806 subsetRenderable.firstImage,
808 (theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset));
815 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
816 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
817 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
818 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
819 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
820 if (screenTextureBinding >= 0) {
821 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
822 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
823 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
824 bindings.addTexture(screenTextureBinding,
825 QRhiShaderResourceBinding::FragmentStage,
826 dummyTexture, sampler);
828 if (screenTextureArrayBinding >= 0) {
829 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
830 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates, QSize(64, 64), Qt::black, inData.layer.viewCount);
831 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
832 bindings.addTexture(screenTextureArrayBinding,
833 QRhiShaderResourceBinding::FragmentStage,
834 dummyTexture, sampler);
839 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
840 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
842 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
843 QRhiSampler::Nearest,
845 QRhiSampler::ClampToEdge,
846 QRhiSampler::ClampToEdge,
849 bindings.addTexture(binding,
850 QRhiShaderResourceBinding::VertexStage,
857 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
858 if (targetsTexture) {
859 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
861 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
862 QRhiSampler::Nearest,
864 QRhiSampler::ClampToEdge,
865 QRhiSampler::ClampToEdge,
866 QRhiSampler::ClampToEdge
868 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
872 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
873 subsetRenderable.rhiRenderData.shadowPass.pipeline = rhiCtxD->pipeline(*ps, pEntry->m_rhiRenderPassDesc[cascadeIndex], srb);
874 subsetRenderable.rhiRenderData.shadowPass.srb[cubeFaceIdx] = srb;
909 QRhiRenderPassDescriptor *renderPassDescriptor,
910 QSSGRhiGraphicsPipelineState *ps,
911 QSSGShaderFeatures featureSet,
914 QSSGRenderCamera *alteredCamera,
915 QMatrix4x4 *alteredModelViewProjection,
916 QSSGRenderTextureCubeFace cubeFace,
920 const auto &defaultMaterialShaderKeyProperties = inData.getDefaultMaterialPropertyTable();
922 switch (inObject.type) {
923 case QSSGRenderableObject::Type::DefaultMaterialMeshSubset:
925 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(inObject));
927 if ((cubeFace == QSSGRenderTextureCubeFaceNone) && subsetRenderable.reflectionProbeIndex >= 0 && subsetRenderable.renderableFlags.testFlag(QSSGRenderableObjectFlag::ReceivesReflections))
928 featureSet.set(QSSGShaderFeatures::Feature::ReflectionProbe,
true);
930 if ((cubeFace != QSSGRenderTextureCubeFaceNone)) {
932 featureSet.disableTonemapping();
935 if (subsetRenderable.renderableFlags.rendersWithLightmap())
936 featureSet.set(QSSGShaderFeatures::Feature::Lightmap,
true);
938 const auto &shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, featureSet);
939 if (shaderPipeline) {
947 QSSGRhiShaderResourceBindingList bindings;
948 const auto &modelNode = subsetRenderable.modelContext.model;
949 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(subsetRenderable.shaderDescription);
956 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
957 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone) * (cubeFaceIdx + (quintptr(subsetRenderable.subset.offset) << 3));
959 const auto entryPartA =
reinterpret_cast<quintptr>(&subsetRenderable.material);
960 const auto entryPartB =
reinterpret_cast<quintptr>(entry);
961 const void *entryId =
reinterpret_cast<
const void *>(entryPartA ^ entryPartB);
963 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
964 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({ passKey, &modelNode, entryId, entryIdx });
966 shaderPipeline->ensureCombinedUniformBuffer(&dcd.ubuf);
967 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
969 Q_ASSERT(alteredModelViewProjection);
970 QSSGRenderCameraList cameras({ alteredCamera });
971 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, cameras,
nullptr, alteredModelViewProjection);
973 Q_ASSERT(!alteredModelViewProjection);
974 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
978 QSSGParticleRenderer::updateUniformsForParticleModel(*shaderPipeline, ubufData, &subsetRenderable.modelContext.model, subsetRenderable.subset.offset);
979 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
982 QSSGParticleRenderer::prepareParticlesForModel(*shaderPipeline, rhiCtx, bindings, &subsetRenderable.modelContext.model);
985 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
986 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
988 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
989 QRhiSampler::Nearest,
991 QRhiSampler::ClampToEdge,
992 QRhiSampler::ClampToEdge,
995 bindings.addTexture(binding,
996 QRhiShaderResourceBinding::VertexStage,
1002 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
1003 if (targetsTexture) {
1004 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
1006 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
1007 QRhiSampler::Nearest,
1009 QRhiSampler::ClampToEdge,
1010 QRhiSampler::ClampToEdge,
1011 QRhiSampler::ClampToEdge
1013 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
1017 ps->samples = samples;
1018 ps->viewCount = viewCount;
1020 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
1021 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
1023 fillTargetBlend(&ps->targetBlend[0], material.blendMode);
1025 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
1027 ia = subsetRenderable.subset.rhi.ia;
1028 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
1029 QVector3D cameraDirection = cameraDatas[0].direction;
1030 QVector3D cameraPosition = cameraDatas[0].position;
1031 if (alteredCamera) {
1032 const QMatrix4x4 camGlobalTranform = inData.getGlobalTransform(*alteredCamera);
1033 cameraDirection = QSSGRenderNode::getScalingCorrectDirection(camGlobalTranform);
1034 cameraPosition = QSSGRenderNode::getGlobalPos(camGlobalTranform);
1036 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDirection, cameraPosition);
1037 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
1039 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf, 0, shaderPipeline->ub0Size());
1041 if (shaderPipeline->isLightingEnabled()) {
1042 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd.ubuf,
1043 shaderPipeline->ub0LightDataOffset(),
1044 sizeof(QSSGShaderLightsUniformData));
1045 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd.ubuf,
1046 shaderPipeline->ub0DirectionalLightDataOffset(),
1047 sizeof(QSSGShaderDirectionalLightsUniformData));
1052 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
1053 while (renderableImage) {
1054 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
1055 const int samplerHint =
int(renderableImage->m_mapType);
1056 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
1057 if (samplerBinding >= 0) {
1058 QRhiTexture *texture = renderableImage->m_texture.m_texture;
1059 if (samplerBinding >= 0 && texture) {
1060 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
1061 QSSGRhiSamplerDescription samplerDesc = {
1062 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
1063 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
1064 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
1065 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
1066 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
1067 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
1069 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
1070 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
1071 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
1074 renderableImage = renderableImage->m_nextImage;
1077 if (shaderPipeline->isLightingEnabled()) {
1079 auto shadowMapAtlas = shaderPipeline->shadowMapAtlasTexture();
1080 if (shadowMapAtlas) {
1081 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture");
1083 QRhiTexture *texture = shadowMapAtlas;
1084 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
1085 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
1086 Q_ASSERT(texture && sampler);
1087 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1094 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
1095 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
1096 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::Linear,
1097 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
1098 QRhiTexture* reflectionTexture = inData.getReflectionMapManager()->reflectionMapEntry(subsetRenderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
1099 if (reflectionSampler >= 0 && reflectionTexture)
1100 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
1101 }
else if (shaderPipeline->lightProbeTexture()) {
1102 int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
1104 auto tiling = shaderPipeline->lightProbeTiling();
1105 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::Linear,
1106 QSSGRhiHelpers::toRhi(tiling.first), QSSGRhiHelpers::toRhi(tiling.second), QRhiSampler::Repeat });
1107 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage,
1108 shaderPipeline->lightProbeTexture(), sampler);
1113 if (shaderPipeline->screenTexture()) {
1114 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
1115 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
1116 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
1121 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
1122 ? QRhiSampler::Linear : QRhiSampler::None;
1123 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
1124 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
1125 if (screenTextureBinding >= 0) {
1126 bindings.addTexture(screenTextureBinding,
1127 QRhiShaderResourceBinding::FragmentStage,
1128 shaderPipeline->screenTexture(), sampler);
1130 if (screenTextureArrayBinding >= 0) {
1131 bindings.addTexture(screenTextureArrayBinding,
1132 QRhiShaderResourceBinding::FragmentStage,
1133 shaderPipeline->screenTexture(), sampler);
1138 if (shaderPipeline->lightmapTexture()) {
1139 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
1141 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
1142 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
1143 bindings.addTexture(binding,
1144 QRhiShaderResourceBinding::FragmentStage,
1145 shaderPipeline->lightmapTexture(), sampler);
1151 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
1154 addNormalTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
1163 QRhiShaderResourceBindings *&srb = dcd.srb;
1164 bool srbChanged =
false;
1165 if (!srb || bindings != dcd.bindings) {
1166 srb = rhiCtxD->srb(bindings);
1167 rhiCtxD->releaseCachedSrb(dcd.bindings);
1168 dcd.bindings = bindings;
1172 if (cubeFace != QSSGRenderTextureCubeFaceNone)
1173 subsetRenderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx] = srb;
1175 subsetRenderable.rhiRenderData.mainPass.srb = srb;
1177 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
1180 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
1181 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
1184 if (cubeFace != QSSGRenderTextureCubeFaceNone)
1185 subsetRenderable.rhiRenderData.reflectionPass.pipeline = dcd.pipeline;
1187 subsetRenderable.rhiRenderData.mainPass.pipeline = dcd.pipeline;
1189 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1190 subsetRenderable.rhiRenderData.reflectionPass.pipeline = rhiCtxD->pipeline(pipelineKey,
1191 renderPassDescriptor,
1193 dcd.pipeline = subsetRenderable.rhiRenderData.reflectionPass.pipeline;
1195 subsetRenderable.rhiRenderData.mainPass.pipeline = rhiCtxD->pipeline(pipelineKey,
1196 renderPassDescriptor,
1198 dcd.pipeline = subsetRenderable.rhiRenderData.mainPass.pipeline;
1200 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
1201 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;
1207 case QSSGRenderableObject::Type::CustomMaterialMeshSubset:
1209 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(inObject));
1210 const QSSGRenderCustomMaterial &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
1211 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
1213 featureSet.set(QSSGShaderFeatures::Feature::LightProbe, inData.layer.lightProbe || material.m_iblProbe);
1215 if ((cubeFace == QSSGRenderTextureCubeFaceNone) && subsetRenderable.reflectionProbeIndex >= 0 && subsetRenderable.renderableFlags.testFlag(QSSGRenderableObjectFlag::ReceivesReflections))
1216 featureSet.set(QSSGShaderFeatures::Feature::ReflectionProbe,
true);
1218 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1220 featureSet.disableTonemapping();
1223 if (subsetRenderable.renderableFlags.rendersWithLightmap())
1224 featureSet.set(QSSGShaderFeatures::Feature::Lightmap,
true);
1226 customMaterialSystem.rhiPrepareRenderable(ps, passKey, subsetRenderable, featureSet,
1227 material, inData, renderPassDescriptor, samples, viewCount,
1228 alteredCamera, cubeFace, alteredModelViewProjection, entry, oit);
1231 case QSSGRenderableObject::Type::Particles:
1234 const auto &shaderPipeline = shadersForParticleMaterial(ps, particleRenderable, oit ? inData.layer.oitMethod : QSSGRenderLayer::OITMethod::None);
1235 if (shaderPipeline) {
1236 QSSGParticleRenderer::rhiPrepareRenderable(*shaderPipeline, passKey, rhiCtx, ps, particleRenderable, inData, renderPassDescriptor, samples, viewCount,
1237 alteredCamera, cubeFace, entry);
1349 QSSGPassKey passKey,
1350 QSSGRhiGraphicsPipelineState &ps,
1351 QSSGRenderShadowMap &shadowMapManager,
1352 const QSSGRenderCamera &camera,
1353 QSSGRenderCamera *debugCamera,
1355 const QSSGRenderableObjectList &sortedOpaqueObjects,
1357 const QSSGBounds3 &castingObjectsBox,
1358 const QSSGBounds3 &receivingObjectsBox)
1361 QSSGDebugDrawSystem *debugDrawSystem = renderer.contextInterface()->debugDrawSystem().get();
1362 const bool drawDirectionalLightShadowBoxes = layerData.layer.drawDirectionalLightShadowBoxes;
1363 const bool drawPointLightShadowBoxes = layerData.layer.drawPointLightShadowBoxes;
1364 const bool drawShadowCastingBounds = layerData.layer.drawShadowCastingBounds;
1365 const bool drawShadowReceivingBounds = layerData.layer.drawShadowReceivingBounds;
1366 const bool drawCascades = layerData.layer.drawCascades;
1367 const bool drawSceneCascadeIntersection = layerData.layer.drawSceneCascadeIntersection;
1368 const bool disableShadowCameraUpdate = layerData.layer.disableShadowCameraUpdate;
1369 const bool drawCulledObjects = layerData.layer.drawCulledObjects;
1370 QVector<
bool> debugIsObjectCulled = drawCulledObjects ? QVector<
bool>(sortedOpaqueObjects.size(),
true) : QVector<
bool>();
1372 static const auto rhiRenderOneShadowMap = [](QSSGRhiContext *rhiCtx,
1373 QSSGRhiGraphicsPipelineState *ps,
1374 const QSSGRenderableObjectList &sortedOpaqueObjects,
1376 const QSSGBounds3 cameraBounds,
1377 QVector<
bool> &debugIsObjectCulled,
1378 bool drawCulledObjects) {
1379 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1380 bool needsSetViewport =
true;
1382 for (
int i = 0, n = sortedOpaqueObjects.size(); i < n; ++i) {
1387 if (theObject->globalBoundsInstancing.isFinite() && theObject->globalBounds.isFinite()) {
1388 const QSSGBounds3 &globalBounds = !theObject->globalBoundsInstancing.isEmpty() ? theObject->globalBoundsInstancing
1389 : theObject->globalBounds;
1390 if (!globalBounds.isEmpty() && !cameraBounds.intersects(globalBounds)) {
1395 if (Q_UNLIKELY(drawCulledObjects))
1396 debugIsObjectCulled[i] =
false;
1398 QSSG_ASSERT(theObject->renderableFlags.castsShadows(),
continue);
1399 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
1400 QSSGSubsetRenderable *renderable(
static_cast<QSSGSubsetRenderable *>(theObject));
1402 QRhiBuffer *vertexBuffer = renderable->subset.rhi.vertexBuffer->buffer();
1403 QRhiBuffer *indexBuffer = renderable->subset.rhi.indexBuffer
1404 ? renderable->subset.rhi.indexBuffer->buffer()
1408 if (!renderable->rhiRenderData.shadowPass.pipeline)
1411 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall);
1413 cb->setGraphicsPipeline(renderable->rhiRenderData.shadowPass.pipeline);
1415 QRhiShaderResourceBindings *srb = renderable->rhiRenderData.shadowPass.srb[cubeFace];
1416 cb->setShaderResources(srb);
1418 if (needsSetViewport) {
1419 cb->setViewport(ps->viewport);
1420 needsSetViewport =
false;
1423 QRhiCommandBuffer::VertexInput vertexBuffers[2];
1424 int vertexBufferCount = 1;
1425 vertexBuffers[0] = QRhiCommandBuffer::VertexInput(vertexBuffer, 0);
1426 quint32 instances = 1;
1427 if (renderable->modelContext.model.instancing()) {
1428 instances = renderable->modelContext.model.instanceCount();
1429 vertexBuffers[1] = QRhiCommandBuffer::VertexInput(renderable->instanceBuffer, 0);
1430 vertexBufferCount = 2;
1433 cb->setVertexInput(0, vertexBufferCount, vertexBuffers, indexBuffer, 0, renderable->subset.rhi.indexBuffer->indexFormat());
1434 cb->drawIndexed(renderable->subset.lodCount(renderable->subsetLevelOfDetail), instances, renderable->subset.lodOffset(renderable->subsetLevelOfDetail));
1435 QSSGRHICTX_STAT(rhiCtx, drawIndexed(renderable->subset.lodCount(renderable->subsetLevelOfDetail), instances));
1437 cb->setVertexInput(0, vertexBufferCount, vertexBuffers);
1438 cb->draw(renderable->subset.count, instances, renderable->subset.offset);
1439 QSSGRHICTX_STAT(rhiCtx, draw(renderable->subset.count, instances));
1441 Q_QUICK3D_PROFILE_END_WITH_IDS(QQuick3DProfiler::Quick3DRenderCall, (renderable->subset.count | quint64(instances) << 32),
1442 QVector<
int>({renderable->modelContext.model.profilingId,
1443 renderable->material.profilingId}));
1448 static const auto rhiClearShadowMap = [](
QSSGRenderer &renderer, QSSGRenderShadowMap &shadowMapManager, QSSGRhiContext *rhiCtx, QSSGRhiGraphicsPipelineState *ps, QRhiRenderPassDescriptor *renderPassDesc) {
1449 auto clearShadowMapShaderPipeline = renderer.contextInterface()->shaderCache()->getBuiltInRhiShaders().getRhiClearShadowMapShader();
1450 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, clearShadowMapShaderPipeline.get());
1453 ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled,
false);
1454 ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1455 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, ps, shadowMapManager.shadowClearSrb(), renderPassDesc, {});
1457 ps->flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
1460 QRhi *rhi = rhiCtx->rhi();
1461 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1465 QVector2D depthAdjust;
1466 if (rhi->isClipDepthZeroToOne()) {
1468 depthAdjust[0] = 0.0f;
1469 depthAdjust[1] = 1.0f;
1472 depthAdjust[0] = 1.0f;
1473 depthAdjust[1] = 0.5f;
1476 if (drawShadowCastingBounds)
1477 ShadowmapHelpers::addDebugBox(castingObjectsBox.toQSSGBoxPointsNoEmptyCheck(), QColorConstants::Red, debugDrawSystem);
1478 if (drawShadowReceivingBounds)
1479 ShadowmapHelpers::addDebugBox(receivingObjectsBox.toQSSGBoxPointsNoEmptyCheck(), QColorConstants::Green, debugDrawSystem);
1482 const QSize atlasTextureSize = shadowMapManager.shadowMapAtlasTexture()->pixelSize();
1484 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
1485 for (
int i = 0, ie = globalLights.size(); i != ie; ++i) {
1486 if (!globalLights[i].shadows || globalLights[i].light->m_fullyBaked)
1493 const auto &light = globalLights[i].light;
1495 if (!shadowMapManager.shadowMapAtlasTexture())
1498 if (light->type == QSSGRenderLight::Type::DirectionalLight || light->type == QSSGRenderLight::Type::SpotLight) {
1499 const QSize size = atlasTextureSize * pEntry->m_atlasInfo[0].uvScale;
1503 if (!disableShadowCameraUpdate && debugCamera) {
1504 debugCamera->clipPlanes = camera.clipPlanes;
1505 debugCamera->projection = camera.projection;
1509 debugCamera->localTransform = layerData.getGlobalTransform(camera);
1512 QVarLengthArray<std::unique_ptr<QSSGRenderCamera>, 4> cascades;
1513 if (light->type == QSSGRenderLight::Type::DirectionalLight) {
1514 const float pcfRadius = light->m_softShadowQuality == QSSGRenderLight::SoftShadowQuality::Hard ? 0.f : light->m_pcfFactor;
1515 const float clipNear = camera.clipPlanes.clipNear();
1516 const float clipFar = qMin(light->m_shadowMapFar, camera.clipPlanes.clipFar());
1517 const float clipRange = clipFar - clipNear;
1518 cascades = setupCascadingCamerasForShadowMap(layerData,
1519 disableShadowCameraUpdate ? *debugCamera : camera,
1526 receivingObjectsBox,
1527 light->m_lockShadowmapTexels,
1530 drawSceneCascadeIntersection);
1533 pEntry->m_csmSplits[0] = clipNear + clipRange * (light->m_csmNumSplits > 0 ? light->m_csmSplit1 : 1.0f);
1534 pEntry->m_csmSplits[1] = clipNear + clipRange * (light->m_csmNumSplits > 1 ? light->m_csmSplit2 : 1.0f);
1535 pEntry->m_csmSplits[2] = clipNear + clipRange * (light->m_csmNumSplits > 2 ? light->m_csmSplit3 : 1.0f);
1536 pEntry->m_csmSplits[3] = clipNear + clipRange * 1.0f;
1537 pEntry->m_shadowMapFar = clipFar;
1538 }
else if (light->type == QSSGRenderLight::Type::SpotLight) {
1539 auto spotlightCamera = std::make_unique<QSSGRenderCamera>(QSSGRenderCamera::Type::PerspectiveCamera);
1540 spotlightCamera->fov = QSSGRenderCamera::FieldOfView::fromDegrees(light->m_coneAngle * 2.0f);
1541 spotlightCamera->clipPlanes = { 1.0f, light->m_shadowMapFar };
1542 const QMatrix4x4 lightGlobalTransform = layerData.getGlobalTransform(*light);
1543 const QVector3D lightDir = QSSGRenderNode::getDirection(lightGlobalTransform);
1544 const QVector3D lightPos = QSSGRenderNode::getGlobalPos(lightGlobalTransform) - lightDir * spotlightCamera->clipPlanes.clipNear();
1545 const QVector3D lightPivot = light->pivot;
1546 const QVector3D forward = lightDir.normalized();
1547 const QVector3D right = qFuzzyCompare(qAbs(forward.y()), 1.0f)
1548 ? QVector3D::crossProduct(forward, QVector3D(1, 0, 0)).normalized()
1549 : QVector3D::crossProduct(forward, QVector3D(0, 1, 0)).normalized();
1550 const QVector3D up = QVector3D::crossProduct(right, forward).normalized();
1551 spotlightCamera->localTransform = QSSGRenderNode::calculateTransformMatrix(lightPos,
1552 QSSGRenderNode::initScale,
1554 QQuaternion::fromDirection(forward, up));
1555 QRectF theViewport(0.0f, 0.0f, (
float)light->m_shadowMapRes, (
float)light->m_shadowMapRes);
1556 QSSGRenderCamera::calculateProjectionInternal(*spotlightCamera, theViewport);
1557 cascades.push_back(
std::move(spotlightCamera));
1558 pEntry->m_shadowMapFar = light->m_shadowMapFar;
1563 memset(pEntry->m_csmActive, 0,
sizeof(pEntry->m_csmActive));
1565 QMatrix4x4 cascadeCameraGlobalTransforms(Qt::Uninitialized);
1566 const QMatrix4x4 bias = { 0.5, 0.0, 0.0, 0.5,
1569 0.0, 0.0, 0.0, 1.0 };
1571 for (
int cascadeIndex = 0; cascadeIndex < cascades.length(); cascadeIndex++) {
1572 const auto &cascadeCamera = cascades[cascadeIndex];
1576 cascadeCameraGlobalTransforms = layerData.getGlobalTransform(*cascadeCamera);
1577 pEntry->m_csmActive[cascadeIndex] = 1.f;
1578 QMatrix4x4 &viewProjection = pEntry->m_lightViewProjection[cascadeIndex];
1579 cascadeCamera->calculateViewProjectionMatrix(cascadeCameraGlobalTransforms, viewProjection);
1580 pEntry->m_lightViewProjection[cascadeIndex] = viewProjection;
1581 pEntry->m_fixedScaleBiasMatrix[cascadeIndex] = bias * viewProjection;
1582 const QMatrix4x4 inverted = viewProjection.inverted();
1583 const float x = 0.5f / (inverted * QVector4D(1, 0, 0, 0)).length();
1584 const float y = 0.5f / (inverted * QVector4D(0, 1, 0, 0)).length();
1585 const float z = 0.5f / (inverted * QVector4D(0, 0, 1, 0)).length();
1586 const QSSGBoxPoints frustumPoints = computeFrustumBounds(viewProjection);
1587 const QSSGBounds3 bounds = QSSGBounds3(frustumPoints);
1588 pEntry->m_dimensionsInverted[cascadeIndex] = QVector4D(x, y, z, 0.0f);
1589 pEntry->m_lightView = cascadeCameraGlobalTransforms.inverted();
1590 const bool isOrtho = cascadeCamera->type == QSSGRenderGraphObject::Type::OrthographicCamera;
1591 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[cascadeIndex], rhi->isYUpInFramebuffer());
1592 rhiPrepareResourcesForShadowMap(rhiCtx, layerData, passKey, pEntry, &ps, &depthAdjust, sortedOpaqueObjects, *cascadeCamera, isOrtho, QSSGRenderTextureCubeFaceNone, cascadeIndex);
1595 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargets[cascadeIndex];
1596 cb->beginPass(rt, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1597 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1598 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1599 rhiClearShadowMap(renderer, shadowMapManager, rhiCtx, &ps, rt->renderPassDescriptor());
1600 rhiRenderOneShadowMap(rhiCtx, &ps, sortedOpaqueObjects, 0, bounds, debugIsObjectCulled, drawCulledObjects);
1602 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1604 if (drawDirectionalLightShadowBoxes) {
1608 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"shadow_map"));
1610 const QSize size = atlasTextureSize * pEntry->m_atlasInfo[0].uvScale;
1611 ps.viewport = QRhiViewport(0, 0,
float(size.width()),
float(size.height()));
1613 QSSGRenderCamera theCameras[6] { QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1614 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1615 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1616 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1617 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1618 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera} };
1619 const float shadowMapFar = qMax<
float>(2.0f, light->m_shadowMapFar);
1620 setupCubeShadowCameras(layerData, light, shadowMapFar, theCameras);
1621 pEntry->m_lightView = QMatrix4x4();
1622 pEntry->m_shadowMapFar = shadowMapFar;
1624 const bool swapYFaces = !rhi->isYUpInFramebuffer();
1625 QMatrix4x4 cameraGlobalTransform(Qt::Uninitialized);
1626 for (
const auto face : QSSGRenderTextureCubeFaces) {
1627 cameraGlobalTransform = layerData.getGlobalTransform(theCameras[quint8(face)]);
1628 theCameras[quint8(face)].calculateViewProjectionMatrix(cameraGlobalTransform, pEntry->m_lightViewProjection[0]);
1629 pEntry->m_lightCubeView[quint8(face)] = cameraGlobalTransform.inverted();
1631 rhiPrepareResourcesForShadowMap(rhiCtx,
1637 sortedOpaqueObjects,
1638 theCameras[quint8(face)],
1645 const QVector3D center = QSSGRenderNode::getGlobalPos(layerData.getGlobalTransform(*light));
1646 const QSSGBounds3 bounds = QSSGBounds3(center - QVector3D(shadowMapFar, shadowMapFar, shadowMapFar),
1647 center + QVector3D(shadowMapFar, shadowMapFar, shadowMapFar));
1649 for (
const auto face : QSSGRenderTextureCubeFaces) {
1653 QSSGRenderTextureCubeFace outFace = face;
1671 if (outFace == QSSGRenderTextureCubeFace::PosY)
1672 outFace = QSSGRenderTextureCubeFace::NegY;
1673 else if (outFace == QSSGRenderTextureCubeFace::NegY)
1674 outFace = QSSGRenderTextureCubeFace::PosY;
1676 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargetCube[quint8(outFace)];
1677 cb->beginPass(rt, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1678 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1679 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1680 rhiRenderOneShadowMap(rhiCtx, &ps, sortedOpaqueObjects, quint8(face), bounds, debugIsObjectCulled, drawCulledObjects);
1682 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1683 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_cube", 0, outFace));
1690 QRhiTextureRenderTarget *rtFront = pEntry->m_rhiRenderTargets[0];
1691 QRhiRenderPassDescriptor *frontDesc = pEntry->m_rhiRenderPassDesc[0];
1692 auto atlasShaderPipeline = renderer.contextInterface()->shaderCache()->getBuiltInRhiShaders().getRhiCubeMapToAtlasShader();
1693 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[0], rhi->isYUpInFramebuffer());
1694 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, atlasShaderPipeline.get());
1695 QRhiShaderResourceBindings *srb = pEntry->m_cubeToAtlasFrontSrb;
1696 cb->beginPass(rtFront, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1697 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rtFront));
1698 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1700 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, frontDesc, QSSGRhiQuadRenderer::UvCoords);
1703 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1704 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_atlas", 6, 0));
1707 QRhiTextureRenderTarget *rtBack = pEntry->m_rhiRenderTargets[1];
1708 QRhiRenderPassDescriptor *backDesc = pEntry->m_rhiRenderPassDesc[1];
1709 srb = pEntry->m_cubeToAtlasBackSrb;
1710 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[1], rhi->isYUpInFramebuffer());
1711 cb->beginPass(rtBack, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1712 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rtBack));
1713 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1715 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, backDesc, QSSGRhiQuadRenderer::UvCoords);
1718 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1719 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_atlas", 7, 0));
1723 ps = layerData.getPipelineState();
1724 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
1726 ps.slopeScaledDepthBias = 1.5f;
1728 if (drawPointLightShadowBoxes) {
1729 ShadowmapHelpers::addDebugBox(bounds.toQSSGBoxPoints(), QColorConstants::Yellow, debugDrawSystem);
1734 if (Q_UNLIKELY(drawCulledObjects)) {
1735 for (
int i = 0, n = sortedOpaqueObjects.size(); i < n; ++i) {
1737 const QSSGBounds3 &globalBounds = !theObject->globalBoundsInstancing.isEmpty() ? theObject->globalBoundsInstancing
1738 : theObject->globalBounds;
1739 const QColor color = debugIsObjectCulled[i] ? QColorConstants::Red : QColorConstants::Green;
1746 QSSGPassKey passKey,
1748 QSSGRhiGraphicsPipelineState *ps,
1749 QSSGRenderReflectionMap &reflectionMapManager,
1750 const QVector<QSSGRenderReflectionProbe *> &reflectionProbes,
1751 const QSSGRenderableObjectList &reflectionPassObjects,
1754 QRhi *rhi = rhiCtx->rhi();
1755 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1757 const bool renderSkybox = (inData.layer.background == QSSGRenderLayer::Background::SkyBox ||
1758 inData.layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap)
1759 && rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch);
1761 for (
int i = 0, ie = reflectionProbes.size(); i != ie; ++i) {
1766 if (!pEntry->m_needsRender)
1769 if (reflectionProbes[i]->refreshMode == QSSGRenderReflectionProbe::ReflectionRefreshMode::FirstFrame && pEntry->m_rendered)
1772 if (reflectionProbes[i]->texture)
1775 Q_ASSERT(pEntry->m_rhiDepthStencil);
1776 Q_ASSERT(pEntry->m_rhiCube);
1778 const QSize size = pEntry->m_rhiCube->pixelSize();
1779 ps->viewport = QRhiViewport(0, 0,
float(size.width()),
float(size.height()));
1781 QSSGRenderCamera theCameras[6] { QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1782 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1783 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1784 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1785 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1786 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera} };
1787 setupCubeReflectionCameras(inData, reflectionProbes[i], theCameras);
1788 const bool swapYFaces = !rhi->isYUpInFramebuffer();
1789 QMatrix4x4 cameraGlobalTransform(Qt::Uninitialized);
1790 for (
const auto face : QSSGRenderTextureCubeFaces) {
1791 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(face);
1792 cameraGlobalTransform = inData.getGlobalTransform(theCameras[cubeFaceIdx]);
1793 theCameras[cubeFaceIdx].calculateViewProjectionMatrix(cameraGlobalTransform, pEntry->m_viewProjection);
1795 rhiPrepareResourcesForReflectionMap(rhiCtx, passKey, inData, pEntry, ps,
1796 reflectionPassObjects, theCameras[cubeFaceIdx], renderer, face);
1798 QRhiRenderPassDescriptor *renderPassDesc =
nullptr;
1799 for (
auto face : QSSGRenderTextureCubeFaces) {
1800 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1801 face = pEntry->m_timeSliceFace;
1803 QSSGRenderTextureCubeFace outFace = face;
1807 if (outFace == QSSGRenderTextureCubeFace::PosY)
1808 outFace = QSSGRenderTextureCubeFace::NegY;
1809 else if (outFace == QSSGRenderTextureCubeFace::NegY)
1810 outFace = QSSGRenderTextureCubeFace::PosY;
1812 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargets[quint8(outFace)];
1813 cb->beginPass(rt, reflectionProbes[i]->clearColor, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1814 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1815 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1817 if (renderSkybox && pEntry->m_skyBoxSrbs[quint8(face)]) {
1818 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1819 const bool isSkyBox = inData.layer.background == QSSGRenderLayer::Background::SkyBox;
1820 const auto &shaderPipeline = isSkyBox ? shaderCache->getBuiltInRhiShaders().getRhiSkyBoxShader(QSSGRenderLayer::TonemapMode::None, inData.layer.skyBoxIsRgbe8, 1)
1821 : shaderCache->getBuiltInRhiShaders().getRhiSkyBoxCubeShader(QSSGRenderLayer::TonemapMode::None, !inData.layer.skyBoxIsSrgb, 1);
1822 Q_ASSERT(shaderPipeline);
1823 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, shaderPipeline.get());
1824 QRhiShaderResourceBindings *srb = pEntry->m_skyBoxSrbs[quint8(face)];
1825 if (!renderPassDesc)
1826 renderPassDesc = rt->newCompatibleRenderPassDescriptor();
1827 rt->setRenderPassDescriptor(renderPassDesc);
1828 isSkyBox ? renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, ps, srb, renderPassDesc, {})
1829 : renderer.rhiCubeRenderer()->recordRenderCube(rhiCtx, ps, srb, renderPassDesc, {});
1832 bool needsSetViewport =
true;
1833 for (
const auto &handle : reflectionPassObjects)
1834 rhiRenderRenderable(rhiCtx, *ps, *handle.obj, &needsSetViewport, face);
1837 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1838 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"reflection_cube", 0, outFace));
1840 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1844 renderPassDesc->deleteLater();
1846 pEntry->renderMips(rhiCtx);
1848 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1849 pEntry->m_timeSliceFace = QSSGBaseTypeHelpers::next(pEntry->m_timeSliceFace);
1851 if (reflectionProbes[i]->refreshMode == QSSGRenderReflectionProbe::ReflectionRefreshMode::FirstFrame)
1852 pEntry->m_rendered =
true;
1854 reflectionProbes[i]->hasScheduledUpdate =
false;
1855 pEntry->m_needsRender =
false;
1906 QSSGPassKey passKey,
1908 QSSGRhiShaderPipeline &shaderPipeline,
1909 QSSGRhiGraphicsPipelineState &ps,
1910 const QSSGAmbientOcclusionSettings &ao,
1911 const QSSGRhiRenderableTexture &rhiAoTexture,
1912 const QSSGRhiRenderableTexture &rhiDepthTexture,
1913 const QSSGRenderCamera &camera)
1915 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
1918 if (!rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
1919 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1921 cb->beginPass(rhiAoTexture.rt, Qt::white, { 1.0f, 0 });
1922 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rhiAoTexture.rt));
1924 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1928 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, &shaderPipeline);
1930 const float R2 = ao.aoDistance * ao.aoDistance * 0.16f;
1931 const QSize textureSize = rhiAoTexture.texture->pixelSize();
1932 const float rw =
float(textureSize.width());
1933 const float rh =
float(textureSize.height());
1934 const float fov = camera.fov.asVerticalFov(rw / rh).radians();
1935 const float tanHalfFovY = tanf(0.5f * fov * (rh / rw));
1936 const float invFocalLenX = tanHalfFovY * (rw / rh);
1938 const QVector4D aoProps(ao.aoStrength * 0.01f, ao.aoDistance * 0.4f, ao.aoSoftness * 0.02f, ao.aoBias);
1939 const QVector4D aoProps2(
float(ao.aoSamplerate), (ao.aoDither) ? 1.0f : 0.0f, 0.0f, 0.0f);
1940 const QVector4D aoScreenConst(1.0f / R2, rh / (2.0f * tanHalfFovY), 1.0f / rw, 1.0f / rh);
1941 const QVector4D uvToEyeConst(2.0f * invFocalLenX, -2.0f * tanHalfFovY, -invFocalLenX, tanHalfFovY);
1942 const QVector2D cameraProps = camera.clipPlanes;
1951 const int UBUF_SIZE = 72;
1952 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({ passKey,
nullptr,
nullptr, 0 }));
1954 dcd.ubuf = rhiCtx->rhi()->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, UBUF_SIZE);
1958 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
1959 memcpy(ubufData, &aoProps, 16);
1960 memcpy(ubufData + 16, &aoProps2, 16);
1961 memcpy(ubufData + 32, &aoScreenConst, 16);
1962 memcpy(ubufData + 48, &uvToEyeConst, 16);
1963 memcpy(ubufData + 64, &cameraProps, 8);
1964 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
1966 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
1967 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
1968 QSSGRhiShaderResourceBindingList bindings;
1969 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf);
1972 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, rhiDepthTexture.texture, sampler);
1973 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
1975 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
1976 renderer.rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, rhiAoTexture.rt, {});
2124 QSSGPassKey passKey,
2125 QSSGRenderLayer &layer,
2126 QSSGRenderCameraList &cameras,
2130 uint tonemapMode = 0)
2132 QSSG_ASSERT(layer.renderData,
return);
2134 const auto *renderData = layer.renderData;
2136 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2137 const bool cubeMapMode = layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap;
2138 const QSSGRenderImageTexture lightProbeTexture =
2139 cubeMapMode ? renderer.contextInterface()->bufferManager()->loadRenderImage(layer.skyBoxCubeMap, QSSGBufferManager::MipModeDisable)
2140 : renderer.contextInterface()->bufferManager()->loadRenderImage(layer.lightProbe, QSSGBufferManager::MipModeBsdf);
2141 const bool hasValidTexture = lightProbeTexture.m_texture !=
nullptr;
2142 if (hasValidTexture) {
2143 if (cubeFace == QSSGRenderTextureCubeFaceNone)
2144 layer.skyBoxIsRgbe8 = lightProbeTexture.m_flags.isRgbe8();
2146 layer.skyBoxIsSrgb = !lightProbeTexture.m_flags.isLinear();
2148 QSSGRhiShaderResourceBindingList bindings;
2150 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
2151 QRhiSampler::Linear,
2152 cubeMapMode ? QRhiSampler::None : QRhiSampler::Linear,
2153 QRhiSampler::Repeat,
2154 QRhiSampler::ClampToEdge,
2155 QRhiSampler::Repeat });
2156 int samplerBinding = 1;
2157 const quint32 ubufSize = cameras.count() >= 2 ? 416 : 240;
2158 bindings.addTexture(samplerBinding,
2159 QRhiShaderResourceBinding::FragmentStage,
2160 lightProbeTexture.m_texture, sampler);
2162 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
2163 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone) * cubeFaceIdx;
2164 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({ passKey,
nullptr, entry, entryIdx });
2166 QRhi *rhi = rhiCtx->rhi();
2168 dcd.ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
2172 float adjustY = rhi->isYUpInNDC() ? 1.0f : -1.0f;
2173 const float exposure = layer.lightProbeSettings.probeExposure;
2175 const QMatrix3x3 &rotationMatrix(layer.lightProbeSettings.probeOrientation);
2178 const float blurAmountOrSrgb = cubeMapMode ? layer.skyBoxIsSrgb : layer.skyboxBlurAmount;
2179 const float maxMipLevelOrTonemapMode = cubeMapMode ?
float(tonemapMode) :
float(lightProbeTexture.m_mipmapCount - 2);
2181 const QVector4D skyboxProperties = {
2185 maxMipLevelOrTonemapMode
2188 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2189 quint32 ubufOffset = 0;
2191 memcpy(ubufData + ubufOffset, &skyboxProperties, 16);
2194 memcpy(ubufData + ubufOffset, rotationMatrix.constData(), 12);
2196 memcpy(ubufData + ubufOffset, (
char *)rotationMatrix.constData() + 12, 12);
2198 memcpy(ubufData + ubufOffset, (
char *)rotationMatrix.constData() + 24, 12);
2201 for (qsizetype viewIdx = 0; viewIdx < cameras.count(); ++viewIdx) {
2202 const QMatrix4x4 &inverseProjection = cameras[viewIdx]->projection.inverted();
2203 const QMatrix4x4 &viewMatrix = renderData->getGlobalTransform(*cameras[viewIdx]);
2204 QMatrix4x4 viewProjection(Qt::Uninitialized);
2205 cameras[viewIdx]->calculateViewProjectionWithoutTranslation(viewMatrix, 0.1f, 5.0f, viewProjection);
2207 quint32 viewDataOffset = ubufOffset;
2208 memcpy(ubufData + viewDataOffset + viewIdx * 64, viewProjection.constData(), 64);
2209 viewDataOffset += cameras.count() * 64;
2210 memcpy(ubufData + viewDataOffset + viewIdx * 64, inverseProjection.constData(), 64);
2211 viewDataOffset += cameras.count() * 64;
2212 memcpy(ubufData + viewDataOffset + viewIdx * 48, viewMatrix.constData(), 48);
2214 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2216 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf);
2218 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
2219 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
2220 entry->m_skyBoxSrbs[cubeFaceIdx] = rhiCtxD->srb(bindings);
2222 layer.skyBoxSrb = rhiCtxD->srb(bindings);
2226 renderer.rhiCubeRenderer()->prepareCube(rhiCtx,
nullptr);
2228 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
2265 QSSGPassKey passKey,
2266 const QSSGRhiGraphicsPipelineState &basePipelineState,
2267 QRhiRenderPassDescriptor *rpDesc,
2269 const QSSGRenderableObjectList &sortedOpaqueObjects,
2270 const QSSGRenderableObjectList &sortedTransparentObjects,
2274 static const auto rhiPrepareDepthPassForObject = [](QSSGRhiContext *rhiCtx,
2275 QSSGPassKey passKey,
2278 QRhiRenderPassDescriptor *rpDesc,
2279 QSSGRhiGraphicsPipelineState *ps) {
2280 QSSGRhiShaderPipelinePtr shaderPipeline;
2281 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2283 const bool isOpaqueDepthPrePass = obj->depthWriteMode == QSSGDepthDrawMode::OpaquePrePass;
2284 QSSGShaderFeatures featureSet;
2285 featureSet.set(QSSGShaderFeatures::Feature::DepthPass,
true);
2286 if (isOpaqueDepthPrePass)
2287 featureSet.set(QSSGShaderFeatures::Feature::OpaqueDepthPrePass,
true);
2289 QSSGRhiDrawCallData *dcd =
nullptr;
2290 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2291 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2292 const void *modelNode = &subsetRenderable.modelContext.model;
2293 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
2296 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
2297 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2298 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
2299 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
2301 shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, featureSet);
2302 if (shaderPipeline) {
2303 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2304 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2305 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
2306 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2310 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2311 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2313 const auto &customMaterial =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
2315 ps->cullMode = QSSGRhiHelpers::toCullMode(customMaterial.m_cullMode);
2317 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
2318 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(ps, customMaterial, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
2320 if (shaderPipeline) {
2321 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2322 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2323 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, customMaterial, subsetRenderable,
2324 inData.renderedCameras,
nullptr,
nullptr);
2325 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2332 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2333 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2334 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
2335 ia = subsetRenderable.subset.rhi.ia;
2337 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
2338 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
2339 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
2341 QSSGRhiShaderResourceBindingList bindings;
2342 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
2345 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
2347 if (isOpaqueDepthPrePass) {
2348 addOpaqueDepthPrePassBindings(rhiCtx,
2349 shaderPipeline.get(),
2350 subsetRenderable.firstImage,
2352 (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset));
2358 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
2359 if (normalTextureBinding >= 0) {
2360 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2361 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
2362 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
2363 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
2364 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
2365 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
2369 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
2370 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
2372 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2373 QRhiSampler::Nearest,
2375 QRhiSampler::ClampToEdge,
2376 QRhiSampler::ClampToEdge,
2379 bindings.addTexture(binding,
2380 QRhiShaderResourceBinding::VertexStage,
2387 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
2388 if (targetsTexture) {
2389 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
2391 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2392 QRhiSampler::Nearest,
2394 QRhiSampler::ClampToEdge,
2395 QRhiSampler::ClampToEdge,
2396 QRhiSampler::ClampToEdge
2398 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
2402 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2404 subsetRenderable.rhiRenderData.depthPrePass.pipeline = rhiCtxD->pipeline(*ps,
2407 subsetRenderable.rhiRenderData.depthPrePass.srb = srb;
2418 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2423 ps.samples = samples;
2424 ps.viewCount = viewCount;
2425 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
2426 ps.targetBlend[0].colorWrite = {};
2428 for (
const QSSGRenderableObjectHandle &handle : sortedOpaqueObjects) {
2429 if (!rhiPrepareDepthPassForObject(rhiCtx, passKey, inData, handle.obj, rpDesc, &ps))
2433 for (
const QSSGRenderableObjectHandle &handle : sortedTransparentObjects) {
2434 if (!rhiPrepareDepthPassForObject(rhiCtx, passKey, inData, handle.obj, rpDesc, &ps))
2561 QSSGPassKey passKey,
2562 const QSSGRhiGraphicsPipelineState &basePipelineState,
2563 QRhiRenderPassDescriptor *rpDesc,
2565 const QSSGRenderableObjectList &sortedOpaqueObjects)
2567 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2568 ps.depthFunc = QRhiGraphicsPipeline::LessOrEqual;
2569 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
false);
2571 for (
const QSSGRenderableObjectHandle &handle : sortedOpaqueObjects) {
2572 QSSGRenderableObject *obj = handle.obj;
2573 QSSGRhiShaderPipelinePtr shaderPipeline;
2574 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2576 QSSGShaderFeatures featureSet;
2577 featureSet.set(QSSGShaderFeatures::Feature::NormalPass,
true);
2579 QSSGRhiDrawCallData *dcd =
nullptr;
2580 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2581 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2582 const void *modelNode = &subsetRenderable.modelContext.model;
2583 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
2586 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
2587 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2588 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
2589 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
2591 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet);
2592 if (shaderPipeline) {
2593 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2594 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2595 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
2596 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2598 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2599 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2601 const auto &customMaterial =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
2603 ps.cullMode = QSSGRhiHelpers::toCullMode(customMaterial.m_cullMode);
2605 const auto &customMaterialSystem = subsetRenderable.renderer->contextInterface()->customMaterialSystem();
2606 shaderPipeline = customMaterialSystem->shadersForCustomMaterial(&ps, customMaterial, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
2608 if (shaderPipeline) {
2609 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2610 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2611 customMaterialSystem->updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, customMaterial, subsetRenderable,
2612 inData.renderedCameras,
nullptr,
nullptr);
2613 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2618 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2619 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2620 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
2621 ia = subsetRenderable.subset.rhi.ia;
2623 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
2624 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
2625 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
2627 QSSGRhiShaderResourceBindingList bindings;
2628 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
2631 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
2632 while (renderableImage) {
2633 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
2634 const int samplerHint =
int(renderableImage->m_mapType);
2635 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
2636 if (samplerBinding >= 0) {
2637 QRhiTexture *texture = renderableImage->m_texture.m_texture;
2638 if (samplerBinding >= 0 && texture) {
2639 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
2640 QSSGRhiSamplerDescription samplerDesc = {
2641 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
2642 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
2643 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
2644 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
2645 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
2646 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
2648 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
2649 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
2650 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
2653 renderableImage = renderableImage->m_nextImage;
2656 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
2659 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
2660 if (normalTextureBinding >= 0) {
2661 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2662 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
2663 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
2664 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
2665 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
2666 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
2672 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
2673 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
2675 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2676 QRhiSampler::Nearest,
2678 QRhiSampler::ClampToEdge,
2679 QRhiSampler::ClampToEdge,
2682 bindings.addTexture(binding,
2683 QRhiShaderResourceBinding::VertexStage,
2690 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
2691 if (targetsTexture) {
2692 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
2694 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2695 QRhiSampler::Nearest,
2697 QRhiSampler::ClampToEdge,
2698 QRhiSampler::ClampToEdge,
2699 QRhiSampler::ClampToEdge
2701 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
2705 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2707 subsetRenderable.rhiRenderData.normalPass.pipeline = rhiCtxD->pipeline(ps,
2710 subsetRenderable.rhiRenderData.normalPass.srb = srb;