1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\example custommaterial
\ingroup quick3d-examples
\title Qt Quick 3D - Custom Materials Example
\examplecategory {3D}
\brief Demonstrates writing shaded custom materials.
\image custommaterial-example.jpg
This example shows how to write \e shaded \l{CustomMaterial}{custom materials}.
With shaded materials, we don't have to write complete shader
programs. Instead, we write functions that modify Qt's standard shaders.
This way the resulting material will by default participate in lighting,
shadow mapping, and be compatible with light probes. We only have to
write custom logic for the cases where we want special behavior. This is
achieved by effectively augmenting the shader code that would be
generated for a PrincipledMaterial with our own custom functions that get
called at certain stages in the vertex and fragment shaders.
To make a shaded custom material, set the
\l{CustomMaterial::shadingMode}{shadingMode} property to
\c CustomMaterial.Shaded.
\section1 A simple material
The first model uses a simple material that does not add any custom logic. We
set the custom material on the model just like any other material:
\snippet custommaterial/main.qml simple
In addition to setting the \c shadingMode and \c fragmentShader, we also add two
properties to the material: \c uDiffuse and \c Specular. These will get picked up by
the fragment shader.
The code for the fragment shader is short:
\quotefile custommaterial/material_simple.frag
All shaders have to implement the \c MAIN function. In this one, we use the properties
defined in the materials to set values that will be used by Qt's standard shader
code. Note that we do not have to declare these as uniforms: all we need to do is to
make sure the names match. We would get a shader compile error if the material did not
have matching properties.
The special variables \c SPECULAR_AMOUNT and \c BASE_COLOR correspond to
\l {PrincipledMaterial::specularAmount}{specularAmount} and
\l {PrincipledMaterial::baseColor}{baseColor} of PrincipledMaterial. These are
then used by the standard shader code to perform lighting calculations just as if we had used
a PrincipledMaterial.
\section1 Custom handling of lights
The next object uses a more complex material that implements custom lighting. The
material has different uniform names, but otherwise we use it in the same way:
\snippet custommaterial/main.qml custom lights
The fragment shader implements custom logic for all the different types of light:
\quotefile custommaterial/material_customlights.frag
Here we use many new special keywords referring to properties of the various light
types. See the CustomMaterial documentation for a description each keyword. Note that
each light type has its own function. Any function not implemented will use the
default implementation, behaving like PrincipledMaterial. For example: in this shader, we have not
implemented \c {SPECULAR_LIGHT()}, so we will get the built-in specular reflection.
\section1 Adding a vertex shader
A custom material can also use a vertex shader to modify the geometry of the model. Here we
specify both the fragment and vertex shaders, and add several more properties that
will be picked up as uniform values:
\snippet custommaterial/main.qml custom vertex
The vertex shader is very short:
\quotefile custommaterial/material_distortion.vert
This deforms the model by displacing each vertex according to a sine-wave that changes with time.
\section1 A transparent material
Finally, we add a sphere with a material that is transparent. For performance reasons,
Qt does not implement transparency in a completely realistic way. Instead, Qt renders
all the opaque object in the scene to a texture, and then transparent materials read
from this texture. This means that transparent materials will give the best result
when placed in front of other objects:
\snippet custommaterial/main.qml transparent
For this example, we implement a simplistic distortion function that does not try to
do real physical refraction:
\quotefile custommaterial/material_transparent.frag
\c SCREEN_TEXTURE refers to the texture showing all the opaque objects in the
scene. We first calculate the uv coordinates inside this texture that matches the
screen position of the current vertex. We then add an offset to this position,
simulating a refraction effect, before doing a texture lookup.
Finally, we blend in 20% white to get a slight cloudiness. Note that the output is
assigned to \c BASE_COLOR, so Qt will add lighting on top of this. This is why we can
see reflections on the surface of the sphere.
\section1 Unshaded materials
It is also possible to have custom materials that use complete shader
programs (while still using the convenience keywords). The
\l{Qt Quick 3D - Custom Shaders Example}{customshaders example}
demonstrates the other group of custom materials: \e unshaded custom
materials.
*/
|