Тип 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, ссылающимся на фрагменты вершинного и фрагментного шейдеров, предоставленные приложением. Это позволяет вставить пользовательскую, специфичную для приложения логику в вершинный шейдер для преобразования геометрии и определить определённые свойства цвета пользовательским способом в фрагментном шейдере. Поскольку это затенённый (shaded) пользовательский материал, цилиндр по-прежнему нормально участвует в освещении сцены.
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. В не-затенённых (unshaded) пользовательских материалах фрагментный шейдер выводит один vec4 цвет, игнорируя источники света, зонды освещения и затенение в сцене. В затенённых (shaded) материалах шейдер должен реализовывать определённые функции и работать с встроенными переменными, чтобы учитывать освещение и затенение в сцене.
По умолчанию обычно выбирается затенённый материал, это отражается в значении по умолчанию свойства 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 - Поддерживаются текстуры, ссылающиеся на файлы изображений и слои элементов Qt Quick. Установка свойства enabled в false приводит к отображению фиктивной текстуры для шейдера, что означает, что шейдеры по-прежнему функциональны, но будут сэмплировать текстуру с непрозрачным чёрным изображением. Обратите внимание на то, что свойства для сэмплеров всегда должны ссылаться на объект TextureInput, а не на Texture напрямую. Когда дело доходит до свойств Texture, учитываются только связанные со источником, выкладкой и фильтрацией, а остальное (например, преобразования UV) шейдерам предстоит реализовывать самостоятельно.
Примечание: Если униформа, на которую ссылается код шейдера, не имеет соответствующего свойства, это вызовет ошибку компиляции шейдера при обработке материала во время выполнения. Существуют некоторые исключения из этого правила, такие как униформы сэмплеров, которые получают привязанную фиктивную текстуру, когда соответствующего свойства QML нет, но в целом все униформы и сэмплеры должны иметь соответствующее свойство, объявленное в объекте CustomMaterial.
Незатенённые пользовательские материалы
Ниже приведён пример не-затенённого (unshaded) пользовательского материала.
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"
} В приведённом выше примере фрагменты вершинного и фрагментного шейдеров для не-затенённого (unshaded) материала могут выглядеть следующим образом. Обратите внимание, как шейдеры не должны и не объявляют униформы или входные данные вершин, так как это обрабатывается 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_MORPH_IN_POSITIONn) перед использованием.
- MORPH_NORMALn -> vec3, нормаль n-ой целевой морфы в вершинном шейдере. Диапазон n от 0 до 4. Связанная модель должна предоставить соответствующие данные. Для безопасности пользователь может проверить defined(QT_MORPH_IN_NORMALn) перед использованием.
- MORPH_TANGENTn -> vec3, касательная n-ой целевой морфы в вершинном шейдере. Диапазон n от 0 до 1. Связанная модель должна предоставить соответствующие данные. Для безопасности пользователь может проверить defined(QT_MORPH_IN_TANGENTn) перед использованием.
- MORPH_BINORMALn -> vec3, бинормаль n-ой целевой морфы в вершинном шейдере. Диапазон n от 0 до 1. Связанная модель должна предоставить соответствующие данные. Для безопасности пользователь может проверить defined(QT_MORPH_IN_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. В отличие от неподсвеченных материалов, которые обеспечивают почти всю логику функций main вершинного и фрагментного шейдеров самостоятельно, предотвращая добавление сгенерированного кода для освещения, затенения, глобального освещения и т. д., подсвеченные материалы позволяют генерации шейдеров происходить обычно, как если бы 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— Цвет самоизлучения. Соответствует цвету самоизлучения встроенных материалов, который комбинируется с помощью свойства emissiveFactor встроенных материалов и свойства emissiveMap встроенных материалов. Значение по умолчанию —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Накапливает значения рассеянного освещения на фрагмент. Функции обработки света обычно добавляют (+=) к нему, так как перезапись значения приведёт к потере contributions от других источников света.
Функция может считывать следующие специальные переменные, помимо матричных (например,
MODEL_MATRIX) и векторных (например,CAMERA_POSITION) униформ из таблицы выше:- vec3
TOTAL_AMBIENT_COLORОбщее значение рассеянного освещения в сцене.
Пример:
void AMBIENT_LIGHT() { DIFFUSE += TOTAL_AMBIENT_COLOR; } - vec3
-
void DIRECTIONAL_LIGHT()Если функция присутствует, она вызывается для каждого активного направленного источника света в сцене для каждого фрагмента. Задача функции — добавить значение рассеянного света в специальную записываемую переменнуюDIFFUSE. Функция также может ничего не делать, в этом случае рассеянные contributions от направленных источников света игнорируются. Если функция отсутствует, то значение рассеянного света от направленных источников света накапливается стандартно, как для PrincipledMaterial.Функция может записывать в следующие специальные переменные:
- vec3
DIFFUSEНакапливает значения рассеянного освещения на фрагмент. Функции обработки света обычно добавляют (+=) к нему, так как перезапись значения приведёт к потере contributions от других источников света.
Функция может считывать следующие специальные переменные, помимо матричных (например,
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. Функция также может ничего не делать, в этом случае рассеянные contributions от точечных источников света игнорируются. Если функция отсутствует, то значение рассеянного света от точечных источников света накапливается стандартно, как для 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. Функция также может ничего не делать, в этом случае рассеянные contributions от прожекторных источников света игнорируются. Если функция отсутствует, то значение рассеянного света от прожекторных источников света накапливается стандартно, как для 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Величина Metalness. - float
ROUGHNESSВеличина 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
-
void POST_PROCESS()При наличии, эта функция вызывается в конце фрагментной обработки. Задача функции — завершитьCOLOR_SUMс окончательными значениями diffuse, specular и emissive. В отличие отFRAGCOLORдля неосвещаемого материала,COLOR_SUMбудет автоматически тонироваться перед записью в буфер кадра. Для отладки иногда полезно вывести значение, которое не должно обрабатываться как цвет. Чтобы избежать искажения этого значения тонированием, можно отключить его, установив свойство tonemapMode вTonemapModeNoneФункция может записывать в следующие специальные переменные:
- vec4
COLOR_SUMвывод из фрагментного шейдера. Значение по умолчанию — vec4(DIFFUSE.rgb + SPECULAR + EMISSIVE, DIFFUSE.a)
Функция может считывать следующие специальные переменные.
- vec4
DIFFUSEОкончательный коэффициент diffuse фрагментного пайплайна. - vec3
SPECULARОкончательный коэффициент specular фрагментного пайплайна. - vec3
EMISSIVEОкончательный коэффициент emissive фрагментного пайплайна. - vec2
UV0- Первый набор координат текстуры из вершинного шейдера. - vec2
UV1- Второй набор координат текстуры из вершинного шейдера.
void POST_PROCESS() { float center_x = textureSize(SCREEN_TEXTURE, 0).x * 0.5; if (gl_FragCoord.x > center_x) COLOR_SUM = DIFFUSE; else COLOR_SUM = vec4(EMISSIVE, DIFFUSE.a); } - vec4
Пользовательские переменные между функциями
Дополнительные переменные могут быть переданы из функции MAIN в другие функции. Ключевое слово SHARED_VARS может быть использовано для определения новых пользовательских переменных. Эти пользовательские переменные можно получить с помощью SHARED.<имя переменной>.
Например, затенённый пользовательский материал может извлечь общее значение в MAIN и использовать его в других функциях.
SHARED_VARS {
vec3 colorThreshold;
};
void MAIN()
{
BASE_COLOR = texture(baseColorMap, UV0);
SHARED.colorThreshold = texture(thresholdMap, UV0).rgb;
}
void DIRECTIONAL_LIGHT()
{
if (DIFFUSE >= SHARED.colorThreshold) {
DIFFUSE = SHARED.colorThreshold;
return;
}
DIFFUSE += LIGHT_COLOR * SHADOW_CONTRIB;
} Примечание: SHARED можно записать во все функции без POST_PROCESS, но безопасно писать его в MAIN и считывать в других функциях.
Примечание: Рекомендуется использовать SHARED в функциях LIGHT для сброса в MAIN и накопления в каждой функции LIGHT.
SHARED_VARS {
float sheenIntensity;
float sheenRoughness;
vec3 sheenColor;
vec3 outSheenColor;
};
void MAIN()
{
...
vec4 tex = texture(uSheenMap, UV0);
SHARED.sheenColor = tex.rgb;
SHARED.sheenIntensity = tex.a;
SHARED.sheenRoughness = uSheenRoughness;
SHARED.outSheenColor = vec3(0.0);
}
void SPECULAR_LIGHT()
{
SHARED.outSheenColor += ...;
}
void POST_PROCESS()
{
COLOR_SUM = DIFFUSE + SPECULAR + EMISSIVE + SHARED.outSheenColor;
} Примечание: MAIN вызывается перед другими функциями, а POST_PROCESS после всех других, но нет гарантии какого-либо другого порядка вызова функций обработки света.
Дополнительные специальные ключевые слова
Код пользовательского фрагментного шейдера может свободно получать доступ к униформам (например, CAMERA_DIRECTION или CAMERA_POSITION) и переменным, переданным от пользовательского вершинного шейдера. Кроме того, доступно множество встроенных переменных как специальные ключевые слова. Некоторые из них необязательны, в том смысле, что вершинный MAIN может вычислять и передавать эти значения самостоятельно, но для уменьшения дублирования данных фрагментные шейдеры также могут использовать эти встроенные значения вместо этого. Эти встроенные значения доступны в функциях обработки света и в фрагментной 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); }
Инстанцирование
При использовании инстанцированной отрисовки некоторые из вышеперечисленных ключевых слов не применяются. Следующие ключевые слова доступны только при инстанцировании:
-
INSTANCE_MODEL_MATRIX-> mat4, замена дляMODEL_MATRIX, включая преобразование инстанцирования. -
INSTANCE_MODELVIEWPROJECTION_MATRIX-> mat4, замена дляMODELVIEWPROJECTION_MATRIX, включая преобразование инстанцирования. -
INSTANCE_COLOR-> vec4, цвет инстанции: комбинируется сCOLOR. -
INSTANCE_DATA-> vec4, пользовательные данные инстанции. -
INSTANCE_INDEX-> int, номер инстанции и индекс в таблице инстанцирования.
Экран, глубина и другие текстуры
Рендеринг пайплайн может предоставить ряд текстур для пользовательских шейдеров материалов с содержимым из специальных проходов отрисовки. Это относится как к затенённым, так и к незатенённым пользовательским материалам.
Например, шейдер может потребовать доступа к текстуре глубины, содержащей данные буфера глубины для непрозрачных объектов в сцене. Это достигается путём выборки DEPTH_TEXTURE. Такая текстура обычно не генерируется, если в ней нет реальной необходимости. Поэтому наличие следующих ключевых слов в вершинном или фрагментном шейдере также действует как переключатель для включения — потенциально дорогостоящих — проходов для генерации соответствующей текстуры. (Конечно, некоторые из этих текстур могут уже быть включены из-за других настроек, таких как параметры затенения окружающей средой в 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, отличие заключается в том, что эта текстура имеет сгенерированные мип-уровни. Это может быть дорогостоящей функцией с точки зрения производительности, в зависимости от размера экрана, и из-за необходимости генерировать мип-уровни каждый раз, когда сцена рендерится. Поэтому предпочтительно всегда использоватьSCREEN_TEXTURE, если не реализован метод, использующий уровни мип-текстуры (например, используяtextureLodв шейдере) в пользовательском материале. -
DEPTH_TEXTURE- При наличии, текстура (sampler2D) с содержимым буфера глубины (без нелинейного преобразования) предоставляется шейдеру под этим именем. Включаются только непрозрачные объекты. Например, фрагментный шейдер может содержать следующее: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;
См. также SceneEnvironment::tonemapMode, 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.2/qml-qtquick3d-custommaterial.html