AttachShader: примеры (JAVASCRIPT)

attachShader: присоединение шейдеров в WebGL
Раздел: WebGL, Шейдеры
attachShader(program: WebGLProgram, shader: WebGLShader): undefined

Основы функции attachShader

Функция attachShader() является частью WebGL API и доступна через объект WebGLProgram. Ее основное назначение - присоединить заранее скомпилированный шейдер (вершинный или фрагментный) к программе WebGL перед линковкой.

Функция используется на этапе создания графического конвейера в WebGL, после компиляции шейдеров и перед вызовом linkProgram(). Без правильного присоединения шейдеров программа не будет работоспособной.

Аргументы функции:

  • program (объект WebGLProgram) - программа, к которой присоединяется шейдер.
  • shader (объект WebGLShader) - скомпилированный шейдер (вершинный или фрагментный).

Функция не возвращает значений. В случае ошибки генерируется исключение или ошибка WebGL контекста.

Базовые примеры использования

Стандартный процесс присоединения шейдеров:

// Создание программы и шейдеров
const gl = canvas.getContext('webgl');
const program = gl.createProgram();
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);

// Компиляция шейдеров (код опущен для краткости)
// ...

// Присоединение шейдеров к программе
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);

// Линковка программы
gl.linkProgram(program);
// Результат: программа готова к использованию
// Проверка статуса линковки:
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    console.error('Ошибка линковки:', gl.getProgramInfoLog(program));
}

Похожие функции в JavaScript

В чистом JavaScript/WebGL прямых аналогов attachShader нет, так как это специфичная функция графического контекста. Однако в рамках WebGL можно отметить:

  • createShader() - создает объект шейдера, но не присоединяет его.
  • shaderSource() - устанавливает исходный код шейдера.
  • compileShader() - компилирует шейдер.
  • linkProgram() - линкует программу после присоединения шейдеров.

В библиотеках более высокого уровня (Three.js, Babylon.js) процесс присоединения шейдеров инкапсулирован, и явный вызов attachShader не требуется.

Альтернативы в других языках

В других языках и графических API существуют аналогичные механизмы:

C/C++ с OpenGL:

GLuint program = glCreateProgram();
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
// ... компиляция шейдера
glAttachShader(program, vertexShader);
glLinkProgram(program);
// Аналогично WebGL, синтаксис практически идентичен

Python с PyOpenGL:

from OpenGL.GL import *
program = glCreateProgram()
vertex_shader = glCreateShader(GL_VERTEX_SHADER)
# ... компиляция шейдера
glAttachShader(program, vertex_shader)
glLinkProgram(program)
// Интерфейс соответствует спецификации OpenGL

PHP с расширением OpenGL (редко): Практически не используется в веб-среде.

Типичные ошибки

1. Передача неправильных объектов:

const gl = canvas.getContext('webgl');
const program = gl.createProgram();
// Ошибка: передача не шейдера
gl.attachShader(program, gl); // TypeError
Uncaught TypeError: Failed to execute 'attachShader' on 'WebGLRenderingContext': parameter 2 is not of type 'WebGLShader'.

2. Присоединение нескомпилированного шейдера:

const shader = gl.createShader(gl.VERTEX_SHADER);
// Шейдер не скомпилирован!
gl.attachShader(program, shader); // Ошибка не здесь, но позже
gl.linkProgram(program); // Программа не слинкуется
// Программа не линкуется, getProgramParameter вернет false

3. Повторное присоединение того же шейдера:

gl.attachShader(program, shader);
gl.attachShader(program, shader); // Нет ошибки, но избыточно
// Функция отработает, но второй вызов бесполезен

Изменения в последних версиях

Функция attachShader остается стабильной и неизменной с момента введения WebGL 1.0. В WebGL 2.0 функция не претерпела изменений в сигнатуре или поведении, но появилась поддержка новых типов шейдеров (например, compute shaders), которые также могут быть присоединены с помощью этой функции.

В современных браузерах функция работает идентично как в WebGL 1.0, так и в WebGL 2.0 контекстах.

Расширенные примеры использования

1. Динамическая замена шейдера в программе:

Пример javascript
// Создание программы с возможностью 'горячей' замены шейдеров
class DynamicShaderProgram {
    constructor(gl) {
        this.gl = gl;
        this.program = gl.createProgram();
        this.attachedShaders = new Set();
    }
    
    attachAndCompile(shaderType, sourceCode) {
        const shader = this.gl.createShader(shaderType);
        this.gl.shaderSource(shader, sourceCode);
        this.gl.compileShader(shader);
        
        // Отсоединяем старый шейдер того же типа, если есть
        for (const oldShader of this.attachedShaders) {
            if (this.gl.getShaderParameter(oldShader, this.gl.SHADER_TYPE) === shaderType) {
                this.gl.detachShader(this.program, oldShader);
                this.attachedShaders.delete(oldShader);
                this.gl.deleteShader(oldShader);
            }
        }
        
        this.gl.attachShader(this.program, shader);
        this.attachedShaders.add(shader);
        return shader;
    }
    
    link() {
        this.gl.linkProgram(this.program);
        // Удаляем шейдеры после успешной линковки
        for (const shader of this.attachedShaders) {
            this.gl.detachShader(this.program, shader);
            this.gl.deleteShader(shader);
        }
        this.attachedShaders.clear();
    }
}
// Класс позволяет менять шейдеры без пересоздания программы

2. Присоединение нескольких шейдеров одного типа (WebGL 2):

Пример javascript
// WebGL 2 поддерживает множественные шейдеры одного типа
const gl = canvas.getContext('webgl2');
const program = gl.createProgram();

// Несколько вершинных шейдеров (редкий случай)
const vs1 = createAndCompileShader(gl, gl.VERTEX_SHADER, source1);
const vs2 = createAndCompileShader(gl, gl.VERTEX_SHADER, source2);

gl.attachShader(program, vs1);
gl.attachShader(program, vs2); // Второй вершинный шейдер
gl.attachShader(program, fragmentShader);

gl.linkProgram(program); // Линковка объединит код шейдеров
// Возможность модульной компиляции шейдерного кода

3. Использование с трансформационными фрагментными шейдерами:

Пример javascript
// Присоединение специализированных шейдеров для постобработки
function createPostProcessingProgram(gl, fragmentShaderSource) {
    const program = gl.createProgram();
    
    // Стандартный вершинный шейдер для полноэкранного квада
    const vsSource = `
        attribute vec2 aPosition;
        varying vec2 vTexCoord;
        void main() {
            vTexCoord = aPosition * 0.5 + 0.5;
            gl_Position = vec4(aPosition, 0.0, 1.0);
        }
    `;
    
    const vs = compileShader(gl, gl.VERTEX_SHADER, vsSource);
    const fs = compileShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
    
    gl.attachShader(program, vs);
    gl.attachShader(program, fs);
    gl.linkProgram(program);
    
    // Шейдеры можно удалить после линковки
    gl.deleteShader(vs);
    gl.deleteShader(fs);
    
    return program;
}
// Создание программы для эффектов постобработки

JS attachShader function comments

En
AttachShader Attaches a WebGLShader to a WebGLProgram