1678 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesScreenTexture))
1679 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::ScreenTexture,
true);
1680 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesScreenMipTexture))
1681 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::ScreenMipTexture,
true);
1682 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesDepthTexture))
1683 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::DepthTexture,
true);
1684 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesNormalTexture))
1685 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::NormalTexture,
true);
1686 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesAoTexture))
1687 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::AoTexture,
true);
1688 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesProjectionMatrix))
1689 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::ProjectionMatrix,
true);
1690 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesInverseProjectionMatrix))
1691 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::InverseProjectionMatrix,
true);
1692 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesVarColor))
1693 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::VarColor,
true);
1694 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesIblOrientation))
1695 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::IblOrientation,
true);
1696 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesLightmap))
1697 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Lightmap,
true);
1698 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesSkinning))
1699 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Skinning,
true);
1700 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesMorphing))
1701 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Morphing,
true);
1702 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesViewIndex))
1703 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::ViewIndex,
true);
1704 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesClearcoat))
1705 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Clearcoat,
true);
1706 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesClearcoatFresnelScaleBias))
1707 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::ClearcoatFresnelScaleBias,
true);
1708 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesFresnelScaleBias))
1709 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::FresnelScaleBias,
true);
1710 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesTransmission)) {
1711 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Transmission,
true);
1712 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::ScreenTexture,
true);
1713 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::ScreenMipTexture,
true);
1717 if (meta.flags.testFlag(QSSGCustomShaderMetaData::OverridesPosition))
1718 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::OverridesPosition,
true);
1721 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesSharedVars))
1722 material->m_usesSharedVariables =
true;
1750QSSGRenderGraphObject *QQuick3DCustomMaterial::updateSpatialNode(QSSGRenderGraphObject *node)
1752 using namespace QSSGShaderUtils;
1754 const auto &renderContext = QQuick3DObjectPrivate::get(
this)->sceneManager->wattached->rci();
1755 if (!renderContext) {
1756 qWarning(
"QQuick3DCustomMaterial: No render context interface?");
1760 QSSGShaderCustomMaterialAdapter::StringPairList uniforms;
1761 QSSGRenderCustomMaterial *customMaterial =
static_cast<QSSGRenderCustomMaterial *>(node);
1762 bool newBackendNode =
false;
1763 bool shadersMayChange =
false;
1764 if (!customMaterial) {
1765 customMaterial =
new QSSGRenderCustomMaterial;
1766 newBackendNode =
true;
1767 }
else if (m_dirtyAttributes & ShaderSettingsDirty) {
1768 shadersMayChange =
true;
1771 if (newBackendNode || shadersMayChange) {
1774 customMaterial->m_properties.clear();
1775 customMaterial->m_textureProperties.clear();
1777 customMaterial->m_shadingMode = QSSGRenderCustomMaterial::ShadingMode(
int(m_shadingMode));
1779 QMetaMethod propertyDirtyMethod;
1780 const int idx = metaObject()->indexOfSlot(
"onPropertyDirty()");
1782 propertyDirtyMethod = metaObject()->method(idx);
1784 const int propCount = metaObject()->propertyCount();
1785 int propOffset = metaObject()->propertyOffset();
1788 const QMetaObject *superClass = metaObject()->superClass();
1789 while (superClass && qstrcmp(superClass->className(),
"QQuick3DCustomMaterial") != 0) {
1790 propOffset = superClass->propertyOffset();
1791 superClass = superClass->superClass();
1794 using TextureInputProperty = QPair<QQuick3DShaderUtilsTextureInput *,
const char *>;
1795 QVector<TextureInputProperty> textureProperties;
1797 for (
int i = propOffset; i != propCount; ++i) {
1798 const auto property = metaObject()->property(i);
1799 if (Q_UNLIKELY(!property.isValid()))
1802 const auto name = property.name();
1803 QMetaType propType = property.metaType();
1804 QVariant propValue = property.read(
this);
1805 if (propType == QMetaType(QMetaType::QVariant))
1806 propType = propValue.metaType();
1808 if (propType.id() >= QMetaType::User) {
1809 if (propType.id() == qMetaTypeId<QQuick3DShaderUtilsTextureInput *>()) {
1810 if (QQuick3DShaderUtilsTextureInput *texture = property.read(
this).value<QQuick3DShaderUtilsTextureInput *>())
1811 textureProperties.push_back({texture, name});
1813 }
else if (propType == QMetaType(QMetaType::QObjectStar)) {
1814 if (QQuick3DShaderUtilsTextureInput *texture = qobject_cast<QQuick3DShaderUtilsTextureInput *>(propValue.value<QObject *>()))
1815 textureProperties.push_back({texture, name});
1817 const auto type = uniformType(propType);
1818 if (type != QSSGRenderShaderValue::Unknown) {
1819 uniforms.append({ uniformTypeName(propType), name });
1820 customMaterial->m_properties.push_back({ name, propValue, uniformType(propType), i});
1821 if (newBackendNode) {
1823 if (property.hasNotifySignal() && propertyDirtyMethod.isValid())
1824 connect(
this, property.notifySignal(),
this, propertyDirtyMethod);
1834 const auto processTextureProperty = [&](QQuick3DShaderUtilsTextureInput &texture,
const QByteArray &name) {
1835 texture.name = name;
1837 QSSGRenderCustomMaterial::TextureProperty textureData;
1838 textureData.texInput = &texture;
1839 textureData.name = name;
1840 textureData.shaderDataType = QSSGRenderShaderValue::Texture;
1842 if (newBackendNode) {
1843 connect(&texture, &QQuick3DShaderUtilsTextureInput::enabledChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
1844 connect(&texture, &QQuick3DShaderUtilsTextureInput::textureChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
1847 QQuick3DTexture *tex = texture.texture();
1848 if (tex && QQuick3DObjectPrivate::get(tex)->type == QQuick3DObjectPrivate::Type::ImageCube) {
1849 uniforms.append({ QByteArrayLiteral(
"samplerCube"), textureData.name });
1850 }
else if (tex && tex->textureData() && tex->textureData()->depth() > 0) {
1851 uniforms.append({ QByteArrayLiteral(
"sampler3D"), textureData.name });
1852 }
else if (tex && tex->textureProvider() && QQuick3DObjectPrivate::get(tex->textureProvider())->type == QQuick3DObjectPrivate::Type::TextureProvider) {
1853 auto textureProvider =
static_cast<QQuick3DTextureProviderExtension *>(tex->textureProvider());
1854 switch (textureProvider->samplerHint()) {
1855 case QQuick3DTextureProviderExtension::SamplerHint::Sampler2D:
1856 uniforms.append({ QByteArrayLiteral(
"sampler2D"), textureData.name });
1858 case QQuick3DTextureProviderExtension::SamplerHint::Sampler2DArray:
1859 uniforms.append({ QByteArrayLiteral(
"sampler2DArray"), textureData.name });
1861 case QQuick3DTextureProviderExtension::SamplerHint::Sampler3D:
1862 uniforms.append({ QByteArrayLiteral(
"sampler3D"), textureData.name });
1864 case QQuick3DTextureProviderExtension::SamplerHint::SamplerCube:
1865 uniforms.append({ QByteArrayLiteral(
"samplerCube"), textureData.name });
1867 case QQuick3DTextureProviderExtension::SamplerHint::SamplerCubeArray:
1868 uniforms.append({ QByteArrayLiteral(
"samplerCubeArray"), textureData.name });
1870 case QQuick3DTextureProviderExtension::SamplerHint::SamplerBuffer:
1871 uniforms.append({ QByteArrayLiteral(
"samplerBuffer"), textureData.name });
1875 uniforms.append({ QByteArrayLiteral(
"sampler2D"), textureData.name });
1878 customMaterial->m_textureProperties.push_back(textureData);
1881 for (
const auto &textureProperty : std::as_const(textureProperties))
1882 processTextureProperty(*textureProperty.first, textureProperty.second);
1884 if (customMaterial->incompleteBuildTimeObject || (m_dirtyAttributes & DynamicPropertiesDirty)) {
1885 const auto names = dynamicPropertyNames();
1886 for (
const auto &name : names) {
1887 QVariant propValue = property(name.constData());
1888 QMetaType propType = propValue.metaType();
1889 if (propType == QMetaType(QMetaType::QVariant))
1890 propType = propValue.metaType();
1892 if (propType.id() >= QMetaType::User) {
1893 if (propType.id() == qMetaTypeId<QQuick3DShaderUtilsTextureInput *>()) {
1894 if (QQuick3DShaderUtilsTextureInput *texture = propValue.value<QQuick3DShaderUtilsTextureInput *>())
1895 textureProperties.push_back({texture, name});
1897 }
else if (propType.id() == QMetaType::QObjectStar) {
1898 if (QQuick3DShaderUtilsTextureInput *texture = qobject_cast<QQuick3DShaderUtilsTextureInput *>(propValue.value<QObject *>()))
1899 textureProperties.push_back({texture, name});
1901 const auto type = uniformType(propType);
1902 if (type != QSSGRenderShaderValue::Unknown) {
1903 uniforms.append({ uniformTypeName(propType), name });
1904 customMaterial->m_properties.push_back({ name, propValue,
1905 uniformType(propType), -1 });
1910 qWarning(
"No known uniform conversion found for custom material property %s. Skipping", name.constData());
1915 for (
const auto &property : std::as_const(textureProperties))
1916 processTextureProperty(*property.first, property.second);
1919 const QQmlContext *context = qmlContext(
this);
1921 QByteArray fragment;
1922 QByteArray vertexProcessed[2];
1923 QSSGCustomShaderMetaData vertexMeta;
1924 QByteArray fragmentProcessed[2];
1925 QSSGCustomShaderMetaData fragmentMeta;
1926 QByteArray shaderPathKey(
"custom material --");
1928 customMaterial->m_renderFlags = {};
1930 if (!m_vertexShader.isEmpty())
1931 vertex = QSSGShaderUtils::resolveShader(m_vertexShader, context, shaderPathKey);
1932 else if (!m_vertexShaderCode.isEmpty())
1933 vertex = m_vertexShaderCode.toLatin1();
1935 if (!m_fragmentShader.isEmpty())
1936 fragment = QSSGShaderUtils::resolveShader(m_fragmentShader, context, shaderPathKey);
1937 else if (!m_fragmentShaderCode.isEmpty())
1938 fragment = m_fragmentShaderCode.toLatin1();
1945 vertexProcessed[QSSGRenderCustomMaterial::RegularShaderPathKeyIndex] =
1946 prepareCustomShader(customMaterial, uniforms, vertex, QSSGShaderCache::ShaderType::Vertex, vertexMeta,
false);
1947 fragmentProcessed[QSSGRenderCustomMaterial::RegularShaderPathKeyIndex] =
1948 prepareCustomShader(customMaterial, uniforms, fragment, QSSGShaderCache::ShaderType::Fragment, fragmentMeta,
false);
1950 vertexProcessed[QSSGRenderCustomMaterial::MultiViewShaderPathKeyIndex] =
1951 prepareCustomShader(customMaterial, uniforms, vertex, QSSGShaderCache::ShaderType::Vertex, vertexMeta,
true);
1952 fragmentProcessed[QSSGRenderCustomMaterial::MultiViewShaderPathKeyIndex] =
1953 prepareCustomShader(customMaterial, uniforms, fragment, QSSGShaderCache::ShaderType::Fragment, fragmentMeta,
true);
1960 customMaterial->m_customShaderPresence = {};
1961 for (
int i : { QSSGRenderCustomMaterial::RegularShaderPathKeyIndex, QSSGRenderCustomMaterial::MultiViewShaderPathKeyIndex }) {
1962 if (vertexProcessed[i].isEmpty() && fragmentProcessed[i].isEmpty())
1965 const QByteArray key = shaderPathKey +
':' + QCryptographicHash::hash(QByteArray(vertexProcessed[i] + fragmentProcessed[i]), QCryptographicHash::Algorithm::Sha1).toHex();
1967 customMaterial->m_shaderPathKey[i] = key;
1968 if (!vertexProcessed[i].isEmpty()) {
1969 customMaterial->m_customShaderPresence.setFlag(QSSGRenderCustomMaterial::CustomShaderPresenceFlag::Vertex);
1970 renderContext->shaderLibraryManager()->setShaderSource(key, QSSGShaderCache::ShaderType::Vertex, vertexProcessed[i], vertexMeta);
1972 if (!fragmentProcessed[i].isEmpty()) {
1973 customMaterial->m_customShaderPresence.setFlag(QSSGRenderCustomMaterial::CustomShaderPresenceFlag::Fragment);
1974 renderContext->shaderLibraryManager()->setShaderSource(key, QSSGShaderCache::ShaderType::Fragment, fragmentProcessed[i], fragmentMeta);
1979 customMaterial->setAlwaysDirty(m_alwaysDirty);
1980 if (m_srcBlend != BlendMode::NoBlend && m_dstBlend != BlendMode::NoBlend) {
1981 customMaterial->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Blending,
true);
1982 customMaterial->m_srcBlend = toRhiBlendFactor(m_srcBlend);
1983 customMaterial->m_dstBlend = toRhiBlendFactor(m_dstBlend);
1985 if (m_srcAlphaBlend != BlendMode::NoBlend && m_dstAlphaBlend != BlendMode::NoBlend) {
1986 customMaterial->m_srcAlphaBlend = toRhiBlendFactor(m_srcAlphaBlend);
1987 customMaterial->m_dstAlphaBlend = toRhiBlendFactor(m_dstAlphaBlend);
1989 customMaterial->m_srcAlphaBlend = customMaterial->m_srcBlend;
1990 customMaterial->m_dstAlphaBlend = customMaterial->m_dstBlend;
1993 customMaterial->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Blending,
false);
1995 customMaterial->m_lineWidth = m_lineWidth;
1997 QQuick3DMaterial::updateSpatialNode(customMaterial);
1999 if (m_dirtyAttributes & Dirty::PropertyDirty) {
2000 for (
auto &prop : customMaterial->m_properties) {
2001 auto p = metaObject()->property(prop.pid);
2002 if (Q_LIKELY(p.isValid()))
2003 prop.value = p.read(
this);
2007 if (m_dirtyAttributes & Dirty::TextureDirty) {
2008 for (QSSGRenderCustomMaterial::TextureProperty &prop : customMaterial->m_textureProperties) {
2009 QQuick3DTexture *tex = prop.texInput->texture();
2011 if (prop.texInput->enabled)
2012 prop.texImage = tex->getRenderImage();
2014 prop.texImage =
nullptr;
2015 prop.minFilterType = tex->minFilter() == QQuick3DTexture::Nearest ? QSSGRenderTextureFilterOp::Nearest
2016 : QSSGRenderTextureFilterOp::Linear;
2017 prop.magFilterType = tex->magFilter() == QQuick3DTexture::Nearest ? QSSGRenderTextureFilterOp::Nearest
2018 : QSSGRenderTextureFilterOp::Linear;
2019 prop.mipFilterType = tex->generateMipmaps() ? (tex->mipFilter() == QQuick3DTexture::Nearest ? QSSGRenderTextureFilterOp::Nearest
2020 : QSSGRenderTextureFilterOp::Linear)
2021 : QSSGRenderTextureFilterOp::None;
2022 prop.horizontalClampType = tex->horizontalTiling() == QQuick3DTexture::Repeat ? QSSGRenderTextureCoordOp::Repeat
2023 : (tex->horizontalTiling() == QQuick3DTexture::ClampToEdge) ? QSSGRenderTextureCoordOp::ClampToEdge
2024 : QSSGRenderTextureCoordOp::MirroredRepeat;
2025 prop.verticalClampType = tex->verticalTiling() == QQuick3DTexture::Repeat ? QSSGRenderTextureCoordOp::Repeat
2026 : (tex->verticalTiling() == QQuick3DTexture::ClampToEdge) ? QSSGRenderTextureCoordOp::ClampToEdge
2027 : QSSGRenderTextureCoordOp::MirroredRepeat;
2028 prop.zClampType = tex->depthTiling() == QQuick3DTexture::Repeat ? QSSGRenderTextureCoordOp::Repeat
2029 : (tex->depthTiling() == QQuick3DTexture::ClampToEdge) ? QSSGRenderTextureCoordOp::ClampToEdge
2030 : QSSGRenderTextureCoordOp::MirroredRepeat;
2032 prop.texImage =
nullptr;
2035 if (tex != prop.lastConnectedTexture) {
2036 prop.lastConnectedTexture = tex;
2037 disconnect(prop.minFilterChangedConn);
2038 disconnect(prop.magFilterChangedConn);
2039 disconnect(prop.mipFilterChangedConn);
2040 disconnect(prop.horizontalTilingChangedConn);
2041 disconnect(prop.verticalTilingChangedConn);
2042 disconnect(prop.depthTilingChangedConn);
2044 prop.minFilterChangedConn = connect(tex, &QQuick3DTexture::minFilterChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
2045 prop.magFilterChangedConn = connect(tex, &QQuick3DTexture::magFilterChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
2046 prop.mipFilterChangedConn = connect(tex, &QQuick3DTexture::mipFilterChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
2047 prop.horizontalTilingChangedConn = connect(tex, &QQuick3DTexture::horizontalTilingChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
2048 prop.verticalTilingChangedConn = connect(tex, &QQuick3DTexture::verticalTilingChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
2049 prop.depthTilingChangedConn = connect(tex, &QQuick3DTexture::depthTilingChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
2055 m_dirtyAttributes = 0;
2057 return customMaterial;