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 File Reference

(c3dbb5b6f6884dfea690d3ad08f7442b7d0084d8)

#include "qquick3dcustommaterial_p.h"
#include <QtQuick3DRuntimeRender/private/qssgrendercustommaterial_p.h>
#include <ssg/qssgrendercontextcore.h>
#include <QtQuick3DRuntimeRender/private/qssgshadermaterialadapter_p.h>
#include <QtQuick/QQuickWindow>
#include "qquick3dobject_p.h"
#include "qquick3dviewport_p.h"
#include "qquick3dscenemanager_p.h"
+ Include dependency graph for qquick3dcustommaterial.cpp:

Go to the source code of this file.

Functions

static QT_BEGIN_NAMESPACE QRhiGraphicsPipeline::BlendFactor toRhiBlendFactor (QQuick3DCustomMaterial::BlendMode mode)
 \qmlproperty url CustomMaterial::vertexShader
 
static void setCustomMaterialFlagsFromShader (QSSGRenderCustomMaterial *material, const QSSGCustomShaderMetaData &meta)
 
static QByteArray prepareCustomShader (QSSGRenderCustomMaterial *customMaterial, const QSSGShaderCustomMaterialAdapter::StringPairList &uniforms, const QByteArray &snippet, QSSGShaderCache::ShaderType shaderType, QSSGCustomShaderMetaData &meta, bool multiViewCompatible)
 

Function Documentation

◆ prepareCustomShader()

static QByteArray prepareCustomShader ( QSSGRenderCustomMaterial * customMaterial,
const QSSGShaderCustomMaterialAdapter::StringPairList & uniforms,
const QByteArray & snippet,
QSSGShaderCache::ShaderType shaderType,
QSSGCustomShaderMetaData & meta,
bool multiViewCompatible )
static

Definition at line 1610 of file qquick3dcustommaterial.cpp.

References QByteArray::append(), QByteArray::first(), QSSGShaderCustomMaterialAdapter::prepareCustomShader(), QByteArray(), and setCustomMaterialFlagsFromShader().

Referenced by QQuick3DCustomMaterial::updateSpatialNode().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ setCustomMaterialFlagsFromShader()

static void setCustomMaterialFlagsFromShader ( QSSGRenderCustomMaterial * material,
const QSSGCustomShaderMetaData & meta )
static

Definition at line 1574 of file qquick3dcustommaterial.cpp.

References QSSGRenderCustomMaterial::AoTexture, QSSGRenderCustomMaterial::DepthTexture, QSSGCustomShaderMetaData::flags, QSSGRenderCustomMaterial::IblOrientation, QSSGRenderCustomMaterial::InverseProjectionMatrix, QSSGRenderCustomMaterial::Lightmap, QSSGRenderCustomMaterial::m_renderFlags, QSSGRenderCustomMaterial::m_usesSharedVariables, QSSGRenderCustomMaterial::Morphing, QSSGRenderCustomMaterial::OverridesPosition, QSSGCustomShaderMetaData::OverridesPosition, QSSGRenderCustomMaterial::ProjectionMatrix, QSSGRenderCustomMaterial::ScreenMipTexture, QSSGRenderCustomMaterial::ScreenTexture, QSSGRenderCustomMaterial::Skinning, QSSGCustomShaderMetaData::UsesAoTexture, QSSGCustomShaderMetaData::UsesDepthTexture, QSSGCustomShaderMetaData::UsesIblOrientation, QSSGCustomShaderMetaData::UsesInverseProjectionMatrix, QSSGCustomShaderMetaData::UsesLightmap, QSSGCustomShaderMetaData::UsesMorphing, QSSGCustomShaderMetaData::UsesProjectionMatrix, QSSGCustomShaderMetaData::UsesScreenMipTexture, QSSGCustomShaderMetaData::UsesScreenTexture, QSSGCustomShaderMetaData::UsesSharedVars, QSSGCustomShaderMetaData::UsesSkinning, QSSGCustomShaderMetaData::UsesVarColor, QSSGCustomShaderMetaData::UsesViewIndex, QSSGRenderCustomMaterial::VarColor, and QSSGRenderCustomMaterial::ViewIndex.

