Spec-Zone.ru › Qt 6.1

Тип QML CustomMaterial

Базовый компонент для создания пользовательских материалов, используемых для затенения моделей. Подробнее...

Заявление об импорте: import QtQuick3D .
Наследует:

Material

  • Список всех членов, включая унаследованные

Свойства

  • 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);
    }
  • void AMBIENT_LIGHT() При наличии этой функции, она вызывается один раз для каждого фрагмента. Задача функции — добавить полное значение окружения к изменяемой специальной переменной DIFFUSE. Она может, конечно, выбрать вычисление другого значения или вообще не трогать DIFFUSE (чтобы полностью игнорировать окружение). Если этой функции нет, вклад окружения вычисляется стандартно, как для PrincipledMaterial.

    Функция может записывать в следующие специальные переменные:

    • vec3 DIFFUSE Накапливает вклады диффузного света по фрагменту. Функции обработки света обычно добавляют (+=) к нему, так как перезапись значения приведёт к потере вклада от других источников света.

    Функция может считывать следующие специальные переменные, помимо матриц (например, MODEL_MATRIX) и векторов (например, CAMERA_POSITION) униформ из таблицы выше:

    • vec3 TOTAL_AMBIENT_COLOR Общее значение окружения в сцене.

    Пример:

    void AMBIENT_LIGHT()
    {
        DIFFUSE += TOTAL_AMBIENT_COLOR;
    }
  • 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)));
    }
  • 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)));
    }
  • 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)));
    }
  • 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;
    }

Дополнительные специальные ключевые слова

Пользовательский фрагментный шейдерный код может свободно обращаться к униформам (например, 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API