blob: 36ea956ccb134e8776909568035e566ae675059e [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Quick 3D.
**
** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qquick3dmaterial_p.h"
#include "qquick3dobject_p_p.h"
#include "qquick3dscenemanager_p.h"
#include <QtQuick3DRuntimeRender/private/qssgrenderdefaultmaterial_p.h>
#include <QtQuick3DRuntimeRender/private/qssgrendercustommaterial_p.h>
QT_BEGIN_NAMESPACE
/*!
\qmltype Material
\inherits Object3D
\inqmlmodule QtQuick3D
\brief Lets you define material for the 3D item.
*/
/*!
\qmlproperty Texture Material::lightmapIndirect
This property defines a baked lightmap Texture containing indirect lighting
information for this material.
\note This feature is still in development so there is currently no way to
bake lights. The texture currently still uses the UV1 coordinates which is
going to change later to UV2.
*/
/*!
\qmlproperty Texture Material::lightmapRadiosity
This property defines a baked lightmap Texture containing direct lighting
information for this material.
\note This feature is still in development so there is currently no way to
bake lights. The texture currently still uses the UV1 coordinates which is
going to change later to UV2.
*/
/*!
\qmlproperty Texture Material::lightmapShadow
This property defines a baked lightmap Texture containing shadowing
information for this material.
\note This feature is still in development so there is currently no way to
bake lights. The texture currently still uses the UV1 coordinates which is
going to change later to UV2.
*/
/*!
\qmlproperty Texture Material::lightProbe
This property defines a Texture for overriding or setting an image based
lighting Texture for use with this material.
\sa SceneEnvironment::lightProbe
*/
/*!
\qmlproperty Texture Material::displacementMap
This property defines grayscale image used to offset the vertices of
geometry across the surface of the material. Brighter pixels indicate raised
regions.
\note Displacement maps require vertices to offset. I.e. the result will be
more accurate on a high poly model than on a low poly model.
\note Displacement maps do not affect the normals of your geometry. To look
correct with lighting or reflections you will likely want to also add a
matching bump map or normal map to your material.
*/
/*!
\qmlproperty real Material::displacementAmount
This property controls the offset amount for the Material::displacmentMap.
*/
/*!
\qmlproperty enumeration Material::cullingMode
This property defines whether culling is enabled and which mode is actually enabled.
Frontface means polygons' winding is clockwise in window coordinates and Backface means otherwise.
\value Material.BackfaceCulling Default; Backface will not be rendered.
\value Material.FrontfaceCulling Frontface will not be rendered.
\value Material.FrontAndBackfaceCulling Both front and back faces will not be rendered.
\value Material.DisableCulling Both faces will be rendered.
*/
QQuick3DMaterial::QQuick3DMaterial() {}
QQuick3DMaterial::~QQuick3DMaterial()
{
for (auto connection : m_connections)
disconnect(connection);
}
static void updatePropertyListener(QQuick3DObject *newO, QQuick3DObject *oldO, QQuick3DSceneManager *window, QHash<QObject*, QMetaObject::Connection> &connections, std::function<void(QQuick3DObject *o)> callFn) {
// disconnect previous destruction listern
if (oldO) {
if (window)
QQuick3DObjectPrivate::get(oldO)->derefSceneManager();
auto connection = connections.find(oldO);
if (connection != connections.end()) {
QObject::disconnect(connection.value());
connections.erase(connection);
}
}
// listen for new map's destruction
if (newO) {
if (window)
QQuick3DObjectPrivate::get(newO)->refSceneManager(window);
auto connection = QObject::connect(newO, &QObject::destroyed, [callFn](){
callFn(nullptr);
});
connections.insert(newO, connection);
}
}
QQuick3DTexture *QQuick3DMaterial::lightmapIndirect() const
{
return m_lightmapIndirect;
}
QQuick3DTexture *QQuick3DMaterial::lightmapRadiosity() const
{
return m_lightmapRadiosity;
}
QQuick3DTexture *QQuick3DMaterial::lightmapShadow() const
{
return m_lightmapShadow;
}
QQuick3DTexture *QQuick3DMaterial::lightProbe() const
{
return m_iblProbe;
}
QQuick3DTexture *QQuick3DMaterial::displacementMap() const
{
return m_displacementMap;
}
float QQuick3DMaterial::displacementAmount() const
{
return m_displacementAmount;
}
QQuick3DMaterial::CullMode QQuick3DMaterial::cullingMode() const
{
return m_cullingMode;
}
void QQuick3DMaterial::setLightmapIndirect(QQuick3DTexture *lightmapIndirect)
{
if (m_lightmapIndirect == lightmapIndirect)
return;
updatePropertyListener(lightmapIndirect, m_lightmapIndirect, sceneManager(), m_connections, [this](QQuick3DObject *n) {
setLightmapIndirect(qobject_cast<QQuick3DTexture *>(n));
});
m_lightmapIndirect = lightmapIndirect;
emit lightmapIndirectChanged(m_lightmapIndirect);
update();
}
void QQuick3DMaterial::setLightmapRadiosity(QQuick3DTexture *lightmapRadiosity)
{
if (m_lightmapRadiosity == lightmapRadiosity)
return;
updatePropertyListener(lightmapRadiosity, m_lightmapRadiosity, sceneManager(), m_connections, [this](QQuick3DObject *n) {
setLightmapRadiosity(qobject_cast<QQuick3DTexture *>(n));
});
m_lightmapRadiosity = lightmapRadiosity;
emit lightmapRadiosityChanged(m_lightmapRadiosity);
update();
}
void QQuick3DMaterial::setLightmapShadow(QQuick3DTexture *lightmapShadow)
{
if (m_lightmapShadow == lightmapShadow)
return;
updatePropertyListener(lightmapShadow, m_lightmapShadow, sceneManager(), m_connections, [this](QQuick3DObject *n) {
setLightmapShadow(qobject_cast<QQuick3DTexture *>(n));
});
m_lightmapShadow = lightmapShadow;
emit lightmapShadowChanged(m_lightmapShadow);
update();
}
void QQuick3DMaterial::setLightProbe(QQuick3DTexture *iblProbe)
{
if (m_iblProbe == iblProbe)
return;
updatePropertyListener(iblProbe, m_iblProbe, sceneManager(), m_connections, [this](QQuick3DObject *n) {
setLightProbe(qobject_cast<QQuick3DTexture *>(n));
});
m_iblProbe = iblProbe;
emit lightProbeChanged(m_iblProbe);
update();
}
void QQuick3DMaterial::setDisplacementMap(QQuick3DTexture *displacementMap)
{
if (m_displacementMap == displacementMap)
return;
updatePropertyListener(displacementMap, m_displacementMap, sceneManager(), m_connections, [this](QQuick3DObject *n) {
setDisplacementMap(qobject_cast<QQuick3DTexture *>(n));
});
m_displacementMap = displacementMap;
emit displacementMapChanged(m_displacementMap);
update();
}
void QQuick3DMaterial::setDisplacementAmount(float displacementAmount)
{
if (qFuzzyCompare(m_displacementAmount, displacementAmount))
return;
m_displacementAmount = displacementAmount;
emit displacementAmountChanged(m_displacementAmount);
update();
}
void QQuick3DMaterial::setCullingMode(QQuick3DMaterial::CullMode cullingMode)
{
if (m_cullingMode == cullingMode)
return;
m_cullingMode = cullingMode;
emit cullingModeChanged(m_cullingMode);
update();
}
QSSGRenderGraphObject *QQuick3DMaterial::updateSpatialNode(QSSGRenderGraphObject *node)
{
if (!node)
return nullptr;
// Set the common properties
if (node->type == QSSGRenderGraphObject::Type::DefaultMaterial || node->type == QSSGRenderGraphObject::Type::PrincipledMaterial) {
auto defaultMaterial = static_cast<QSSGRenderDefaultMaterial *>(node);
if (!m_lightmapIndirect)
defaultMaterial->lightmaps.m_lightmapIndirect = nullptr;
else
defaultMaterial->lightmaps.m_lightmapIndirect = m_lightmapIndirect->getRenderImage();
if (!m_lightmapRadiosity)
defaultMaterial->lightmaps.m_lightmapRadiosity = nullptr;
else
defaultMaterial->lightmaps.m_lightmapRadiosity = m_lightmapRadiosity->getRenderImage();
if (!m_lightmapShadow)
defaultMaterial->lightmaps.m_lightmapShadow = nullptr;
else
defaultMaterial->lightmaps.m_lightmapShadow = m_lightmapShadow->getRenderImage();
if (!m_iblProbe)
defaultMaterial->iblProbe = nullptr;
else
defaultMaterial->iblProbe = m_iblProbe->getRenderImage();
if (!m_displacementMap)
defaultMaterial->displacementMap = nullptr;
else
defaultMaterial->displacementMap = m_displacementMap->getRenderImage();
defaultMaterial->displaceAmount = m_displacementAmount;
defaultMaterial->cullingMode = QSSGCullFaceMode(m_cullingMode);
node = defaultMaterial;
} else if (node->type == QSSGRenderGraphObject::Type::CustomMaterial) {
auto customMaterial = static_cast<QSSGRenderCustomMaterial *>(node);
if (!m_lightmapIndirect)
customMaterial->m_lightmaps.m_lightmapIndirect = nullptr;
else
customMaterial->m_lightmaps.m_lightmapIndirect = m_lightmapIndirect->getRenderImage();
if (!m_lightmapRadiosity)
customMaterial->m_lightmaps.m_lightmapRadiosity = nullptr;
else
customMaterial->m_lightmaps.m_lightmapRadiosity = m_lightmapRadiosity->getRenderImage();
if (!m_lightmapShadow)
customMaterial->m_lightmaps.m_lightmapShadow = nullptr;
else
customMaterial->m_lightmaps.m_lightmapShadow = m_lightmapShadow->getRenderImage();
if (!m_iblProbe)
customMaterial->m_iblProbe = nullptr;
else
customMaterial->m_iblProbe = m_iblProbe->getRenderImage();
if (!m_displacementMap)
customMaterial->m_displacementMap = nullptr;
else
customMaterial->m_displacementMap = m_displacementMap->getRenderImage();
customMaterial->m_displaceAmount = m_displacementAmount;
customMaterial->cullingMode = QSSGCullFaceMode(m_cullingMode);
node = customMaterial;
}
return node;
}
void QQuick3DMaterial::itemChange(QQuick3DObject::ItemChange change, const QQuick3DObject::ItemChangeData &value)
{
if (change == QQuick3DObject::ItemSceneChange)
updateSceneManager(value.sceneManager);
}
void QQuick3DMaterial::setDynamicTextureMap(QQuick3DTexture *textureMap)
{
if (!textureMap)
return;
auto it = m_dynamicTextureMaps.begin();
const auto end = m_dynamicTextureMaps.end();
for (; it != end; ++it) {
if (*it == textureMap)
break;
}
if (it != end)
return;
updatePropertyListener(textureMap, nullptr, sceneManager(), m_connections, [this](QQuick3DObject *n) {
setDynamicTextureMap(qobject_cast<QQuick3DTexture *>(n));
});
m_dynamicTextureMaps.push_back(textureMap);
update();
}
void QQuick3DMaterial::updateSceneManager(QQuick3DSceneManager *sceneManager)
{
if (sceneManager) {
if (m_lightmapIndirect) {
QQuick3DObjectPrivate::get(m_lightmapIndirect)->refSceneManager(sceneManager);
}
if (m_lightmapRadiosity) {
QQuick3DObjectPrivate::get(m_lightmapRadiosity)->refSceneManager(sceneManager);
}
if (m_lightmapShadow) {
QQuick3DObjectPrivate::get(m_lightmapShadow)->refSceneManager(sceneManager);
}
if (m_iblProbe) {
QQuick3DObjectPrivate::get(m_iblProbe)->refSceneManager(sceneManager);
}
if (m_displacementMap) {
QQuick3DObjectPrivate::get(m_displacementMap)->refSceneManager(sceneManager);
}
for (auto it : m_dynamicTextureMaps)
QQuick3DObjectPrivate::get(it)->refSceneManager(sceneManager);
} else {
if (m_lightmapIndirect) {
QQuick3DObjectPrivate::get(m_lightmapIndirect)->derefSceneManager();
}
if (m_lightmapRadiosity) {
QQuick3DObjectPrivate::get(m_lightmapRadiosity)->derefSceneManager();
}
if (m_lightmapShadow) {
QQuick3DObjectPrivate::get(m_lightmapShadow)->derefSceneManager();
}
if (m_iblProbe) {
QQuick3DObjectPrivate::get(m_iblProbe)->derefSceneManager();
}
if (m_displacementMap) {
QQuick3DObjectPrivate::get(m_displacementMap)->derefSceneManager();
}
for (auto it : m_dynamicTextureMaps)
QQuick3DObjectPrivate::get(it)->derefSceneManager();
}
}
QT_END_NAMESPACE