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);
1110 qWarning(
"Could not find sampler for lightprobe");
1115 if (shaderPipeline->screenTexture()) {
1116 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
1117 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
1118 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
1123 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
1124 ? QRhiSampler::Linear : QRhiSampler::None;
1125 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
1126 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
1127 if (screenTextureBinding >= 0) {
1128 bindings.addTexture(screenTextureBinding,
1129 QRhiShaderResourceBinding::FragmentStage,
1130 shaderPipeline->screenTexture(), sampler);
1132 if (screenTextureArrayBinding >= 0) {
1133 bindings.addTexture(screenTextureArrayBinding,
1134 QRhiShaderResourceBinding::FragmentStage,
1135 shaderPipeline->screenTexture(), sampler);
1140 if (shaderPipeline->lightmapTexture()) {
1141 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
1143 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
1144 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
1145 bindings.addTexture(binding,
1146 QRhiShaderResourceBinding::FragmentStage,
1147 shaderPipeline->lightmapTexture(), sampler);
1153 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
1156 addNormalTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
1165 QRhiShaderResourceBindings *&srb = dcd.srb;
1166 bool srbChanged =
false;
1167 if (!srb || bindings != dcd.bindings) {
1168 srb = rhiCtxD->srb(bindings);
1169 rhiCtxD->releaseCachedSrb(dcd.bindings);
1170 dcd.bindings = bindings;
1174 if (cubeFace != QSSGRenderTextureCubeFaceNone)
1175 subsetRenderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx] = srb;
1177 subsetRenderable.rhiRenderData.mainPass.srb = srb;
1179 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
1182 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
1183 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
1186 if (cubeFace != QSSGRenderTextureCubeFaceNone)
1187 subsetRenderable.rhiRenderData.reflectionPass.pipeline = dcd.pipeline;
1189 subsetRenderable.rhiRenderData.mainPass.pipeline = dcd.pipeline;
1191 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1192 subsetRenderable.rhiRenderData.reflectionPass.pipeline = rhiCtxD->pipeline(pipelineKey,
1193 renderPassDescriptor,
1195 dcd.pipeline = subsetRenderable.rhiRenderData.reflectionPass.pipeline;
1197 subsetRenderable.rhiRenderData.mainPass.pipeline = rhiCtxD->pipeline(pipelineKey,
1198 renderPassDescriptor,
1200 dcd.pipeline = subsetRenderable.rhiRenderData.mainPass.pipeline;
1202 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
1203 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;
1209 case QSSGRenderableObject::Type::CustomMaterialMeshSubset:
1211 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(inObject));
1212 const QSSGRenderCustomMaterial &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
1213 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
1215 featureSet.set(QSSGShaderFeatures::Feature::LightProbe, inData.layer.lightProbe || material.m_iblProbe);
1217 if ((cubeFace == QSSGRenderTextureCubeFaceNone) && subsetRenderable.reflectionProbeIndex >= 0 && subsetRenderable.renderableFlags.testFlag(QSSGRenderableObjectFlag::ReceivesReflections))
1218 featureSet.set(QSSGShaderFeatures::Feature::ReflectionProbe,
true);
1220 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1222 featureSet.disableTonemapping();
1225 if (subsetRenderable.renderableFlags.rendersWithLightmap())
1226 featureSet.set(QSSGShaderFeatures::Feature::Lightmap,
true);
1228 customMaterialSystem.rhiPrepareRenderable(ps, passKey, subsetRenderable, featureSet,
1229 material, inData, renderPassDescriptor, samples, viewCount,
1230 alteredCamera, cubeFace, alteredModelViewProjection, entry, oit);
1233 case QSSGRenderableObject::Type::Particles:
1236 const auto &shaderPipeline = shadersForParticleMaterial(ps, particleRenderable, oit ? inData.layer.oitMethod : QSSGRenderLayer::OITMethod::None);
1237 if (shaderPipeline) {
1238 QSSGParticleRenderer::rhiPrepareRenderable(*shaderPipeline, passKey, rhiCtx, ps, particleRenderable, inData, renderPassDescriptor, samples, viewCount,
1239 alteredCamera, cubeFace, entry);
1351 QSSGPassKey passKey,
1352 QSSGRhiGraphicsPipelineState &ps,
1353 QSSGRenderShadowMap &shadowMapManager,
1354 const QSSGRenderCamera &camera,
1355 QSSGRenderCamera *debugCamera,
1357 const QSSGRenderableObjectList &sortedOpaqueObjects,
1359 const QSSGBounds3 &castingObjectsBox,
1360 const QSSGBounds3 &receivingObjectsBox)
1363 QSSGDebugDrawSystem *debugDrawSystem = renderer.contextInterface()->debugDrawSystem().get();
1364 const bool drawDirectionalLightShadowBoxes = layerData.layer.drawDirectionalLightShadowBoxes;
1365 const bool drawPointLightShadowBoxes = layerData.layer.drawPointLightShadowBoxes;
1366 const bool drawShadowCastingBounds = layerData.layer.drawShadowCastingBounds;
1367 const bool drawShadowReceivingBounds = layerData.layer.drawShadowReceivingBounds;
1368 const bool drawCascades = layerData.layer.drawCascades;
1369 const bool drawSceneCascadeIntersection = layerData.layer.drawSceneCascadeIntersection;
1370 const bool disableShadowCameraUpdate = layerData.layer.disableShadowCameraUpdate;
1371 const bool drawCulledObjects = layerData.layer.drawCulledObjects;
1372 QVector<
bool> debugIsObjectCulled = drawCulledObjects ? QVector<
bool>(sortedOpaqueObjects.size(),
true) : QVector<
bool>();
1374 static const auto rhiRenderOneShadowMap = [](QSSGRhiContext *rhiCtx,
1375 QSSGRhiGraphicsPipelineState *ps,
1376 const QSSGRenderableObjectList &sortedOpaqueObjects,
1378 const QSSGBounds3 cameraBounds,
1379 QVector<
bool> &debugIsObjectCulled,
1380 bool drawCulledObjects) {
1381 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1382 bool needsSetViewport =
true;
1384 for (
int i = 0, n = sortedOpaqueObjects.size(); i < n; ++i) {
1389 if (theObject->globalBoundsInstancing.isFinite() && theObject->globalBounds.isFinite()) {
1390 const QSSGBounds3 &globalBounds = !theObject->globalBoundsInstancing.isEmpty() ? theObject->globalBoundsInstancing
1391 : theObject->globalBounds;
1392 if (!globalBounds.isEmpty() && !cameraBounds.intersects(globalBounds)) {
1397 if (Q_UNLIKELY(drawCulledObjects))
1398 debugIsObjectCulled[i] =
false;
1400 QSSG_ASSERT(theObject->renderableFlags.castsShadows(),
continue);
1401 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
1402 QSSGSubsetRenderable *renderable(
static_cast<QSSGSubsetRenderable *>(theObject));
1404 QRhiBuffer *vertexBuffer = renderable->subset.rhi.vertexBuffer->buffer();
1405 QRhiBuffer *indexBuffer = renderable->subset.rhi.indexBuffer
1406 ? renderable->subset.rhi.indexBuffer->buffer()
1410 if (!renderable->rhiRenderData.shadowPass.pipeline)
1413 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall);
1415 cb->setGraphicsPipeline(renderable->rhiRenderData.shadowPass.pipeline);
1417 QRhiShaderResourceBindings *srb = renderable->rhiRenderData.shadowPass.srb[cubeFace];
1418 cb->setShaderResources(srb);
1420 if (needsSetViewport) {
1421 cb->setViewport(ps->viewport);
1422 needsSetViewport =
false;
1425 QRhiCommandBuffer::VertexInput vertexBuffers[2];
1426 int vertexBufferCount = 1;
1427 vertexBuffers[0] = QRhiCommandBuffer::VertexInput(vertexBuffer, 0);
1428 quint32 instances = 1;
1429 if (renderable->modelContext.model.instancing()) {
1430 instances = renderable->modelContext.model.instanceCount();
1431 vertexBuffers[1] = QRhiCommandBuffer::VertexInput(renderable->instanceBuffer, 0);
1432 vertexBufferCount = 2;
1435 cb->setVertexInput(0, vertexBufferCount, vertexBuffers, indexBuffer, 0, renderable->subset.rhi.indexBuffer->indexFormat());
1436 cb->drawIndexed(renderable->subset.lodCount(renderable->subsetLevelOfDetail), instances, renderable->subset.lodOffset(renderable->subsetLevelOfDetail));
1437 QSSGRHICTX_STAT(rhiCtx, drawIndexed(renderable->subset.lodCount(renderable->subsetLevelOfDetail), instances));
1439 cb->setVertexInput(0, vertexBufferCount, vertexBuffers);
1440 cb->draw(renderable->subset.count, instances, renderable->subset.offset);
1441 QSSGRHICTX_STAT(rhiCtx, draw(renderable->subset.count, instances));
1443 Q_QUICK3D_PROFILE_END_WITH_IDS(QQuick3DProfiler::Quick3DRenderCall, (renderable->subset.count | quint64(instances) << 32),
1444 QVector<
int>({renderable->modelContext.model.profilingId,
1445 renderable->material.profilingId}));
1450 static const auto rhiClearShadowMap = [](
QSSGRenderer &renderer, QSSGRenderShadowMap &shadowMapManager, QSSGRhiContext *rhiCtx, QSSGRhiGraphicsPipelineState *ps, QRhiRenderPassDescriptor *renderPassDesc) {
1451 auto clearShadowMapShaderPipeline = renderer.contextInterface()->shaderCache()->getBuiltInRhiShaders().getRhiClearShadowMapShader();
1452 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, clearShadowMapShaderPipeline.get());
1455 ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled,
false);
1456 ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1457 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, ps, shadowMapManager.shadowClearSrb(), renderPassDesc, {});
1459 ps->flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
1462 QRhi *rhi = rhiCtx->rhi();
1463 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1467 QVector2D depthAdjust;
1468 if (rhi->isClipDepthZeroToOne()) {
1470 depthAdjust[0] = 0.0f;
1471 depthAdjust[1] = 1.0f;
1474 depthAdjust[0] = 1.0f;
1475 depthAdjust[1] = 0.5f;
1478 if (drawShadowCastingBounds)
1479 ShadowmapHelpers::addDebugBox(castingObjectsBox.toQSSGBoxPointsNoEmptyCheck(), QColorConstants::Red, debugDrawSystem);
1480 if (drawShadowReceivingBounds)
1481 ShadowmapHelpers::addDebugBox(receivingObjectsBox.toQSSGBoxPointsNoEmptyCheck(), QColorConstants::Green, debugDrawSystem);
1484 const QSize atlasTextureSize = shadowMapManager.shadowMapAtlasTexture()->pixelSize();
1486 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
1487 for (
int i = 0, ie = globalLights.size(); i != ie; ++i) {
1488 if (!globalLights[i].shadows || globalLights[i].light->m_fullyBaked)
1495 const auto &light = globalLights[i].light;
1497 if (!shadowMapManager.shadowMapAtlasTexture())
1500 if (light->type == QSSGRenderLight::Type::DirectionalLight || light->type == QSSGRenderLight::Type::SpotLight) {
1501 const QSize size = atlasTextureSize * pEntry->m_atlasInfo[0].uvScale;
1505 if (!disableShadowCameraUpdate && debugCamera) {
1506 debugCamera->clipPlanes = camera.clipPlanes;
1507 debugCamera->projection = camera.projection;
1511 debugCamera->localTransform = layerData.getGlobalTransform(camera);
1514 QVarLengthArray<std::unique_ptr<QSSGRenderCamera>, 4> cascades;
1515 if (light->type == QSSGRenderLight::Type::DirectionalLight) {
1516 const float pcfRadius = light->m_softShadowQuality == QSSGRenderLight::SoftShadowQuality::Hard ? 0.f : light->m_pcfFactor;
1517 const float clipNear = camera.clipPlanes.clipNear();
1518 const float clipFar = qMin(light->m_shadowMapFar, camera.clipPlanes.clipFar());
1519 const float clipRange = clipFar - clipNear;
1520 cascades = setupCascadingCamerasForShadowMap(layerData,
1521 disableShadowCameraUpdate ? *debugCamera : camera,
1528 receivingObjectsBox,
1529 light->m_lockShadowmapTexels,
1532 drawSceneCascadeIntersection);
1535 pEntry->m_csmSplits[0] = clipNear + clipRange * (light->m_csmNumSplits > 0 ? light->m_csmSplit1 : 1.0f);
1536 pEntry->m_csmSplits[1] = clipNear + clipRange * (light->m_csmNumSplits > 1 ? light->m_csmSplit2 : 1.0f);
1537 pEntry->m_csmSplits[2] = clipNear + clipRange * (light->m_csmNumSplits > 2 ? light->m_csmSplit3 : 1.0f);
1538 pEntry->m_csmSplits[3] = clipNear + clipRange * 1.0f;
1539 pEntry->m_shadowMapFar = clipFar;
1540 }
else if (light->type == QSSGRenderLight::Type::SpotLight) {
1541 auto spotlightCamera = std::make_unique<QSSGRenderCamera>(QSSGRenderCamera::Type::PerspectiveCamera);
1542 spotlightCamera->fov = QSSGRenderCamera::FieldOfView::fromDegrees(light->m_coneAngle * 2.0f);
1543 spotlightCamera->clipPlanes = { 1.0f, light->m_shadowMapFar };
1544 const QMatrix4x4 lightGlobalTransform = layerData.getGlobalTransform(*light);
1545 const QVector3D lightDir = QSSGRenderNode::getDirection(lightGlobalTransform);
1546 const QVector3D lightPos = QSSGRenderNode::getGlobalPos(lightGlobalTransform) - lightDir * spotlightCamera->clipPlanes.clipNear();
1547 const QVector3D lightPivot = light->pivot;
1548 const QVector3D forward = lightDir.normalized();
1549 const QVector3D right = qFuzzyCompare(qAbs(forward.y()), 1.0f)
1550 ? QVector3D::crossProduct(forward, QVector3D(1, 0, 0)).normalized()
1551 : QVector3D::crossProduct(forward, QVector3D(0, 1, 0)).normalized();
1552 const QVector3D up = QVector3D::crossProduct(right, forward).normalized();
1553 spotlightCamera->localTransform = QSSGRenderNode::calculateTransformMatrix(lightPos,
1554 QSSGRenderNode::initScale,
1556 QQuaternion::fromDirection(forward, up));
1557 QRectF theViewport(0.0f, 0.0f, (
float)light->m_shadowMapRes, (
float)light->m_shadowMapRes);
1558 QSSGRenderCamera::calculateProjectionInternal(*spotlightCamera, theViewport);
1559 cascades.push_back(
std::move(spotlightCamera));
1560 pEntry->m_shadowMapFar = light->m_shadowMapFar;
1565 memset(pEntry->m_csmActive, 0,
sizeof(pEntry->m_csmActive));
1567 QMatrix4x4 cascadeCameraGlobalTransforms(Qt::Uninitialized);
1568 const QMatrix4x4 bias = { 0.5, 0.0, 0.0, 0.5,
1571 0.0, 0.0, 0.0, 1.0 };
1573 for (
int cascadeIndex = 0; cascadeIndex < cascades.length(); cascadeIndex++) {
1574 const auto &cascadeCamera = cascades[cascadeIndex];
1578 cascadeCameraGlobalTransforms = layerData.getGlobalTransform(*cascadeCamera);
1579 pEntry->m_csmActive[cascadeIndex] = 1.f;
1580 QMatrix4x4 &viewProjection = pEntry->m_lightViewProjection[cascadeIndex];
1581 cascadeCamera->calculateViewProjectionMatrix(cascadeCameraGlobalTransforms, viewProjection);
1582 pEntry->m_lightViewProjection[cascadeIndex] = viewProjection;
1583 pEntry->m_fixedScaleBiasMatrix[cascadeIndex] = bias * viewProjection;
1584 const QMatrix4x4 inverted = viewProjection.inverted();
1585 const float x = 0.5f / (inverted * QVector4D(1, 0, 0, 0)).length();
1586 const float y = 0.5f / (inverted * QVector4D(0, 1, 0, 0)).length();
1587 const float z = 0.5f / (inverted * QVector4D(0, 0, 1, 0)).length();
1588 const QSSGBoxPoints frustumPoints = computeFrustumBounds(viewProjection);
1589 const QSSGBounds3 bounds = QSSGBounds3(frustumPoints);
1590 pEntry->m_dimensionsInverted[cascadeIndex] = QVector4D(x, y, z, 0.0f);
1591 pEntry->m_lightView = cascadeCameraGlobalTransforms.inverted();
1592 const bool isOrtho = cascadeCamera->type == QSSGRenderGraphObject::Type::OrthographicCamera;
1593 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[cascadeIndex], rhi->isYUpInFramebuffer());
1594 rhiPrepareResourcesForShadowMap(rhiCtx, layerData, passKey, pEntry, &ps, &depthAdjust, sortedOpaqueObjects, *cascadeCamera, isOrtho, QSSGRenderTextureCubeFaceNone, cascadeIndex);
1597 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargets[cascadeIndex];
1598 cb->beginPass(rt, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1599 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1600 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1601 rhiClearShadowMap(renderer, shadowMapManager, rhiCtx, &ps, rt->renderPassDescriptor());
1602 rhiRenderOneShadowMap(rhiCtx, &ps, sortedOpaqueObjects, 0, bounds, debugIsObjectCulled, drawCulledObjects);
1604 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1606 if (drawDirectionalLightShadowBoxes) {
1610 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"shadow_map"));
1612 const QSize size = atlasTextureSize * pEntry->m_atlasInfo[0].uvScale;
1613 ps.viewport = QRhiViewport(0, 0,
float(size.width()),
float(size.height()));
1615 QSSGRenderCamera theCameras[6] { QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1616 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1617 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1618 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1619 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1620 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera} };
1621 const float shadowMapFar = qMax<
float>(2.0f, light->m_shadowMapFar);
1622 setupCubeShadowCameras(layerData, light, shadowMapFar, theCameras);
1623 pEntry->m_lightView = QMatrix4x4();
1624 pEntry->m_shadowMapFar = shadowMapFar;
1626 const bool swapYFaces = !rhi->isYUpInFramebuffer();
1627 QMatrix4x4 cameraGlobalTransform(Qt::Uninitialized);
1628 for (
const auto face : QSSGRenderTextureCubeFaces) {
1629 cameraGlobalTransform = layerData.getGlobalTransform(theCameras[quint8(face)]);
1630 theCameras[quint8(face)].calculateViewProjectionMatrix(cameraGlobalTransform, pEntry->m_lightViewProjection[0]);
1631 pEntry->m_lightCubeView[quint8(face)] = cameraGlobalTransform.inverted();
1633 rhiPrepareResourcesForShadowMap(rhiCtx,
1639 sortedOpaqueObjects,
1640 theCameras[quint8(face)],
1647 const QVector3D center = QSSGRenderNode::getGlobalPos(layerData.getGlobalTransform(*light));
1648 const QSSGBounds3 bounds = QSSGBounds3(center - QVector3D(shadowMapFar, shadowMapFar, shadowMapFar),
1649 center + QVector3D(shadowMapFar, shadowMapFar, shadowMapFar));
1651 for (
const auto face : QSSGRenderTextureCubeFaces) {
1655 QSSGRenderTextureCubeFace outFace = face;
1673 if (outFace == QSSGRenderTextureCubeFace::PosY)
1674 outFace = QSSGRenderTextureCubeFace::NegY;
1675 else if (outFace == QSSGRenderTextureCubeFace::NegY)
1676 outFace = QSSGRenderTextureCubeFace::PosY;
1678 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargetCube[quint8(outFace)];
1679 cb->beginPass(rt, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1680 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1681 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1682 rhiRenderOneShadowMap(rhiCtx, &ps, sortedOpaqueObjects, quint8(face), bounds, debugIsObjectCulled, drawCulledObjects);
1684 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1685 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_cube", 0, outFace));
1692 QRhiTextureRenderTarget *rtFront = pEntry->m_rhiRenderTargets[0];
1693 QRhiRenderPassDescriptor *frontDesc = pEntry->m_rhiRenderPassDesc[0];
1694 auto atlasShaderPipeline = renderer.contextInterface()->shaderCache()->getBuiltInRhiShaders().getRhiCubeMapToAtlasShader();
1695 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[0], rhi->isYUpInFramebuffer());
1696 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, atlasShaderPipeline.get());
1697 QRhiShaderResourceBindings *srb = pEntry->m_cubeToAtlasFrontSrb;
1698 cb->beginPass(rtFront, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1699 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rtFront));
1700 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1702 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, frontDesc, QSSGRhiQuadRenderer::UvCoords);
1705 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1706 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_atlas", 6, 0));
1709 QRhiTextureRenderTarget *rtBack = pEntry->m_rhiRenderTargets[1];
1710 QRhiRenderPassDescriptor *backDesc = pEntry->m_rhiRenderPassDesc[1];
1711 srb = pEntry->m_cubeToAtlasBackSrb;
1712 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[1], rhi->isYUpInFramebuffer());
1713 cb->beginPass(rtBack, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1714 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rtBack));
1715 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1717 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, backDesc, QSSGRhiQuadRenderer::UvCoords);
1720 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1721 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_atlas", 7, 0));
1725 ps = layerData.getPipelineState();
1726 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
1728 ps.slopeScaledDepthBias = 1.5f;
1730 if (drawPointLightShadowBoxes) {
1731 ShadowmapHelpers::addDebugBox(bounds.toQSSGBoxPoints(), QColorConstants::Yellow, debugDrawSystem);
1736 if (Q_UNLIKELY(drawCulledObjects)) {
1737 for (
int i = 0, n = sortedOpaqueObjects.size(); i < n; ++i) {
1739 const QSSGBounds3 &globalBounds = !theObject->globalBoundsInstancing.isEmpty() ? theObject->globalBoundsInstancing
1740 : theObject->globalBounds;
1741 const QColor color = debugIsObjectCulled[i] ? QColorConstants::Red : QColorConstants::Green;
1748 QSSGPassKey passKey,
1750 QSSGRhiGraphicsPipelineState *ps,
1751 QSSGRenderReflectionMap &reflectionMapManager,
1752 const QVector<QSSGRenderReflectionProbe *> &reflectionProbes,
1753 const QSSGRenderableObjectList &reflectionPassObjects,
1756 QRhi *rhi = rhiCtx->rhi();
1757 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1759 const bool renderSkybox = (inData.layer.background == QSSGRenderLayer::Background::SkyBox ||
1760 inData.layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap)
1761 && rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch);
1763 for (
int i = 0, ie = reflectionProbes.size(); i != ie; ++i) {
1768 if (!pEntry->m_needsRender)
1771 if (reflectionProbes[i]->refreshMode == QSSGRenderReflectionProbe::ReflectionRefreshMode::FirstFrame && pEntry->m_rendered)
1774 if (reflectionProbes[i]->texture)
1777 Q_ASSERT(pEntry->m_rhiDepthStencil);
1778 Q_ASSERT(pEntry->m_rhiCube);
1780 const QSize size = pEntry->m_rhiCube->pixelSize();
1781 ps->viewport = QRhiViewport(0, 0,
float(size.width()),
float(size.height()));
1783 QSSGRenderCamera theCameras[6] { QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1784 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1785 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1786 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1787 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1788 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera} };
1789 setupCubeReflectionCameras(inData, reflectionProbes[i], theCameras);
1790 const bool swapYFaces = !rhi->isYUpInFramebuffer();
1791 QMatrix4x4 cameraGlobalTransform(Qt::Uninitialized);
1792 for (
const auto face : QSSGRenderTextureCubeFaces) {
1793 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(face);
1794 cameraGlobalTransform = inData.getGlobalTransform(theCameras[cubeFaceIdx]);
1795 theCameras[cubeFaceIdx].calculateViewProjectionMatrix(cameraGlobalTransform, pEntry->m_viewProjection);
1797 rhiPrepareResourcesForReflectionMap(rhiCtx, passKey, inData, pEntry, ps,
1798 reflectionPassObjects, theCameras[cubeFaceIdx], renderer, face);
1800 QRhiRenderPassDescriptor *renderPassDesc =
nullptr;
1801 for (
auto face : QSSGRenderTextureCubeFaces) {
1802 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1803 face = pEntry->m_timeSliceFace;
1805 QSSGRenderTextureCubeFace outFace = face;
1809 if (outFace == QSSGRenderTextureCubeFace::PosY)
1810 outFace = QSSGRenderTextureCubeFace::NegY;
1811 else if (outFace == QSSGRenderTextureCubeFace::NegY)
1812 outFace = QSSGRenderTextureCubeFace::PosY;
1814 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargets[quint8(outFace)];
1815 cb->beginPass(rt, reflectionProbes[i]->clearColor, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1816 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1817 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1819 if (renderSkybox && pEntry->m_skyBoxSrbs[quint8(face)]) {
1820 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1821 const bool isSkyBox = inData.layer.background == QSSGRenderLayer::Background::SkyBox;
1822 const auto &shaderPipeline = isSkyBox ? shaderCache->getBuiltInRhiShaders().getRhiSkyBoxShader(QSSGRenderLayer::TonemapMode::None, inData.layer.skyBoxIsRgbe8, 1)
1823 : shaderCache->getBuiltInRhiShaders().getRhiSkyBoxCubeShader(1);
1824 Q_ASSERT(shaderPipeline);
1825 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, shaderPipeline.get());
1826 QRhiShaderResourceBindings *srb = pEntry->m_skyBoxSrbs[quint8(face)];
1827 if (!renderPassDesc)
1828 renderPassDesc = rt->newCompatibleRenderPassDescriptor();
1829 rt->setRenderPassDescriptor(renderPassDesc);
1830 isSkyBox ? renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, ps, srb, renderPassDesc, {})
1831 : renderer.rhiCubeRenderer()->recordRenderCube(rhiCtx, ps, srb, renderPassDesc, {});
1834 bool needsSetViewport =
true;
1835 for (
const auto &handle : reflectionPassObjects)
1836 rhiRenderRenderable(rhiCtx, *ps, *handle.obj, &needsSetViewport, face);
1839 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1840 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"reflection_cube", 0, outFace));
1842 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1846 renderPassDesc->deleteLater();
1848 pEntry->renderMips(rhiCtx);
1850 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1851 pEntry->m_timeSliceFace = QSSGBaseTypeHelpers::next(pEntry->m_timeSliceFace);
1853 if (reflectionProbes[i]->refreshMode == QSSGRenderReflectionProbe::ReflectionRefreshMode::FirstFrame)
1854 pEntry->m_rendered =
true;
1856 reflectionProbes[i]->hasScheduledUpdate =
false;
1857 pEntry->m_needsRender =
false;
1908 QSSGPassKey passKey,
1910 QSSGRhiShaderPipeline &shaderPipeline,
1911 QSSGRhiGraphicsPipelineState &ps,
1912 const QSSGAmbientOcclusionSettings &ao,
1913 const QSSGRhiRenderableTexture &rhiAoTexture,
1914 const QSSGRhiRenderableTexture &rhiDepthTexture,
1915 const QSSGRenderCamera &camera)
1917 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
1920 if (!rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
1921 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1923 cb->beginPass(rhiAoTexture.rt, Qt::white, { 1.0f, 0 });
1924 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rhiAoTexture.rt));
1926 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1930 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, &shaderPipeline);
1932 const float R2 = ao.aoDistance * ao.aoDistance * 0.16f;
1933 const QSize textureSize = rhiAoTexture.texture->pixelSize();
1934 const float rw =
float(textureSize.width());
1935 const float rh =
float(textureSize.height());
1936 const float fov = camera.fov.asVerticalFov(rw / rh).radians();
1937 const float tanHalfFovY = tanf(0.5f * fov * (rh / rw));
1938 const float invFocalLenX = tanHalfFovY * (rw / rh);
1940 const QVector4D aoProps(ao.aoStrength * 0.01f, ao.aoDistance * 0.4f, ao.aoSoftness * 0.02f, ao.aoBias);
1941 const QVector4D aoProps2(
float(ao.aoSamplerate), (ao.aoDither) ? 1.0f : 0.0f, 0.0f, 0.0f);
1942 const QVector4D aoScreenConst(1.0f / R2, rh / (2.0f * tanHalfFovY), 1.0f / rw, 1.0f / rh);
1943 const QVector4D uvToEyeConst(2.0f * invFocalLenX, -2.0f * tanHalfFovY, -invFocalLenX, tanHalfFovY);
1944 const QVector2D cameraProps = camera.clipPlanes;
1953 const int UBUF_SIZE = 72;
1954 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({ passKey,
nullptr,
nullptr, 0 }));
1956 dcd.ubuf = rhiCtx->rhi()->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, UBUF_SIZE);
1960 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
1961 memcpy(ubufData, &aoProps, 16);
1962 memcpy(ubufData + 16, &aoProps2, 16);
1963 memcpy(ubufData + 32, &aoScreenConst, 16);
1964 memcpy(ubufData + 48, &uvToEyeConst, 16);
1965 memcpy(ubufData + 64, &cameraProps, 8);
1966 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
1968 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
1969 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
1970 QSSGRhiShaderResourceBindingList bindings;
1971 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf);
1974 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, rhiDepthTexture.texture, sampler);
1975 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
1977 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
1978 renderer.rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, rhiAoTexture.rt, {});
2126 QSSGPassKey passKey,
2127 QSSGRenderLayer &layer,
2128 QSSGRenderCameraList &cameras,
2133 QSSG_ASSERT(layer.renderData,
return);
2135 const auto *renderData = layer.renderData;
2137 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2138 const bool cubeMapMode = layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap;
2139 const QSSGRenderImageTexture lightProbeTexture =
2140 cubeMapMode ? renderer.contextInterface()->bufferManager()->loadRenderImage(layer.skyBoxCubeMap, QSSGBufferManager::MipModeDisable)
2141 : renderer.contextInterface()->bufferManager()->loadRenderImage(layer.lightProbe, QSSGBufferManager::MipModeBsdf);
2142 const bool hasValidTexture = lightProbeTexture.m_texture !=
nullptr;
2143 if (hasValidTexture) {
2144 if (cubeFace == QSSGRenderTextureCubeFaceNone)
2145 layer.skyBoxIsRgbe8 = lightProbeTexture.m_flags.isRgbe8();
2147 QSSGRhiShaderResourceBindingList bindings;
2149 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
2150 QRhiSampler::Linear,
2151 cubeMapMode ? QRhiSampler::None : QRhiSampler::Linear,
2152 QRhiSampler::Repeat,
2153 QRhiSampler::ClampToEdge,
2154 QRhiSampler::Repeat });
2155 int samplerBinding = 1;
2156 const quint32 ubufSize = cameras.count() >= 2 ? 416 : 240;
2157 bindings.addTexture(samplerBinding,
2158 QRhiShaderResourceBinding::FragmentStage,
2159 lightProbeTexture.m_texture, sampler);
2161 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
2162 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone) * cubeFaceIdx;
2163 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({ passKey,
nullptr, entry, entryIdx });
2165 QRhi *rhi = rhiCtx->rhi();
2167 dcd.ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
2171 float adjustY = rhi->isYUpInNDC() ? 1.0f : -1.0f;
2172 const float exposure = layer.lightProbeSettings.probeExposure;
2174 const QMatrix3x3 &rotationMatrix(layer.lightProbeSettings.probeOrientation);
2175 const float blurAmount = layer.skyboxBlurAmount;
2176 const float maxMipLevel =
float(lightProbeTexture.m_mipmapCount - 2);
2178 const QVector4D skyboxProperties = {
2185 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2186 quint32 ubufOffset = 0;
2188 memcpy(ubufData + ubufOffset, &skyboxProperties, 16);
2191 memcpy(ubufData + ubufOffset, rotationMatrix.constData(), 12);
2193 memcpy(ubufData + ubufOffset, (
char *)rotationMatrix.constData() + 12, 12);
2195 memcpy(ubufData + ubufOffset, (
char *)rotationMatrix.constData() + 24, 12);
2198 for (qsizetype viewIdx = 0; viewIdx < cameras.count(); ++viewIdx) {
2199 const QMatrix4x4 &inverseProjection = cameras[viewIdx]->projection.inverted();
2200 const QMatrix4x4 &viewMatrix = renderData->getGlobalTransform(*cameras[viewIdx]);
2201 QMatrix4x4 viewProjection(Qt::Uninitialized);
2202 cameras[viewIdx]->calculateViewProjectionWithoutTranslation(viewMatrix, 0.1f, 5.0f, viewProjection);
2204 quint32 viewDataOffset = ubufOffset;
2205 memcpy(ubufData + viewDataOffset + viewIdx * 64, viewProjection.constData(), 64);
2206 viewDataOffset += cameras.count() * 64;
2207 memcpy(ubufData + viewDataOffset + viewIdx * 64, inverseProjection.constData(), 64);
2208 viewDataOffset += cameras.count() * 64;
2209 memcpy(ubufData + viewDataOffset + viewIdx * 48, viewMatrix.constData(), 48);
2211 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2213 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf);
2215 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
2216 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
2217 entry->m_skyBoxSrbs[cubeFaceIdx] = rhiCtxD->srb(bindings);
2219 layer.skyBoxSrb = rhiCtxD->srb(bindings);
2223 renderer.rhiCubeRenderer()->prepareCube(rhiCtx,
nullptr);
2225 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
2261 QSSGPassKey passKey,
2262 const QSSGRhiGraphicsPipelineState &basePipelineState,
2263 QRhiRenderPassDescriptor *rpDesc,
2265 const QSSGRenderableObjectList &sortedOpaqueObjects,
2266 const QSSGRenderableObjectList &sortedTransparentObjects,
2270 static const auto rhiPrepareDepthPassForObject = [](QSSGRhiContext *rhiCtx,
2271 QSSGPassKey passKey,
2274 QRhiRenderPassDescriptor *rpDesc,
2275 QSSGRhiGraphicsPipelineState *ps) {
2276 QSSGRhiShaderPipelinePtr shaderPipeline;
2277 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2279 const bool isOpaqueDepthPrePass = obj->depthWriteMode == QSSGDepthDrawMode::OpaquePrePass;
2280 QSSGShaderFeatures featureSet;
2281 featureSet.set(QSSGShaderFeatures::Feature::DepthPass,
true);
2282 if (isOpaqueDepthPrePass)
2283 featureSet.set(QSSGShaderFeatures::Feature::OpaqueDepthPrePass,
true);
2285 QSSGRhiDrawCallData *dcd =
nullptr;
2286 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2287 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2288 const void *modelNode = &subsetRenderable.modelContext.model;
2289 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
2292 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
2293 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2294 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
2295 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
2297 shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, featureSet);
2298 if (shaderPipeline) {
2299 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2300 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2301 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
2302 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2306 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2307 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2309 const auto &customMaterial =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
2311 ps->cullMode = QSSGRhiHelpers::toCullMode(customMaterial.m_cullMode);
2313 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
2314 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(ps, customMaterial, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
2316 if (shaderPipeline) {
2317 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2318 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2319 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, customMaterial, subsetRenderable,
2320 inData.renderedCameras,
nullptr,
nullptr);
2321 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2328 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2329 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2330 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
2331 ia = subsetRenderable.subset.rhi.ia;
2333 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
2334 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
2335 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
2337 QSSGRhiShaderResourceBindingList bindings;
2338 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
2341 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
2343 if (isOpaqueDepthPrePass) {
2344 addOpaqueDepthPrePassBindings(rhiCtx,
2345 shaderPipeline.get(),
2346 subsetRenderable.firstImage,
2348 (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset));
2354 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
2355 if (normalTextureBinding >= 0) {
2356 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2357 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
2358 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
2359 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
2360 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
2361 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
2365 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
2366 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
2368 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2369 QRhiSampler::Nearest,
2371 QRhiSampler::ClampToEdge,
2372 QRhiSampler::ClampToEdge,
2375 bindings.addTexture(binding,
2376 QRhiShaderResourceBinding::VertexStage,
2383 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
2384 if (targetsTexture) {
2385 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
2387 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2388 QRhiSampler::Nearest,
2390 QRhiSampler::ClampToEdge,
2391 QRhiSampler::ClampToEdge,
2392 QRhiSampler::ClampToEdge
2394 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
2398 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2400 subsetRenderable.rhiRenderData.depthPrePass.pipeline = rhiCtxD->pipeline(*ps,
2403 subsetRenderable.rhiRenderData.depthPrePass.srb = srb;
2414 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2419 ps.samples = samples;
2420 ps.viewCount = viewCount;
2421 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
2422 ps.targetBlend[0].colorWrite = {};
2424 for (
const QSSGRenderableObjectHandle &handle : sortedOpaqueObjects) {
2425 if (!rhiPrepareDepthPassForObject(rhiCtx, passKey, inData, handle.obj, rpDesc, &ps))
2429 for (
const QSSGRenderableObjectHandle &handle : sortedTransparentObjects) {
2430 if (!rhiPrepareDepthPassForObject(rhiCtx, passKey, inData, handle.obj, rpDesc, &ps))
2557 QSSGPassKey passKey,
2558 const QSSGRhiGraphicsPipelineState &basePipelineState,
2559 QRhiRenderPassDescriptor *rpDesc,
2561 const QSSGRenderableObjectList &sortedOpaqueObjects)
2563 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2564 ps.depthFunc = QRhiGraphicsPipeline::LessOrEqual;
2565 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
false);
2567 for (
const QSSGRenderableObjectHandle &handle : sortedOpaqueObjects) {
2568 QSSGRenderableObject *obj = handle.obj;
2569 QSSGRhiShaderPipelinePtr shaderPipeline;
2570 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2572 QSSGShaderFeatures featureSet;
2573 featureSet.set(QSSGShaderFeatures::Feature::NormalPass,
true);
2575 QSSGRhiDrawCallData *dcd =
nullptr;
2576 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2577 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2578 const void *modelNode = &subsetRenderable.modelContext.model;
2579 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
2582 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
2583 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2584 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
2585 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
2587 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet);
2588 if (shaderPipeline) {
2589 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2590 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2591 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
2592 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2594 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2595 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2597 const auto &customMaterial =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
2599 ps.cullMode = QSSGRhiHelpers::toCullMode(customMaterial.m_cullMode);
2601 const auto &customMaterialSystem = subsetRenderable.renderer->contextInterface()->customMaterialSystem();
2602 shaderPipeline = customMaterialSystem->shadersForCustomMaterial(&ps, customMaterial, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
2604 if (shaderPipeline) {
2605 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2606 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2607 customMaterialSystem->updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, customMaterial, subsetRenderable,
2608 inData.renderedCameras,
nullptr,
nullptr);
2609 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2614 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2615 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2616 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
2617 ia = subsetRenderable.subset.rhi.ia;
2619 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
2620 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
2621 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
2623 QSSGRhiShaderResourceBindingList bindings;
2624 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
2627 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
2628 while (renderableImage) {
2629 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
2630 const int samplerHint =
int(renderableImage->m_mapType);
2631 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
2632 if (samplerBinding >= 0) {
2633 QRhiTexture *texture = renderableImage->m_texture.m_texture;
2634 if (samplerBinding >= 0 && texture) {
2635 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
2636 QSSGRhiSamplerDescription samplerDesc = {
2637 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
2638 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
2639 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
2640 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
2641 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
2642 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
2644 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
2645 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
2646 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
2649 renderableImage = renderableImage->m_nextImage;
2652 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
2655 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
2656 if (normalTextureBinding >= 0) {
2657 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2658 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
2659 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
2660 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
2661 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
2662 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
2668 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
2669 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
2671 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2672 QRhiSampler::Nearest,
2674 QRhiSampler::ClampToEdge,
2675 QRhiSampler::ClampToEdge,
2678 bindings.addTexture(binding,
2679 QRhiShaderResourceBinding::VertexStage,
2686 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
2687 if (targetsTexture) {
2688 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
2690 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2691 QRhiSampler::Nearest,
2693 QRhiSampler::ClampToEdge,
2694 QRhiSampler::ClampToEdge,
2695 QRhiSampler::ClampToEdge
2697 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
2701 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2703 subsetRenderable.rhiRenderData.normalPass.pipeline = rhiCtxD->pipeline(ps,
2706 subsetRenderable.rhiRenderData.normalPass.srb = srb;