Referenced by prepareCustomShader().

+ Here is the caller graph for this function:

◆ toRhiBlendFactor()

\qmlproperty url CustomMaterial::vertexShader

\qmltype CustomMaterial
\inherits Material
\inqmlmodule QtQuick3D
\brief Base component for creating custom materials used to shade models.

The custom material allows using custom shader code for a material, enabling
programmability on graphics shader level. A vertex, fragment, or both
shaders can be provided. The \l vertexShader and \l fragmentShader
properties are URLs, referencing files containing shader snippets, and work
very similarly to ShaderEffect or \l{Image::source}{Image.source}. Only the
\c file and \c qrc schemes are supported with custom materials. It is also
possible to omit the \c file scheme, allowing to specify a relative path in
a convenient way. Such a path is resolved relative to the component's (the
\c{.qml} file's) location.

For a getting started guide to custom materials, see the page \l{Programmable
Materials, Effects, Geometry, and Texture data}.

\section1 Introduction

Consider the following versions of the same scene. On the left, the cylinder
is using a built-in, non-programmable material. Such materials are
configurable through a wide range of properties, but there is no further
control given over the shaders that are generated under the hood. On the
right, the same cylinder is now associated with a CustomMaterial referencing
application-provided vertex and fragment shader snippets. This allows
inserting custom, application-specific logic into the vertex shader to
transform the geometry, and to determine certain color properties in a
custom manner in the fragment shader. As this is a
\l{shadingMode}{shaded} custom material, the cylinder still
participates in the scene lighting normally.

\table 70%
\row
\li \qml
View3D {
    anchors.fill: parent
    PerspectiveCamera {
        id: camera
        position: Qt.vector3d(0, 0, 600)
    }
    camera: camera
    DirectionalLight {
        position: Qt.vector3d(-500, 500, -100)
        color: Qt.rgba(0.2, 0.2, 0.2, 1.0)
        ambientColor: Qt.rgba(0.1, 0.1, 0.1, 1.0)
    }
    Model {
        source: "#Cylinder"
        eulerRotation: Qt.vector3d(30, 30, 0)
        scale: Qt.vector3d(1.5, 1.5, 1.5)
        materials: [
            DefaultMaterial {
                diffuseColor: Qt.rgba(0, 1, 0, 1)
            }
        ]
    }
}
    \endqml
\li \qml
View3D {
    anchors.fill: parent
    PerspectiveCamera {
        id: camera
        position: Qt.vector3d(0, 0, 600)
    }
    camera: camera
    DirectionalLight {
        position: Qt.vector3d(-500, 500, -100)
        color: Qt.rgba(0.2, 0.2, 0.2, 1.0)
        ambientColor: Qt.rgba(0.1, 0.1, 0.1, 1.0)
    }
    Model {
        source: "#Cylinder"
        eulerRotation: Qt.vector3d(30, 30, 0)
        scale: Qt.vector3d(1.5, 1.5, 1.5)
        materials: [
            CustomMaterial {
                vertexShader: "material.vert"
                fragmentShader: "material.frag"
                property real uTime
                property real uAmplitude: 50
                NumberAnimation on uTime { from: 0; to: 100; duration: 10000; loops: -1 }
            }
        ]
    }
}
    \endqml
\endtable

Let's assume that the shader snippets in \c{material.vert} and \c{material.frag} are
the following:

\table 70%
\row
\li \badcode
void MAIN()
{
    VERTEX.x += sin(uTime + VERTEX.y) * uAmplitude;
}
\endcode
\li \badcode
void MAIN()
{
    BASE_COLOR = vec4(0.0, 1.0, 0.0, 1.0);
}
\endcode
\endtable

