1686 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesScreenTexture))
1687 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::ScreenTexture,
true);
1688 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesScreenMipTexture))
1689 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::ScreenMipTexture,
true);
1690 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesDepthTexture))
1691 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::DepthTexture,
true);
1692 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesNormalTexture))
1693 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::NormalTexture,
true);
1694 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesAoTexture))
1695 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::AoTexture,
true);
1696 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesProjectionMatrix))
1697 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::ProjectionMatrix,
true);
1698 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesInverseProjectionMatrix))
1699 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::InverseProjectionMatrix,
true);
1700 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesVarColor))
1701 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::VarColor,
true);
1702 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesIblOrientation))
1703 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::IblOrientation,
true);
1704 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesLightmap))
1705 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Lightmap,
true);
1706 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesSkinning))
1707 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Skinning,
true);
1708 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesMorphing))
1709 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Morphing,
true);
1710 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesViewIndex))
1711 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::ViewIndex,
true);
1712 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesClearcoat))
1713 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Clearcoat,
true);
1714 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesClearcoatFresnelScaleBias))
1715 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::ClearcoatFresnelScaleBias,
true);
1716 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesFresnelScaleBias))
1717 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::FresnelScaleBias,
true);
1718 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesMotionVectorTexture))
1719 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::MotionVectorTexture,
true);
1720 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesTransmission)) {
1721 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Transmission,
true);
1722 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::ScreenTexture,
true);
1723 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::ScreenMipTexture,
true);
1727 if (meta.flags.testFlag(QSSGCustomShaderMetaData::OverridesPosition))
1728 material->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::OverridesPosition,
true);
1731 if (meta.flags.testFlag(QSSGCustomShaderMetaData::UsesSharedVars))
1732 material->m_usesSharedVariables =
true;
1760QSSGRenderGraphObject *QQuick3DCustomMaterial::updateSpatialNode(QSSGRenderGraphObject *node)
1762 using namespace QSSGShaderUtils;
1764 const auto &renderContext = QQuick3DObjectPrivate::get(
this)->sceneManager->wattached->rci();
1765 if (!renderContext) {
1766 qWarning(
"QQuick3DCustomMaterial: No render context interface?");
1770 QSSGShaderCustomMaterialAdapter::StringPairList uniforms;
1771 QSSGRenderCustomMaterial *customMaterial =
static_cast<QSSGRenderCustomMaterial *>(node);
1772 bool newBackendNode =
false;
1773 bool shadersMayChange =
false;
1774 if (!customMaterial) {
1775 customMaterial =
new QSSGRenderCustomMaterial;
1776 newBackendNode =
true;
1777 }
else if (m_dirtyAttributes & ShaderSettingsDirty) {
1778 shadersMayChange =
true;
1781 if (newBackendNode || shadersMayChange) {
1784 customMaterial->m_properties.clear();
1785 customMaterial->m_textureProperties.clear();
1787 customMaterial->m_shadingMode = QSSGRenderCustomMaterial::ShadingMode(
int(m_shadingMode));
1789 QMetaMethod propertyDirtyMethod;
1790 const int idx = metaObject()->indexOfSlot(
"onPropertyDirty()");
1792 propertyDirtyMethod = metaObject()->method(idx);
1794 const int propCount = metaObject()->propertyCount();
1795 int propOffset = metaObject()->propertyOffset();
1798 const QMetaObject *superClass = metaObject()->superClass();
1799 while (superClass && qstrcmp(superClass->className(),
"QQuick3DCustomMaterial") != 0) {
1800 propOffset = superClass->propertyOffset();
1801 superClass = superClass->superClass();
1804 using TextureInputProperty = QPair<QQuick3DShaderUtilsTextureInput *,
const char *>;
1805 QVector<TextureInputProperty> textureProperties;
1807 for (
int i = propOffset; i != propCount; ++i) {
1808 const auto property = metaObject()->property(i);
1809 if (Q_UNLIKELY(!property.isValid()))
1812 const auto name = property.name();
1813 QMetaType propType = property.metaType();
1814 QVariant propValue = property.read(
this);
1815 if (propType == QMetaType(QMetaType::QVariant))
1816 propType = propValue.metaType();
1818 if (propType.id() >= QMetaType::User) {
1819 if (propType.id() == qMetaTypeId<QQuick3DShaderUtilsTextureInput *>()) {
1820 if (QQuick3DShaderUtilsTextureInput *texture = property.read(
this).value<QQuick3DShaderUtilsTextureInput *>())
1821 textureProperties.push_back({texture, name});
1823 }
else if (propType == QMetaType(QMetaType::QObjectStar)) {
1824 if (QQuick3DShaderUtilsTextureInput *texture = qobject_cast<QQuick3DShaderUtilsTextureInput *>(propValue.value<QObject *>()))
1825 textureProperties.push_back({texture, name});
1827 const auto type = uniformType(propType);
1828 if (type != QSSGRenderShaderValue::Unknown) {
1829 uniforms.append({ uniformTypeName(propType), name });
1830 customMaterial->m_properties.push_back({ name, propValue, uniformType(propType), i});
1831 if (newBackendNode) {
1833 if (property.hasNotifySignal() && propertyDirtyMethod.isValid())
1834 connect(
this, property.notifySignal(),
this, propertyDirtyMethod);
1844 const auto processTextureProperty = [&](QQuick3DShaderUtilsTextureInput &texture,
const QByteArray &name) {
1845 texture.name = name;
1847 QSSGRenderCustomMaterial::TextureProperty textureData;
1848 textureData.texInput = &texture;
1849 textureData.name = name;
1850 textureData.shaderDataType = QSSGRenderShaderValue::Texture;
1852 if (newBackendNode) {
1853 connect(&texture, &QQuick3DShaderUtilsTextureInput::enabledChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
1854 connect(&texture, &QQuick3DShaderUtilsTextureInput::textureChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
1857 QQuick3DTexture *tex = texture.texture();
1858 if (tex && QQuick3DObjectPrivate::get(tex)->type == QQuick3DObjectPrivate::Type::ImageCube) {
1859 uniforms.append({ QByteArrayLiteral(
"samplerCube"), textureData.name });
1860 }
else if (tex && tex->textureData() && tex->textureData()->depth() > 0) {
1861 uniforms.append({ QByteArrayLiteral(
"sampler3D"), textureData.name });
1862 }
else if (tex && tex->textureProvider() && QQuick3DObjectPrivate::get(tex->textureProvider())->type == QQuick3DObjectPrivate::Type::TextureProvider) {
1863 auto textureProvider =
static_cast<QQuick3DTextureProviderExtension *>(tex->textureProvider());
1864 switch (textureProvider->samplerHint()) {
1865 case QQuick3DTextureProviderExtension::SamplerHint::Sampler2D:
1866 uniforms.append({ QByteArrayLiteral(
"sampler2D"), textureData.name });
1868 case QQuick3DTextureProviderExtension::SamplerHint::Sampler2DArray:
1869 uniforms.append({ QByteArrayLiteral(
"sampler2DArray"), textureData.name });
1871 case QQuick3DTextureProviderExtension::SamplerHint::Sampler3D:
1872 uniforms.append({ QByteArrayLiteral(
"sampler3D"), textureData.name });
1874 case QQuick3DTextureProviderExtension::SamplerHint::SamplerCube:
1875 uniforms.append({ QByteArrayLiteral(
"samplerCube"), textureData.name });
1877 case QQuick3DTextureProviderExtension::SamplerHint::SamplerCubeArray:
1878 uniforms.append({ QByteArrayLiteral(
"samplerCubeArray"), textureData.name });
1880 case QQuick3DTextureProviderExtension::SamplerHint::SamplerBuffer:
1881 uniforms.append({ QByteArrayLiteral(
"samplerBuffer"), textureData.name });
1885 uniforms.append({ QByteArrayLiteral(
"sampler2D"), textureData.name });
1888 customMaterial->m_textureProperties.push_back(textureData);
1891 for (
const auto &textureProperty : std::as_const(textureProperties))
1892 processTextureProperty(*textureProperty.first, textureProperty.second);
1894 if (customMaterial->incompleteBuildTimeObject || (m_dirtyAttributes & DynamicPropertiesDirty)) {
1895 const auto names = dynamicPropertyNames();
1896 for (
const auto &name : names) {
1897 QVariant propValue = property(name.constData());
1898 QMetaType propType = propValue.metaType();
1899 if (propType == QMetaType(QMetaType::QVariant))
1900 propType = propValue.metaType();
1902 if (propType.id() >= QMetaType::User) {
1903 if (propType.id() == qMetaTypeId<QQuick3DShaderUtilsTextureInput *>()) {
1904 if (QQuick3DShaderUtilsTextureInput *texture = propValue.value<QQuick3DShaderUtilsTextureInput *>())
1905 textureProperties.push_back({texture, name});
1907 }
else if (propType.id() == QMetaType::QObjectStar) {
1908 if (QQuick3DShaderUtilsTextureInput *texture = qobject_cast<QQuick3DShaderUtilsTextureInput *>(propValue.value<QObject *>()))
1909 textureProperties.push_back({texture, name});
1911 const auto type = uniformType(propType);
1912 if (type != QSSGRenderShaderValue::Unknown) {
1913 uniforms.append({ uniformTypeName(propType), name });
1914 customMaterial->m_properties.push_back({ name, propValue,
1915 uniformType(propType), -1 });
1920 qWarning(
"No known uniform conversion found for custom material property %s. Skipping", name.constData());
1925 for (
const auto &property : std::as_const(textureProperties))
1926 processTextureProperty(*property.first, property.second);
1929 const QQmlContext *context = qmlContext(
this);
1931 QByteArray fragment;
1932 QByteArray vertexProcessed[2];
1933 QSSGCustomShaderMetaData vertexMeta;
1934 QByteArray fragmentProcessed[2];
1935 QSSGCustomShaderMetaData fragmentMeta;
1936 QByteArray shaderPathKey(
"custom material --");
1938 customMaterial->m_renderFlags = {};
1940 if (!m_vertexShader.isEmpty())
1941 vertex = QSSGShaderUtils::resolveShader(m_vertexShader, context, shaderPathKey);
1942 else if (!m_vertexShaderCode.isEmpty())
1943 vertex = m_vertexShaderCode.toLatin1();
1945 if (!m_fragmentShader.isEmpty())
1946 fragment = QSSGShaderUtils::resolveShader(m_fragmentShader, context, shaderPathKey);
1947 else if (!m_fragmentShaderCode.isEmpty())
1948 fragment = m_fragmentShaderCode.toLatin1();
1955 vertexProcessed[QSSGRenderCustomMaterial::RegularShaderPathKeyIndex] =
1956 prepareCustomShader(customMaterial, uniforms, vertex, QSSGShaderCache::ShaderType::Vertex, vertexMeta,
false);
1957 fragmentProcessed[QSSGRenderCustomMaterial::RegularShaderPathKeyIndex] =
1958 prepareCustomShader(customMaterial, uniforms, fragment, QSSGShaderCache::ShaderType::Fragment, fragmentMeta,
false);
1960 vertexProcessed[QSSGRenderCustomMaterial::MultiViewShaderPathKeyIndex] =
1961 prepareCustomShader(customMaterial, uniforms, vertex, QSSGShaderCache::ShaderType::Vertex, vertexMeta,
true);
1962 fragmentProcessed[QSSGRenderCustomMaterial::MultiViewShaderPathKeyIndex] =
1963 prepareCustomShader(customMaterial, uniforms, fragment, QSSGShaderCache::ShaderType::Fragment, fragmentMeta,
true);
1970 customMaterial->m_customShaderPresence = {};
1971 for (
int i : { QSSGRenderCustomMaterial::RegularShaderPathKeyIndex, QSSGRenderCustomMaterial::MultiViewShaderPathKeyIndex }) {
1972 if (vertexProcessed[i].isEmpty() && fragmentProcessed[i].isEmpty())
1975 const QByteArray key = shaderPathKey +
':' + QCryptographicHash::hash(QByteArray(vertexProcessed[i] + fragmentProcessed[i]), QCryptographicHash::Algorithm::Sha1).toHex();
1977 customMaterial->m_shaderPathKey[i] = key;
1978 if (!vertexProcessed[i].isEmpty()) {
1979 customMaterial->m_customShaderPresence.setFlag(QSSGRenderCustomMaterial::CustomShaderPresenceFlag::Vertex);
1980 renderContext->shaderLibraryManager()->setShaderSource(key, QSSGShaderCache::ShaderType::Vertex, vertexProcessed[i], vertexMeta);
1982 if (!fragmentProcessed[i].isEmpty()) {
1983 customMaterial->m_customShaderPresence.setFlag(QSSGRenderCustomMaterial::CustomShaderPresenceFlag::Fragment);
1984 renderContext->shaderLibraryManager()->setShaderSource(key, QSSGShaderCache::ShaderType::Fragment, fragmentProcessed[i], fragmentMeta);
1989 customMaterial->setAlwaysDirty(m_alwaysDirty);
1990 if (m_srcBlend != BlendMode::NoBlend && m_dstBlend != BlendMode::NoBlend) {
1991 customMaterial->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Blending,
true);
1992 customMaterial->m_srcBlend = toRhiBlendFactor(m_srcBlend);
1993 customMaterial->m_dstBlend = toRhiBlendFactor(m_dstBlend);
1995 if (m_srcAlphaBlend != BlendMode::NoBlend && m_dstAlphaBlend != BlendMode::NoBlend) {
1996 customMaterial->m_srcAlphaBlend = toRhiBlendFactor(m_srcAlphaBlend);
1997 customMaterial->m_dstAlphaBlend = toRhiBlendFactor(m_dstAlphaBlend);
1999 customMaterial->m_srcAlphaBlend = customMaterial->m_srcBlend;
2000 customMaterial->m_dstAlphaBlend = customMaterial->m_dstBlend;
2003 customMaterial->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Blending,
false);
2005 customMaterial->m_lineWidth = m_lineWidth;
2007 QQuick3DMaterial::updateSpatialNode(customMaterial);
2009 if (m_dirtyAttributes & Dirty::PropertyDirty) {
2010 for (
auto &prop : customMaterial->m_properties) {
2011 auto p = metaObject()->property(prop.pid);
2012 if (Q_LIKELY(p.isValid()))
2013 prop.value = p.read(
this);
2017 if (m_dirtyAttributes & Dirty::TextureDirty) {
2018 for (QSSGRenderCustomMaterial::TextureProperty &prop : customMaterial->m_textureProperties) {
2019 QQuick3DTexture *tex = prop.texInput->texture();
2021 if (prop.texInput->enabled)
2022 prop.texImage = tex->getRenderImage();
2024 prop.texImage =
nullptr;
2025 prop.minFilterType = tex->minFilter() == QQuick3DTexture::Nearest ? QSSGRenderTextureFilterOp::Nearest
2026 : QSSGRenderTextureFilterOp::Linear;
2027 prop.magFilterType = tex->magFilter() == QQuick3DTexture::Nearest ? QSSGRenderTextureFilterOp::Nearest
2028 : QSSGRenderTextureFilterOp::Linear;
2029 prop.mipFilterType = tex->generateMipmaps() ? (tex->mipFilter() == QQuick3DTexture::Nearest ? QSSGRenderTextureFilterOp::Nearest
2030 : QSSGRenderTextureFilterOp::Linear)
2031 : QSSGRenderTextureFilterOp::None;
2032 prop.horizontalClampType = tex->horizontalTiling() == QQuick3DTexture::Repeat ? QSSGRenderTextureCoordOp::Repeat
2033 : (tex->horizontalTiling() == QQuick3DTexture::ClampToEdge) ? QSSGRenderTextureCoordOp::ClampToEdge
2034 : QSSGRenderTextureCoordOp::MirroredRepeat;
2035 prop.verticalClampType = tex->verticalTiling() == QQuick3DTexture::Repeat ? QSSGRenderTextureCoordOp::Repeat
2036 : (tex->verticalTiling() == QQuick3DTexture::ClampToEdge) ? QSSGRenderTextureCoordOp::ClampToEdge
2037 : QSSGRenderTextureCoordOp::MirroredRepeat;
2038 prop.zClampType = tex->depthTiling() == QQuick3DTexture::Repeat ? QSSGRenderTextureCoordOp::Repeat
2039 : (tex->depthTiling() == QQuick3DTexture::ClampToEdge) ? QSSGRenderTextureCoordOp::ClampToEdge
2040 : QSSGRenderTextureCoordOp::MirroredRepeat;
2042 prop.texImage =
nullptr;
2045 if (tex != prop.lastConnectedTexture) {
2046 prop.lastConnectedTexture = tex;
2047 disconnect(prop.minFilterChangedConn);
2048 disconnect(prop.magFilterChangedConn);
2049 disconnect(prop.mipFilterChangedConn);
2050 disconnect(prop.horizontalTilingChangedConn);
2051 disconnect(prop.verticalTilingChangedConn);
2052 disconnect(prop.depthTilingChangedConn);
2054 prop.minFilterChangedConn = connect(tex, &QQuick3DTexture::minFilterChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
2055 prop.magFilterChangedConn = connect(tex, &QQuick3DTexture::magFilterChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
2056 prop.mipFilterChangedConn = connect(tex, &QQuick3DTexture::mipFilterChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
2057 prop.horizontalTilingChangedConn = connect(tex, &QQuick3DTexture::horizontalTilingChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
2058 prop.verticalTilingChangedConn = connect(tex, &QQuick3DTexture::verticalTilingChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
2059 prop.depthTilingChangedConn = connect(tex, &QQuick3DTexture::depthTilingChanged,
this, &QQuick3DCustomMaterial::onTextureDirty);
2065 m_dirtyAttributes = 0;
2067 return customMaterial;