869void QSSGLayerRenderData::prepareImageForRender(QSSGRenderImage &inImage,
870 QSSGRenderableImage::Type inMapType,
871 QSSGRenderableImage *&ioFirstImage,
872 QSSGRenderableImage *&ioNextImage,
873 QSSGRenderableObjectFlags &ioFlags,
874 QSSGShaderDefaultMaterialKey &inShaderKey,
875 quint32 inImageIndex,
876 QSSGRenderDefaultMaterial *inMaterial)
878 QSSGRenderContextInterface &contextInterface = *renderer->contextInterface();
879 const auto &bufferManager = contextInterface.bufferManager();
881 if (inImage.clearDirty())
882 ioFlags |= QSSGRenderableObjectFlag::Dirty;
893 const QSSGRenderImageTexture texture = bufferManager->loadRenderImage(&inImage);
895 if (texture.m_texture) {
896 if (texture.m_flags.hasTransparency()
897 && (inMapType == QSSGRenderableImage::Type::Diffuse
898 || inMapType == QSSGRenderableImage::Type::Opacity
899 || inMapType == QSSGRenderableImage::Type::Translucency))
901 ioFlags |= QSSGRenderableObjectFlag::HasTransparency;
904 QSSGRenderableImage *theImage = RENDER_FRAME_NEW<QSSGRenderableImage>(contextInterface, inMapType, inImage, texture);
905 QSSGShaderKeyImageMap &theKeyProp = defaultMaterialShaderKeyProperties.m_imageMaps[inImageIndex];
907 theKeyProp.setEnabled(inShaderKey,
true);
908 switch (inImage.m_mappingMode) {
909 case QSSGRenderImage::MappingModes::Normal:
911 case QSSGRenderImage::MappingModes::Environment:
912 theKeyProp.setEnvMap(inShaderKey,
true);
914 case QSSGRenderImage::MappingModes::LightProbe:
915 theKeyProp.setLightProbe(inShaderKey,
true);
925 switch (texture.m_texture->format()) {
926 case QRhiTexture::Format::RED_OR_ALPHA8:
927 hasA = !renderer->contextInterface()->rhiContext()->rhi()->isFeatureSupported(QRhi::RedOrAlpha8IsRed);
929 case QRhiTexture::Format::R8:
939 if (inImage.isImageTransformIdentity())
940 theKeyProp.setIdentityTransform(inShaderKey,
true);
942 if (inImage.m_indexUV == 1)
943 theKeyProp.setUsesUV1(inShaderKey,
true);
945 if (texture.m_flags.isLinear())
946 theKeyProp.setLinear(inShaderKey,
true);
948 if (ioFirstImage ==
nullptr)
949 ioFirstImage = theImage;
951 ioNextImage->m_nextImage = theImage;
953 ioNextImage = theImage;
955 if (inMaterial && inImageIndex >= QSSGShaderDefaultMaterialKeyProperties::SingleChannelImagesFirst) {
956 QSSGRenderDefaultMaterial::TextureChannelMapping value = QSSGRenderDefaultMaterial::R;
958 const quint32 scIndex = inImageIndex - QSSGShaderDefaultMaterialKeyProperties::SingleChannelImagesFirst;
959 QSSGShaderKeyTextureChannel &channelKey = defaultMaterialShaderKeyProperties.m_textureChannels[scIndex];
960 switch (inImageIndex) {
961 case QSSGShaderDefaultMaterialKeyProperties::OpacityMap:
962 value = inMaterial->opacityChannel;
964 case QSSGShaderDefaultMaterialKeyProperties::RoughnessMap:
965 value = inMaterial->roughnessChannel;
967 case QSSGShaderDefaultMaterialKeyProperties::MetalnessMap:
968 value = inMaterial->metalnessChannel;
970 case QSSGShaderDefaultMaterialKeyProperties::OcclusionMap:
971 value = inMaterial->occlusionChannel;
973 case QSSGShaderDefaultMaterialKeyProperties::TranslucencyMap:
974 value = inMaterial->translucencyChannel;
976 case QSSGShaderDefaultMaterialKeyProperties::HeightMap:
977 value = inMaterial->heightChannel;
979 case QSSGShaderDefaultMaterialKeyProperties::ClearcoatMap:
980 value = inMaterial->clearcoatChannel;
982 case QSSGShaderDefaultMaterialKeyProperties::ClearcoatRoughnessMap:
983 value = inMaterial->clearcoatRoughnessChannel;
985 case QSSGShaderDefaultMaterialKeyProperties::TransmissionMap:
986 value = inMaterial->transmissionChannel;
988 case QSSGShaderDefaultMaterialKeyProperties::ThicknessMap:
989 value = inMaterial->thicknessChannel;
991 case QSSGShaderDefaultMaterialKeyProperties::BaseColorMap:
992 value = inMaterial->baseColorChannel;
994 case QSSGShaderDefaultMaterialKeyProperties::SpecularAmountMap:
995 value = inMaterial->specularAmountChannel;
997 case QSSGShaderDefaultMaterialKeyProperties::EmissiveMap:
998 value = inMaterial->emissiveChannel;
1003 bool useDefault =
false;
1005 case QSSGRenderDefaultMaterial::TextureChannelMapping::G:
1008 case QSSGRenderDefaultMaterial::TextureChannelMapping::B:
1011 case QSSGRenderDefaultMaterial::TextureChannelMapping::A:
1018 value = QSSGRenderDefaultMaterial::R;
1019 channelKey.setTextureChannel(QSSGShaderKeyTextureChannel::TexturChannelBits(value), inShaderKey);
1446bool QSSGLayerRenderData::prepareModelsForRender(QSSGRenderContextInterface &contextInterface,
1447 const RenderableNodeEntries &renderableModels,
1448 QSSGLayerRenderPreparationResultFlags &ioFlags,
1449 const QSSGRenderCameraList &allCameras,
1450 const QSSGRenderCameraDataList &allCameraData,
1451 TModelContextPtrList &modelContexts,
1452 QSSGRenderableObjectList &opaqueObjects,
1453 QSSGRenderableObjectList &transparentObjects,
1454 QSSGRenderableObjectList &screenTextureObjects,
1457 const auto &rhiCtx = contextInterface.rhiContext();
1458 const auto &bufferManager = contextInterface.bufferManager();
1460 const auto &debugDrawSystem = contextInterface.debugDrawSystem();
1461 const bool maybeDebugDraw = debugDrawSystem && debugDrawSystem->isEnabled();
1463 bool wasDirty =
false;
1465 for (
const QSSGRenderableNodeEntry &renderable : renderableModels) {
1466 if ((renderable.overridden & QSSGRenderableNodeEntry::Overridden::Disabled) != 0)
1469 const QSSGRenderModel &model = *
static_cast<QSSGRenderModel *>(renderable.node);
1470 const auto &lights = renderable.lights;
1471 QSSGRenderMesh *theMesh = modelData->getMesh(model);
1475 const bool altGlobalTransform = ((renderable.overridden & QSSGRenderableNodeEntry::Overridden::GlobalTransform) != 0);
1476 const auto &globalTransform = altGlobalTransform ? renderable.extOverrides.globalTransform : getGlobalTransform(model);
1477 QMatrix3x3 normalMatrix { Qt::Uninitialized };
1478 QSSGLayerRenderData::ModelViewProjections mvps;
1479 if (altGlobalTransform) {
1480 QSSGRenderNode::calculateNormalMatrix(globalTransform, normalMatrix);
1481 size_t mvpCount = 0;
1482 for (
const auto &cameraData : allCameraData) {
1483 QSSGRenderNode::calculateMVPAndNormalMatrix(globalTransform, cameraData.viewProjection, mvps[mvpCount++], normalMatrix);
1486 if (model.usesBoneTexture()) {
1490 size_t mvpCount = 0;
1491 for (
const QSSGRenderCameraData &cameraData : allCameraData) {
1492 mvps[mvpCount++] = cameraData.viewProjection;
1493 normalMatrix = QMatrix3x3();
1496 normalMatrix = getNormalMatrix(model);
1497 mvps = getModelMvps(model);
1500 const bool altModelOpacity = ((renderable.overridden & QSSGRenderableNodeEntry::Overridden::GlobalOpacity) != 0);
1501 const float modelGlobalOpacity = altModelOpacity ? renderable.extOverrides.globalOpacity : getGlobalOpacity(model);
1502 QSSGModelContext &theModelContext = *RENDER_FRAME_NEW<QSSGModelContext>(contextInterface, model, globalTransform, normalMatrix, mvps);
1503 modelContexts.push_back(&theModelContext);
1506 const auto &meshSubsets = theMesh->subsets;
1507 const auto meshSubsetCount = meshSubsets.size();
1508 theModelContext.subsets = RENDER_FRAME_NEW_BUFFER<QSSGSubsetRenderable>(contextInterface, meshSubsetCount);
1512 auto boneTexture = bufferManager->loadSkinmap(model.skin);
1513 setBonemapTexture(theModelContext, boneTexture.m_texture);
1514 }
else if (model.skeleton) {
1515 auto boneTexture = bufferManager->loadSkinmap(&(model.skeleton->boneTexData));
1516 setBonemapTexture(theModelContext, boneTexture.m_texture);
1520 QSSGRenderableObjectFlags renderableFlagsForModel;
1522 if (meshSubsetCount > 0) {
1523 const QSSGRenderSubset &theSubset = meshSubsets.at(0);
1525 renderableFlagsForModel.setCastsShadows(model.castsShadows);
1526 renderableFlagsForModel.setReceivesShadows(model.receivesShadows);
1527 renderableFlagsForModel.setReceivesReflections(model.receivesReflections);
1528 renderableFlagsForModel.setCastsReflections(model.castsReflections);
1530 renderableFlagsForModel.setUsedInBakedLighting(model.usedInBakedLighting);
1531 if (model.hasLightmap()) {
1532 QSSGRenderImageTexture lmImageTexture = bufferManager->loadLightmap(model);
1533 if (lmImageTexture.m_texture) {
1534 renderableFlagsForModel.setRendersWithLightmap(
true);
1535 setLightmapTexture(theModelContext, lmImageTexture.m_texture);
1544 bool hasJoint =
false;
1545 bool hasWeight =
false;
1546 bool hasMorphTarget = theSubset.rhi.targetsTexture !=
nullptr;
1547 for (
const QSSGRhiInputAssemblerState::InputSemantic &sem : std::as_const(theSubset.rhi.ia.inputs)) {
1548 if (sem == QSSGRhiInputAssemblerState::PositionSemantic) {
1549 renderableFlagsForModel.setHasAttributePosition(
true);
1550 }
else if (sem == QSSGRhiInputAssemblerState::NormalSemantic) {
1551 renderableFlagsForModel.setHasAttributeNormal(
true);
1552 }
else if (sem == QSSGRhiInputAssemblerState::TexCoord0Semantic) {
1553 renderableFlagsForModel.setHasAttributeTexCoord0(
true);
1554 }
else if (sem == QSSGRhiInputAssemblerState::TexCoord1Semantic) {
1555 renderableFlagsForModel.setHasAttributeTexCoord1(
true);
1556 }
else if (sem == QSSGRhiInputAssemblerState::TexCoordLightmapSemantic) {
1557 renderableFlagsForModel.setHasAttributeTexCoordLightmap(
true);
1558 }
else if (sem == QSSGRhiInputAssemblerState::TangentSemantic) {
1559 renderableFlagsForModel.setHasAttributeTangent(
true);
1560 }
else if (sem == QSSGRhiInputAssemblerState::BinormalSemantic) {
1561 renderableFlagsForModel.setHasAttributeBinormal(
true);
1562 }
else if (sem == QSSGRhiInputAssemblerState::ColorSemantic) {
1563 renderableFlagsForModel.setHasAttributeColor(
true);
1566 }
else if (sem == QSSGRhiInputAssemblerState::JointSemantic) {
1568 }
else if (sem == QSSGRhiInputAssemblerState::WeightSemantic) {
1572 renderableFlagsForModel.setHasAttributeJointAndWeight(hasJoint && hasWeight);
1573 renderableFlagsForModel.setHasAttributeMorphTarget(hasMorphTarget);
1576 QSSGRenderableObjectList bakedLightingObjects;
1577 bool usesBlendParticles = particlesEnabled && theModelContext.model.particleBuffer !=
nullptr
1578 && model.particleBuffer->particleCount();
1579 const bool anyLightHasShadows = std::find_if(lights.begin(),
1581 [](
const QSSGShaderLight &light) {
return light.shadows; })
1583 const bool hasAnyLights = !lights.isEmpty();
1584 QSSGRenderLight::SoftShadowQuality maxSoftShadowQuality = QSSGRenderLight::SoftShadowQuality::Hard;
1585 if (anyLightHasShadows) {
1587 for (
const QSSGShaderLight &light : lights) {
1588 if (light.shadows && light.light->m_softShadowQuality > maxSoftShadowQuality)
1589 maxSoftShadowQuality = light.light->m_softShadowQuality;
1595 auto &renderableSubsets = theModelContext.subsets;
1596 const bool hasMaterialOverrides = ((renderable.overridden & QSSGRenderableNodeEntry::Overridden::Materials) != 0);
1597 const auto &materials = hasMaterialOverrides ? renderable.extOverrides.materials : modelData->getMaterials(model);
1598 const auto materialCount = materials.size();
1599 QSSGRenderGraphObject *lastMaterial = !materials.isEmpty() ? materials.last() :
nullptr;
1600 int idx = 0, subsetIdx = 0;
1601 for (; idx < meshSubsetCount; ++idx) {
1603 QSSGRenderGraphObject *theMaterialObject = (idx >= materialCount) ? lastMaterial : materials[idx];
1604 if (!theMaterialObject)
1607 const QSSGRenderSubset &theSubset = meshSubsets.at(idx);
1608 QSSGRenderableObjectFlags renderableFlags = renderableFlagsForModel;
1609 float subsetOpacity = modelGlobalOpacity;
1611 renderableFlags.setPointsTopology(theSubset.rhi.ia.topology == QRhiGraphicsPipeline::Points);
1612 QSSGRenderableObject *theRenderableObject = &renderableSubsets[subsetIdx++];
1614 const bool usesInstancing = theModelContext.model.instancing()
1615 && rhiCtx->rhi()->isFeatureSupported(QRhi::Instancing);
1616 if (usesInstancing && theModelContext.model.instanceTable->hasTransparency())
1617 renderableFlags |= QSSGRenderableObjectFlag::HasTransparency;
1618 if (theModelContext.model.hasTransparency)
1619 renderableFlags |= QSSGRenderableObjectFlag::HasTransparency;
1622 quint32 subsetLevelOfDetail = 0;
1623 if (!theSubset.lods.isEmpty() && lodThreshold > 0.0f) {
1625 float lodDistanceMultiplier = camerasView[0]->getLevelOfDetailMultiplier();
1626 float distanceThreshold = 0.0f;
1627 const auto scale = QSSGUtils::mat44::getScale(globalTransform);
1628 float modelScale = qMax(scale.x(), qMax(scale.y(), scale.z()));
1629 QSSGBounds3 transformedBounds = theSubset.bounds;
1630 if (camerasView[0]->type != QSSGRenderGraphObject::Type::OrthographicCamera) {
1631 transformedBounds.transform(globalTransform);
1632 if (maybeDebugDraw && debugDrawSystem->isEnabled(QSSGDebugDrawSystem::Mode::MeshLod))
1633 debugDrawSystem->drawBounds(transformedBounds, QColor(Qt::red));
1634 const QMatrix4x4 cameraGlobalTranform = getGlobalTransform(*camerasView[0]);
1635 const QVector3D cameraNormal = QSSGRenderNode::getScalingCorrectDirection(cameraGlobalTranform);
1636 const QVector3D cameraPosition = QSSGRenderNode::getGlobalPos(cameraGlobalTranform);
1637 const QSSGPlane cameraPlane = QSSGPlane(cameraPosition, cameraNormal);
1638 const QVector3D lodSupportMin = transformedBounds.getSupport(-cameraNormal);
1639 const QVector3D lodSupportMax = transformedBounds.getSupport(cameraNormal);
1640 if (maybeDebugDraw && debugDrawSystem->isEnabled(QSSGDebugDrawSystem::Mode::MeshLod))
1641 debugDrawSystem->drawPoint(lodSupportMin, QColor(
"orange"));
1643 const float distanceMin = cameraPlane.distance(lodSupportMin);
1644 const float distanceMax = cameraPlane.distance(lodSupportMax);
1646 if (distanceMin * distanceMax < 0.0)
1647 distanceThreshold = 0.0;
1648 else if (distanceMin >= 0.0)
1649 distanceThreshold = distanceMin;
1650 else if (distanceMax <= 0.0)
1651 distanceThreshold = -distanceMax;
1655 distanceThreshold = 1.0;
1658 int currentLod = -1;
1659 if (model.levelOfDetailBias > 0.0f) {
1660 const float threshold = distanceThreshold * lodDistanceMultiplier;
1661 const float modelBias = 1 / model.levelOfDetailBias;
1662 for (qsizetype i = 0; i < theSubset.lods.count(); ++i) {
1663 float subsetDistance = theSubset.lods[i].distance * modelScale * modelBias;
1664 float screenSize = subsetDistance / threshold;
1665 if (screenSize > lodThreshold)
1670 if (currentLod == -1)
1671 subsetLevelOfDetail = 0;
1673 subsetLevelOfDetail = currentLod + 1;
1674 if (maybeDebugDraw && debugDrawSystem->isEnabled(QSSGDebugDrawSystem::Mode::MeshLod))
1675 debugDrawSystem->drawBounds(transformedBounds, QSSGDebugDrawSystem::levelOfDetailColor(subsetLevelOfDetail));
1678 QVector3D theModelCenter(theSubset.bounds.center());
1679 theModelCenter = QSSGUtils::mat44::transform(globalTransform, theModelCenter);
1680 if (maybeDebugDraw && debugDrawSystem->isEnabled(QSSGDebugDrawSystem::Mode::MeshLodNormal)) {
1681 const QMatrix4x4 allCamera0GlobalTransform = getGlobalTransform(*allCameras[0]);
1682 debugDrawSystem->debugNormals(*bufferManager, theModelContext, theSubset, subsetLevelOfDetail, (theModelCenter - QSSGRenderNode::getGlobalPos(allCamera0GlobalTransform)).length() * 0.01);
1685 auto checkF32TypeIndex = [&rhiCtx](QRhiVertexInputAttribute::Format f) {
1686 if ((f == QRhiVertexInputAttribute::Format::Float4)
1687 || (f == QRhiVertexInputAttribute::Format::Float3)
1688 || (f == QRhiVertexInputAttribute::Format::Float2)
1689 || (f == QRhiVertexInputAttribute::Format::Float)) {
1692 if (!rhiCtx->rhi()->isFeatureSupported(QRhi::IntAttributes))
1693 qWarning() <<
"WARN: Model has non-integer type indices for skinning but current RHI backend doesn't support it!";
1697 if (theMaterialObject->type == QSSGRenderGraphObject::Type::DefaultMaterial ||
1698 theMaterialObject->type == QSSGRenderGraphObject::Type::PrincipledMaterial ||
1699 theMaterialObject->type == QSSGRenderGraphObject::Type::SpecularGlossyMaterial) {
1700 QSSGRenderDefaultMaterial &theMaterial(
static_cast<QSSGRenderDefaultMaterial &>(*theMaterialObject));
1701 QSSGDefaultMaterialPreparationResult theMaterialPrepResult(prepareDefaultMaterialForRender(theMaterial, renderableFlags, subsetOpacity, hasAnyLights, anyLightHasShadows, ioFlags));
1702 QSSGShaderDefaultMaterialKey &theGeneratedKey(theMaterialPrepResult.materialKey);
1703 subsetOpacity = theMaterialPrepResult.opacity;
1704 QSSGRenderableImage *firstImage(theMaterialPrepResult.firstImage);
1705 wasDirty |= theMaterialPrepResult.dirty;
1706 renderableFlags = theMaterialPrepResult.renderableFlags;
1707 if (renderableFlags.hasTransparency())
1708 ioFlags.setHasCustomBlendMode(theMaterial.blendMode != QSSGRenderDefaultMaterial::MaterialBlendMode::SourceOver);
1711 defaultMaterialShaderKeyProperties.m_blendParticles.setValue(theGeneratedKey, usesBlendParticles);
1714 const auto boneCount = model.skin ? model.skin->boneCount :
1715 model.skeleton ? model.skeleton->boneCount : 0;
1716 defaultMaterialShaderKeyProperties.m_boneCount.setValue(theGeneratedKey, boneCount);
1717 if (
auto idJoint = theSubset.rhi.ia.inputs.indexOf(QSSGRhiInputAssemblerState::JointSemantic); idJoint != -1) {
1718 const auto attr = theSubset.rhi.ia.inputLayout.attributeAt(idJoint);
1719 defaultMaterialShaderKeyProperties.m_usesFloatJointIndices.setValue(theGeneratedKey, checkF32TypeIndex(attr->format()));
1723 defaultMaterialShaderKeyProperties.m_shadowSoftness.setShadowSoftness(theGeneratedKey, maxSoftShadowQuality);
1726 defaultMaterialShaderKeyProperties.m_usesInstancing.setValue(theGeneratedKey, usesInstancing);
1728 defaultMaterialShaderKeyProperties.m_targetCount.setValue(theGeneratedKey,
1729 theSubset.rhi.ia.targetCount);
1730 defaultMaterialShaderKeyProperties.m_targetPositionOffset.setValue(theGeneratedKey,
1731 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::PositionSemantic]);
1732 defaultMaterialShaderKeyProperties.m_targetNormalOffset.setValue(theGeneratedKey,
1733 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::NormalSemantic]);
1734 defaultMaterialShaderKeyProperties.m_targetTangentOffset.setValue(theGeneratedKey,
1735 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::TangentSemantic]);
1736 defaultMaterialShaderKeyProperties.m_targetBinormalOffset.setValue(theGeneratedKey,
1737 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::BinormalSemantic]);
1738 defaultMaterialShaderKeyProperties.m_targetTexCoord0Offset.setValue(theGeneratedKey,
1739 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::TexCoord0Semantic]);
1740 defaultMaterialShaderKeyProperties.m_targetTexCoord1Offset.setValue(theGeneratedKey,
1741 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::TexCoord1Semantic]);
1742 defaultMaterialShaderKeyProperties.m_targetColorOffset.setValue(theGeneratedKey,
1743 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::ColorSemantic]);
1745 new (theRenderableObject) QSSGSubsetRenderable(QSSGSubsetRenderable::Type::DefaultMaterialMeshSubset,
1752 subsetLevelOfDetail,
1757 anyLightHasShadows);
1758 wasDirty = wasDirty || renderableFlags.isDirty();
1759 }
else if (theMaterialObject->type == QSSGRenderGraphObject::Type::CustomMaterial) {
1760 QSSGRenderCustomMaterial &theMaterial(
static_cast<QSSGRenderCustomMaterial &>(*theMaterialObject));
1762 const auto &theMaterialSystem(contextInterface.customMaterialSystem());
1763 wasDirty |= theMaterialSystem->prepareForRender(theModelContext.model, theSubset, theMaterial);
1765 if (theMaterial.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::Blending))
1766 ioFlags.setHasCustomBlendMode(!hasCustomBlendMode(theMaterial));
1768 QSSGDefaultMaterialPreparationResult theMaterialPrepResult(
1769 prepareCustomMaterialForRender(theMaterial, renderableFlags, subsetOpacity, wasDirty,
1770 hasAnyLights, anyLightHasShadows, ioFlags));
1771 QSSGShaderDefaultMaterialKey &theGeneratedKey(theMaterialPrepResult.materialKey);
1772 subsetOpacity = theMaterialPrepResult.opacity;
1773 QSSGRenderableImage *firstImage(theMaterialPrepResult.firstImage);
1774 renderableFlags = theMaterialPrepResult.renderableFlags;
1776 if (model.particleBuffer && model.particleBuffer->particleCount())
1777 defaultMaterialShaderKeyProperties.m_blendParticles.setValue(theGeneratedKey,
true);
1779 defaultMaterialShaderKeyProperties.m_blendParticles.setValue(theGeneratedKey,
false);
1782 defaultMaterialShaderKeyProperties.m_shadowSoftness.setShadowSoftness(theGeneratedKey, maxSoftShadowQuality);
1785 const auto boneCount = model.skin ? model.skin->boneCount :
1786 model.skeleton ? model.skeleton->boneCount : 0;
1787 defaultMaterialShaderKeyProperties.m_boneCount.setValue(theGeneratedKey, boneCount);
1788 if (
auto idJoint = theSubset.rhi.ia.inputs.indexOf(QSSGRhiInputAssemblerState::JointSemantic); idJoint != -1) {
1789 const auto attr = theSubset.rhi.ia.inputLayout.attributeAt(idJoint);
1790 defaultMaterialShaderKeyProperties.m_usesFloatJointIndices.setValue(theGeneratedKey, checkF32TypeIndex(attr->format()));
1794 bool usesInstancing = theModelContext.model.instancing()
1795 && rhiCtx->rhi()->isFeatureSupported(QRhi::Instancing);
1796 defaultMaterialShaderKeyProperties.m_usesInstancing.setValue(theGeneratedKey, usesInstancing);
1798 defaultMaterialShaderKeyProperties.m_targetCount.setValue(theGeneratedKey,
1799 theSubset.rhi.ia.targetCount);
1800 defaultMaterialShaderKeyProperties.m_targetPositionOffset.setValue(theGeneratedKey,
1801 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::PositionSemantic]);
1802 defaultMaterialShaderKeyProperties.m_targetNormalOffset.setValue(theGeneratedKey,
1803 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::NormalSemantic]);
1804 defaultMaterialShaderKeyProperties.m_targetTangentOffset.setValue(theGeneratedKey,
1805 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::TangentSemantic]);
1806 defaultMaterialShaderKeyProperties.m_targetBinormalOffset.setValue(theGeneratedKey,
1807 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::BinormalSemantic]);
1808 defaultMaterialShaderKeyProperties.m_targetTexCoord0Offset.setValue(theGeneratedKey,
1809 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::TexCoord0Semantic]);
1810 defaultMaterialShaderKeyProperties.m_targetTexCoord1Offset.setValue(theGeneratedKey,
1811 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::TexCoord1Semantic]);
1812 defaultMaterialShaderKeyProperties.m_targetColorOffset.setValue(theGeneratedKey,
1813 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::ColorSemantic]);
1815 if (theMaterial.m_iblProbe)
1816 theMaterial.m_iblProbe->clearDirty();
1818 new (theRenderableObject) QSSGSubsetRenderable(QSSGSubsetRenderable::Type::CustomMaterialMeshSubset,
1825 subsetLevelOfDetail,
1830 anyLightHasShadows);
1832 if (theRenderableObject)
1833 theRenderableObject->camdistSq = getCameraDistanceSq(*theRenderableObject, allCameraData[0]);
1837 if (Q_UNLIKELY(idx != subsetIdx))
1838 renderableSubsets.mSize = subsetIdx;
1840 for (
auto &ro : renderableSubsets) {
1841 const auto depthMode = ro.depthWriteMode;
1842 hasDepthWriteObjects |= (depthMode == QSSGDepthDrawMode::Always || depthMode == QSSGDepthDrawMode::OpaqueOnly);
1843 enum ObjectType : quint8 { ScreenTexture, Transparent, Opaque };
1844 static constexpr DepthPrepassObject ppState[][2] = { {DepthPrepassObject::None, DepthPrepassObject::ScreenTexture},
1845 {DepthPrepassObject::None, DepthPrepassObject::Transparent},
1846 {DepthPrepassObject::None, DepthPrepassObject::Opaque} };
1848 if (ro.renderableFlags.requiresScreenTexture()) {
1849 depthPrepassObjectsState |= DepthPrepassObjectStateT(ppState[ObjectType::ScreenTexture][size_t(depthMode == QSSGDepthDrawMode::OpaquePrePass)]);
1850 screenTextureObjects.push_back({&ro, ro.camdistSq});
1851 }
else if (ro.renderableFlags.hasTransparency()) {
1852 depthPrepassObjectsState |= DepthPrepassObjectStateT(ppState[ObjectType::Transparent][size_t(depthMode == QSSGDepthDrawMode::OpaquePrePass)]);
1853 transparentObjects.push_back({&ro, ro.camdistSq});
1855 depthPrepassObjectsState |= DepthPrepassObjectStateT(ppState[ObjectType::Opaque][size_t(depthMode == QSSGDepthDrawMode::OpaquePrePass)]);
1856 opaqueObjects.push_back({&ro, ro.camdistSq});
1859 if (ro.renderableFlags.usedInBakedLighting())
1860 bakedLightingObjects.push_back({&ro, ro.camdistSq});
1863 if (!bakedLightingObjects.isEmpty())
1864 bakedLightingModels.push_back(QSSGBakedLightingModel(&model, bakedLightingObjects));
2116void QSSGLayerRenderData::prepareForRender()
2118 QSSG_ASSERT_X(layerPrepResult.isNull(),
"Prep-result was not reset for render!", layerPrepResult = {});
2120 QRect theViewport(renderer->viewport());
2124 frameData.m_ctx = renderer->contextInterface();
2129 ps.viewport = {
float(theViewport.x()),
float(theViewport.y()),
float(theViewport.width()),
float(theViewport.height()), 0.0f, 1.0f };
2130 if (layer.scissorRect.isValid()) {
2131 ps.flags |= QSSGRhiGraphicsPipelineState::Flag::UsesScissor;
2132 ps.scissor = { layer.scissorRect.x(),
2133 theViewport.height() - (layer.scissorRect.y() + layer.scissorRect.height()),
2134 layer.scissorRect.width(),
2135 layer.scissorRect.height() };
2138 ps.depthFunc = QRhiGraphicsPipeline::LessOrEqual;
2139 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
false);
2142 ps.polygonMode = layer.wireframeMode ? QRhiGraphicsPipeline::Line : QRhiGraphicsPipeline::Fill;
2144 bool wasDirty =
false;
2145 bool wasDataDirty =
false;
2146 wasDirty = layer.isDirty();
2149 layerPrepResult = { theViewport, layer };
2152 const bool SSAOEnabled = layer.ssaoEnabled();
2153 layerPrepResult.flags.setRequiresSsaoPass(SSAOEnabled);
2154 features.set(QSSGShaderFeatures::Feature::Ssao, SSAOEnabled);
2157 bool requiresDepthTexture = SSAOEnabled;
2158 bool requiresNormalTexture =
false;
2159 for (QSSGRenderEffect *theEffect = layer.firstEffect; theEffect; theEffect = theEffect->m_nextEffect) {
2160 if (theEffect->isDirty()) {
2162 theEffect->clearDirty();
2164 if (theEffect->testFlag(QSSGRenderEffect::Flags::UsesDepthTexture))
2165 requiresDepthTexture =
true;
2166 if (theEffect->testFlag(QSSGRenderEffect::Flags::UsesNormalTexture))
2167 requiresNormalTexture =
true;
2170 const auto &rhiCtx = renderer->contextInterface()->rhiContext();
2171 orderIndependentTransparencyEnabled = (layer.oitMethod != QSSGRenderLayer::OITMethod::None);
2172 if (layer.oitMethod == QSSGRenderLayer::OITMethod::WeightedBlended) {
2173 orderIndependentTransparencyEnabled = rhiCtx->rhi()->isFeatureSupported(QRhi::PerRenderTargetBlending);
2174 if (rhiCtx->mainPassSampleCount() > 1)
2175 orderIndependentTransparencyEnabled |= rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch) && rhiCtx->rhi()->isFeatureSupported(QRhi::SampleVariables);
2176 if (!orderIndependentTransparencyEnabled && !oitWarningUnsupportedShown) {
2177 qCWarning(lcQuick3DRender) <<
"Order Independent Transparency is requested, but it is not supported.";
2178 oitWarningUnsupportedShown =
true;
2181 if (layer.oitMethodDirty) {
2182 oitRenderContext.reset();
2183 for (
auto &renderResult : renderResults)
2184 renderResult.reset();
2187 layerPrepResult.flags.setRequiresDepthTexture(requiresDepthTexture);
2189 layerPrepResult.flags.setRequiresNormalTexture(requiresNormalTexture);
2193 if (!layer.firstEffect)
2194 QSSGLayerRenderData::setTonemapFeatures(features, layer.tonemapMode);
2201 if (rhiCtx->rhi()->resourceLimit(QRhi::MaxUniformBufferRange) < REDUCED_MAX_LIGHT_COUNT_THRESHOLD_BYTES) {
2202 features.set(QSSGShaderFeatures::Feature::ReduceMaxNumLights,
true);
2203 static bool notified =
false;
2206 qCDebug(lcQuick3DRender,
"Qt Quick 3D maximum number of lights has been reduced from %d to %d due to the graphics driver's limitations",
2207 QSSG_MAX_NUM_LIGHTS, QSSG_REDUCED_MAX_NUM_LIGHTS);
2212 QSSGRenderImageTexture lightProbeTexture;
2213 if (layer.lightProbe) {
2214 const auto &lightProbeSettings = layer.lightProbeSettings;
2215 if (layer.lightProbe->m_format == QSSGRenderTextureFormat::Unknown) {
2218 if (renderer->contextInterface()->rhiContext()->rhi()->isTextureFormatSupported(QRhiTexture::RGBA16F))
2219 layer.lightProbe->m_format = QSSGRenderTextureFormat::RGBA16F;
2221 layer.lightProbe->m_format = QSSGRenderTextureFormat::RGBE8;
2224 if (layer.lightProbe->clearDirty())
2225 wasDataDirty =
true;
2228 lightProbeTexture = renderer->contextInterface()->bufferManager()->loadRenderImage(layer.lightProbe, QSSGBufferManager::MipModeBsdf);
2229 if (lightProbeTexture.m_texture) {
2231 features.set(QSSGShaderFeatures::Feature::LightProbe,
true);
2232 features.set(QSSGShaderFeatures::Feature::IblOrientation, !lightProbeSettings.probeOrientation.isIdentity());
2236 if (lightProbeTexture.m_flags.isRgbe8())
2237 features.set(QSSGShaderFeatures::Feature::RGBELightProbe,
true);
2239 layer.lightProbe =
nullptr;
2242 const bool forceIblExposureValues = (features.isSet(QSSGShaderFeatures::Feature::LightProbe) && layer.tonemapMode == QSSGRenderLayer::TonemapMode::Custom);
2243 features.set(QSSGShaderFeatures::Feature::ForceIblExposure, forceIblExposureValues);
2246 frameData.m_ctx->bufferManager()->setLightmapSource(layer.lightmapSource);
2250 version = nodeData->version();
2255 auto &globalTransforms = nodeData->globalTransforms;
2256 auto &globalOpacities = nodeData->globalOpacities;
2257 auto &instanceTransforms = nodeData->instanceTransforms;
2260 QSSGRenderDataHelpers::GlobalStateResultT globalStateResult = QSSGRenderDataHelpers::GlobalStateResult::None;
2262 const bool layerTreeWasDirty = layer.isDirty(QSSGRenderLayer::DirtyFlag::TreeDirty);
2263 layer.clearDirty(QSSGRenderLayer::DirtyFlag::TreeDirty);
2264 if (layerTreeWasDirty) {
2265 wasDataDirty =
true;
2266 layerNodes = nodeData->getLayerNodeView(layer);
2268 for (
auto &node : layerNodes)
2269 globalStateResult |= QSSGRenderDataHelpers::updateGlobalNodeState(node, version);
2271 bool transformAndOpacityDirty =
false;
2272 for (
auto &node : layerNodes)
2273 transformAndOpacityDirty |= QSSGRenderDataHelpers::calcGlobalNodeData<QSSGRenderDataHelpers::Strategy::Update>(node, version, globalTransforms, globalOpacities);
2276 if (transformAndOpacityDirty) {
2277 for (
const auto &node : layerNodes)
2278 wasDataDirty |= QSSGRenderDataHelpers::calcInstanceTransforms(node, version, globalTransforms, instanceTransforms);
2281 wasDataDirty |= transformAndOpacityDirty;
2287 const bool hasExplicitCamera = (layer.explicitCameras.size() != 0);
2288 bool cameraLayerMaskDirty =
false;
2289 quint32 layerMask = QSSGRenderCamera::LayerMaskAll;
2290 if (hasExplicitCamera) {
2291 QSSGRenderCamera *explicitCamera = layer.explicitCameras[0];
2292 layerMask = explicitCamera->tag.value();
2293 cameraLayerMaskDirty = explicitCamera->isDirty(QSSGRenderCamera::DirtyFlag::LayerMaskDirty);
2294 explicitCamera->clearDirty(QSSGRenderCamera::DirtyFlag::LayerMaskDirty);
2297 const bool restatNodes = (layerTreeWasDirty || (globalStateResult & QSSGRenderDataHelpers::GlobalStateResult::ActiveChanged) || cameraLayerMaskDirty);
2301 particlesView.clear();
2302 item2DsView.clear();
2303 camerasView.clear();
2305 reflectionProbesView.clear();
2306 nonCategorizedView.clear();
2308 enum NodeType : size_t { Model = 0, Particles, Item2D, Camera, ImportedCamera, Light, ReflectionProbe, Other, Inactive };
2309 const auto nodeType = [layerMask](QSSGRenderNode *node) -> NodeType {
2310 if (!(node->getGlobalState(QSSGRenderNode::GlobalState::Active) && (node->tag.isSet(layerMask))))
2311 return NodeType::Inactive;
2312 switch (node->type) {
2313 case QSSGRenderGraphObject::Type::Model:
return NodeType::Model;
2314 case QSSGRenderGraphObject::Type::Particles:
return NodeType::Particles;
2315 case QSSGRenderGraphObject::Type::Item2D:
return NodeType::Item2D;
2316 case QSSGRenderGraphObject::Type::ReflectionProbe:
return NodeType::ReflectionProbe;
2320 if (QSSGRenderGraphObject::isCamera(node->type)) {
2323 const bool isImported = node->getGlobalState(QSSGRenderNode::GlobalState::Imported);
2324 constexpr NodeType cameraTypes[2] { NodeType::Camera, NodeType::ImportedCamera };
2325 return cameraTypes[size_t(isImported)];
2327 if (QSSGRenderGraphObject::isLight(node->type))
2328 return NodeType::Light;
2330 return NodeType::Other;
2342 layerNodesCategorized = { layerNodes.begin(), layerNodes.end() };
2344 std::stable_sort(layerNodesCategorized.begin(), layerNodesCategorized.end(), [nodeType](QSSGRenderNode *a, QSSGRenderNode *b) {
2345 return nodeType(a) < nodeType(b);
2350 const LayerNodeStatResult stat = statLayerNodes(layerNodesCategorized, layerMask);
2355 if (stat.modelCount > 0) {
2356 modelsView = QSSGModelsView((QSSGRenderModel **)(layerNodesCategorized.data() + next), stat.modelCount);
2357 next = modelsView.size();
2359 if (stat.particlesCount > 0) {
2360 particlesView = QSSGParticlesView((QSSGRenderParticles **)(layerNodesCategorized.data() + next), stat.particlesCount);
2361 next += particlesView.size();
2363 if (stat.item2DCount > 0) {
2364 item2DsView = QSSGItem2DsView((QSSGRenderItem2D **)(layerNodesCategorized.data() + next), stat.item2DCount);
2365 next += item2DsView.size();
2367 if (stat.cameraCount > 0) {
2368 camerasView = QSSGCamerasView((QSSGRenderCamera **)(layerNodesCategorized.data() + next), stat.cameraCount);
2369 next += camerasView.size();
2371 if (stat.lightCount > 0) {
2372 lightsView = QSSGLightsView((QSSGRenderLight **)(layerNodesCategorized.data() + next), stat.lightCount);
2373 next += lightsView.size();
2375 if (stat.reflectionProbeCount > 0) {
2376 reflectionProbesView = QSSGReflectionProbesView((QSSGRenderReflectionProbe **)(layerNodesCategorized.data() + next), stat.reflectionProbeCount);
2377 next += reflectionProbesView.size();
2379 if (stat.otherCount > 0) {
2380 nonCategorizedView = QSSGNonCategorizedView((QSSGRenderNode **)(layerNodesCategorized.data() + next), stat.otherCount);
2381 next += nonCategorizedView.size();
2387 renderableModels.clear();
2388 renderableParticles.clear();
2389 renderableModels.reserve(modelsView.size());
2390 renderableParticles.reserve(particlesView.size());
2392 renderableModels = {modelsView.begin(), modelsView.end()};
2393 renderableParticles = {particlesView.begin(), particlesView.end()};
2400 QSSGRenderCamera::Configuration cameraConfig { renderer->dpr(), layer.isSsaaEnabled() ? layer.ssaaMultiplier : 1.0f };
2401 renderedCameras.clear();
2402 if (!layer.explicitCameras.isEmpty()) {
2403 for (QSSGRenderCamera *cam : std::as_const(layer.explicitCameras)) {
2405 if (cam->getGlobalState(QSSGRenderCamera::GlobalState::Active)) {
2406 const bool computeFrustumSucceeded = cam->calculateProjection(theViewport, cameraConfig);
2407 if (Q_LIKELY(computeFrustumSucceeded))
2408 renderedCameras.append(cam);
2410 qCCritical(INTERNAL_ERROR,
"Failed to calculate camera frustum");
2414 }
else if (QSSG_GUARD_X(layer.viewCount == 1,
"Multiview rendering requires explicit cameras to be set!.")) {
2419 for (
auto iter = camerasView.begin(); renderedCameras.isEmpty() && iter != camerasView.end(); iter++) {
2420 QSSGRenderCamera *theCamera = *iter;
2421 if (theCamera->getGlobalState(QSSGRenderCamera::GlobalState::Active)) {
2422 const bool computeFrustumSucceeded = theCamera->calculateProjection(theViewport, cameraConfig);
2423 if (Q_LIKELY(computeFrustumSucceeded))
2424 renderedCameras.append(theCamera);
2426 qCCritical(INTERNAL_ERROR,
"Failed to calculate camera frustum");
2431 float meshLodThreshold = 1.0f;
2432 if (!renderedCameras.isEmpty())
2433 meshLodThreshold = renderedCameras[0]->levelOfDetailPixelThreshold / theViewport.width();
2435 layer.renderedCamerasMutex.lock();
2436 layer.renderedCameras = renderedCameras;
2437 layer.renderedCamerasMutex.unlock();
2440 const QSSGRenderCameraDataList &renderCameraData = getCachedCameraDatas();
2441 modelData->updateModelData(modelsView, renderer, renderCameraData);
2444 item2DData->updateItem2DData(item2DsView, renderer, renderCameraData);
2447 prepareResourceLoaders();
2450 updateDirtySkeletons(*
this, modelsView);
2453 int directionalLightsCount = 0;
2454 int positionalLightsCount = 0;
2455 const int maxLightCount = effectiveMaxLightCount(features);
2456 const int maxDirectionalLights = effectiveMaxDirectionalLightCount(features);
2457 QSSGShaderLightList renderableLights;
2458 int shadowMapCount = 0;
2459 bool hasScopedLights =
false;
2465 auto it = std::make_reverse_iterator(lightsView.end());
2466 const auto end = it + qMin(maxLightCount, lightsView.size());
2467 for (; it != end; ++it) {
2468 QSSGRenderLight *renderLight = (*it);
2469 QMatrix4x4 renderLightTransform = getGlobalTransform(*renderLight);
2470 if (renderLight->type == QSSGRenderGraphObject::Type::DirectionalLight)
2471 directionalLightsCount++;
2473 positionalLightsCount++;
2475 if (positionalLightsCount > maxLightCount)
2477 if (directionalLightsCount > maxDirectionalLights)
2481 hasScopedLights |= (renderLight->m_scope !=
nullptr);
2482 const bool castShadows = renderLight->m_castShadow && !renderLight->m_fullyBaked;
2483 shadowMapCount +=
int(castShadows);
2484 const auto &direction = renderLight->getScalingCorrectDirection(renderLightTransform);
2485 renderableLights.push_back(QSSGShaderLight{ renderLight, castShadows, direction });
2489 const bool showLightCountWarning = !tooManyLightsWarningShown && (positionalLightsCount > maxLightCount);
2490 if (showLightCountWarning) {
2491 qWarning(
"Too many lights in scene, maximum is %d", maxLightCount);
2492 tooManyLightsWarningShown =
true;
2495 const bool showDirectionalLightCountWarning = !tooManyDirectionalLightsWarningShown && (directionalLightsCount > maxDirectionalLights);
2496 if (showDirectionalLightCountWarning) {
2497 qWarning(
"Too many directional lights in scene, maximum is %d", maxDirectionalLights);
2498 tooManyDirectionalLightsWarningShown =
true;
2501 if (shadowMapCount > 0) {
2502 requestShadowMapManager();
2503 layerPrepResult.flags.setRequiresShadowMapPass(
true);
2508 features.set(QSSGShaderFeatures::Feature::Ssm,
true);
2509 shadowMapManager->addShadowMaps(renderableLights);
2510 }
else if (shadowMapManager) {
2512 shadowMapManager->releaseCachedResources();
2518 QSSG_ASSERT(globalLights.isEmpty(), globalLights.clear());
2519 if (hasScopedLights) {
2520 for (
const auto &shaderLight : std::as_const(renderableLights)) {
2521 if (!shaderLight.light->m_scope)
2522 globalLights.push_back(shaderLight);
2525 const auto prepareLightsWithScopedLights = [&renderableLights,
this](QVector<QSSGRenderableNodeEntry> &renderableNodes) {
2526 for (qint32 idx = 0, end = renderableNodes.size(); idx < end; ++idx) {
2527 QSSGRenderableNodeEntry &theNodeEntry(renderableNodes[idx]);
2528 QSSGShaderLightList filteredLights;
2529 for (
const auto &light : std::as_const(renderableLights)) {
2530 if (light.light->m_scope && !scopeLight(theNodeEntry.node, light.light->m_scope))
2532 filteredLights.push_back(light);
2535 if (filteredLights.isEmpty()) {
2536 theNodeEntry.lights = QSSGDataView(globalLights);
2541 auto customLightList = RENDER_FRAME_NEW_BUFFER<QSSGShaderLight>(*renderer->contextInterface(), filteredLights.size());
2542 std::copy(filteredLights.cbegin(), filteredLights.cend(), customLightList.begin());
2543 theNodeEntry.lights = customLightList;
2548 prepareLightsWithScopedLights(renderableModels);
2549 prepareLightsWithScopedLights(renderableParticles);
2551 globalLights = renderableLights;
2553 const auto prepareLights = [
this](QVector<QSSGRenderableNodeEntry> &renderableNodes) {
2554 for (qint32 idx = 0, end = renderableNodes.size(); idx < end; ++idx) {
2555 QSSGRenderableNodeEntry &theNodeEntry(renderableNodes[idx]);
2556 theNodeEntry.lights = QSSGDataView(globalLights);
2560 prepareLights(renderableModels);
2561 prepareLights(renderableParticles);
2567 Q_STATIC_ASSERT(USERPASSES == size_t(QSSGRenderLayer::RenderExtensionStage::Count));
2568 for (size_t i = 0; i != size_t(QSSGRenderLayer::RenderExtensionStage::Count); ++i) {
2569 const auto &renderExtensions = layer.renderExtensions[i];
2570 auto &userPass = userPasses[i];
2571 for (
auto rit = renderExtensions.crbegin(), rend = renderExtensions.crend(); rit != rend; ++rit) {
2572 if ((*rit)->prepareData(frameData)) {
2574 userPass.extensions.push_back(*rit);
2580 auto &opaqueObjects = opaqueObjectStore[0];
2581 auto &transparentObjects = transparentObjectStore[0];
2582 auto &screenTextureObjects = screenTextureObjectStore[0];
2584 if (!renderedCameras.isEmpty()) {
2585 wasDirty |= prepareModelsForRender(*renderer->contextInterface(), renderableModels, layerPrepResult.flags, renderedCameras, getCachedCameraDatas(), modelContexts, opaqueObjects, transparentObjects, screenTextureObjects, meshLodThreshold);
2586 if (particlesEnabled) {
2587 const auto &cameraDatas = getCachedCameraDatas();
2588 wasDirty |= prepareParticlesForRender(renderableParticles, cameraDatas[0], layerPrepResult.flags);
2591 wasDirty |= (item2DsView.size() != 0);
2593 if (orderIndependentTransparencyEnabled) {
2595 if (transparentObjects.size() > 0 && !layerPrepResult.flags.hasCustomBlendMode()) {
2596 if (layer.oitMethod == QSSGRenderLayer::OITMethod::WeightedBlended) {
2597 if (rhiCtx->mainPassSampleCount() > 1)
2598 layerPrepResult.flags.setRequiresDepthTextureMS(
true);
2600 layerPrepResult.flags.setRequiresDepthTexture(
true);
2603 orderIndependentTransparencyEnabled =
false;
2604 if (!oitWarningInvalidBlendModeShown) {
2605 qCWarning(lcQuick3DRender) <<
"Order Independent Transparency requested, but disabled due to invalid blend modes.";
2606 qCWarning(lcQuick3DRender) <<
"Use SourceOver blend mode for Order Independent Transparency.";
2607 oitWarningInvalidBlendModeShown =
true;
2611 layer.oitMethodDirty =
false;
2613 prepareReflectionProbesForRender();
2615 wasDirty = wasDirty || wasDataDirty;
2616 layerPrepResult.flags.setWasDirty(wasDirty);
2617 layerPrepResult.flags.setLayerDataDirty(wasDataDirty);
2620 const bool animating = wasDirty;
2622 layer.progAAPassIndex = 0;
2624 const bool progressiveAA = layer.isProgressiveAAEnabled() && !animating;
2625 layer.progressiveAAIsActive = progressiveAA;
2626 const bool temporalAA = layer.isTemporalAAEnabled() && !progressiveAA;
2628 layer.temporalAAIsActive = temporalAA;
2630 QVector2D vertexOffsetsAA;
2632 if (progressiveAA && layer.progAAPassIndex > 0 && layer.progAAPassIndex < quint32(layer.antialiasingQuality)) {
2633 int idx = layer.progAAPassIndex - 1;
2634 vertexOffsetsAA = s_ProgressiveAAVertexOffsets[idx] / QVector2D{
float(theViewport.width()/2.0),
float(theViewport.height()/2.0) };
2638 const int t = 1 - 2 * (layer.tempAAPassIndex % 2);
2639 const float f = t * layer.temporalAAStrength;
2640 vertexOffsetsAA = { f /
float(theViewport.width()/2.0), f /
float(theViewport.height()/2.0) };
2643 if (!renderedCameras.isEmpty()) {
2644 if (temporalAA || progressiveAA ) {
2645 QMatrix4x4 offsetProjection = renderedCameras[0]->projection;
2646 QMatrix4x4 invProjection = renderedCameras[0]->projection.inverted();
2647 if (renderedCameras[0]->type == QSSGRenderCamera::Type::OrthographicCamera) {
2648 offsetProjection(0, 3) -= vertexOffsetsAA.x();
2649 offsetProjection(1, 3) -= vertexOffsetsAA.y();
2650 }
else if (renderedCameras[0]->type == QSSGRenderCamera::Type::PerspectiveCamera) {
2651 offsetProjection(0, 2) += vertexOffsetsAA.x();
2652 offsetProjection(1, 2) += vertexOffsetsAA.y();
2654 for (
auto &modelContext : std::as_const(modelContexts)) {
2655 for (
int mvpIdx = 0; mvpIdx < renderedCameras.count(); ++mvpIdx)
2656 modelContext->modelViewProjections[mvpIdx] = offsetProjection * invProjection * modelContext->modelViewProjections[mvpIdx];
2661 const bool hasItem2Ds = (item2DsView.size() > 0);
2662 const bool layerEnableDepthTest = layer.layerFlags.testFlag(QSSGRenderLayer::LayerFlag::EnableDepthTest);
2663 const bool layerEnabledDepthPrePass = layer.layerFlags.testFlag(QSSGRenderLayer::LayerFlag::EnableDepthPrePass);
2664 const bool depthTestEnableDefault = layerEnableDepthTest && (!opaqueObjects.isEmpty() || depthPrepassObjectsState || hasDepthWriteObjects);
2665 const bool zPrePassForced = (depthPrepassObjectsState != 0);
2666 zPrePassActive = zPrePassForced || (layerEnabledDepthPrePass && layerEnableDepthTest && (hasDepthWriteObjects || hasItem2Ds));
2667 const bool depthWriteEnableDefault = depthTestEnableDefault && (!layerEnabledDepthPrePass || !zPrePassActive);
2669 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, depthTestEnableDefault);
2670 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, depthWriteEnableDefault);
2674 layerPrepResult.setState(QSSGLayerRenderPreparationResult::State::Done);
2677 QSSG_ASSERT(activePasses.isEmpty(), activePasses.clear());
2681 if (layerPrepResult.flags.requiresDepthTexture())
2682 activePasses.push_back(&depthMapPass);
2683 if (layerPrepResult.flags.requiresDepthTextureMS())
2684 activePasses.push_back(&depthMapPassMS);
2686 if (layerPrepResult.flags.requiresNormalTexture())
2687 activePasses.push_back(&normalPass);
2690 if (layerPrepResult.flags.requiresSsaoPass())
2691 activePasses.push_back(&ssaoMapPass);
2694 if (layerPrepResult.flags.requiresShadowMapPass())
2695 activePasses.push_back(&shadowMapPass);
2698 activePasses.push_back(&zPrePassPass);
2701 if (layerPrepResult.flags.requiresScreenTexture())
2702 activePasses.push_back(&screenMapPass);
2705 activePasses.push_back(&reflectionMapPass);
2707 auto &textureExtensionPass = userPasses[size_t(QSSGRenderLayer::RenderExtensionStage::TextureProviders)];
2708 if (textureExtensionPass.hasData())
2709 activePasses.push_back(&textureExtensionPass);
2711 auto &underlayPass = userPasses[size_t(QSSGRenderLayer::RenderExtensionStage::Underlay)];
2712 if (underlayPass.hasData())
2713 activePasses.push_back(&underlayPass);
2715 const bool hasOpaqueObjects = (opaqueObjects.size() > 0);
2717 if (hasOpaqueObjects)
2718 activePasses.push_back(&opaquePass);
2722 if (renderer->contextInterface()->rhiContext()->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
2723 if (layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap && layer.skyBoxCubeMap)
2724 activePasses.push_back(&skyboxCubeMapPass);
2725 else if (layer.background == QSSGRenderLayer::Background::SkyBox && layer.lightProbe)
2726 activePasses.push_back(&skyboxPass);
2730 activePasses.push_back(&item2DPass);
2732 if (layerPrepResult.flags.requiresScreenTexture())
2733 activePasses.push_back(&reflectionPass);
2736 if (transparentObjects.size() > 0 || (!layerEnableDepthTest && hasOpaqueObjects)) {
2737 if (orderIndependentTransparencyEnabled) {
2738 activePasses.push_back(&oitRenderPass);
2739 activePasses.push_back(&oitCompositePass);
2740 oitRenderPass.setMethod(layer.oitMethod);
2741 oitCompositePass.setMethod(layer.oitMethod);
2743 activePasses.push_back(&transparentPass);
2747 auto &overlayPass = userPasses[size_t(QSSGRenderLayer::RenderExtensionStage::Overlay)];
2748 if (overlayPass.hasData())
2749 activePasses.push_back(&overlayPass);
2751 if (layer.gridEnabled)
2752 activePasses.push_back(&infiniteGridPass);
2754 if (
const auto &dbgDrawSystem = renderer->contextInterface()->debugDrawSystem(); dbgDrawSystem && dbgDrawSystem->isEnabled())
2755 activePasses.push_back(&debugDrawPass);