Notice how \c uTime and \c uAmplitude are properties of the CustomMaterial
element. They can change values and get animated normally, the values will
be exposed to the shaders automatically without any further action from the
developer.

The result is a cylinder that animates its vertices:

\image custommaterial_cylinder.png

\section1 Two flavors of custom materials

There are two main types of custom materials. This is specified by the \l
shadingMode property. In \l{CustomMaterial::shadingMode}{unshaded} custom
materials the fragment shader outputs a single \c vec4 color, ignoring
lights, light probes, shadowing in the scene. In
\l{CustomMaterial::shadingMode}{shaded} materials the shader is expected to
implement certain functions and work with built-in variables to take
lighting and shadow contribution into account.

The default choice is typically a shaded material, this is reflected in the
default value of the \l shadingMode property. This fits materials that needs
to transform vertices or other incoming data from the geometry, or determine
values like \c BASE_COLOR or \c EMISSIVE_COLOR in a custom manner, perhaps
by sampling \c SCREEN_TEXTURE or \c DEPTH_TEXTURE, while still reciving
light and shadow contributions from the scene. Additionally, such materials
can also override and reimplement the equations used to calculate the
contributions from directional, point, and other lights. The
application-provided shader snippets are heavily amended by the Qt Quick 3D
engine under the hood, in order to provide the features, such as lighting,
the standard materials have.

Unshaded materials are useful when the object's appearance is determined
completely by the custom shader code.  The shaders for such materials
receive minimal additions by the engine, and therefore it is completely up
to the shader to determine the final fragment color. This gives more
freedom, but also limits possiblities to integrate with other elements of
the scene, such as lights.

\note Shader code is always provided using Vulkan-style GLSL, regardless of
the graphics API used by Qt at run time.

\note The vertex and fragment shader code provided by the material are not
full, complete GLSL shaders on their own. Rather, they provide a set of
functions, which are then amended with further shader code by the engine.

\section1 Exposing data to the shaders

The dynamic properties of the CustomMaterial can be changed and animated
using QML and Qt Quick facilities, and the values are exposed to the
shaders automatically. This in practice is very similar ShaderEffect. The
following list shows how properties are mapped:

\list
\li bool, int, real -> bool, int, float
\li QColor, \l{QtQml::Qt::rgba()}{color} -> vec4, and the color gets
converted to linear, assuming sRGB space for the color value specified in
QML. The built-in Qt colors, such as \c{"green"} are in sRGB color space as
well, and the same conversion is performed for all color properties of
DefaultMaterial and PrincipledMaterial, so this behavior of CustomMaterial
matches those. Unlike Qt Quick, for Qt Quick 3D linearizing is essential as
there will typically be tonemapping performed on the 3D scene.
\li QRect, QRectF, \l{QtQml::Qt::rect()}{rect} -> vec4
\li QPoint, QPointF, \l{QtQml::Qt::point()}{point}, QSize, QSizeF, \l{QtQml::Qt::size()}{size} -> vec2
\li QVector2D, \l{QtQml::Qt::vector2d()}{vector2d} -> vec2
\li QVector3D, \l{QtQml::Qt::vector3d()}{vector3d} -> vec3
\li QVector4D, \l{QtQml::Qt::vector4d()}{vector4d} -> vec4
\li QMatrix4x4, \l{QtQml::Qt::matrix4x4()}{matrix4x4} -> mat4
\li QQuaternion, \l{QtQml::Qt::quaternion()}{quaternion} -> vec4, scalar value is \c w

\li TextureInput -> sampler2D or samplerCube, depending on whether \l
Texture or \l CubeMapTexture is used in the texture property of the
TextureInput. Setting the \l{TextureInput::enabled}{enabled} property to
false leads to exposing a dummy texture to the shader, meaning the shaders
are still functional but will sample a texture with opaque black image
content. Pay attention to the fact that properties for samplers must always
reference a \l TextureInput object, not a \l Texture directly. When it
comes to the \l Texture properties, the source, tiling, and filtering
related ones are the only ones that are taken into account implicitly with
custom materials, as the rest (such as, UV transformations) is up to the
custom shaders to implement as they see fit.

