Пользовательские шейдеры через компонент shader

В A-Frame шейдеры позволяют управлять визуальной обработкой материалов объектов на низком уровне, предоставляя полный контроль над цветом, освещением, текстурами и эффектами постобработки. Компонент shader выступает интерфейсом для интеграции пользовательских шейдеров, работающих поверх системы материалов A-Frame.


Подключение шейдера через компонент

Для использования собственного шейдера необходимо создать компонент, который укажет на GLSL-код вершинного и фрагментного шейдера. Структура подключения выглядит следующим образом:

AFRAME.registerShader('custom-shader', {
  schema: {
    color: { type: 'color', default: '#FFF' },
    time: { type: 'time', default: 0 }
  },
  vertexShader: `
    varying vec3 vPosition;
    void main() {
      vPosition = position;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    uniform vec3 color;
    uniform float time;
    varying vec3 vPosition;
    void main() {
      gl_FragColor = vec4(abs(sin(time + vPosition.x)), color.g, color.b, 1.0);
    }
  `
});

Ключевые моменты:

  • schema задаёт параметры шейдера, доступные для изменения через HTML-атрибуты.
  • vertexShader отвечает за преобразование вершин и передачу данных в фрагментный шейдер.
  • fragmentShader определяет окончательный цвет пикселя.

После регистрации шейдера его можно применять к объектам через атрибут material:

<a-box material="shader: custom-shader; color: #FF0000"></a-box>

Использование uniform-переменных

Uniform-переменные обеспечивают передачу динамических данных из JavaScript в GLSL. Их можно обновлять через компонент или через анимации A-Frame:

AFRAME.registerComponent('animate-shader', {
  tick: function (time) {
    this.el.getObject3D('mesh').material.uniforms.time.value = time / 1000;
  }
});

Применение:

<a-box material="shader: custom-shader" animate-shader></a-box>

Особенности:

  • uniforms автоматически создаются для каждого свойства, указанного в schema.
  • Доступ к uniforms возможен через объект материала Three.js (this.el.getObject3D('mesh').material.uniforms).

Передача текстур и внешних данных

A-Frame позволяет подключать текстуры к пользовательским шейдерам через тип map в schema:

AFRAME.registerShader('texture-shader', {
  schema: {
    map: { type: 'map' }
  },
  vertexShader: `
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    uniform sampler2D map;
    varying vec2 vUv;
    void main() {
      gl_FragColor = texture2D(map, vUv);
    }
  `
});

HTML:

<a-plane material="shader: texture-shader; map: url(texture.png)"></a-plane>

Примечания:

  • Тип map автоматически загружает изображение через менеджер ресурсов A-Frame.
  • UV-координаты передаются из вершинного шейдера в фрагментный через varying.

Интеграция с эффектами освещения

Для взаимодействия с освещением сцены используется встроенная поддержка lights в Three.js. В шейдере можно добавлять uniform-переменные для передачи нормалей и вычисления освещённости:

vertexShader: `
  varying vec3 vNormal;
  varying vec3 vPosition;
  void main() {
    vNormal = normalize(normalMatrix * normal);
    vPosition = (modelViewMatrix * vec4(position, 1.0)).xyz;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }
`,
fragmentShader: `
  uniform vec3 color;
  varying vec3 vNormal;
  varying vec3 vPosition;
  void main() {
    vec3 lightDir = normalize(vec3(1.0, 1.0, 1.0));
    float diff = max(dot(vNormal, lightDir), 0.0);
    gl_FragColor = vec4(color * diff, 1.0);
  }
`

Особенности:

  • normalMatrix автоматически корректирует нормали при трансформации объекта.
  • Подобные шейдеры могут использоваться для имитации диффузного освещения без стандартного материала.

Динамические эффекты через шейдеры

С помощью параметров времени, координат и пользовательских uniform-переменных можно создавать эффекты анимации, такие как пульсация, деформация поверхности или цветовые градиенты. Например, волновая анимация поверхности:

vertexShader: `
  uniform float time;
  varying vec3 vNormal;
  void main() {
    vec3 pos = position;
    pos.y += sin(pos.x * 2.0 + time) * 0.2;
    vNormal = normal;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
  }
`

Особенности:

  • Комбинация sin и time обеспечивает циклические колебания.
  • Любые изменения в вершинном шейдере автоматически влияют на освещение и взаимодействие с физикой, если они используются.

Рекомендации по организации сложных шейдеров

  1. Разделение логики: Вертексный шейдер отвечает только за положение вершин, фрагментный — за цвет и освещение.
  2. Использование varying: Передача данных между шейдерами через varying обеспечивает гибкость и минимизирует повторения.
  3. Оптимизация: Униформы следует обновлять только при изменении параметров, чтобы избежать лишней нагрузки на GPU.
  4. Реиспользуемость: Создание библиотеки пользовательских шейдеров позволяет применять их к различным объектам без дублирования кода.

Пример комплексного шейдера с несколькими эффектами

AFRAME.registerShader('complex-shader', {
  schema: {
    time: { type: 'time' },
    color1: { type: 'color', default: '#FF0000' },
    color2: { type: 'color', default: '#0000FF' },
    map: { type: 'map' }
  },
  vertexShader: `
    uniform float time;
    varying vec2 vUv;
    varying float vWave;
    void main() {
      vUv = uv;
      vec3 pos = position;
      vWave = sin(pos.x * 5.0 + time) * 0.5;
      pos.y += vWave;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
    }
  `,
  fragmentShader: `
    uniform sampler2D map;
    uniform vec3 color1;
    uniform vec3 color2;
    varying vec2 vUv;
    varying float vWave;
    void main() {
      vec4 tex = texture2D(map, vUv);
      vec3 mixColor = mix(color1, color2, abs(vWave));
      gl_FragColor = vec4(tex.rgb * mixColor, 1.0);
    }
  `
});

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