Тип QML CustomMaterial
Базовый компонент для создания пользовательских материалов, используемых для затенения моделей. Подробнее...
| Заявление об импорте: | import QtQuick3D . |
| Наследует: |
Свойства
- alwaysDirty : bool
- destinationBlend : перечисление
- fragmentShader : url
- lineWidth : вещественное
- shadingMode : перечисление
- sourceBlend : перечисление
- vertexShader : url
Подробное описание
Пользовательский материал позволяет использовать пользовательский код шейдера для материала, обеспечивая возможность программирования на уровне графического шейдера. Можно указать вершинный, фрагментный или оба шейдера. Свойства vertexShader и fragmentShader представляют собой URL-адреса, ссылающиеся на файлы, содержащие фрагменты шейдера, и работают очень похоже на ShaderEffect или Image.source. С пользовательскими материалами поддерживаются только схемы file и qrc. Также можно опустить схему file, что позволяет удобным образом указать относительный путь. Такой путь разрешается относительно расположения компонента (файла .qml).
Руководство для начала работы с пользовательскими материалами см. на странице Программируемые материалы, эффекты, геометрия и данные текстуры.
Введение
Рассмотрим следующие версии одной и той же сцены. Слева цилиндр использует встроенный, не программируемый материал. Такие материалы можно настраивать с помощью широкого набора свойств, но нет дальнейшего контроля над шейдерами, которые генерируются под капотом. Справа тот же цилиндр теперь связан с CustomMaterial, ссылающимся на фрагменты вершинного и фрагментного шейдеров, предоставленные приложением. Это позволяет вставлять пользовательскую, специфичную для приложения логику в вершинный шейдер для преобразования геометрии и определять определенные свойства цвета пользовательским способом в фрагментном шейдере. Поскольку это затенённый пользовательский материал, цилиндр по-прежнему участвует в освещении сцены обычно.
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)
}
]
}
} |
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 }
}
]
}
} |
Предположим, что фрагменты шейдеров в material.vert и material.frag выглядят следующим образом:
void MAIN()
{
VERTEX.x += sin(uTime + VERTEX.y) * uAmplitude;
} |
void MAIN()
{
BASE_COLOR = vec4(0.0, 1.0, 0.0, 1.0);
} |
Обратите внимание, как uTime и uAmplitude являются свойствами элемента CustomMaterial. Они могут изменять значения и анимироваться обычно, значения будут автоматически переданы шейдерам без каких-либо дополнительных действий со стороны разработчика.
В результате получается цилиндр, который анимирует свои вершины:
Два вида пользовательских материалов
Существует два основных типа пользовательских материалов. Это определяется свойством shadingMode. В не-затенённых пользовательских материалах фрагментный шейдер выводит единый цвет vec4, игнорируя источники света, зонды света и затемнение в сцене. В затенённых материалах ожидается, что шейдер будет реализовывать определённые функции и работать с встроенными переменными, чтобы учесть вклад освещения и теней в сцене.
По умолчанию обычно используется затенённый материал, что отражается в значении свойства shadingMode по умолчанию. Это подходит для материалов, которые должны преобразовывать вершины или другую входящую информацию из геометрии или определять значения, такие как BASE_COLOR или EMISSIVE_COLOR, пользовательским способом, возможно, с помощью выборки SCREEN_TEXTURE или DEPTH_TEXTURE, при этом по-прежнему получая вклад света и теней от сцены. Кроме того, такие материалы также могут переопределять и повторно реализовывать уравнения, используемые для вычисления вклада направленных, точечных и других источников света. Фрагменты шейдеров, предоставленные приложением, значительно дополняются движком Qt Quick 3D под капотом, чтобы предоставить такие возможности, как освещение, как у стандартных материалов.
Незатенённые материалы полезны, когда внешний вид объекта определяется полностью пользовательским кодом шейдера. Шейдеры таких материалов получают минимальные дополнения от движка, поэтому окончательный цвет фрагмента полностью определяется шейдером. Это даёт больше свободы, но также ограничивает возможности интеграции с другими элементами сцены, такими как источники света.
Примечание: Код шейдера всегда предоставляется в стиле Vulkan-GLSL, независимо от графического API, используемого Qt во время выполнения.
Примечание: Код вершинного и фрагментного шейдеров, предоставленный материалом, не является полными, законченными шейдерами GLSL сами по себе. Вместо этого они предоставляют набор функций, которые затем дополняются движком дополнительным кодом шейдера.
Передача данных шейдерам
Динамические свойства CustomMaterial можно изменять и анимировать с помощью QML и средств Qt Quick, и значения автоматически передаются шейдерам. На практике это очень похоже на ShaderEffect. Следующий список показывает, как отображаются свойства:
- bool, int, real -> bool, int, float
-
QColor, color -> vec4, и цвет преобразуется в линейный, предполагая sRGB-пространство для значения цвета, указанного в QML. Встроенные цвета Qt, такие как
"green", также находятся в цветовом пространстве sRGB, и для всех цветовых свойств DefaultMaterial и PrincipledMaterial выполняется то же преобразование, поэтому это поведение CustomMaterial соответствует им. В отличие от Qt Quick, для Qt Quick 3D линейная обработка является необходимой, поскольку в 3D-сцене обычно выполняется тональная коррекция. - QRect, QRectF, rect -> vec4
- QPoint, QPointF, point, QSize, QSizeF, size -> vec2
- QVector2D, vector2d -> vec2
- QVector3D, vector3d -> vec3
- QVector4D, vector4d -> vec4
- QMatrix4x4, matrix4x4 -> mat4
-
QQuaternion, quaternion -> vec4, скалярное значение
w - TextureInput -> sampler2D - Поддерживаются текстуры, ссылающиеся на файлы изображений image files и слои элементов Qt Quick Qt Quick item layers. Установка свойства enabled в false приводит к отображению фиктивной текстуры в шейдере, что означает, что шейдеры по-прежнему функциональны, но будут считывать текстуру с непрозрачным чёрным изображением. Обратите внимание на то, что свойства для сэмплеров всегда должны ссылаться на объект TextureInput, а не напрямую на Texture. Что касается свойств текстуры, то только те, которые связаны с источником, мозаикой и фильтрацией, неявно учитываются пользовательскими материалами, так как остальное (например, преобразования UV) реализуется в пользовательских шейдерах, как им заблагорассудится.
Примечание: Если в коде шейдера есть униформа, для которой нет соответствующего свойства, при обработке материала во время выполнения произойдёт ошибка компиляции шейдера. Есть некоторые исключения из этого правила, такие как сэмплеры униформ, которые получают привязанную фиктивную текстуру, когда нет соответствующего QML-свойства, но в общем случае все униформы и сэмплеры должны иметь соответствующее объявленное свойство в объекте CustomMaterial.
Незатенённые пользовательские материалы
Ниже приведён пример не затенённого пользовательского материала.
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"
} В приведённом выше примере фрагменты вершинного и фрагментного шейдеров для незатенённого материала могут выглядеть следующим образом. Обратите внимание, как шейдеры не объявляют и не должны объявлять униформы или вершинные входные данные, так как этим занимается Qt при сборке окончательного кода шейдера.
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);
} 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;
} Доступны следующие специальные ключевые слова с заглавными буквами:
- MAIN -> имя точки входа в фрагментном или вершинном фрагменте шейдера должно всегда быть
MAIN. Предоставление этой функции обязательно в фрагментах шейдеров для неподсвеченных пользовательских материалов. - VARYING -> объявляет вывод из вершинного шейдера или вход в фрагментный шейдер
- POSITION -> vec4, вывод из вершинного шейдера
- FRAGCOLOR -> vec4, вывод из фрагментного шейдера. Доступен только для неподсвеченных пользовательских материалов.
- VERTEX -> vec3, положение вершины в вершинном шейдере.
- NORMAL -> vec3, нормаль вершины в вершинном шейдере. Если для сетки связанной модели нет данных о нормалях, значение равно vec3(0.0).
- UV0 -> vec2, первый набор текстурных координат в вершинном шейдере. Если для сетки связанной модели нет текстурных координат, значение равно vec2(0.0).
- UV1 -> vec2, второй набор текстурных координат в вершинном шейдере. Если для сетки связанной модели нет второго набора текстурных координат, значение равно vec2(0.0).
- COLOR -> vec4, цвет вершины в вершинном шейдере. Если для сетки связанной модели нет данных о цвете каждой вершины, значение равно vec4(1.0).
- TANGENT -> vec3, касательная в вершинном шейдере. Если для сетки связанной модели нет данных о касательной, значение равно vec3(0.0).
- BINORMAL -> vec3, бинормаль в вершинном шейдере. Если для сетки связанной модели нет данных о бинормали, значение равно vec3(0.0).
- JOINTS -> ivec4, индексы суставов в вершинном шейдере. Если для сетки связанной модели нет данных об индексах суставов, значение равно ivec4(0).
- WEIGHTS -> vec4, веса суставов в вершинном шейдере. Если для сетки связанной модели нет данных о весах суставов, значение равно vec4(0.0).
- MORPH_POSITIONn -> vec3, положение n-го целевого морфинга в вершинном шейдере. Диапазон n от 0 до 7. Связанная модель должна предоставлять правильные данные. Для безопасности пользователь может проверить defined(QT_ATTR_MORPH_POSITIONn) перед использованием.
- MORPH_NORMALn -> vec3, нормаль n-го целевого морфинга в вершинном шейдере. Диапазон n от 0 до 4. Связанная модель должна предоставлять правильные данные. Для безопасности пользователь может проверить defined(QT_ATTR_MORPH_NORMALn) перед использованием.
- MORPH_TANGENTn -> vec3, касательная n-го целевого морфинга в вершинном шейдере. Диапазон n от 0 до 1. Связанная модель должна предоставлять правильные данные. Для безопасности пользователь может проверить defined(QT_ATTR_MORPH_TANGENTn) перед использованием.
- MORPH_BINORMALn -> vec3, бинормаль n-го целевого морфинга в вершинном шейдере. Диапазон n от 0 до 1. Связанная модель должна предоставлять правильные данные. Для безопасности пользователь может проверить defined(QT_ATTR_MORPH_BINORMALn) перед использованием.
- MODELVIEWPROJECTION_MATRIX -> mat4, матрица модели-вида-проекции. Матрицы проекции всегда следуют соглашениям OpenGL, с встроенным преобразованием для направления оси Y и глубины обрезки, в зависимости от используемого графического API во время выполнения.
- VIEWPROJECTION_MATRIX -> mat4, матрица вида-проекции
- PROJECTION_MATRIX -> mat4, матрица проекции
- INVERSE_PROJECTION_MATRIX -> mat4, обратная матрица проекции
- VIEW_MATRIX -> mat4, матрица вида (камеры)
- MODEL_MATRIX -> mat4, матрица модели (мира)
- NORMAL_MATRIX -> mat3, матрица нормалей (транспонированная обратная верхняя левая 3x3 часть матрицы модели)
- BONE_TRANSFORMS -> mat4[], массив матриц костей модели
- BONE_NORMAL_TRANSFORMS -> mat3[], массив матриц нормалей костей модели (транспонированная обратная верхняя левая 3x3 часть каждой матрицы костей)
- MORPH_WEIGHTS -> float[], массив весов морфинга. Связанная модель должна предоставлять правильные данные. Для безопасности QT_MORPH_MAX_COUNT определен как размер этого массива.
- CAMERA_POSITION -> vec3, положение камеры в мировом пространстве
- CAMERA_DIRECTION -> vec3, вектор направления камеры
- CAMERA_PROPERTIES -> vec2, значения ближней и дальней плоскости обрезки для камеры
- POINT_SIZE -> float, доступно только для записи в вершинном шейдере. При отрисовке геометрии с топологией точек пользовательский вершинный шейдер должен установить это значение либо в 1.0, либо в другое значение, как в подсвеченных, так и в неподсвеченных пользовательских материалах. См. PrincipledMaterial::pointSize для получения дополнительных сведений об обработке размеров, отличных от 1.
Подсвеченные пользовательские материалы
Материал с подсвечиванием augments код шейдера, который был бы сгенерирован PrincipledMaterial. В отличие от неподсвеченных материалов, которые предоставляют почти всю логику для основных функций вершинного и фрагментного шейдеров самостоятельно, предотвращая добавление сгенерированного кода для освещения, теней, глобального освещения и т. д., подсвеченные материалы позволяют генерировать шейдеры обычно, как если бы CustomMaterial был PrincipledMaterial. Фрагментные и вершинные фрагменты шейдеров должны предоставить необязательные функции, которые затем вызываются в определенные моменты, давая им возможность настраивать цвета и другие значения, которые затем используются для расчета освещения и окончательного цвета фрагмента.
Вместо реализации только функции MAIN, фрагментный шейдер для подсвеченного пользовательского материала может реализовывать несколько функций. Все функции, включая MAIN, являются необязательными для реализации в подсвеченных пользовательских материалах. Также допустимы пустой фрагмент шейдера или даже отсутствие свойств vertexShader или fragmentShader.
Фрагменты вершинного шейдера в подсвеченном пользовательском материале
В фрагменте вершинного шейдера могут быть реализованы следующие функции:
-
void MAIN()Если присутствует, эта функция вызывается для задания значенияPOSITION, результата vec4 вершинного шейдера, и, по желанию, для изменения значенийVERTEX,COLOR,NORMAL,UV0,UV1,TANGENT,BINORMAL,JOINTS, иWEIGHTS. В отличие от неподсвеченных материалов, запись в эти значения имеет смысл, потому что измененные значения учитываются в остальной части сгенерированного кода шейдера (в то время как для неподсвеченных материалов дополнительного кода шейдера не генерируется). Например, если пользовательский вершинный шейдер смещает вершины или нормали, он должен сохранить измененные значения вVERTEXилиNORMAL, чтобы обеспечить правильный расчет освещения впоследствии. Кроме того, функция может записывать в переменные, определенные с помощьюVARYING, для передачи интерполированных данных фрагменту шейдера. Если эта функция или переопределениеPOSITIONотсутствуют,POSITIONрассчитывается на основеVERTEXиMODELVIEWPROJECTION_MATRIX, как это делал бы PrincipledMaterial.Пример, использующий как свойства QML, экспонированные как униформы, так и передачу данных фрагменту шейдера:
VARYING vec3 vNormal; VARYING vec3 vViewVec; void MAIN() { VERTEX.x += sin(uTime * 4.0 + VERTEX.y) * uAmplitude; vNormal = normalize(NORMAL_MATRIX * NORMAL); vViewVec = CAMERA_POSITION - (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; POSITION = MODELVIEWPROJECTION_MATRIX * vec4(VERTEX, 1.0); }Примечание: В приведенном примере присвоение значения
POSITIONнеобязательно, поскольку использование в этом случае идентично поведению по умолчанию.
Фрагменты фрагментного шейдера в подсвеченном пользовательском материале
В фрагменте фрагментного шейдера могут быть реализованы следующие функции:
-
void MAIN()При наличии этой функции, она вызывается для установки значений специальных изменяемых переменныхBASE_COLOR,METALNESS,ROUGHNESS,SPECULAR_AMOUNT, NORMAL иFRESNEL_POWER.Одним из распространённых случаев использования является установка значения
BASE_COLORна основе выборки текстуры, будь то карта базового цвета,SCREEN_TEXTURE, или какой-либо другой источник. Это может быть актуально и удобно, особенно когда не реализованы пользовательские функции обработки света. УстановкаBASE_COLOR.aна значение, отличное от стандартного 1.0, позволяет влиять на конечное значение альфа-канала фрагмента. (Обратите внимание, что это часто потребует также включения альфа-смешивания в sourceBlend и destinationBlend)Другой сценарий — когда нет пользовательской функции
SPECULAR_LIGHT, или когда в SceneEnvironment установлен зонд освещения. Значения металличности, шероховатости и другие значения, влияющие на расчёт отражения, могут быть установлены вMAINна желаемые пользовательские значения.Функция может записывать в следующие специальные переменные. Значения, записываемые в эти переменные, обычно являются либо жёстко заданными, либо рассчитываются на основе свойств QML, сопоставленных с униформами. Семантика идентична PrincipledMaterial.
- vec4
BASE_COLOR- Базовый цвет и значение альфа-канала материала. Соответствует свойству цвета встроенных материалов. Когда функции обработки света не реализованы, может быть удобно установить пользовательский базовый цвет вMAIN, поскольку это затем учитывается в расчётах стандартного освещения. Значение по умолчанию —vec4(1.0), то есть белый цвет с альфа-каналом 1.0. Значение альфа-канала влияет на окончательное значение альфа-канала фрагмента. Конечное значение альфа-канала — это непрозрачность объекта (модели), умноженная на альфа-канал базового цвета. При указании значения непосредственно в коде шейдера, не полагаясь на значения униформ, экспонируемых из свойств color в QML, следует помнить, что преобразование sRGB в линейное, если необходимо, выполняется шейдером. Например, предполагаяvec3 colorиfloat alpha, это можно достичь следующим образом:float C1 = 0.305306011; vec3 C2 = vec3(0.682171111, 0.682171111, 0.682171111); vec3 C3 = vec3(0.012522878, 0.012522878, 0.012522878); BASE_COLOR = vec4(rgb * (rgb * (rgb * C1 + C2) + C3), alpha);
- vec3
EMISSIVE_COLOR- Цвет самоизлучения. Соответствует свойству встроенных материалов emissiveColor. Значение по умолчанию —vec3(0.0). При указании значения непосредственно в коде шейдера, не полагаясь на значения униформ, экспонируемых из свойств color в QML, следует помнить, что преобразование sRGB в линейное, если необходимо, выполняется шейдером. - float
METALNESSСтепень металличности в диапазоне 0.0 — 1.0. Значение по умолчанию — 0. Должно быть установлено в ненулевое значение, чтобы иметь эффект. - float
ROUGHNESSЗначение шероховатости в диапазоне 0.0 — 1.0. Значение по умолчанию — 0. - float
FRESNEL_POWERУказывает на мощность френеля. Типичное значение, а также значение по умолчанию —5.0, поскольку это используется PrincipledMaterial. - float
SPECULAR_AMOUNTСтепень отражения в диапазоне 0.0 — 1.0. Значение по умолчанию —0.5, соответствует PrincipledMaterial::specularAmount. Должно быть установлено в ненулевое значение, чтобы иметь эффект. - vec3
NORMAL- Нормаль, полученная из вершинного шейдера в пространстве мира. Хотя эта переменная имеет то же начальное значение, что иVAR_WORLD_NORMAL, только изменение значенияNORMALповлияет на освещение. - vec3
TANGENT- Касательная, полученная из вершинного шейдера в пространстве мира. Это значение может быть скорректировано для двустороннего отображения. - vec3
BINORMAL- Бинормаль, полученная из вершинного шейдера в пространстве мира. Это значение может быть скорректировано для двустороннего отображения. - vec2
UV0- Первый набор текстурных координат из вершинного шейдера. Это свойство является только для чтения в фрагментном шейдере. - vec2
UV1- Второй набор текстурных координат в вершинном шейдере. Это свойство является только для чтения во фрагментном шейдере.
Примечание: В отличие от нетенированных материалов, фрагмент
MAINдля затенённого материала не имеет прямого управления надFRAGCOLOR. Скорее, значенияDIFFUSEиSPECULARв функциях обработки света определяют окончательный цвет фрагмента. Когда функция обработки света не реализована, выполняются стандартные расчёты затенения, как для PrincipledMaterial, учитываяBASE_COLORи другие значения из списка выше.Пример простого, металлического пользовательского шейдера материала может быть следующим:
void MAIN() { METALNESS = 1.0; ROUGHNESS = 0.5; FRESNEL_POWER = 5.0; }Другой пример, где базовый цвет и альфа-канал задаются выборкой из текстуры:
VARYING vec2 texcoord; void MAIN() { BASE_COLOR = texture(uColorMap, texcoord); } - vec4
-
void AMBIENT_LIGHT()При наличии этой функции, она вызывается один раз для каждого фрагмента. Задача функции — добавить полное значение окружения к изменяемой специальной переменнойDIFFUSE. Она может, конечно, выбрать вычисление другого значения или вообще не трогатьDIFFUSE(чтобы полностью игнорировать окружение). Если этой функции нет, вклад окружения вычисляется стандартно, как для PrincipledMaterial.Функция может записывать в следующие специальные переменные:
- vec3
DIFFUSEНакапливает вклады диффузного света по фрагменту. Функции обработки света обычно добавляют (+=) к нему, так как перезапись значения приведёт к потере вклада от других источников света.
Функция может считывать следующие специальные переменные, помимо матриц (например,
MODEL_MATRIX) и векторов (например,CAMERA_POSITION) униформ из таблицы выше:- vec3
TOTAL_AMBIENT_COLORОбщее значение окружения в сцене.
Пример:
void AMBIENT_LIGHT() { DIFFUSE += TOTAL_AMBIENT_COLOR; } - vec3
-
void DIRECTIONAL_LIGHT()При наличии этой функции, она вызывается для каждого активного направленного источника света в сцене для каждого фрагмента. Задача функции — добавить вклад диффузии к изменяемой специальной переменнойDIFFUSE. Функция также может ничего не делать, в этом случае вклады диффузии от направленных источников света игнорируются. Если функция отсутствует, вклады диффузии от направленных источников света накапливаются стандартно, как для PrincipledMaterial.Функция может записывать в следующие специальные переменные:
- vec3
DIFFUSEНакапливает вклады диффузного света по фрагменту. Функции обработки света обычно добавляют (+=) к нему, так как перезапись значения приведёт к потере вклада от других источников света.
Функция может считывать следующие специальные переменные, помимо матриц (например,
MODEL_MATRIX) и векторов (например,CAMERA_POSITION) униформ из таблицы выше:- vec3
LIGHT_COLORЦвет диффузного света. - float
SHADOW_CONTRIBВклад тени, или 1.0, если тень отсутствует или фрагмент не получает тени. - vec3
TO_LIGHT_DIRВектор, направленный к источнику света. - vec3
NORMALВектор нормали в пространстве мира. - vec4
BASE_COLORБазовый цвет и значение альфа-канала материала. - float
METALNESSСтепень металличности. - float
ROUGHNESSСтепень шероховатости.
Пример:
void DIRECTIONAL_LIGHT() { DIFFUSE += LIGHT_COLOR * SHADOW_CONTRIB * vec3(max(0.0, dot(normalize(VAR_WORLD_NORMAL), TO_LIGHT_DIR))); } - vec3
-
void POINT_LIGHT()При наличии этой функции, она вызывается для каждого активного точечного источника света в сцене для каждого фрагмента. Задача функции — добавить вклад диффузии к изменяемой специальной переменнойDIFFUSE. Функция также может ничего не делать, в этом случае вклады диффузии от точечных источников света игнорируются. Если функция отсутствует, вклады диффузии от точечных источников света накапливаются стандартно, как для PrincipledMaterial.Функция может записывать в следующие специальные переменные:
- vec3
DIFFUSEНакапливает вклады диффузного света по фрагменту.
Функция может считывать следующие специальные переменные, помимо матриц (например,
MODEL_MATRIX) и векторов (например,CAMERA_POSITION) униформ из таблицы выше:- vec3
LIGHT_COLORЦвет диффузного света. - float
LIGHT_ATTENUATIONЗатухание света. - float
SHADOW_CONTRIBВклад тени, или 1.0, если тень отсутствует или фрагмент не получает тени. - vec3
TO_LIGHT_DIRВектор, направленный к источнику света. - vec3
NORMALВектор нормали в пространстве мира. - vec4
BASE_COLORБазовый цвет и значение альфа-канала материала. - float
METALNESSСтепень металличности. - float
ROUGHNESSСтепень шероховатости.
Пример:
void POINT_LIGHT() { DIFFUSE += LIGHT_COLOR * LIGHT_ATTENUATION * SHADOW_CONTRIB * vec3(max(0.0, dot(normalize(VAR_WORLD_NORMAL), TO_LIGHT_DIR))); } - vec3
-
void SPOT_LIGHT()При наличии этой функции, она вызывается для каждого активного прожекторного источника света в сцене для каждого фрагмента. Задача функции — добавить вклад диффузии к изменяемой специальной переменнойDIFFUSE. Функция также может ничего не делать, в этом случае вклады диффузии от прожекторных источников света игнорируются. Если функция отсутствует, вклады диффузии от прожекторных источников света накапливаются стандартно, как для PrincipledMaterial.Функция может записывать в следующие специальные переменные:
- vec3
DIFFUSEНакапливает вклады диффузного света по фрагменту.
Функция может считывать следующие специальные переменные, помимо матриц (например,
MODEL_MATRIX) и векторов (например,CAMERA_POSITION) униформ из таблицы выше:- vec3
LIGHT_COLORЦвет диффузного света. - float
LIGHT_ATTENUATIONЗатухание света. - float
SHADOW_CONTRIBВклад тени, или 1.0, если тень отсутствует или фрагмент не получает тени. - vec3
TO_LIGHT_DIRВектор, направленный к источнику света. - float
SPOT_FACTORКоэффициент прожектора. - vec3
NORMALВектор нормали в пространстве мира. - vec4
BASE_COLORБазовый цвет и значение альфа-канала материала. - float
METALNESSСтепень металличности. - float
ROUGHNESSСтепень шероховатости.
Пример:
void SPOT_LIGHT() { DIFFUSE += LIGHT_COLOR * LIGHT_ATTENUATION * SPOT_FACTOR * SHADOW_CONTRIB * vec3(max(0.0, dot(normalize(VAR_WORLD_NORMAL), TO_LIGHT_DIR))); } - vec3
-
void SPECULAR_LIGHT()При наличии, эта функция вызывается для каждого активного света в сцене для каждого фрагмента. Задача функции — добавить вклад specular к записываемой специальной переменнойSPECULAR. Функция также может выбрать ничего не делать, в этом случае вклады specular от источников света игнорируются. Если функция отсутствует, вклады specular от источников света накапливаются обычно, как это делает PrincipledMaterial.Функция может записывать в следующие специальные переменные:
- vec3
SPECULARНакапливает вклады specular света для каждого фрагмента. Функции обработки света обычно добавляют (+=) к этому значению, так как перезапись значения приведёт к потере вклада от других источников света.
Функция может считывать следующие специальные переменные, помимо матриц (например,
MODEL_MATRIX) и векторов (например,CAMERA_POSITION) из таблицы выше:- vec3
LIGHT_COLORЦвет света specular. - float
LIGHT_ATTENUATIONЗатухание света. Для направленных источников света значение равно 1.0. Для точечных источников света значение такое же, какLIGHT_ATTENUATION * SPOT_FACTORуvoid SPOT_LIGHT(). - float
SHADOW_CONTRIBВклад тени, или 1.0, если объект не находится в тени или не получает тени. - vec3
FRESNEL_CONTRIBВклад Fresnel от встроенного расчёта Fresnel. - vec3
TO_LIGHT_DIRВектор, направленный к источнику света. - vec3
NORMALВектор нормали в пространстве мира. - vec4
BASE_COLORОсновной цвет и значение альфа-канала материала. - float
METALNESSЗначение металличности. - float
ROUGHNESSЗначение шероховатости. - float
SPECULAR_AMOUNTЗначение specular. Это значение будет находиться между 0.0 и 1.0 и будет таким же, как установлено в пользовательской функцииMAIN. Это значение будет полезно для расчёта вкладов Fresnel, когда не используется встроенный вклад Fresnel, предоставленныйFRESNEL_CONTRIB.
void SPECULAR_LIGHT() { vec3 H = normalize(VIEW_VECTOR + TO_LIGHT_DIR); float cosAlpha = max(0.0, dot(H, normalize(NORMAL))); float shine = pow(cosAlpha, exp2(15.0 * (1.0 - ROUGHNESS) + 1.0) * 0.25); SPECULAR += shine * LIGHT_COLOR * FRESNEL_CONTRIB * SHADOW_CONTRIB * LIGHT_ATTENUATION; } - vec3
Дополнительные специальные ключевые слова
Пользовательский фрагментный шейдерный код может свободно обращаться к униформам (например, CAMERA_DIRECTION или CAMERA_POSITION) и переменным, переданным из пользовательского вершинного шейдера. Кроме того, есть ряд встроенных переменных, доступных как специальные ключевые слова. Некоторые из них являются необязательными в том смысле, что вершинный MAIN может сам вычислять и передавать эти значения, но для уменьшения дублирования данных фрагментные шейдеры также могут использовать эти встроенные значения вместо этого. Эти встроенные значения доступны в функциях обработки света и в основной функции фрагмента.
- vec3
VAR_WORLD_NORMAL- Интерполированная нормаль, преобразованнаяNORMAL_MATRIX. - vec3
VAR_WORLD_TANGENT- Интерполированная касательная, преобразованнаяMODEL_MATRIX. - vec3
VAR_WORLD_BINORMAL- Интерполированная бинормаль, преобразованнаяMODEL_MATRIX - vec3
NORMAL- В отличие отVAR_WORLD_NORMAL, которая является интерполированной нормалью как есть, это значение может быть скорректировано для двустороннего отображения: при отрисовке без обрезки нормаль может быть инвертирована при необходимости. Поэтому рекомендуется использоватьNORMALвместоVAR_WORLD_NORMALв расчётах освещения и других расчётах, чтобы обеспечить корректное поведение во всех режимах обрезки. - vec3
TANGENT- Как иNORMAL, это значение может быть скорректировано для двустороннего отображения: при отрисовке без обрезки касательная может быть инвертирована при необходимости. - vec3
BINORMAL- Как иNORMAL, это значение может быть скорректировано для двустороннего отображения: при отрисовке без обрезки бинормаль может быть инвертирована при необходимости. - vec3
VAR_WORLD_POSITION- Интерполированная позиция вершины в пространстве мира ((MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz). - vec4
VAR_COLOR- Интерполированный цвет вершины, если цвета заданы в сетке.vec4(1.0)в противном случае. - vec3
VIEW_VECTOR- Направлен на камеру. По сути, это нормализованный векторCAMERA_POSITION - VAR_WORLD_POSITION. - vec4
FRAGCOORD- Содержит координаты текущего фрагмента в окне. - float
FRAMEBUFFER_Y_UP- Значение равно1, когда ось Y направлена вверх в системе координат для буферов кадра (текстур), что означает, что(0, 0)находится в левом нижнем углу. Значение равно-1, когда ось Y направлена вниз,(0, 0)- в левом верхнем углу. Такие различия в базовых графических API не касаются большинства пользовательских материалов. Заметное исключение — выборкаSCREEN_TEXTUREс координатами текстуры, не основанными наFRAGCOORD. Поскольку ориентацияSCREEN_TEXTUREсвязана с базовым графическим API по своей природе, при использовании координат текстуры из сетки могут потребоваться корректировки координаты Y.Например, следующий фрагментный шейдер, подходящий для прямоугольных или кубовых сеток, отобразит непрозрачные объекты из сцены на модели:
VARYING vec2 texcoord; void MAIN() { vec2 screencoord = texcoord; if (FRAMEBUFFER_Y_UP < 0.0) // effectively: if not OpenGL screencoord.y = 1.0 - screencoord.y; BASE_COLOR = texture(SCREEN_TEXTURE, screencoord); }При выборке текстур, отличных от
SCREEN_TEXTUREиDEPTH_TEXTURE, или когдаFRAGCOORDиспользуется для расчёта координаты текстуры (что является типичным случаем доступа к текстурам экрана и глубины), такая корректировка не требуется. - float
NDC_Y_UP- Значение равно1, когда ось Y направлена вверх в пространстве нормализованных координат устройства, и-1, когда ось Y направлена вниз. Y, направленный вниз, является случаем, когда рендеринг происходит с Vulkan. Большинству материалов не нужно беспокоиться об этом, но возможность ветвления на основе этого может оказаться полезной в некоторых сложных случаях. - float
NEAR_CLIP_VALUE- Значение равно-1, когда диапазон плоскости обрезки начинается с-1и заканчивается1. Это верно при использовании OpenGL для рендеринга. Для других рендеринговых бэкендов значение этого свойства будет0, что означает, что диапазон плоскости обрезки от0до1Это значение полезно для некоторых техник, связанных сDEPTH_TEXTUREНапример, следующий фрагментный шейдер демонстрирует технику реконструирования позиции значения из буфера глубины для определения расстояния от текущей рендерируемой позиции. При использовании в сочетании с
INVERSE_PROJECTION_MATRIXзначение глубины должно быть в нормализованных координатах устройства, поэтому важно убедиться, что диапазон значений глубины отражает это. КогдаNEAR_CLIP_VALUEравно-1, значение глубины масштабируется в диапазон от-1до1.void MAIN() { vec2 screen_uv = FRAGCOORD.xy / vec2(textureSize(SCREEN_TEXTURE, 0)); float depth = texture(DEPTH_TEXTURE, screen_uv).r; if (NEAR_CLIP_VALUE < 0.0) // effectively: if opengl depth = depth * 2.0 - 1.0; vec4 unproject = INVERSE_PROJECTION_MATRIX * vec4(screen_uv, depth, 1.0); depth = (unproject.xyz / unproject.w).z; float viewVectorZ = (VIEW_MATRIX * vec4(VAR_WORLD_POSITION, 1.0)).z; depth = viewVectorZ - depth; BASE_COLOR = vec4(depth, depth, depth, 1.0); }
Инстанцирование
Примечание: Функция инстанцирования находится в стадии технического предварительного просмотра в Qt 6.1. API находится в разработке и может быть изменён.
При выполнении инстанцированного рендеринга некоторые из вышеперечисленных ключевых слов неприменимы. Следующие ключевые слова доступны только при инстанцировании:
-
INSTANCE_MODEL_MATRIX-> mat4, заменаMODEL_MATRIX, включая преобразование инстанцирования. -
INSTANCE_MODELVIEWPROJECTION_MATRIX-> mat4, заменаMODELVIEWPROJECTION_MATRIX, включая преобразование инстанцирования. -
INSTANCE_COLOR-> vec4, цвет инстанса: для комбинирования сCOLOR. -
INSTANCE_DATA-> vec4, пользовательное данные инстанса. -
INSTANCE_INDEX-> int, номер инстанса и индекс в таблице инстанцирования.
Текстуры экрана, глубины и другие текстуры
Рендеринговая система может предоставлять пользовательским шейдерам материалы из специальных проходов рендеринга. Это относится как к затенённым, так и к незатенённым пользовательским материалам.
Например, шейдер может потребовать доступа к текстуре глубины, содержащей содержимое буфера глубины для непрозрачных объектов в сцене. Это достигается путём выборки DEPTH_TEXTURE. Такая текстура обычно не генерируется, если нет реальной необходимости. Поэтому наличие следующих ключевых слов в вершинном или фрагментном шейдере также служит переключателем для включения — потенциально дорогостоящих — проходов для генерации соответствующей текстуры. (Конечно, возможно, что некоторые из этих проходов уже включены из-за других настроек, таких как параметры окружения ambient occlusion в SceneEnvironment или из-за эффекта пост-обработки, использующего текстуру глубины, в этом случае текстуры генерируются независимо от пользовательского материала, и выборка этих специальных текстур в материале происходит без дополнительных затрат, помимо доступа к текстуре)
-
SCREEN_TEXTURE- При наличии, текстура (sampler2D) с цветовым буфером из прохода рендеринга, содержащего непрозрачные объекты сцены, доступна шейдеру под этим именем. Это также подразумевает, что любой объект с пользовательским материалом, где шейдеры используютSCREEN_TEXTURE, будет обрабатываться так, как будто у него включена полупрозрачность, даже если непрозрачность объекта равна 1.0 и смешивание не было включено в CustomMaterial. Это связано с тем, что такой объект не может быть частью списков непрозрачного рендеринга, поскольку сам зависит от результатов рендеринга этих объектов и, следовательно, не может быть рендерен в том же списке. Пиксели, не покрытые непрозрачными объектами, будут установлены в прозрачный цвет (vec4(0.0)) в текстуре. Например, фрагментный шейдер может содержать следующее:vec2 uv = FRAGCOORD.xy / vec2(textureSize(SCREEN_TEXTURE, 0)); vec2 displace = vec2(0.1); vec4 c = texture(SCREEN_TEXTURE, uv + displace);
Обратите внимание, что использование
SCREEN_TEXTUREтребует соответствующего, осознанного проектирования сцены. Объекты, использующие такие материалы, должны быть расположены аккуратно, обычно над всеми другими объектами, которые ожидается увидеть в текстуре. Объекты, использующие полупрозрачность в какой-либо форме, никогда не являются частьюSCREEN_TEXTURE. ЧастоSCREEN_TEXTUREиспользуется в сочетании сBASE_COLORвMAIN. Например, следующий пользовательский фрагментный шейдер применяет эффект рельефа, сохраняя фрагменты, не затронутые непрозрачными объектами, прозрачными. Предполагается, что объект с материалом размещен спереди и что у него включено смешивание.void MAIN() { vec2 size = vec2(textureSize(SCREEN_TEXTURE, 0)); vec2 uv = FRAGCOORD.xy / size; // basic emboss effect vec2 d = vec2(1.0 / size.x, 1.0 / size.y); vec4 diff = texture(SCREEN_TEXTURE, uv + d) - texture(SCREEN_TEXTURE, uv - d); float c = (diff.x + diff.y + diff.z) + 0.5; float alpha = texture(SCREEN_TEXTURE, uv).a; BASE_COLOR = vec4(vec3(c), alpha); } -
SCREEN_MIP_TEXTURE- Почти идентиченSCREEN_TEXTURE, разница заключается в том, что эта текстура имеет сгенерированные mip-уровни. Это может быть ресурсоемкая функция с точки зрения производительности, в зависимости от размера экрана, и из-за необходимости генерировать mip-уровни каждый раз при рендеринге сцены. Поэтому предпочтительно всегда использоватьSCREEN_TEXTURE, если не реализована техника, использующая уровни mip-текстуры (например, используяtextureLodв шейдере) в пользовательском материале. -
DEPTH_TEXTURE- При наличии, содержимое буфера глубины (нелинейное) предоставляется шейдеру под этим именем. Включаются только непрозрачные объекты. Например, фрагментный шейдер может содержать следующее:ivec2 dtSize = textureSize(DEPTH_TEXTURE, 0); vec2 dtUV = (FRAGCOORD.xy) / vec2(dtSize); vec4 depthSample = texture(DEPTH_TEXTURE, dtUV); float zNear = CAMERA_PROPERTIES.x; float zFar = CAMERA_PROPERTIES.y; float zRange = zFar - zNear; float z_n = 2.0 * depthSample.r - 1.0; float d = 2.0 * zNear * zFar / (zFar + zNear - z_n * zRange); d /= zFar;
-
AO_TEXTURE- При наличии и включенном пространственном затенении (означает, когда сила и расстояние AO не равны нулю) в SceneEnvironment, текстура SSAO (sampler2D) предоставляется шейдеру под этим именем. Выборка этой текстуры может быть полезна в неподсвеченных материалах. Подсвеченные материалы имеют встроенную поддержку затенения. Это означает, что фактор затенения учитывается автоматически. В то время как во фрагментном шейдере для неподсвеченного материала можно записать следующее, чтобы добиться того же:ivec2 aoSize = textureSize(AO_TEXTURE, 0); vec2 aoUV = (FRAGCOORD.xy) / vec2(aoSize); float aoFactor = texture(AO_TEXTURE, aoUV).x;
См. также Qt Quick 3D - Пример пользовательских шейдеров, Qt Quick 3D - Пример пользовательских материалов и Программируемые материалы, эффекты, геометрия и данные текстур.
Документация свойств
alwaysDirty : bool
Указывает, что состояние материала всегда грязное, что означает, что материал необходимо обновить каждый раз, когда он используется модулем QtQuick3D.
destinationBlend : перечисление
Указывает коэффициент смешивания назначения. Значение по умолчанию — CustomMaterial.NoBlend.
| Константа | Значение |
|---|---|
CustomMaterial.NoBlend | |
CustomMaterial.Zero | |
CustomMaterial.One | |
CustomMaterial.SrcColor | |
CustomMaterial.OneMinusSrcColor | |
CustomMaterial.DstColor | |
CustomMaterial.OneMinusDstColor | |
CustomMaterial.SrcAlpha | |
CustomMaterial.OneMinusSrcAlpha | |
CustomMaterial.DstAlpha | |
CustomMaterial.OneMinusDstAlpha | |
CustomMaterial.ConstantColor | |
CustomMaterial.OneMinusConstantColor | |
CustomMaterial.ConstantAlpha | |
CustomMaterial.OneMinusConstantAlpha | |
CustomMaterial.SrcAlphaSaturate |
fragmentShader : url
Указывает файл с фрагментом пользовательского фрагментного шейдера.
Значение — URL и должно быть либо локальным файлом, либо использовать схему qrc для доступа к файлам, вставленным с помощью системы ресурсов Qt. Также принимаются относительные пути к файлам (без схемы), в этом случае файл обрабатывается как относительный к компоненту (файлу .qml).
См. также vertexShader.
lineWidth : вещественный
Это свойство определяет ширину линий, отрисованных, когда геометрия использует тип примитива линии или линии-полосы. Значение по умолчанию — 1.0. Это свойство не имеет отношения к рендерингу других типов геометрии, таких как, треугольные сетки.
Предупреждение: Ширина линий, отличная от 1, может не поддерживаться во время выполнения, в зависимости от базового API графики. В этом случае запрос на изменение ширины игнорируется. Например, ни одно из следующих не может поддерживать широкие линии: Direct3D, Metal, OpenGL с контекстами профиля core.
Примечание: В отличие от ширины линии, значение которой является частью объекта графической трубы, размер точки для геометрии с топологией точек управляется фрагментным шейдером (при поддержке) и, следовательно, не имеет соответствующего свойства QML.
shadingMode : перечисление
Указывает тип материала. Значение по умолчанию — Shaded.
| Константа | Значение |
|---|---|
CustomMaterial.Unshaded | |
CustomMaterial.Shaded |
sourceBlend : перечисление
Указывает коэффициент смешивания источника. Значение по умолчанию — CustomMaterial.NoBlend.
| Константа | Значение |
|---|---|
CustomMaterial.NoBlend | |
CustomMaterial.Zero | |
CustomMaterial.One | |
CustomMaterial.SrcColor | |
CustomMaterial.OneMinusSrcColor | |
CustomMaterial.DstColor | |
CustomMaterial.OneMinusDstColor | |
CustomMaterial.SrcAlpha | |
CustomMaterial.OneMinusSrcAlpha | |
CustomMaterial.DstAlpha | |
CustomMaterial.OneMinusDstAlpha | |
CustomMaterial.ConstantColor | |
CustomMaterial.OneMinusConstantColor | |
CustomMaterial.ConstantAlpha | |
CustomMaterial.OneMinusConstantAlpha | |
CustomMaterial.SrcAlphaSaturate |
vertexShader : url
Указывает файл с фрагментом пользовательского вершинного шейдера.
Значение — URL и должно быть либо локальным файлом, либо использовать схему qrc для доступа к файлам, вставленным с помощью системы ресурсов Qt. Также принимаются относительные пути к файлам (без схемы), в этом случае файл обрабатывается как относительный к компоненту (файлу .qml).
См. также fragmentShader.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.1/qml-qtquick3d-custommaterial.html