\endlist

\note When a uniform referenced in the shader code does not have a
corresponding property, it will cause a shader compilation error when
processing the material at run time. There are some exceptions to this,
such as, sampler uniforms, that get a dummy texture bound when no
corresponding QML property is present, but as a general rule, all uniforms
and samplers must have a corresponding property declared in the
CustomMaterial object.

\section1 Unshaded custom materials

The following is an example of an \l{CustomMaterial::shadingMode}{unshaded}
custom material.

\qml
CustomMaterial {

These properties are automatically exposed to the shaders property real time: 0.0 property real amplitude: 5.0 property real alpha: 1.0 property TextureInput tex: TextureInput { enabled: true texture: Texture { source: "image.png" } }

shadingMode: CustomMaterial.Unshaded sourceBlend: alpha < 1.0 ? CustomMaterial.SrcAlpha : CustomMaterial.NoBlend destinationBlend: alpha < 1.0 ? CustomMaterial.OneMinusSrcAlpha : CustomMaterial.NoBlend cullMode: CustomMaterial.BackFaceCulling

vertexShader: "customshader.vert" fragmentShader: "customshader.frag" } \endqml

With the above example, the \l{CustomMaterial::shadingMode}{unshaded} vertex and fragment shaders snippets could look like the following. Note how the shaders do not, and must not, declare uniforms or vertex inputs as that is taken care of by Qt when assembling the final shader code.

\badcode VARYING vec3 pos; VARYING vec2 texcoord;

void MAIN() { pos = VERTEX; pos.x += sin(time * 4.0 + pos.y) * amplitude; texcoord = UV0; POSITION = MODELVIEWPROJECTION_MATRIX * vec4(pos, 1.0); }

\badcode VARYING vec3 pos; VARYING vec2 texcoord;

void MAIN() { vec4 c = texture(tex, texcoord); FRAGCOLOR = vec4(pos.x * 0.02, pos.y * 0.02, pos.z * 0.02, alpha) * c; }

The following special, uppercase keywords are available:

