Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquick3dcustommaterial.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
5#include <QtQuick3DRuntimeRender/private/qssgrendercustommaterial_p.h>
6#include <ssg/qssgrendercontextcore.h>
7#include <QtQuick3DRuntimeRender/private/qssgshadermaterialadapter_p.h>
8#include <QtQuick/QQuickWindow>
9
10#include "qquick3dobject_p.h"
11#include "qquick3dviewport_p.h"
13
15
1382{
1383 switch (mode) {
1414 default:
1416 }
1417}
1418
1423
1425
1430
1432{
1433 if (m_srcBlend == mode)
1434 return;
1435
1436 m_srcBlend = mode;
1437 update();
1439}
1440
1445
1447{
1448 if (m_dstBlend == mode)
1449 return;
1450
1451 m_dstBlend = mode;
1452 update();
1454}
1455
1456QQuick3DCustomMaterial::BlendMode QQuick3DCustomMaterial::srcAlphaBlend() const
1457{
1458 return m_srcAlphaBlend;
1459}
1460
1461void QQuick3DCustomMaterial::setSrcAlphaBlend(QQuick3DCustomMaterial::BlendMode mode)
1462{
1463 if (m_srcAlphaBlend == mode)
1464 return;
1465
1466 m_srcAlphaBlend = mode;
1467 update();
1468 emit srcAlphaBlendChanged();
1469}
1470
1471QQuick3DCustomMaterial::BlendMode QQuick3DCustomMaterial::dstAlphaBlend() const
1472{
1473 return m_dstAlphaBlend;
1474}
1475
1476void QQuick3DCustomMaterial::setDstAlphaBlend(QQuick3DCustomMaterial::BlendMode mode)
1477{
1478 if (m_dstAlphaBlend == mode)
1479 return;
1480
1481 m_dstAlphaBlend = mode;
1482 update();
1483 emit dstAlphaBlendChanged();
1484}
1485
1490
1492{
1493 if (m_shadingMode == mode)
1494 return;
1495
1496 m_shadingMode = mode;
1499}
1500
1502{
1503 return m_vertexShader;
1504}
1505
1507{
1508 if (m_vertexShader == url)
1509 return;
1510
1511 m_vertexShader = url;
1514}
1515
1517{
1518 return m_fragmentShader;
1519}
1520
1522{
1523 if (m_fragmentShader == url)
1524 return;
1525
1526 m_fragmentShader = url;
1529}
1530
1532{
1533 return m_lineWidth;
1534}
1535
1537{
1538 if (qFuzzyCompare(m_lineWidth, width))
1539 return;
1540 m_lineWidth = width;
1541 update();
1543}
1544
1550
1552{
1553 if (!(that.m_dirtyAttributes & quint32(type))) {
1554 that.m_dirtyAttributes |= quint32(type);
1555 that.update();
1556 }
1557}
1558
1560{
1561 return m_alwaysDirty;
1562}
1563
1565{
1566 if (m_alwaysDirty == alwaysDirty)
1567 return;
1568
1569 m_alwaysDirty = alwaysDirty;
1570 update();
1572}
1573
1575{
1600
1601 // vertex only
1604
1605 // fragment only
1607 material->m_usesSharedVariables = true;
1608}
1609
1612 const QByteArray &snippet,
1613 QSSGShaderCache::ShaderType shaderType,
1615 bool multiViewCompatible)
1616{
1617 if (snippet.isEmpty())
1618 return QByteArray();
1619
1620 QByteArray sourceCode = snippet;
1623 sourceCode,
1624 shaderType,
1625 uniforms,
1626 {},
1627 {},
1628 multiViewCompatible);
1629 sourceCode = result.first;
1630 sourceCode.append(buf);
1631 meta = result.second;
1632 setCustomMaterialFlagsFromShader(customMaterial, meta);
1633 return sourceCode;
1634}
1635
1637{
1638 using namespace QSSGShaderUtils;
1639
1640 const auto &renderContext = QQuick3DObjectPrivate::get(this)->sceneManager->wattached->rci();
1641 if (!renderContext) {
1642 qWarning("QQuick3DCustomMaterial: No render context interface?");
1643 return nullptr;
1644 }
1645
1647 QSSGRenderCustomMaterial *customMaterial = static_cast<QSSGRenderCustomMaterial *>(node);
1648 bool newBackendNode = false;
1649 bool shadersMayChange = false;
1650 if (!customMaterial) {
1651 customMaterial = new QSSGRenderCustomMaterial;
1652 newBackendNode = true;
1653 } else if (m_dirtyAttributes & ShaderSettingsDirty) {
1654 shadersMayChange = true;
1655 }
1656
1657 if (newBackendNode || shadersMayChange) {
1658 markAllDirty();
1659
1660 customMaterial->m_properties.clear();
1661 customMaterial->m_textureProperties.clear();
1662
1663 customMaterial->m_shadingMode = QSSGRenderCustomMaterial::ShadingMode(int(m_shadingMode));
1664
1665 QMetaMethod propertyDirtyMethod;
1666 const int idx = metaObject()->indexOfSlot("onPropertyDirty()");
1667 if (idx != -1)
1668 propertyDirtyMethod = metaObject()->method(idx);
1669
1670 const int propCount = metaObject()->propertyCount();
1671 int propOffset = metaObject()->propertyOffset();
1672
1673 // Custom materials can have multilayered inheritance structure, so find the actual propOffset
1674 const QMetaObject *superClass = metaObject()->superClass();
1675 while (superClass && qstrcmp(superClass->className(), "QQuick3DCustomMaterial") != 0) {
1676 propOffset = superClass->propertyOffset();
1677 superClass = superClass->superClass();
1678 }
1679
1680 using TextureInputProperty = QPair<QQuick3DShaderUtilsTextureInput *, const char *>;
1681 QVector<TextureInputProperty> textureProperties; // We'll deal with these later
1682
1683 for (int i = propOffset; i != propCount; ++i) {
1684 const auto property = metaObject()->property(i);
1685 if (Q_UNLIKELY(!property.isValid()))
1686 continue;
1687
1688 const auto name = property.name();
1689 QMetaType propType = property.metaType();
1690 QVariant propValue = property.read(this);
1691 if (propType == QMetaType(QMetaType::QVariant))
1692 propType = propValue.metaType();
1693
1694 if (propType.id() >= QMetaType::User) {
1695 if (propType.id() == qMetaTypeId<QQuick3DShaderUtilsTextureInput *>()) {
1697 textureProperties.push_back({texture, name});
1698 }
1699 } else if (propType == QMetaType(QMetaType::QObjectStar)) {
1700 if (QQuick3DShaderUtilsTextureInput *texture = qobject_cast<QQuick3DShaderUtilsTextureInput *>(propValue.value<QObject *>()))
1701 textureProperties.push_back({texture, name});
1702 } else {
1703 const auto type = uniformType(propType);
1705 uniforms.append({ uniformTypeName(propType), name });
1706 customMaterial->m_properties.push_back({ name, propValue, uniformType(propType), i});
1707 if (newBackendNode) {
1708 // Track the property changes
1709 if (property.hasNotifySignal() && propertyDirtyMethod.isValid())
1710 connect(this, property.notifySignal(), this, propertyDirtyMethod);
1711 } // else already connected
1712 } else {
1713 // ### figure out how _not_ to warn when there are no dynamic
1714 // properties defined (because warnings like Blah blah objectName etc. are not helpful)
1715 //qWarning("No known uniform conversion found for effect property %s. Skipping", property.name());
1716 }
1717 }
1718 }
1719
1720 const auto processTextureProperty = [&](QQuick3DShaderUtilsTextureInput &texture, const QByteArray &name) {
1721 texture.name = name;
1722
1724 textureData.texInput = &texture;
1725 textureData.name = name;
1727
1728 if (newBackendNode) {
1729 connect(&texture, &QQuick3DShaderUtilsTextureInput::enabledChanged, this, &QQuick3DCustomMaterial::onTextureDirty);
1730 connect(&texture, &QQuick3DShaderUtilsTextureInput::textureChanged, this, &QQuick3DCustomMaterial::onTextureDirty);
1731 } // else already connected
1732
1733 QQuick3DTexture *tex = texture.texture(); // may be null if the TextureInput has no 'texture' set
1734 if (tex && QQuick3DObjectPrivate::get(tex)->type == QQuick3DObjectPrivate::Type::ImageCube)
1735 uniforms.append({ QByteArrayLiteral("samplerCube"), textureData.name });
1736 else if (tex && tex->textureData() && tex->textureData()->depth() > 0)
1737 uniforms.append({ QByteArrayLiteral("sampler3D"), textureData.name });
1738 else
1739 uniforms.append({ QByteArrayLiteral("sampler2D"), textureData.name });
1740
1741 customMaterial->m_textureProperties.push_back(textureData);
1742 };
1743
1744 for (const auto &textureProperty : std::as_const(textureProperties))
1745 processTextureProperty(*textureProperty.first, textureProperty.second);
1746
1747 if (customMaterial->incompleteBuildTimeObject || (m_dirtyAttributes & DynamicPropertiesDirty)) { // This object came from the shadergen tool
1748 const auto names = dynamicPropertyNames();
1749 for (const auto &name : names) {
1750 QVariant propValue = property(name.constData());
1751 QMetaType propType = propValue.metaType();
1752 if (propType == QMetaType(QMetaType::QVariant))
1753 propType = propValue.metaType();
1754
1755 if (propType.id() >= QMetaType::User) {
1756 if (propType.id() == qMetaTypeId<QQuick3DShaderUtilsTextureInput *>()) {
1758 textureProperties.push_back({texture, name});
1759 }
1760 } else if (propType.id() == QMetaType::QObjectStar) {
1761 if (QQuick3DShaderUtilsTextureInput *texture = qobject_cast<QQuick3DShaderUtilsTextureInput *>(propValue.value<QObject *>()))
1762 textureProperties.push_back({texture, name});
1763 } else {
1764 const auto type = uniformType(propType);
1766 uniforms.append({ uniformTypeName(propType), name });
1767 customMaterial->m_properties.push_back({ name, propValue,
1768 uniformType(propType), -1 /* aka. dynamic property */});
1769 // We don't need to track property changes
1770 } else {
1771 // ### figure out how _not_ to warn when there are no dynamic
1772 // properties defined (because warnings like Blah blah objectName etc. are not helpful)
1773 qWarning("No known uniform conversion found for custom material property %s. Skipping", name.constData());
1774 }
1775 }
1776 }
1777
1778 for (const auto &property : std::as_const(textureProperties))
1779 processTextureProperty(*property.first, property.second);
1780 }
1781
1782 const QQmlContext *context = qmlContext(this);
1783 QByteArray vertex;
1784 QByteArray fragment;
1785 QByteArray vertexProcessed[2];
1786 QSSGCustomShaderMetaData vertexMeta;
1787 QByteArray fragmentProcessed[2];
1788 QSSGCustomShaderMetaData fragmentMeta;
1789 QByteArray shaderPathKey("custom material --");
1790
1791 customMaterial->m_renderFlags = {};
1792
1793 if (!m_vertexShader.isEmpty())
1794 vertex = QSSGShaderUtils::resolveShader(m_vertexShader, context, shaderPathKey);
1795
1796 if (!m_fragmentShader.isEmpty())
1797 fragment = QSSGShaderUtils::resolveShader(m_fragmentShader, context, shaderPathKey);
1798
1799 // Multiview is a problem, because we will get a dedicated snippet after
1800 // preparation (the one that has [qt_viewIndex] added where it matters).
1801 // But at least the view count plays no role here on this level. So one
1802 // normal and one multiview "variant" is good enough.
1803
1805 prepareCustomShader(customMaterial, uniforms, vertex, QSSGShaderCache::ShaderType::Vertex, vertexMeta, false);
1807 prepareCustomShader(customMaterial, uniforms, fragment, QSSGShaderCache::ShaderType::Fragment, fragmentMeta, false);
1808
1810 prepareCustomShader(customMaterial, uniforms, vertex, QSSGShaderCache::ShaderType::Vertex, vertexMeta, true);
1812 prepareCustomShader(customMaterial, uniforms, fragment, QSSGShaderCache::ShaderType::Fragment, fragmentMeta, true);
1813
1814 // At this point we have snippets that look like this:
1815 // - the original code, with VARYING ... lines removed
1816 // - followed by QQ3D_SHADER_META block for uniforms
1817 // - followed by QQ3D_SHADER_META block for inputs/outputs
1818
1819 customMaterial->m_customShaderPresence = {};
1821 if (vertexProcessed[i].isEmpty() && fragmentProcessed[i].isEmpty())
1822 continue;
1823
1824 const QByteArray key = shaderPathKey + ':' + QCryptographicHash::hash(QByteArray(vertexProcessed[i] + fragmentProcessed[i]), QCryptographicHash::Algorithm::Sha1).toHex();
1825 // the processed snippet code is different for regular and multiview, so 'key' reflects that already
1826 customMaterial->m_shaderPathKey[i] = key;
1827 if (!vertexProcessed[i].isEmpty()) {
1828 customMaterial->m_customShaderPresence.setFlag(QSSGRenderCustomMaterial::CustomShaderPresenceFlag::Vertex);
1829 renderContext->shaderLibraryManager()->setShaderSource(key, QSSGShaderCache::ShaderType::Vertex, vertexProcessed[i], vertexMeta);
1830 }
1831 if (!fragmentProcessed[i].isEmpty()) {
1832 customMaterial->m_customShaderPresence.setFlag(QSSGRenderCustomMaterial::CustomShaderPresenceFlag::Fragment);
1833 renderContext->shaderLibraryManager()->setShaderSource(key, QSSGShaderCache::ShaderType::Fragment, fragmentProcessed[i], fragmentMeta);
1834 }
1835 }
1836 }
1837
1838 customMaterial->setAlwaysDirty(m_alwaysDirty);
1839 if (m_srcBlend != BlendMode::NoBlend && m_dstBlend != BlendMode::NoBlend) { // both must be set to something other than NoBlend
1840 customMaterial->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Blending, true);
1841 customMaterial->m_srcBlend = toRhiBlendFactor(m_srcBlend);
1842 customMaterial->m_dstBlend = toRhiBlendFactor(m_dstBlend);
1843 // alpha blending is only active if rgb blending is
1844 if (m_srcAlphaBlend != BlendMode::NoBlend && m_dstAlphaBlend != BlendMode::NoBlend) {
1845 customMaterial->m_srcAlphaBlend = toRhiBlendFactor(m_srcAlphaBlend);
1846 customMaterial->m_dstAlphaBlend = toRhiBlendFactor(m_dstAlphaBlend);
1847 } else {
1848 customMaterial->m_srcAlphaBlend = customMaterial->m_srcBlend;
1849 customMaterial->m_dstAlphaBlend = customMaterial->m_dstBlend;
1850 }
1851 } else {
1852 customMaterial->m_renderFlags.setFlag(QSSGRenderCustomMaterial::RenderFlag::Blending, false);
1853 }
1854 customMaterial->m_lineWidth = m_lineWidth;
1855
1857
1858 if (m_dirtyAttributes & Dirty::PropertyDirty) {
1859 for (auto &prop : customMaterial->m_properties) {
1860 auto p = metaObject()->property(prop.pid);
1861 if (Q_LIKELY(p.isValid()))
1862 prop.value = p.read(this);
1863 }
1864 }
1865
1866 if (m_dirtyAttributes & Dirty::TextureDirty) {
1867 for (QSSGRenderCustomMaterial::TextureProperty &prop : customMaterial->m_textureProperties) {
1868 QQuick3DTexture *tex = prop.texInput->texture();
1869 if (tex) {
1870 if (prop.texInput->enabled)
1871 prop.texImage = tex->getRenderImage();
1872 else
1873 prop.texImage = nullptr;
1887 prop.zClampType = tex->depthTiling() == QQuick3DTexture::Repeat ? QSSGRenderTextureCoordOp::Repeat
1890 } else {
1891 prop.texImage = nullptr;
1892 }
1893
1894 if (tex != prop.lastConnectedTexture) {
1895 prop.lastConnectedTexture = tex;
1896 disconnect(prop.minFilterChangedConn);
1897 disconnect(prop.magFilterChangedConn);
1898 disconnect(prop.mipFilterChangedConn);
1899 disconnect(prop.horizontalTilingChangedConn);
1900 disconnect(prop.verticalTilingChangedConn);
1901 disconnect(prop.depthTilingChangedConn);
1902 if (tex) {
1903 prop.minFilterChangedConn = connect(tex, &QQuick3DTexture::minFilterChanged, this, &QQuick3DCustomMaterial::onTextureDirty);
1904 prop.magFilterChangedConn = connect(tex, &QQuick3DTexture::magFilterChanged, this, &QQuick3DCustomMaterial::onTextureDirty);
1905 prop.mipFilterChangedConn = connect(tex, &QQuick3DTexture::mipFilterChanged, this, &QQuick3DCustomMaterial::onTextureDirty);
1906 prop.horizontalTilingChangedConn = connect(tex, &QQuick3DTexture::horizontalTilingChanged, this, &QQuick3DCustomMaterial::onTextureDirty);
1907 prop.verticalTilingChangedConn = connect(tex, &QQuick3DTexture::verticalTilingChanged, this, &QQuick3DCustomMaterial::onTextureDirty);
1908 prop.depthTilingChangedConn = connect(tex, &QQuick3DTexture::depthTilingChanged, this, &QQuick3DCustomMaterial::onTextureDirty);
1909 }
1910 }
1911 }
1912 }
1913
1914 m_dirtyAttributes = 0;
1915
1916 return customMaterial;
1917}
1918
1919void QQuick3DCustomMaterial::itemChange(QQuick3DObject::ItemChange change, const QQuick3DObject::ItemChangeData &value)
1920{
1922 if (change == QQuick3DObject::ItemSceneChange) {
1923 if (auto sceneManager = value.sceneManager) {
1924 for (const auto &it : std::as_const(m_dynamicTextureMaps)) {
1925 if (auto tex = it->texture())
1926 QQuick3DObjectPrivate::refSceneManager(tex, *sceneManager);
1927 }
1928 } else {
1929 for (const auto &it : std::as_const(m_dynamicTextureMaps)) {
1930 if (auto tex = it->texture())
1932 }
1933 }
1934 }
1935}
1936
1937void QQuick3DCustomMaterial::onPropertyDirty()
1938{
1940 update();
1941}
1942
1943void QQuick3DCustomMaterial::onTextureDirty()
1944{
1946 update();
1947}
1948
1949void QQuick3DCustomMaterial::setDynamicTextureMap(QQuick3DShaderUtilsTextureInput *textureMap)
1950{
1951 // There can only be one texture input per property, as the texture input is a combination
1952 // of the texture used and the uniform name!
1953 auto it = m_dynamicTextureMaps.constFind(textureMap);
1954
1955 if (it == m_dynamicTextureMaps.constEnd()) {
1956 // Track the object, if it's destroyed we need to remove it from our table.
1957 connect(textureMap, &QQuick3DShaderUtilsTextureInput::destroyed, this, [this, textureMap]() {
1958 auto it = m_dynamicTextureMaps.constFind(textureMap);
1959 if (it != m_dynamicTextureMaps.constEnd())
1960 m_dynamicTextureMaps.erase(it);
1961 });
1962 m_dynamicTextureMaps.insert(textureMap);
1963
1964 update();
1965 }
1966}
1967
\inmodule QtCore
Definition qbytearray.h:57
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QByteArray first(qsizetype n) const &
Definition qbytearray.h:196
static QByteArray hash(QByteArrayView data, Algorithm method)
Returns the hash of data using method.
\inmodule QtCore
Definition qmetaobject.h:19
const char * name() const
Returns this property's name.
\inmodule QtCore
Definition qmetatype.h:341
int id(int=0) const
Definition qmetatype.h:475
friend class QVariant
Definition qmetatype.h:796
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
QList< QByteArray > dynamicPropertyNames() const
Definition qobject.cpp:4352
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
Q_REVISION(6, 7) void setSrcAlphaBlend(QQuick3DCustomMaterial Q_REVISION(6, 7) void setDstAlphaBlend(QQuick3DCustomMaterial void setAlwaysDirty(bool alwaysDirty)
QQuick3DCustomMaterial(QQuick3DObject *parent=nullptr)
void setFragmentShader(const QUrl &url)
void setSrcBlend(QQuick3DCustomMaterial::BlendMode mode)
static void markDirty(QQuick3DCustomMaterial &that, QQuick3DCustomMaterial::Dirty type)
void itemChange(ItemChange, const ItemChangeData &) override
void setVertexShader(const QUrl &url)
QSSGRenderGraphObject * updateSpatialNode(QSSGRenderGraphObject *node) override
void setDstBlend(QQuick3DCustomMaterial::BlendMode mode)
void setShadingMode(QQuick3DCustomMaterial::ShadingMode mode)
QSSGRenderGraphObject * updateSpatialNode(QSSGRenderGraphObject *node) override
void itemChange(ItemChange, const ItemChangeData &) override
void refSceneManager(QQuick3DSceneManager &)
static QQuick3DObjectPrivate * get(QQuick3DObject *item)
\qmltype Object3D \inqmlmodule QtQuick3D \instantiates QQuick3DObject \inherits QtObject
virtual void markAllDirty()
int depth() const
Returns the depth of the texture data in pixels.
void minFilterChanged()
void horizontalTilingChanged()
void verticalTilingChanged()
void magFilterChanged()
QQuick3DTextureData * textureData
void mipFilterChanged()
QSSGRenderImage * getRenderImage()
TilingMode verticalTiling() const
\qmlproperty enumeration QtQuick3D::Texture::tilingModeVertical
TilingMode horizontalTiling() const
\qmlproperty enumeration QtQuick3D::Texture::tilingModeHorizontal
BlendFactor
Specifies the blend factor.
Definition qrhi.h:1309
const_iterator constEnd() const noexcept
Definition qset.h:143
iterator erase(const_iterator i)
Definition qset.h:145
const_iterator constFind(const T &value) const
Definition qset.h:161
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
Definition qurl.h:94
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
Definition qurl.cpp:1896
void append(const T &t)
\inmodule QtCore
Definition qvariant.h:65
QSet< QString >::iterator it
\qmltype Shader \inherits Object \inqmlmodule QtQuick3D
QByteArray resolveShader(const QUrl &fileUrl, const QQmlContext *context, QByteArray &shaderPathKey)
Combined button and popup list for selecting options.
static void * context
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
Q_CORE_EXPORT int qstrcmp(const char *str1, const char *str2)
#define Q_UNLIKELY(x)
#define Q_LIKELY(x)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
@ None
Definition qhash.cpp:531
#define qWarning
Definition qlogging.h:166
GLenum mode
GLuint64 key
GLint GLsizei width
GLenum type
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum GLuint texture
GLenum GLuint GLsizei propCount
GLuint name
GLuint GLuint * names
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:75
static QByteArray prepareCustomShader(QSSGRenderCustomMaterial *customMaterial, const QSSGShaderCustomMaterialAdapter::StringPairList &uniforms, const QByteArray &snippet, QSSGShaderCache::ShaderType shaderType, QSSGCustomShaderMetaData &meta, bool multiViewCompatible)
static QT_BEGIN_NAMESPACE QRhiGraphicsPipeline::BlendFactor toRhiBlendFactor(QQuick3DCustomMaterial::BlendMode mode)
\qmlproperty url CustomMaterial::vertexShader
static void setCustomMaterialFlagsFromShader(QSSGRenderCustomMaterial *material, const QSSGCustomShaderMetaData &meta)
QSSGRenderTextureCoordOp
QSSGRenderTextureFilterOp
#define emit
unsigned int quint32
Definition qtypes.h:50
const char property[13]
Definition qwizard.cpp:101
QUrl url("example.com")
[constructor-url-reference]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
obj metaObject() -> className()
myObject disconnect()
[26]
\inmodule QtCore
QMetaProperty property(int index) const
Returns the meta-data for the property with the given index.
const char * className() const
Returns the class name.
const QMetaObject * superClass() const
Returns the meta-object of the superclass, or \nullptr if there is no such object.
int propertyOffset() const
Returns the property offset for this class; i.e.
static ShaderCodeAndMetaData prepareCustomShader(QByteArray &dst, const QByteArray &shaderCode, QSSGShaderCache::ShaderType type, const StringPairList &baseUniforms, const StringPairList &baseInputs=StringPairList(), const StringPairList &baseOutputs=StringPairList(), bool multiViewCompatible=false)
Definition moc.h:23