Передача uniforms из JavaScript

В библиотеке PlayCanvas важную роль в рендеринге играет система шейдеров, которая позволяет гибко управлять графическими эффектами. В этой статье рассматривается процесс передачи значений uniforms в шейдеры непосредственно из JavaScript. Uniforms — это параметры, которые остаются постоянными для всех вершин или фрагментов в одном рендере, но могут изменяться между рендерами.

Шейдеры и uniforms

Шейдеры в PlayCanvas состоят из двух основных частей: вершинного шейдера (vertex shader) и фрагментного шейдера (fragment shader). Вершинный шейдер обрабатывает вершины геометрии, а фрагментный — пиксели. Эти шейдеры используют uniforms для получения данных, которые должны оставаться неизменными на протяжении всего рендера.

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

Создание шейдера и определение uniforms

Для того чтобы передать значения uniforms в шейдер, сначала нужно создать сам шейдер и правильно определить переменные в коде. В PlayCanvas это делается через создание экземпляра класса Shader, который затем используется в материале.

Пример простого фрагментного шейдера, который использует uniform для цвета:

precision mediump float;

uniform vec4 u_color;  // Uniform для передачи цвета

void main() {
    gl_FragColor = u_color;  // Применение цвета к пикселю
}

В этом примере u_color — это uniform-переменная, которая будет передаваться из JavaScript в шейдер. Теперь нужно передать значение этого uniform из JavaScript.

Передача uniform-переменных в шейдер из JavaScript

Чтобы передать значения uniforms из JavaScript, необходимо использовать API PlayCanvas для работы с материалами и шейдерами. Важным шагом является получение доступа к шейдеру, после чего можно передать данные через его uniform-переменные.

Пример передачи цвета в шейдер:

// Создание материала с кастомным шейдером
var material = new pc.Material();
material.shader = new pc.Shader(device, {
    attributes: {
        a_position: pc.SEMANTIC_POSITION
    },
    vshader: `
        attribute vec3 a_position;
        void main() {
            gl_Position = vec4(a_position, 1.0);
        }
    `,
    fshader: `
        precision mediump float;
        uniform vec4 u_color;
        void main() {
            gl_FragColor = u_color;
        }
    `
});

// Установка uniform значения (цвет)
var color = new pc.Color(1, 0, 0, 1); // Красный цвет
material.setParameter('u_color', color);

// Применение материала к объекту
entity.model.material = material;

В этом примере создается материал с кастомным шейдером, где передается цвет через uniform u_color. Метод setParameter используется для передачи значения. Важно заметить, что тип данных uniform должен соответствовать типу данных, ожидаемому в шейдере. В данном случае передается объект типа pc.Color, который автоматически преобразуется в vec4 в шейдере.

Обновление uniforms на каждом кадре

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

Пример обновления значения uniform в процессе рендеринга:

var time = 0;

function update() {
    time += 0.01;
    var color = new pc.Color(Math.sin(time), Math.cos(time), 0.5, 1); // Плавно меняющийся цвет
    material.setParameter('u_color', color);
}

Здесь каждый кадр обновляется значение uniform u_color, что позволяет изменять цвет объекта в зависимости от времени.

Использование матриц в uniforms

Одним из самых популярных типов данных, передаваемых через uniforms, являются матрицы, например, матрицы преобразования для моделирования, проекции или вида.

Пример передачи матрицы преобразования в шейдер:

var modelMatrix = new pc.Mat4(); // Матрица преобразования
modelMatrix.setTranslate(1, 0, 0); // Применение трансляции

material.setParameter('u_modelMatrix', modelMatrix);

В шейдере для такого uniform будет использоваться матрица типа mat4:

uniform mat4 u_modelMatrix;

void main() {
    // Применение матрицы преобразования
    gl_Position = u_modelMatrix * vec4(a_position, 1.0);
}

Работа с текстурами через uniforms

Передача текстур через uniforms — это обычная практика в 3D-графике. В PlayCanvas текстуры передаются как сэмплеры и привязываются к конкретным slot’ам.

Пример передачи текстуры в шейдер:

// Загрузка текстуры
var texture = new pc.Texture(device);
texture.setSourceFromFile('path_to_texture.png');

// Создание материала и шейдера с текстурой
material.shader = new pc.Shader(device, {
    attributes: {
        a_position: pc.SEMANTIC_POSITION,
        a_texCoord0: pc.SEMANTIC_TEXCOORD0
    },
    vshader: `
        attribute vec3 a_position;
        attribute vec2 a_texCoord0;
        varying vec2 v_texCoord;
        void main() {
            gl_Position = vec4(a_position, 1.0);
            v_texCoord = a_texCoord0;
        }
    `,
    fshader: `
        precision mediump float;
        uniform sampler2D u_texture;
        varying vec2 v_texCoord;
        void main() {
            gl_FragColor = texture2D(u_texture, v_texCoord);
        }
    `
});

// Установка текстуры как uniform
material.setParameter('u_texture', texture);

// Применение материала к объекту
entity.model.material = material;

Здесь текстура передается в uniform u_texture, который используется для получения цвета из текстуры на основе координат.

Заключение

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