924void QSSGLayerRenderData::prepareImageForRender(QSSGRenderImage &inImage,
925 QSSGRenderableImage::Type inMapType,
926 QSSGRenderableImage *&ioFirstImage,
927 QSSGRenderableImage *&ioNextImage,
928 QSSGRenderableObjectFlags &ioFlags,
929 QSSGShaderDefaultMaterialKey &inShaderKey,
930 quint32 inImageIndex,
931 QSSGRenderDefaultMaterial *inMaterial)
933 QSSGRenderContextInterface &contextInterface = *renderer->contextInterface();
934 const auto &bufferManager = contextInterface.bufferManager();
936 if (inImage.clearDirty())
937 ioFlags |= QSSGRenderableObjectFlag::Dirty;
948 const QSSGRenderImageTexture texture = bufferManager->loadRenderImage(&inImage);
950 if (texture.m_texture) {
951 if (texture.m_flags.hasTransparency()
952 && (inMapType == QSSGRenderableImage::Type::Diffuse
953 || inMapType == QSSGRenderableImage::Type::Opacity
954 || inMapType == QSSGRenderableImage::Type::Translucency))
956 ioFlags |= QSSGRenderableObjectFlag::HasTransparency;
959 QSSGRenderableImage *theImage = RENDER_FRAME_NEW<QSSGRenderableImage>(contextInterface, inMapType, inImage, texture);
960 QSSGShaderKeyImageMap &theKeyProp = defaultMaterialShaderKeyProperties.m_imageMaps[inImageIndex];
962 theKeyProp.setEnabled(inShaderKey,
true);
963 switch (inImage.m_mappingMode) {
964 case QSSGRenderImage::MappingModes::Normal:
966 case QSSGRenderImage::MappingModes::Environment:
967 theKeyProp.setEnvMap(inShaderKey,
true);
969 case QSSGRenderImage::MappingModes::LightProbe:
970 theKeyProp.setLightProbe(inShaderKey,
true);
980 switch (texture.m_texture->format()) {
981 case QRhiTexture::Format::RED_OR_ALPHA8:
982 hasA = !renderer->contextInterface()->rhiContext()->rhi()->isFeatureSupported(QRhi::RedOrAlpha8IsRed);
984 case QRhiTexture::Format::R8:
994 if (inImage.isImageTransformIdentity())
995 theKeyProp.setIdentityTransform(inShaderKey,
true);
997 if (inImage.m_indexUV == 1)
998 theKeyProp.setUsesUV1(inShaderKey,
true);
1000 if (texture.m_flags.isLinear())
1001 theKeyProp.setLinear(inShaderKey,
true);
1003 if (ioFirstImage ==
nullptr)
1004 ioFirstImage = theImage;
1006 ioNextImage->m_nextImage = theImage;
1008 ioNextImage = theImage;
1010 if (inMaterial && inImageIndex >= QSSGShaderDefaultMaterialKeyProperties::SingleChannelImagesFirst) {
1011 QSSGRenderDefaultMaterial::TextureChannelMapping value = QSSGRenderDefaultMaterial::R;
1013 const quint32 scIndex = inImageIndex - QSSGShaderDefaultMaterialKeyProperties::SingleChannelImagesFirst;
1014 QSSGShaderKeyTextureChannel &channelKey = defaultMaterialShaderKeyProperties.m_textureChannels[scIndex];
1015 switch (inImageIndex) {
1016 case QSSGShaderDefaultMaterialKeyProperties::OpacityMap:
1017 value = inMaterial->opacityChannel;
1019 case QSSGShaderDefaultMaterialKeyProperties::RoughnessMap:
1020 value = inMaterial->roughnessChannel;
1022 case QSSGShaderDefaultMaterialKeyProperties::MetalnessMap:
1023 value = inMaterial->metalnessChannel;
1025 case QSSGShaderDefaultMaterialKeyProperties::OcclusionMap:
1026 value = inMaterial->occlusionChannel;
1028 case QSSGShaderDefaultMaterialKeyProperties::TranslucencyMap:
1029 value = inMaterial->translucencyChannel;
1031 case QSSGShaderDefaultMaterialKeyProperties::HeightMap:
1032 value = inMaterial->heightChannel;
1034 case QSSGShaderDefaultMaterialKeyProperties::ClearcoatMap:
1035 value = inMaterial->clearcoatChannel;
1037 case QSSGShaderDefaultMaterialKeyProperties::ClearcoatRoughnessMap:
1038 value = inMaterial->clearcoatRoughnessChannel;
1040 case QSSGShaderDefaultMaterialKeyProperties::TransmissionMap:
1041 value = inMaterial->transmissionChannel;
1043 case QSSGShaderDefaultMaterialKeyProperties::ThicknessMap:
1044 value = inMaterial->thicknessChannel;
1046 case QSSGShaderDefaultMaterialKeyProperties::BaseColorMap:
1047 value = inMaterial->baseColorChannel;
1049 case QSSGShaderDefaultMaterialKeyProperties::SpecularAmountMap:
1050 value = inMaterial->specularAmountChannel;
1052 case QSSGShaderDefaultMaterialKeyProperties::EmissiveMap:
1053 value = inMaterial->emissiveChannel;
1058 bool useDefault =
false;
1060 case QSSGRenderDefaultMaterial::TextureChannelMapping::G:
1063 case QSSGRenderDefaultMaterial::TextureChannelMapping::B:
1066 case QSSGRenderDefaultMaterial::TextureChannelMapping::A:
1073 value = QSSGRenderDefaultMaterial::R;
1074 channelKey.setTextureChannel(QSSGShaderKeyTextureChannel::TexturChannelBits(value), inShaderKey);
1501bool QSSGLayerRenderData::prepareModelsForRender(QSSGRenderContextInterface &contextInterface,
1502 const RenderableNodeEntries &renderableModels,
1503 QSSGLayerRenderPreparationResultFlags &ioFlags,
1504 const QSSGRenderCameraList &allCameras,
1505 const QSSGRenderCameraDataList &allCameraData,
1506 TModelContextPtrList &modelContexts,
1507 QSSGRenderableObjectList &opaqueObjects,
1508 QSSGRenderableObjectList &transparentObjects,
1509 QSSGRenderableObjectList &screenTextureObjects,
1512 const auto &rhiCtx = contextInterface.rhiContext();
1513 const auto &bufferManager = contextInterface.bufferManager();
1515 const auto &debugDrawSystem = contextInterface.debugDrawSystem();
1516 const bool maybeDebugDraw = debugDrawSystem && debugDrawSystem->isEnabled();
1518 bool wasDirty =
false;
1520 for (
const QSSGRenderableNodeEntry &renderable : renderableModels) {
1521 if ((renderable.overridden & QSSGRenderableNodeEntry::Overridden::Disabled) != 0)
1524 const QSSGRenderModel &model = *
static_cast<QSSGRenderModel *>(renderable.node);
1525 const auto &lights = renderable.lights;
1526 QSSGRenderMesh *theMesh = modelData->getMesh(model);
1530 const bool altGlobalTransform = ((renderable.overridden & QSSGRenderableNodeEntry::Overridden::GlobalTransform) != 0);
1531 const auto &globalTransform = altGlobalTransform ? renderable.extOverrides.globalTransform : getGlobalTransform(model);
1532 QMatrix3x3 normalMatrix { Qt::Uninitialized };
1533 QSSGLayerRenderData::ModelViewProjections mvps;
1534 if (altGlobalTransform) {
1535 QSSGRenderNode::calculateNormalMatrix(globalTransform, normalMatrix);
1536 size_t mvpCount = 0;
1537 for (
const auto &cameraData : allCameraData) {
1538 QSSGRenderNode::calculateMVPAndNormalMatrix(globalTransform, cameraData.viewProjection, mvps[mvpCount++], normalMatrix);
1541 if (model.usesBoneTexture()) {
1545 size_t mvpCount = 0;
1546 for (
const QSSGRenderCameraData &cameraData : allCameraData) {
1547 mvps[mvpCount++] = cameraData.viewProjection;
1548 normalMatrix = QMatrix3x3();
1551 normalMatrix = getNormalMatrix(model);
1552 mvps = getModelMvps(model);
1555 const bool altModelOpacity = ((renderable.overridden & QSSGRenderableNodeEntry::Overridden::GlobalOpacity) != 0);
1556 const float modelGlobalOpacity = altModelOpacity ? renderable.extOverrides.globalOpacity : getGlobalOpacity(model);
1557 QSSGModelContext &theModelContext = *RENDER_FRAME_NEW<QSSGModelContext>(contextInterface, model, globalTransform, normalMatrix, mvps);
1558 modelContexts.push_back(&theModelContext);
1561 const auto &meshSubsets = theMesh->subsets;
1562 const auto meshSubsetCount = meshSubsets.size();
1563 theModelContext.subsets = RENDER_FRAME_NEW_BUFFER<QSSGSubsetRenderable>(contextInterface, meshSubsetCount);
1567 auto boneTexture = bufferManager->loadSkinmap(model.skin);
1568 setBonemapTexture(theModelContext, boneTexture.m_texture);
1569 }
else if (model.skeleton) {
1570 auto boneTexture = bufferManager->loadSkinmap(&(model.skeleton->boneTexData));
1571 setBonemapTexture(theModelContext, boneTexture.m_texture);
1575 QSSGRenderableObjectFlags renderableFlagsForModel;
1577 if (meshSubsetCount > 0) {
1578 const QSSGRenderSubset &theSubset = meshSubsets.at(0);
1580 renderableFlagsForModel.setCastsShadows(model.castsShadows);
1581 renderableFlagsForModel.setReceivesShadows(model.receivesShadows);
1582 renderableFlagsForModel.setReceivesReflections(model.receivesReflections);
1583 renderableFlagsForModel.setCastsReflections(model.castsReflections);
1585 renderableFlagsForModel.setUsedInBakedLighting(model.usedInBakedLighting);
1586 if (model.hasLightmap()) {
1587 QSSGRenderImageTexture lmImageTexture = bufferManager->loadLightmap(model);
1588 if (lmImageTexture.m_texture) {
1589 renderableFlagsForModel.setRendersWithLightmap(
true);
1590 setLightmapTexture(theModelContext, lmImageTexture.m_texture);
1599 bool hasJoint =
false;
1600 bool hasWeight =
false;
1601 bool hasMorphTarget = theSubset.rhi.targetsTexture !=
nullptr;
1602 for (
const QSSGRhiInputAssemblerState::InputSemantic &sem : std::as_const(theSubset.rhi.ia.inputs)) {
1603 if (sem == QSSGRhiInputAssemblerState::PositionSemantic) {
1604 renderableFlagsForModel.setHasAttributePosition(
true);
1605 }
else if (sem == QSSGRhiInputAssemblerState::NormalSemantic) {
1606 renderableFlagsForModel.setHasAttributeNormal(
true);
1607 }
else if (sem == QSSGRhiInputAssemblerState::TexCoord0Semantic) {
1608 renderableFlagsForModel.setHasAttributeTexCoord0(
true);
1609 }
else if (sem == QSSGRhiInputAssemblerState::TexCoord1Semantic) {
1610 renderableFlagsForModel.setHasAttributeTexCoord1(
true);
1611 }
else if (sem == QSSGRhiInputAssemblerState::TexCoordLightmapSemantic) {
1612 renderableFlagsForModel.setHasAttributeTexCoordLightmap(
true);
1613 }
else if (sem == QSSGRhiInputAssemblerState::TangentSemantic) {
1614 renderableFlagsForModel.setHasAttributeTangent(
true);
1615 }
else if (sem == QSSGRhiInputAssemblerState::BinormalSemantic) {
1616 renderableFlagsForModel.setHasAttributeBinormal(
true);
1617 }
else if (sem == QSSGRhiInputAssemblerState::ColorSemantic) {
1618 renderableFlagsForModel.setHasAttributeColor(
true);
1621 }
else if (sem == QSSGRhiInputAssemblerState::JointSemantic) {
1623 }
else if (sem == QSSGRhiInputAssemblerState::WeightSemantic) {
1627 renderableFlagsForModel.setHasAttributeJointAndWeight(hasJoint && hasWeight);
1628 renderableFlagsForModel.setHasAttributeMorphTarget(hasMorphTarget);
1631 QSSGRenderableObjectList bakedLightingObjects;
1632 bool usesBlendParticles = particlesEnabled && theModelContext.model.particleBuffer !=
nullptr
1633 && model.particleBuffer->particleCount();
1634 const bool anyLightHasShadows = std::find_if(lights.begin(),
1636 [](
const QSSGShaderLight &light) {
return light.shadows; })
1638 const bool hasAnyLights = !lights.isEmpty();
1641 auto &renderableSubsets = theModelContext.subsets;
1642 const bool hasMaterialOverrides = ((renderable.overridden & QSSGRenderableNodeEntry::Overridden::Materials) != 0);
1643 const auto &materials = hasMaterialOverrides ? renderable.extOverrides.materials : modelData->getMaterials(model);
1644 const auto materialCount = materials.size();
1645 QSSGRenderGraphObject *lastMaterial = !materials.isEmpty() ? materials.last() :
nullptr;
1646 int idx = 0, subsetIdx = 0;
1647 for (; idx < meshSubsetCount; ++idx) {
1649 QSSGRenderGraphObject *theMaterialObject = (idx >= materialCount) ? lastMaterial : materials[idx];
1650 if (!theMaterialObject)
1653 const QSSGRenderSubset &theSubset = meshSubsets.at(idx);
1654 QSSGRenderableObjectFlags renderableFlags = renderableFlagsForModel;
1655 float subsetOpacity = modelGlobalOpacity;
1657 renderableFlags.setPointsTopology(theSubset.rhi.ia.topology == QRhiGraphicsPipeline::Points);
1658 QSSGRenderableObject *theRenderableObject = &renderableSubsets[subsetIdx++];
1660 const bool usesInstancing = theModelContext.model.instancing()
1661 && rhiCtx->rhi()->isFeatureSupported(QRhi::Instancing);
1662 if (usesInstancing && theModelContext.model.instanceTable->hasTransparency())
1663 renderableFlags |= QSSGRenderableObjectFlag::HasTransparency;
1664 if (theModelContext.model.hasTransparency)
1665 renderableFlags |= QSSGRenderableObjectFlag::HasTransparency;
1668 quint32 subsetLevelOfDetail = 0;
1669 if (!theSubset.lods.isEmpty() && lodThreshold > 0.0f) {
1671 float lodDistanceMultiplier = camerasView[0]->getLevelOfDetailMultiplier();
1672 float distanceThreshold = 0.0f;
1673 const auto scale = QSSGUtils::mat44::getScale(globalTransform);
1674 float modelScale = qMax(scale.x(), qMax(scale.y(), scale.z()));
1675 QSSGBounds3 transformedBounds = theSubset.bounds;
1676 if (camerasView[0]->type != QSSGRenderGraphObject::Type::OrthographicCamera) {
1677 transformedBounds.transform(globalTransform);
1678 if (maybeDebugDraw && debugDrawSystem->isEnabled(QSSGDebugDrawSystem::Mode::MeshLod))
1679 debugDrawSystem->drawBounds(transformedBounds, QColor(Qt::red));
1680 const QMatrix4x4 cameraGlobalTranform = getGlobalTransform(*camerasView[0]);
1681 const QVector3D cameraNormal = QSSGRenderNode::getScalingCorrectDirection(cameraGlobalTranform);
1682 const QVector3D cameraPosition = QSSGRenderNode::getGlobalPos(cameraGlobalTranform);
1683 const QSSGPlane cameraPlane = QSSGPlane(cameraPosition, cameraNormal);
1684 const QVector3D lodSupportMin = transformedBounds.getSupport(-cameraNormal);
1685 const QVector3D lodSupportMax = transformedBounds.getSupport(cameraNormal);
1686 if (maybeDebugDraw && debugDrawSystem->isEnabled(QSSGDebugDrawSystem::Mode::MeshLod))
1687 debugDrawSystem->drawPoint(lodSupportMin, QColor(
"orange"));
1689 const float distanceMin = cameraPlane.distance(lodSupportMin);
1690 const float distanceMax = cameraPlane.distance(lodSupportMax);
1692 if (distanceMin * distanceMax < 0.0)
1693 distanceThreshold = 0.0;
1694 else if (distanceMin >= 0.0)
1695 distanceThreshold = distanceMin;
1696 else if (distanceMax <= 0.0)
1697 distanceThreshold = -distanceMax;
1701 distanceThreshold = 1.0;
1704 int currentLod = -1;
1705 if (model.levelOfDetailBias > 0.0f) {
1706 const float threshold = distanceThreshold * lodDistanceMultiplier;
1707 const float modelBias = 1 / model.levelOfDetailBias;
1708 for (qsizetype i = 0; i < theSubset.lods.count(); ++i) {
1709 float subsetDistance = theSubset.lods[i].distance * modelScale * modelBias;
1710 float screenSize = subsetDistance / threshold;
1711 if (screenSize > lodThreshold)
1716 if (currentLod == -1)
1717 subsetLevelOfDetail = 0;
1719 subsetLevelOfDetail = currentLod + 1;
1720 if (maybeDebugDraw && debugDrawSystem->isEnabled(QSSGDebugDrawSystem::Mode::MeshLod))
1721 debugDrawSystem->drawBounds(transformedBounds, QSSGDebugDrawSystem::levelOfDetailColor(subsetLevelOfDetail));
1724 QVector3D theModelCenter(theSubset.bounds.center());
1725 theModelCenter = QSSGUtils::mat44::transform(globalTransform, theModelCenter);
1726 if (maybeDebugDraw && debugDrawSystem->isEnabled(QSSGDebugDrawSystem::Mode::MeshLodNormal)) {
1727 const QMatrix4x4 allCamera0GlobalTransform = getGlobalTransform(*allCameras[0]);
1728 debugDrawSystem->debugNormals(*bufferManager, theModelContext, theSubset, subsetLevelOfDetail, (theModelCenter - QSSGRenderNode::getGlobalPos(allCamera0GlobalTransform)).length() * 0.01);
1731 auto checkF32TypeIndex = [&rhiCtx](QRhiVertexInputAttribute::Format f) {
1732 if ((f == QRhiVertexInputAttribute::Format::Float4)
1733 || (f == QRhiVertexInputAttribute::Format::Float3)
1734 || (f == QRhiVertexInputAttribute::Format::Float2)
1735 || (f == QRhiVertexInputAttribute::Format::Float)) {
1738 if (!rhiCtx->rhi()->isFeatureSupported(QRhi::IntAttributes))
1739 qWarning() <<
"WARN: Model has non-integer type indices for skinning but current RHI backend doesn't support it!";
1743 if (theMaterialObject->type == QSSGRenderGraphObject::Type::DefaultMaterial ||
1744 theMaterialObject->type == QSSGRenderGraphObject::Type::PrincipledMaterial ||
1745 theMaterialObject->type == QSSGRenderGraphObject::Type::SpecularGlossyMaterial) {
1746 QSSGRenderDefaultMaterial &theMaterial(
static_cast<QSSGRenderDefaultMaterial &>(*theMaterialObject));
1747 QSSGDefaultMaterialPreparationResult theMaterialPrepResult(prepareDefaultMaterialForRender(theMaterial, renderableFlags, subsetOpacity, hasAnyLights, anyLightHasShadows, ioFlags));
1748 QSSGShaderDefaultMaterialKey &theGeneratedKey(theMaterialPrepResult.materialKey);
1749 subsetOpacity = theMaterialPrepResult.opacity;
1750 QSSGRenderableImage *firstImage(theMaterialPrepResult.firstImage);
1751 wasDirty |= theMaterialPrepResult.dirty;
1752 renderableFlags = theMaterialPrepResult.renderableFlags;
1753 if (renderableFlags.hasTransparency())
1754 ioFlags.setHasCustomBlendMode(theMaterial.blendMode != QSSGRenderDefaultMaterial::MaterialBlendMode::SourceOver);
1757 defaultMaterialShaderKeyProperties.m_blendParticles.setValue(theGeneratedKey, usesBlendParticles);
1760 const auto boneCount = model.skin ? model.skin->boneCount :
1761 model.skeleton ? model.skeleton->boneCount : 0;
1762 defaultMaterialShaderKeyProperties.m_boneCount.setValue(theGeneratedKey, boneCount);
1763 if (
auto idJoint = theSubset.rhi.ia.inputs.indexOf(QSSGRhiInputAssemblerState::JointSemantic); idJoint != -1) {
1764 const auto attr = theSubset.rhi.ia.inputLayout.attributeAt(idJoint);
1765 defaultMaterialShaderKeyProperties.m_usesFloatJointIndices.setValue(theGeneratedKey, checkF32TypeIndex(attr->format()));
1769 defaultMaterialShaderKeyProperties.m_usesInstancing.setValue(theGeneratedKey, usesInstancing);
1771 defaultMaterialShaderKeyProperties.m_targetCount.setValue(theGeneratedKey,
1772 theSubset.rhi.ia.targetCount);
1773 defaultMaterialShaderKeyProperties.m_targetPositionOffset.setValue(theGeneratedKey,
1774 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::PositionSemantic]);
1775 defaultMaterialShaderKeyProperties.m_targetNormalOffset.setValue(theGeneratedKey,
1776 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::NormalSemantic]);
1777 defaultMaterialShaderKeyProperties.m_targetTangentOffset.setValue(theGeneratedKey,
1778 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::TangentSemantic]);
1779 defaultMaterialShaderKeyProperties.m_targetBinormalOffset.setValue(theGeneratedKey,
1780 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::BinormalSemantic]);
1781 defaultMaterialShaderKeyProperties.m_targetTexCoord0Offset.setValue(theGeneratedKey,
1782 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::TexCoord0Semantic]);
1783 defaultMaterialShaderKeyProperties.m_targetTexCoord1Offset.setValue(theGeneratedKey,
1784 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::TexCoord1Semantic]);
1785 defaultMaterialShaderKeyProperties.m_targetColorOffset.setValue(theGeneratedKey,
1786 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::ColorSemantic]);
1788 new (theRenderableObject) QSSGSubsetRenderable(QSSGSubsetRenderable::Type::DefaultMaterialMeshSubset,
1795 subsetLevelOfDetail,
1800 anyLightHasShadows);
1801 wasDirty = wasDirty || renderableFlags.isDirty();
1802 }
else if (theMaterialObject->type == QSSGRenderGraphObject::Type::CustomMaterial) {
1803 QSSGRenderCustomMaterial &theMaterial(
static_cast<QSSGRenderCustomMaterial &>(*theMaterialObject));
1805 const auto &theMaterialSystem(contextInterface.customMaterialSystem());
1806 wasDirty |= theMaterialSystem->prepareForRender(theModelContext.model, theSubset, theMaterial);
1808 if (theMaterial.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::Blending))
1809 ioFlags.setHasCustomBlendMode(!hasCustomBlendMode(theMaterial));
1811 QSSGDefaultMaterialPreparationResult theMaterialPrepResult(
1812 prepareCustomMaterialForRender(theMaterial, renderableFlags, subsetOpacity, wasDirty,
1813 hasAnyLights, anyLightHasShadows, ioFlags));
1814 QSSGShaderDefaultMaterialKey &theGeneratedKey(theMaterialPrepResult.materialKey);
1815 subsetOpacity = theMaterialPrepResult.opacity;
1816 QSSGRenderableImage *firstImage(theMaterialPrepResult.firstImage);
1817 renderableFlags = theMaterialPrepResult.renderableFlags;
1819 if (model.particleBuffer && model.particleBuffer->particleCount())
1820 defaultMaterialShaderKeyProperties.m_blendParticles.setValue(theGeneratedKey,
true);
1822 defaultMaterialShaderKeyProperties.m_blendParticles.setValue(theGeneratedKey,
false);
1825 const auto boneCount = model.skin ? model.skin->boneCount :
1826 model.skeleton ? model.skeleton->boneCount : 0;
1827 defaultMaterialShaderKeyProperties.m_boneCount.setValue(theGeneratedKey, boneCount);
1828 if (
auto idJoint = theSubset.rhi.ia.inputs.indexOf(QSSGRhiInputAssemblerState::JointSemantic); idJoint != -1) {
1829 const auto attr = theSubset.rhi.ia.inputLayout.attributeAt(idJoint);
1830 defaultMaterialShaderKeyProperties.m_usesFloatJointIndices.setValue(theGeneratedKey, checkF32TypeIndex(attr->format()));
1834 bool usesInstancing = theModelContext.model.instancing()
1835 && rhiCtx->rhi()->isFeatureSupported(QRhi::Instancing);
1836 defaultMaterialShaderKeyProperties.m_usesInstancing.setValue(theGeneratedKey, usesInstancing);
1838 defaultMaterialShaderKeyProperties.m_targetCount.setValue(theGeneratedKey,
1839 theSubset.rhi.ia.targetCount);
1840 defaultMaterialShaderKeyProperties.m_targetPositionOffset.setValue(theGeneratedKey,
1841 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::PositionSemantic]);
1842 defaultMaterialShaderKeyProperties.m_targetNormalOffset.setValue(theGeneratedKey,
1843 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::NormalSemantic]);
1844 defaultMaterialShaderKeyProperties.m_targetTangentOffset.setValue(theGeneratedKey,
1845 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::TangentSemantic]);
1846 defaultMaterialShaderKeyProperties.m_targetBinormalOffset.setValue(theGeneratedKey,
1847 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::BinormalSemantic]);
1848 defaultMaterialShaderKeyProperties.m_targetTexCoord0Offset.setValue(theGeneratedKey,
1849 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::TexCoord0Semantic]);
1850 defaultMaterialShaderKeyProperties.m_targetTexCoord1Offset.setValue(theGeneratedKey,
1851 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::TexCoord1Semantic]);
1852 defaultMaterialShaderKeyProperties.m_targetColorOffset.setValue(theGeneratedKey,
1853 theSubset.rhi.ia.targetOffsets[QSSGRhiInputAssemblerState::ColorSemantic]);
1855 if (theMaterial.m_iblProbe)
1856 theMaterial.m_iblProbe->clearDirty();
1858 new (theRenderableObject) QSSGSubsetRenderable(QSSGSubsetRenderable::Type::CustomMaterialMeshSubset,
1865 subsetLevelOfDetail,
1870 anyLightHasShadows);
1872 if (theRenderableObject)
1873 theRenderableObject->camdistSq = getCameraDistanceSq(*theRenderableObject, allCameraData[0]);
1877 if (Q_UNLIKELY(idx != subsetIdx))
1878 renderableSubsets.mSize = subsetIdx;
1880 for (
auto &ro : renderableSubsets) {
1881 const auto depthMode = ro.depthWriteMode;
1882 hasDepthWriteObjects |= (depthMode == QSSGDepthDrawMode::Always || depthMode == QSSGDepthDrawMode::OpaqueOnly);
1883 enum ObjectType : quint8 { ScreenTexture, Transparent, Opaque };
1884 static constexpr DepthPrepassObject ppState[][2] = { {DepthPrepassObject::None, DepthPrepassObject::ScreenTexture},
1885 {DepthPrepassObject::None, DepthPrepassObject::Transparent},
1886 {DepthPrepassObject::None, DepthPrepassObject::Opaque} };
1888 if (ro.renderableFlags.requiresScreenTexture()) {
1889 depthPrepassObjectsState |= DepthPrepassObjectStateT(ppState[ObjectType::ScreenTexture][size_t(depthMode == QSSGDepthDrawMode::OpaquePrePass)]);
1890 screenTextureObjects.push_back({&ro, ro.camdistSq});
1891 }
else if (ro.renderableFlags.hasTransparency()) {
1892 depthPrepassObjectsState |= DepthPrepassObjectStateT(ppState[ObjectType::Transparent][size_t(depthMode == QSSGDepthDrawMode::OpaquePrePass)]);
1893 transparentObjects.push_back({&ro, ro.camdistSq});
1895 depthPrepassObjectsState |= DepthPrepassObjectStateT(ppState[ObjectType::Opaque][size_t(depthMode == QSSGDepthDrawMode::OpaquePrePass)]);
1896 opaqueObjects.push_back({&ro, ro.camdistSq});
1899 if (ro.renderableFlags.usedInBakedLighting())
1900 bakedLightingObjects.push_back({&ro, ro.camdistSq});
1903 if (!bakedLightingObjects.isEmpty())
1904 bakedLightingModels.push_back(QSSGBakedLightingModel(&model, bakedLightingObjects));
2156void QSSGLayerRenderData::prepareForRender()
2158 QSSG_ASSERT_X(layerPrepResult.isNull(),
"Prep-result was not reset for render!", layerPrepResult = {});
2160 QRect theViewport(renderer->viewport());
2164 frameData.m_ctx = renderer->contextInterface();
2169 ps.viewport = {
float(theViewport.x()),
float(theViewport.y()),
float(theViewport.width()),
float(theViewport.height()), 0.0f, 1.0f };
2170 if (layer.scissorRect.isValid()) {
2171 ps.flags |= QSSGRhiGraphicsPipelineState::Flag::UsesScissor;
2172 ps.scissor = { layer.scissorRect.x(),
2173 theViewport.height() - (layer.scissorRect.y() + layer.scissorRect.height()),
2174 layer.scissorRect.width(),
2175 layer.scissorRect.height() };
2178 ps.depthFunc = QRhiGraphicsPipeline::LessOrEqual;
2179 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
false);
2182 ps.polygonMode = layer.wireframeMode ? QRhiGraphicsPipeline::Line : QRhiGraphicsPipeline::Fill;
2184 bool wasDirty =
false;
2185 bool wasDataDirty =
false;
2186 wasDirty = layer.isDirty();
2189 layerPrepResult = { theViewport, layer };
2192 const bool SSAOEnabled = layer.ssaoEnabled();
2193 layerPrepResult.flags.setRequiresSsaoPass(SSAOEnabled);
2194 features.set(QSSGShaderFeatures::Feature::Ssao, SSAOEnabled);
2197 bool requiresDepthTexture = SSAOEnabled;
2198 bool requiresNormalTexture =
false;
2199 for (QSSGRenderEffect *theEffect = layer.firstEffect; theEffect; theEffect = theEffect->m_nextEffect) {
2200 if (theEffect->isDirty()) {
2202 theEffect->clearDirty();
2204 if (theEffect->testFlag(QSSGRenderEffect::Flags::UsesDepthTexture))
2205 requiresDepthTexture =
true;
2206 if (theEffect->testFlag(QSSGRenderEffect::Flags::UsesNormalTexture))
2207 requiresNormalTexture =
true;
2210 const auto &rhiCtx = renderer->contextInterface()->rhiContext();
2211 orderIndependentTransparencyEnabled = (layer.oitMethod != QSSGRenderLayer::OITMethod::None);
2212 if (layer.oitMethod == QSSGRenderLayer::OITMethod::WeightedBlended) {
2213 orderIndependentTransparencyEnabled = rhiCtx->rhi()->isFeatureSupported(QRhi::PerRenderTargetBlending);
2214 if (rhiCtx->mainPassSampleCount() > 1)
2215 orderIndependentTransparencyEnabled |= rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch) && rhiCtx->rhi()->isFeatureSupported(QRhi::SampleVariables);
2216 if (!orderIndependentTransparencyEnabled && !oitWarningUnsupportedShown) {
2217 qCWarning(lcQuick3DRender) <<
"Order Independent Transparency is requested, but it is not supported.";
2218 oitWarningUnsupportedShown =
true;
2221 if (layer.oitMethodDirty) {
2222 oitRenderContext.reset();
2223 for (
auto &renderResult : renderResults)
2224 renderResult.reset();
2227 layerPrepResult.flags.setRequiresDepthTexture(requiresDepthTexture);
2229 layerPrepResult.flags.setRequiresNormalTexture(requiresNormalTexture);
2233 if (!layer.firstEffect)
2234 QSSGLayerRenderData::setTonemapFeatures(features, layer.tonemapMode);
2241 if (rhiCtx->rhi()->resourceLimit(QRhi::MaxUniformBufferRange) < REDUCED_MAX_LIGHT_COUNT_THRESHOLD_BYTES) {
2242 features.set(QSSGShaderFeatures::Feature::ReduceMaxNumLights,
true);
2243 static bool notified =
false;
2246 qCDebug(lcQuick3DRender,
"Qt Quick 3D maximum number of lights has been reduced from %d to %d due to the graphics driver's limitations",
2247 QSSG_MAX_NUM_LIGHTS, QSSG_REDUCED_MAX_NUM_LIGHTS);
2252 QSSGRenderImageTexture lightProbeTexture;
2253 if (layer.lightProbe) {
2254 const auto &lightProbeSettings = layer.lightProbeSettings;
2255 if (layer.lightProbe->m_format == QSSGRenderTextureFormat::Unknown) {
2258 if (renderer->contextInterface()->rhiContext()->rhi()->isTextureFormatSupported(QRhiTexture::RGBA16F))
2259 layer.lightProbe->m_format = QSSGRenderTextureFormat::RGBA16F;
2261 layer.lightProbe->m_format = QSSGRenderTextureFormat::RGBE8;
2264 if (layer.lightProbe->clearDirty())
2265 wasDataDirty =
true;
2268 lightProbeTexture = renderer->contextInterface()->bufferManager()->loadRenderImage(layer.lightProbe, QSSGBufferManager::MipModeBsdf);
2269 if (lightProbeTexture.m_texture) {
2271 features.set(QSSGShaderFeatures::Feature::LightProbe,
true);
2272 features.set(QSSGShaderFeatures::Feature::IblOrientation, !lightProbeSettings.probeOrientation.isIdentity());
2276 if (lightProbeTexture.m_flags.isRgbe8())
2277 features.set(QSSGShaderFeatures::Feature::RGBELightProbe,
true);
2279 layer.lightProbe =
nullptr;
2282 const bool forceIblExposureValues = (features.isSet(QSSGShaderFeatures::Feature::LightProbe) && layer.tonemapMode == QSSGRenderLayer::TonemapMode::Custom);
2283 features.set(QSSGShaderFeatures::Feature::ForceIblExposure, forceIblExposureValues);
2286 frameData.m_ctx->bufferManager()->setLightmapSource(layer.lightmapSource);
2290 version = nodeData->version();
2295 auto &globalTransforms = nodeData->globalTransforms;
2296 auto &globalOpacities = nodeData->globalOpacities;
2297 auto &instanceTransforms = nodeData->instanceTransforms;
2300 QSSGRenderDataHelpers::GlobalStateResultT globalStateResult = QSSGRenderDataHelpers::GlobalStateResult::None;
2302 const bool layerTreeWasDirty = layer.isDirty(QSSGRenderLayer::DirtyFlag::TreeDirty);
2303 layer.clearDirty(QSSGRenderLayer::DirtyFlag::TreeDirty);
2304 if (layerTreeWasDirty) {
2305 wasDataDirty =
true;
2306 layerNodes = nodeData->getLayerNodeView(layer);
2308 for (
auto &node : layerNodes)
2309 globalStateResult |= QSSGRenderDataHelpers::updateGlobalNodeState(node, version);
2311 bool transformAndOpacityDirty =
false;
2312 for (
auto &node : layerNodes)
2313 transformAndOpacityDirty |= QSSGRenderDataHelpers::calcGlobalNodeData<QSSGRenderDataHelpers::Strategy::Update>(node, version, globalTransforms, globalOpacities);
2316 if (transformAndOpacityDirty) {
2317 for (
const auto &node : layerNodes)
2318 wasDataDirty |= QSSGRenderDataHelpers::calcInstanceTransforms(node, version, globalTransforms, instanceTransforms);
2321 wasDataDirty |= transformAndOpacityDirty;
2327 const bool hasExplicitCamera = (layer.explicitCameras.size() != 0);
2328 bool cameraLayerMaskDirty =
false;
2329 quint32 layerMask = QSSGRenderCamera::LayerMaskAll;
2330 if (hasExplicitCamera) {
2331 QSSGRenderCamera *explicitCamera = layer.explicitCameras[0];
2332 layerMask = explicitCamera->tag.value();
2333 cameraLayerMaskDirty = explicitCamera->isDirty(QSSGRenderCamera::DirtyFlag::LayerMaskDirty);
2334 explicitCamera->clearDirty(QSSGRenderCamera::DirtyFlag::LayerMaskDirty);
2337 const bool restatNodes = (layerTreeWasDirty || (globalStateResult & QSSGRenderDataHelpers::GlobalStateResult::ActiveChanged) || cameraLayerMaskDirty);
2341 particlesView.clear();
2342 item2DsView.clear();
2343 camerasView.clear();
2345 reflectionProbesView.clear();
2346 nonCategorizedView.clear();
2348 enum NodeType : size_t { Model = 0, Particles, Item2D, Camera, Light, ReflectionProbe, Other, Inactive };
2349 const auto nodeType = [layerMask](QSSGRenderNode *node) -> NodeType {
2350 if (!(node->getGlobalState(QSSGRenderNode::GlobalState::Active) && (node->tag.isSet(layerMask))))
2351 return NodeType::Inactive;
2352 switch (node->type) {
2353 case QSSGRenderGraphObject::Type::Model:
return NodeType::Model;
2354 case QSSGRenderGraphObject::Type::Particles:
return NodeType::Particles;
2355 case QSSGRenderGraphObject::Type::Item2D:
return NodeType::Item2D;
2356 case QSSGRenderGraphObject::Type::ReflectionProbe:
return NodeType::ReflectionProbe;
2360 if (QSSGRenderGraphObject::isCamera(node->type))
2361 return NodeType::Camera;
2362 if (QSSGRenderGraphObject::isLight(node->type))
2363 return NodeType::Light;
2365 return NodeType::Other;
2377 layerNodesCategorized = { layerNodes.begin(), layerNodes.end() };
2379 std::stable_sort(layerNodesCategorized.begin(), layerNodesCategorized.end(), [nodeType](QSSGRenderNode *a, QSSGRenderNode *b) {
2380 return nodeType(a) < nodeType(b);
2385 const LayerNodeStatResult stat = statLayerNodes(layerNodesCategorized, layerMask);
2390 if (stat.modelCount > 0) {
2391 modelsView = QSSGModelsView((QSSGRenderModel **)(layerNodesCategorized.data() + next), stat.modelCount);
2392 next = modelsView.size();
2394 if (stat.particlesCount > 0) {
2395 particlesView = QSSGParticlesView((QSSGRenderParticles **)(layerNodesCategorized.data() + next), stat.particlesCount);
2396 next += particlesView.size();
2398 if (stat.item2DCount > 0) {
2399 item2DsView = QSSGItem2DsView((QSSGRenderItem2D **)(layerNodesCategorized.data() + next), stat.item2DCount);
2400 next += item2DsView.size();
2402 if (stat.cameraCount > 0) {
2403 camerasView = QSSGCamerasView((QSSGRenderCamera **)(layerNodesCategorized.data() + next), stat.cameraCount);
2404 next += camerasView.size();
2406 if (stat.lightCount > 0) {
2407 lightsView = QSSGLightsView((QSSGRenderLight **)(layerNodesCategorized.data() + next), stat.lightCount);
2408 next += lightsView.size();
2410 if (stat.reflectionProbeCount > 0) {
2411 reflectionProbesView = QSSGReflectionProbesView((QSSGRenderReflectionProbe **)(layerNodesCategorized.data() + next), stat.reflectionProbeCount);
2412 next += reflectionProbesView.size();
2414 if (stat.otherCount > 0) {
2415 nonCategorizedView = QSSGNonCategorizedView((QSSGRenderNode **)(layerNodesCategorized.data() + next), stat.otherCount);
2416 next += nonCategorizedView.size();
2422 renderableModels.clear();
2423 renderableParticles.clear();
2424 renderableModels.reserve(modelsView.size());
2425 renderableParticles.reserve(particlesView.size());
2427 renderableModels = {modelsView.begin(), modelsView.end()};
2428 renderableParticles = {particlesView.begin(), particlesView.end()};
2435 QSSGRenderCamera::Configuration cameraConfig { renderer->dpr(), layer.isSsaaEnabled() ? layer.ssaaMultiplier : 1.0f };
2436 renderedCameras.clear();
2437 if (!layer.explicitCameras.isEmpty()) {
2438 for (QSSGRenderCamera *cam : std::as_const(layer.explicitCameras)) {
2440 if (cam->getGlobalState(QSSGRenderCamera::GlobalState::Active)) {
2441 const bool computeFrustumSucceeded = cam->calculateProjection(theViewport, cameraConfig);
2442 if (Q_LIKELY(computeFrustumSucceeded))
2443 renderedCameras.append(cam);
2445 qCCritical(INTERNAL_ERROR,
"Failed to calculate camera frustum");
2449 }
else if (QSSG_GUARD_X(layer.viewCount == 1,
"Multiview rendering requires explicit cameras to be set!.")) {
2454 for (
auto iter = camerasView.begin(); renderedCameras.isEmpty() && iter != camerasView.end(); iter++) {
2455 QSSGRenderCamera *theCamera = *iter;
2456 if (theCamera->getGlobalState(QSSGRenderCamera::GlobalState::Active)) {
2457 const bool computeFrustumSucceeded = theCamera->calculateProjection(theViewport, cameraConfig);
2458 if (Q_LIKELY(computeFrustumSucceeded))
2459 renderedCameras.append(theCamera);
2461 qCCritical(INTERNAL_ERROR,
"Failed to calculate camera frustum");
2466 float meshLodThreshold = 1.0f;
2467 if (!renderedCameras.isEmpty())
2468 meshLodThreshold = renderedCameras[0]->levelOfDetailPixelThreshold / theViewport.width();
2470 layer.renderedCamerasMutex.lock();
2471 layer.renderedCameras = renderedCameras;
2472 layer.renderedCamerasMutex.unlock();
2475 const QSSGRenderCameraDataList &renderCameraData = getCachedCameraDatas();
2476 modelData->updateModelData(modelsView, renderer, renderCameraData);
2479 item2DData->updateItem2DData(item2DsView, renderer, renderCameraData);
2482 prepareResourceLoaders();
2485 updateDirtySkeletons(*
this, modelsView);
2488 int directionalLightsCount = 0;
2489 int positionalLightsCount = 0;
2490 const int maxLightCount = effectiveMaxLightCount(features);
2491 const int maxDirectionalLights = effectiveMaxDirectionalLightCount(features);
2492 QSSGShaderLightList renderableLights;
2493 int shadowMapCount = 0;
2494 bool hasScopedLights =
false;
2500 auto it = std::make_reverse_iterator(lightsView.end());
2501 const auto end = it + qMin(maxLightCount, lightsView.size());
2502 for (; it != end; ++it) {
2503 QSSGRenderLight *renderLight = (*it);
2504 QMatrix4x4 renderLightTransform = getGlobalTransform(*renderLight);
2505 if (renderLight->type == QSSGRenderGraphObject::Type::DirectionalLight)
2506 directionalLightsCount++;
2508 positionalLightsCount++;
2510 if (positionalLightsCount > maxLightCount)
2512 if (directionalLightsCount > maxDirectionalLights)
2516 hasScopedLights |= (renderLight->m_scope !=
nullptr);
2517 const bool castShadows = renderLight->m_castShadow && !renderLight->m_fullyBaked;
2518 shadowMapCount +=
int(castShadows);
2519 const auto &direction = renderLight->getScalingCorrectDirection(renderLightTransform);
2520 renderableLights.push_back(QSSGShaderLight{ renderLight, castShadows, direction });
2524 const bool showLightCountWarning = !tooManyLightsWarningShown && (positionalLightsCount > maxLightCount);
2525 if (showLightCountWarning) {
2526 qWarning(
"Too many lights in scene, maximum is %d", maxLightCount);
2527 tooManyLightsWarningShown =
true;
2530 const bool showDirectionalLightCountWarning = !tooManyDirectionalLightsWarningShown && (directionalLightsCount > maxDirectionalLights);
2531 if (showDirectionalLightCountWarning) {
2532 qWarning(
"Too many directional lights in scene, maximum is %d", maxDirectionalLights);
2533 tooManyDirectionalLightsWarningShown =
true;
2536 if (shadowMapCount > 0) {
2537 requestShadowMapManager();
2538 layerPrepResult.flags.setRequiresShadowMapPass(
true);
2543 features.set(QSSGShaderFeatures::Feature::Ssm,
true);
2544 shadowMapManager->addShadowMaps(renderableLights);
2545 }
else if (shadowMapManager) {
2547 shadowMapManager->releaseCachedResources();
2553 QSSG_ASSERT(globalLights.isEmpty(), globalLights.clear());
2554 if (hasScopedLights) {
2555 for (
const auto &shaderLight : std::as_const(renderableLights)) {
2556 if (!shaderLight.light->m_scope)
2557 globalLights.push_back(shaderLight);
2560 const auto prepareLightsWithScopedLights = [&renderableLights,
this](QVector<QSSGRenderableNodeEntry> &renderableNodes) {
2561 for (qint32 idx = 0, end = renderableNodes.size(); idx < end; ++idx) {
2562 QSSGRenderableNodeEntry &theNodeEntry(renderableNodes[idx]);
2563 QSSGShaderLightList filteredLights;
2564 for (
const auto &light : std::as_const(renderableLights)) {
2565 if (light.light->m_scope && !scopeLight(theNodeEntry.node, light.light->m_scope))
2567 filteredLights.push_back(light);
2570 if (filteredLights.isEmpty()) {
2571 theNodeEntry.lights = QSSGDataView(globalLights);
2576 auto customLightList = RENDER_FRAME_NEW_BUFFER<QSSGShaderLight>(*renderer->contextInterface(), filteredLights.size());
2577 std::copy(filteredLights.cbegin(), filteredLights.cend(), customLightList.begin());
2578 theNodeEntry.lights = customLightList;
2583 prepareLightsWithScopedLights(renderableModels);
2584 prepareLightsWithScopedLights(renderableParticles);
2586 globalLights = renderableLights;
2588 const auto prepareLights = [
this](QVector<QSSGRenderableNodeEntry> &renderableNodes) {
2589 for (qint32 idx = 0, end = renderableNodes.size(); idx < end; ++idx) {
2590 QSSGRenderableNodeEntry &theNodeEntry(renderableNodes[idx]);
2591 theNodeEntry.lights = QSSGDataView(globalLights);
2595 prepareLights(renderableModels);
2596 prepareLights(renderableParticles);
2602 Q_STATIC_ASSERT(USERPASSES == size_t(QSSGRenderLayer::RenderExtensionStage::Count));
2603 for (size_t i = 0; i != size_t(QSSGRenderLayer::RenderExtensionStage::Count); ++i) {
2604 const auto &renderExtensions = layer.renderExtensions[i];
2605 auto &userPass = userPasses[i];
2606 for (
auto rit = renderExtensions.crbegin(), rend = renderExtensions.crend(); rit != rend; ++rit) {
2607 if ((*rit)->prepareData(frameData)) {
2609 userPass.extensions.push_back(*rit);
2615 auto &opaqueObjects = opaqueObjectStore[0];
2616 auto &transparentObjects = transparentObjectStore[0];
2617 auto &screenTextureObjects = screenTextureObjectStore[0];
2619 if (!renderedCameras.isEmpty()) {
2620 wasDirty |= prepareModelsForRender(*renderer->contextInterface(), renderableModels, layerPrepResult.flags, renderedCameras, getCachedCameraDatas(), modelContexts, opaqueObjects, transparentObjects, screenTextureObjects, meshLodThreshold);
2621 if (particlesEnabled) {
2622 const auto &cameraDatas = getCachedCameraDatas();
2623 wasDirty |= prepareParticlesForRender(renderableParticles, cameraDatas[0], layerPrepResult.flags);
2626 wasDirty |= (item2DsView.size() != 0);
2628 if (orderIndependentTransparencyEnabled) {
2630 if (transparentObjects.size() > 0 && !layerPrepResult.flags.hasCustomBlendMode()) {
2631 if (layer.oitMethod == QSSGRenderLayer::OITMethod::WeightedBlended) {
2632 if (rhiCtx->mainPassSampleCount() > 1)
2633 layerPrepResult.flags.setRequiresDepthTextureMS(
true);
2635 layerPrepResult.flags.setRequiresDepthTexture(
true);
2638 orderIndependentTransparencyEnabled =
false;
2639 if (!oitWarningInvalidBlendModeShown) {
2640 qCWarning(lcQuick3DRender) <<
"Order Independent Transparency requested, but disabled due to invalid blend modes.";
2641 qCWarning(lcQuick3DRender) <<
"Use SourceOver blend mode for Order Independent Transparency.";
2642 oitWarningInvalidBlendModeShown =
true;
2646 layer.oitMethodDirty =
false;
2648 prepareReflectionProbesForRender();
2650 wasDirty = wasDirty || wasDataDirty;
2651 layerPrepResult.flags.setWasDirty(wasDirty);
2652 layerPrepResult.flags.setLayerDataDirty(wasDataDirty);
2655 const bool animating = wasDirty;
2657 layer.progAAPassIndex = 0;
2659 const bool progressiveAA = layer.isProgressiveAAEnabled() && !animating;
2660 layer.progressiveAAIsActive = progressiveAA;
2661 const bool temporalAA = layer.isTemporalAAEnabled() && !progressiveAA;
2663 layer.temporalAAIsActive = temporalAA;
2665 QVector2D vertexOffsetsAA;
2667 if (progressiveAA && layer.progAAPassIndex > 0 && layer.progAAPassIndex < quint32(layer.antialiasingQuality)) {
2668 int idx = layer.progAAPassIndex - 1;
2669 vertexOffsetsAA = s_ProgressiveAAVertexOffsets[idx] / QVector2D{
float(theViewport.width()/2.0),
float(theViewport.height()/2.0) };
2673 const int t = 1 - 2 * (layer.tempAAPassIndex % 2);
2674 const float f = t * layer.temporalAAStrength;
2675 vertexOffsetsAA = { f /
float(theViewport.width()/2.0), f /
float(theViewport.height()/2.0) };
2678 if (!renderedCameras.isEmpty()) {
2679 if (temporalAA || progressiveAA ) {
2680 QMatrix4x4 offsetProjection = renderedCameras[0]->projection;
2681 QMatrix4x4 invProjection = renderedCameras[0]->projection.inverted();
2682 if (renderedCameras[0]->type == QSSGRenderCamera::Type::OrthographicCamera) {
2683 offsetProjection(0, 3) -= vertexOffsetsAA.x();
2684 offsetProjection(1, 3) -= vertexOffsetsAA.y();
2685 }
else if (renderedCameras[0]->type == QSSGRenderCamera::Type::PerspectiveCamera) {
2686 offsetProjection(0, 2) += vertexOffsetsAA.x();
2687 offsetProjection(1, 2) += vertexOffsetsAA.y();
2689 for (
auto &modelContext : std::as_const(modelContexts)) {
2690 for (
int mvpIdx = 0; mvpIdx < renderedCameras.count(); ++mvpIdx)
2691 modelContext->modelViewProjections[mvpIdx] = offsetProjection * invProjection * modelContext->modelViewProjections[mvpIdx];
2696 const bool hasItem2Ds = (item2DsView.size() > 0);
2697 const bool layerEnableDepthTest = layer.layerFlags.testFlag(QSSGRenderLayer::LayerFlag::EnableDepthTest);
2698 const bool layerEnabledDepthPrePass = layer.layerFlags.testFlag(QSSGRenderLayer::LayerFlag::EnableDepthPrePass);
2699 const bool depthTestEnableDefault = layerEnableDepthTest && (!opaqueObjects.isEmpty() || depthPrepassObjectsState || hasDepthWriteObjects);
2700 const bool zPrePassForced = (depthPrepassObjectsState != 0);
2701 zPrePassActive = zPrePassForced || (layerEnabledDepthPrePass && layerEnableDepthTest && (hasDepthWriteObjects || hasItem2Ds));
2702 const bool depthWriteEnableDefault = depthTestEnableDefault && (!layerEnabledDepthPrePass || !zPrePassActive);
2704 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, depthTestEnableDefault);
2705 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, depthWriteEnableDefault);
2709 layerPrepResult.setState(QSSGLayerRenderPreparationResult::State::Done);
2712 QSSG_ASSERT(activePasses.isEmpty(), activePasses.clear());
2716 if (layerPrepResult.flags.requiresDepthTexture())
2717 activePasses.push_back(&depthMapPass);
2718 if (layerPrepResult.flags.requiresDepthTextureMS())
2719 activePasses.push_back(&depthMapPassMS);
2721 if (layerPrepResult.flags.requiresNormalTexture())
2722 activePasses.push_back(&normalPass);
2725 if (layerPrepResult.flags.requiresSsaoPass())
2726 activePasses.push_back(&ssaoMapPass);
2729 if (layerPrepResult.flags.requiresShadowMapPass())
2730 activePasses.push_back(&shadowMapPass);
2733 activePasses.push_back(&zPrePassPass);
2736 if (layerPrepResult.flags.requiresScreenTexture())
2737 activePasses.push_back(&screenMapPass);
2740 activePasses.push_back(&reflectionMapPass);
2742 auto &textureExtensionPass = userPasses[size_t(QSSGRenderLayer::RenderExtensionStage::TextureProviders)];
2743 if (textureExtensionPass.hasData())
2744 activePasses.push_back(&textureExtensionPass);
2746 auto &underlayPass = userPasses[size_t(QSSGRenderLayer::RenderExtensionStage::Underlay)];
2747 if (underlayPass.hasData())
2748 activePasses.push_back(&underlayPass);
2750 const bool hasOpaqueObjects = (opaqueObjects.size() > 0);
2752 if (hasOpaqueObjects)
2753 activePasses.push_back(&opaquePass);
2757 if (renderer->contextInterface()->rhiContext()->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
2758 if (layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap && layer.skyBoxCubeMap)
2759 activePasses.push_back(&skyboxCubeMapPass);
2760 else if (layer.background == QSSGRenderLayer::Background::SkyBox && layer.lightProbe)
2761 activePasses.push_back(&skyboxPass);
2765 activePasses.push_back(&item2DPass);
2767 if (layerPrepResult.flags.requiresScreenTexture())
2768 activePasses.push_back(&reflectionPass);
2771 if (transparentObjects.size() > 0 || (!layerEnableDepthTest && hasOpaqueObjects)) {
2772 if (orderIndependentTransparencyEnabled) {
2773 activePasses.push_back(&oitRenderPass);
2774 activePasses.push_back(&oitCompositePass);
2775 oitRenderPass.setMethod(layer.oitMethod);
2776 oitCompositePass.setMethod(layer.oitMethod);
2778 activePasses.push_back(&transparentPass);
2782 auto &overlayPass = userPasses[size_t(QSSGRenderLayer::RenderExtensionStage::Overlay)];
2783 if (overlayPass.hasData())
2784 activePasses.push_back(&overlayPass);
2786 if (layer.gridEnabled)
2787 activePasses.push_back(&infiniteGridPass);
2789 if (
const auto &dbgDrawSystem = renderer->contextInterface()->debugDrawSystem(); dbgDrawSystem && dbgDrawSystem->isEnabled())
2790 activePasses.push_back(&debugDrawPass);