AttachShader: примеры (JAVASCRIPT)
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); // TypeErrorUncaught 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. Динамическая замена шейдера в программе:
// Создание программы с возможностью 'горячей' замены шейдеров
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):
// 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. Использование с трансформационными фрагментными шейдерами:
// Присоединение специализированных шейдеров для постобработки
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;
}// Создание программы для эффектов постобработки