Пользовательские шейдеры: pc.Shader, pc.ShaderDefinition

PlayCanvas предоставляет мощные инструменты для создания 3D-графики с использованием JavaScript. Одним из ключевых элементов, который позволяет добиться высокого уровня кастомизации визуальных эффектов, являются пользовательские шейдеры. С помощью шейдеров можно реализовать любые графические эффекты — от сложных материалов до специфических эффектов освещения и постобработки.

В этой главе рассматриваются пользовательские шейдеры PlayCanvas, включая классы pc.Shader и pc.ShaderDefinition. Эти классы обеспечивают доступ к низкоуровневым инструментам для создания шейдеров, которые используются для описания поведения материалов и рендеринга объектов.

Класс pc.Shader

Класс pc.Shader является основным для работы с шейдерами в PlayCanvas. Этот класс инкапсулирует шейдерную программу и управляет её компиляцией и применением. Он позволяет подключать шейдеры на уровне объекта или материала, а также управлять ими через API PlayCanvas.

Создание шейдера

Шейдер создается на основе определённой программы, состоящей из вершинного шейдера и фрагментного шейдера. Для создания шейдера используется конструктор pc.Shader, который принимает два параметра:

  1. Графический контекст (pc.GraphicsDevice), необходимый для работы с рендером.
  2. Определение шейдера (pc.ShaderDefinition), в котором содержится исходный код вершинного и фрагментного шейдеров, а также другие параметры.
var shaderDefinition = new pc.ShaderDefinition({
    attributes: {
        aPosition: pc.SEMANTIC_POSITION,
        aNormal: pc.SEMANTIC_NORMAL
    },
    vshader: `
        attribute vec3 aPosition;
        attribute vec3 aNormal;
        varying vec3 vNormal;
        
        void main(void) {
            gl_Position = vec4(aPosition, 1.0);
            vNormal = aNormal;
        }
    `,
    fshader: `
        varying vec3 vNormal;
        
        void main(void) {
            gl_FragColor = vec4(abs(vNormal), 1.0);
        }
    `
});

var shader = new pc.Shader(graphicsDevice, shaderDefinition);

Этот код создаёт простейший шейдер, который передаёт нормали из вершинного шейдера в фрагментный и выводит их как цвет.

Применение шейдера

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

var material = new pc.Material();
material.shader = shader;

Этот код привязывает шейдер к материалу, который затем можно использовать для отрисовки объектов.

Управление Uniform-переменными

Важной частью шейдера являются uniform-переменные, которые позволяют передавать данные, которые не изменяются для всех вершин и фрагментов одного рисунка. Например, можно передавать световые источники, трансформации камеры и другие параметры.

Для работы с uniform-переменными в pc.Shader предусмотрены методы setParameter и getParameter.

shader.setParameter("uTime", 1.0);

Этот код передаёт значение времени в uniform-переменную uTime.

Класс pc.ShaderDefinition

pc.ShaderDefinition — это структура данных, которая описывает шейдер. Она служит для задания всех необходимых параметров и кода шейдера, который затем компилируется в pc.Shader. В pc.ShaderDefinition определяются такие параметры, как:

  • Атрибуты: переменные, передаваемые в шейдер для каждой вершины (например, позиции, нормали, текстурные координаты).
  • Шейдеры: строки с кодом вершинного и фрагментного шейдера.
  • Uniform-переменные: глобальные переменные, которые передаются в шейдер и остаются неизменными для всех вершин и фрагментов.
  • Техники: наборы шейдеров, которые могут быть использованы для разных условий рендеринга.

Атрибуты и семантика

Атрибуты в шейдерах могут быть привязаны к различным данным, таким как позиция вершины или её нормаль. Каждому атрибуту присваивается семантика, которая указывает, как данные должны интерпретироваться. В PlayCanvas используются следующие семантики:

  • pc.SEMANTIC_POSITION: позиция вершины.
  • pc.SEMANTIC_NORMAL: нормаль вершины.
  • pc.SEMANTIC_TEXCOORD: текстурные координаты.
  • pc.SEMANTIC_COLOR: цвет.

Для определения атрибутов используется объект в pc.ShaderDefinition:

var shaderDefinition = new pc.ShaderDefinition({
    attributes: {
        aPosition: pc.SEMANTIC_POSITION,
        aNormal: pc.SEMANTIC_NORMAL
    },
    vshader: `
        attribute vec3 aPosition;
        attribute vec3 aNormal;
        varying vec3 vNormal;
        
        void main(void) {
            gl_Position = vec4(aPosition, 1.0);
            vNormal = aNormal;
        }
    `,
    fshader: `
        varying vec3 vNormal;
        
        void main(void) {
            gl_FragColor = vec4(abs(vNormal), 1.0);
        }
    `
});

Шейдеры и техника

pc.ShaderDefinition также поддерживает концепцию техник (techniques), которая позволяет определить несколько версий шейдера для разных условий рендеринга (например, для разных типов освещения). Каждая техника включает в себя набор вершинных и фрагментных шейдеров, которые могут быть выбраны в зависимости от условий.

var shaderDefinition = new pc.ShaderDefinition({
    techniques: {
        normal: {
            attributes: {
                aPosition: pc.SEMANTIC_POSITION,
                aNormal: pc.SEMANTIC_NORMAL
            },
            vshader: `
                attribute vec3 aPosition;
                attribute vec3 aNormal;
                varying vec3 vNormal;
                
                void main(void) {
                    gl_Position = vec4(aPosition, 1.0);
                    vNormal = aNormal;
                }
            `,
            fshader: `
                varying vec3 vNormal;
                
                void main(void) {
                    gl_FragColor = vec4(abs(vNormal), 1.0);
                }
            `
        }
    }
});

Таким образом, для каждого состояния рендеринга можно выбрать наиболее подходящую технику шейдера.

Заключение

Пользовательские шейдеры в PlayCanvas открывают широкий спектр возможностей для создания уникальных визуальных эффектов и рендеринга. Используя классы pc.Shader и pc.ShaderDefinition, можно гибко настраивать графику, адаптируя её под конкретные задачи. Шейдеры позволяют создавать как простые эффекты, так и сложные системы освещения, обработки текстур и другие графические решения, которые невозможно реализовать с помощью стандартных материалов PlayCanvas.