\list

  • MAIN -> the name of the entry point in the vertex or fragment shader snippet must always be MAIN. Providing this function is mandatory in shader snippets for unshaded custom materials.
  • VARYING -> declares an output from the vertex shader or an input to the fragment shader
  • POSITION -> vec4, the output from the vertex shader
  • FRAGCOLOR -> vec4, the output from the fragment shader. Available only for unshaded custom materials.
  • VERTEX -> vec3, the vertex position in the vertex shader.
  • NORMAL -> vec3, the vertex normal in the vertex shader. When the mesh for the associated model does not provide normals, the value is vec3(0.0).
  • UV0 -> vec2, the first set of texture coordinates in the vertex shader. When the mesh for the associated model does not provide texture coordinates, the value is vec2(0.0).
  • UV1 -> vec2, the second set of texture coordinates in the vertex shader. When the mesh for the associated model does not provide a second set of texture coordinates, the value is vec2(0.0).
  • COLOR -> vec4, the vertex color in the vertex shader. When the mesh for the associated model does not provide per-vertex colors, the value is vec4(1.0).
  • TANGENT -> vec3, tangent in the vertex shader. When the mesh for the associated model does not provide tangent data, the value is vec3(0.0).
  • BINORMAL -> vec3, binormal in the vertex shader. When the mesh for the associated model does not provide binormal data, the value is vec3(0.0).
  • JOINTS -> ivec4, joint indexes in the vertex shader. When the mesh for the associated model does not provide joint indexes data, the value is ivec4(0).
  • WEIGHTS -> vec4, joint weights in the vertex shader. When the mesh for the associated model does not provide joint weights data, the value is vec4(0.0).
  • MORPH_POSITION({n}) -> vec3, the {n+1}th morph target position in the vertex shader. The associated model should provide proper data.
  • MORPH_NORMAL({n}) -> vec3, the {n+1}th morph target normal in the vertex shader. The associated model should provide proper data.
  • MORPH_TANGENT({n}) -> vec3, the {n+1}th morph target tangent in the vertex shader. The associated model should provide proper data.
  • MORPH_BINORMAL({n}) -> vec3, the {n+1}th morph target binormal in the vertex shader. The associated model should provide proper data.
  • MODELVIEWPROJECTION_MATRIX -> mat4, the model-view-projection matrix. Projection matrices always follow OpenGL conventions, with a baked-in transformation for the Y axis direction and clip depth, depending on the graphics API used at run time.
  • VIEWPROJECTION_MATRIX -> mat4, the view-projection matrix
  • PROJECTION_MATRIX -> mat4, the projection matrix
  • INVERSE_PROJECTION_MATRIX -> mat4, the inverse projection matrix
  • VIEW_MATRIX -> mat4, the view (camera) matrix
  • MODEL_MATRIX -> mat4, the model (world) matrix
  • NORMAL_MATRIX -> mat3, the normal matrix (the transpose of the inverse of the top-left 3x3 part of the model matrix)
  • BONE_TRANSFORMS -> mat4[], the array of the model's bone matrixes
  • BONE_NORMAL_TRANSFORMS -> mat3[], the array of the model's bone normal matrixes (the transpose of the inverse of the top-left 3x3 part of the each bone matrixes)
  • MORPH_WEIGHTS -> float[], the array of the morph weights. The associated model should provide proper data. For safety, {QT_MORPH_MAX_COUNT} is defined to the size of this array.
  • CAMERA_POSITION -> vec3, the camera position in world space
  • CAMERA_DIRECTION -> vec3, the camera direction vector
  • CAMERA_PROPERTIES -> vec2, the near and far clip values for the camera
  • POINT_SIZE -> float, writable in the vertex shader only. When rendering geometry with a topology of points, the custom vertex shader must set this to either 1.0 or another value, both in shaded and unshaded custom materials. See \l{PrincipledMaterial::pointSize} for further notes on support for sizes other than 1.

\endlist

Definition at line 1381 of file qquick3dcustommaterial.cpp.

References QRhiGraphicsPipeline::ConstantAlpha, QQuick3DCustomMaterial::ConstantAlpha, QRhiGraphicsPipeline::ConstantColor, QQuick3DCustomMaterial::ConstantColor, QRhiGraphicsPipeline::DstAlpha, QQuick3DCustomMaterial::DstAlpha, QRhiGraphicsPipeline::DstColor, QQuick3DCustomMaterial::DstColor, QRhiGraphicsPipeline::One, QQuick3DCustomMaterial::One, QRhiGraphicsPipeline::OneMinusConstantAlpha, QQuick3DCustomMaterial::OneMinusConstantAlpha, QRhiGraphicsPipeline::OneMinusConstantColor, QQuick3DCustomMaterial::OneMinusConstantColor, QRhiGraphicsPipeline::OneMinusDstAlpha, QQuick3DCustomMaterial::OneMinusDstAlpha, QRhiGraphicsPipeline::OneMinusDstColor, QQuick3DCustomMaterial::OneMinusDstColor, QRhiGraphicsPipeline::OneMinusSrcAlpha, QQuick3DCustomMaterial::OneMinusSrcAlpha, QRhiGraphicsPipeline::OneMinusSrcColor, QQuick3DCustomMaterial::OneMinusSrcColor, QRhiGraphicsPipeline::SrcAlpha, QQuick3DCustomMaterial::SrcAlpha, QRhiGraphicsPipeline::SrcAlphaSaturate, QQuick3DCustomMaterial::SrcAlphaSaturate, QRhiGraphicsPipeline::SrcColor, QQuick3DCustomMaterial::SrcColor, QRhiGraphicsPipeline::Zero, and QQuick3DCustomMaterial::Zero.