ShaderMaterial: полностью кастомный материал

ShaderMaterial предоставляет полный контроль над визуальным представлением объекта, позволяя использовать собственные GLSL-шейдеры для вершин и фрагментов. В отличие от стандартных материалов (MeshStandardMaterial, MeshPhongMaterial и других), где визуальные свойства ограничены предопределёнными параметрами, ShaderMaterial открывает доступ к полной графической цепочке рендеринга.

Основные параметры ShaderMaterial:

  • vertexShader – GLSL-код вершинного шейдера.
  • fragmentShader – GLSL-код фрагментного шейдера.
  • uniforms – объект, содержащий данные, передаваемые шейдерам.
  • defines – предопределённые макросы для шейдеров.
  • transparent, side, blending – стандартные свойства материала для контроля прозрачности, сторон и смешивания.

Пример базовой структуры:

const material = new THREE.ShaderMaterial({
    vertexShader: `
        varying vec3 vPosition;
        void main() {
            vPosition = position;
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        }
    `,
    fragmentShader: `
        varying vec3 vPosition;
        void main() {
            gl_FragColor = vec4(vPosition * 0.5 + 0.5, 1.0);
        }
    `
});

Здесь vPosition передаёт координаты вершин из вершинного шейдера во фрагментный, что позволяет управлять цветом на основе положения.


Использование Uniforms

uniforms позволяют передавать динамические данные из JavaScript в GLSL. Это может быть время, текстуры, векторы, матрицы или любые другие значения.

Пример:

const uniforms = {
    time: { value: 0.0 },
    color: { value: new THREE.Color(0xff0000) }
};

const material = new THREE.ShaderMaterial({
    uniforms,
    vertexShader: vertexShaderCode,
    fragmentShader: fragmentShaderCode
});

function animate(deltaTime) {
    uniforms.time.value += deltaTime;
}

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

  • Значения обновляются в реальном времени.
  • Можно использовать массивы и структуры GLSL.
  • Поддерживают типы: float, vec2, vec3, vec4, mat3, mat4, sampler2D и другие.

Связь вершинного и фрагментного шейдеров

Взаимодействие между вершинным и фрагментным шейдерами осуществляется через varying переменные. Они автоматически интерполируются для каждого фрагмента. Пример передачи нормалей и UV-координат:

// Вершинный шейдер
varying vec3 vNormal;
varying vec2 vUv;

void main() {
    vNormal = normalMatrix * normal;
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

// Фрагментный шейдер
varying vec3 vNormal;
varying vec2 vUv;

void main() {
    float intensity = dot(normalize(vNormal), vec3(0.0, 0.0, 1.0));
    gl_FragColor = vec4(vUv, intensity, 1.0);
}

Интерполяция varying позволяет создавать плавные переходы цветов, освещения или эффектов по поверхности модели.


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

ShaderMaterial поддерживает любые текстуры через uniforms типа sampler2D. Для этого создаётся uniform с текстурой и передаётся в GLSL:

const texture = new THREE.TextureLoader().load('texture.jpg');

const material = new THREE.ShaderMaterial({
    uniforms: {
        uTexture: { value: texture }
    },
    vertexShader: `
        varying vec2 vUv;
        void main() {
            vUv = uv;
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        }
    `,
    fragmentShader: `
        uniform sampler2D uTexture;
        varying vec2 vUv;
        void main() {
            gl_FragColor = texture2D(uTexture, vUv);
        }
    `
});

Поддерживаются прозрачные текстуры и альфа-каналы при transparent: true. Можно комбинировать несколько текстур с помощью разных uniforms.


Применение анимации в ShaderMaterial

Для создания динамических эффектов часто используют uniform time. Это позволяет реализовать пульсации, смещения, волны и другие эффекты без изменения геометрии:

uniforms: {
    time: { value: 0.0 }
},

fragmentShader: `
    uniform float time;
    varying vec2 vUv;
    void main() {
        float wave = sin(vUv.x * 10.0 + time) * 0.5 + 0.5;
        gl_FragColor = vec4(vec3(wave), 1.0);
    }
`

В JavaScript-анимации:

function animate(deltaTime) {
    uniforms.time.value += deltaTime;
    renderer.render(scene, camera);
    requestAnimationFrame(animate);
}

Настройка рендеринга и прозрачности

ShaderMaterial поддерживает:

  • Прозрачность: transparent: true и управление альфа-каналом через gl_FragColor.a.
  • Двустороннюю отрисовку: side: THREE.DoubleSide.
  • Режим смешивания: blending: THREE.AdditiveBlending или другие режимы для эффектов свечения.

Пример создания полупрозрачного материала с двойной стороной:

const material = new THREE.ShaderMaterial({
    vertexShader: vertexShaderCode,
    fragmentShader: fragmentShaderCode,
    transparent: true,
    side: THREE.DoubleSide
});

Использование defines и макросов

defines позволяет внедрять макросы на этапе компиляции GLSL, что упрощает условные конструкции и конфигурацию шейдера:

const material = new THREE.ShaderMaterial({
    defines: {
        USE_WAVE: true
    },
    vertexShader: `
        #ifdef USE_WAVE
        uniform float time;
        #endif
        void main() {
            vec3 pos = position;
            #ifdef USE_WAVE
            pos.y += sin(position.x * 5.0 + time);
            #endif
            gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
        }
    `,
    fragmentShader: fragmentShaderCode
});

Макросы позволяют отключать или включать сложные эффекты без изменения основной логики шейдера.


Оптимизация ShaderMaterial

Для больших сцен и сложных эффектов важно:

  • Минимизировать количество uniforms и varyings.
  • Использовать текстуры вместо вычислений в фрагментном шейдере, когда возможно.
  • Компилировать шейдеры заранее через material.needsUpdate = true при изменении кода.
  • Использовать precision и простые математические функции для улучшения производительности.

Примеры эффектов

  • Пульсирующие поверхности – с использованием времени и синусоид.
  • Градиентные цвета – через координаты вершин и интерполяцию.
  • Эффекты волн и деформации – модификация позиции вершин.
  • Текстурные переходы и смешивания – через sampler2D и mix.

ShaderMaterial является ключевым инструментом для создания уникальных визуальных эффектов, полного контроля над рендерингом и реализации GPU-вычислений в Three.js.