Spec-Zone.ru › Qt 6.0

Тип 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 внутри, чтобы предоставить такие функции, как освещение, как и стандартные материалы.

Незатененные материалы полезны, когда внешний вид объекта полностью определяется кодом пользовательского шейдера. Шейдеры таких материалов получают минимальные дополнения от движка, поэтому окончательный цвет фрагмента полностью определяется шейдером. Это предоставляет больше свободы, но также ограничивает возможности интеграции с другими элементами сцены, такими как источники света.

Примечание: Код шейдера всегда предоставляется в стиле GLSL Vulkan, независимо от графического 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.

Незатененные пользовательские материалы

Ниже приведен пример незатененного пользовательского материала.

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).
  • 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 часть каждой матрицы костей)
  • 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 — Цвет самоизлучения. Соответствует свойству встроенных материалов 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 Цвет отражённого света.
    • float LIGHT_ATTENUATION Затухание света. Для направленных источников света значение равно 1.0.
    • 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 может рассчитать и передать их самостоятельно, но для уменьшения дублирования данных фрагментные шейдеры также могут использовать эти встроенные значения вместо этого. Эти встроенные значения доступны в функциях обработки света и в функции фрагмента MAIN.

  • vec3 VAR_WORLD_NORMAL - Интерполированная нормаль, преобразованная NORMAL_MATRIX.
  • vec3 NORMAL - В отличие от VAR_WORLD_NORMAL, которая является интерполированной нормалью как есть, это значение может быть скорректировано для двустороннего отображения: при рендеринге без отсечения нормаль может быть инвертирована по необходимости. Поэтому для корректной работы со всеми режимами отсечения рекомендуется использовать NORMAL вместо VAR_WORLD_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 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);
    }

Текстуры экрана, глубины и другие

Рендеринг-пайплайн может предоставить ряд текстур для пользовательских шейдеров материалов с содержимым из специальных рендеринговых проходов. Это относится как к затенённым, так и к незатенённым пользовательским материалам.

Например, шейдер может потребовать доступа к текстуре глубины, содержащей содержимое буфера глубины для непрозрачных объектов в сцене. Это достигается путём выборки 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, разница в том, что эта текстура имеет сгенерированные mip-уровни. Это может быть дорогостоящей функцией с точки зрения производительности, в зависимости от размера экрана, и из-за необходимости генерации mip-уровней каждый раз при рендеринге сцены. Поэтому всегда предпочтительнее использовать SCREEN_TEXTURE, если не реализована техника, использующая уровни mip текстур (например, используя 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 - При наличии и включенном пространственном затенении окружающей среды (что означает, что сила затенения окружающей среды и расстояние оба не равны нулю) в 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 : real

Это свойство определяет ширину линий, которые отрисовываются, когда геометрия использует тип примитива линии или полоски линий. Значение по умолчанию — 1,0. Это свойство не актуально при отрисовке другого типа геометрии, например, треугольных мешей.

Предупреждение: Ширины линий, отличные от 1, могут быть не поддерживаемы во время выполнения, в зависимости от базового графического API. В таком случае запрос на изменение ширины игнорируется. Например, ни один из следующих случаев не может ожидаться для поддержки широких линий: Direct3D, Metal, OpenGL с контекстами профиля Core.

Примечание: В отличие от ширины линии, значение которой является частью объекта графической трубы, размер точки для геометрий с топологией точек контролируется шейдером вершин (если поддерживается), и поэтому не имеет соответствующего свойства QML.

shadingMode : enumeration

Указывает тип материала. Значение по умолчанию — Shaded.

Постоянная Значение
CustomMaterial.Unshaded
CustomMaterial.Shaded

sourceBlend : enumeration

Указывает исходный коэффициент смешивания. Значение по умолчанию — 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.0/qml-qtquick3d-custommaterial.html

Spec-Zone.ru

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