WebGL - Графический конвейер

Здравствуйте, будущие программисты! Сегодня мы отправимся в увлекательное путешествие по Графическому конвейеру WebGL. Не волнуйтесь, если вы новички в программировании - я буду вашим дружелюбным проводником, и мы будем двигаться шаг за шагом. К концу этого урока вы получите прочное представление о том, как WebGL преобразует ваш код в потрясающие визуальные эффекты на вашем экране.

WebGL - Graphics Pipeline

JavaScript: Точка старта

Прежде чем мы погрузимся в глубины WebGL, давайте начнем с чего-то знакомого - JavaScript. WebGL доступен через JavaScript, что делает его идеальной отправной точкой для нашего приключения.

Ваш первый WebGL program

Давайте начнем с простого примера:

// Получаем элемент canvas
const canvas = document.getElementById('myCanvas');

// Получаем контекст WebGL
const gl = canvas.getContext('webgl');

// Устанавливаем цвет cleared (цвет фона)
gl.clearColor(0.0, 0.0, 0.0, 1.0);

// Очищаем canvas
gl.clear(gl.COLOR_BUFFER_BIT);

В этом фрагменте кода мы делаем несколько вещей:

  1. Получаем ссылку на наш элемент HTML canvas.
  2. Получаем контекст рендеринга WebGL.
  3. Устанавливаем цвет cleared (в данном случае, черный).
  4. Очищаем canvas是我们的 specified цветом.

Это может показаться не много, но恭喜您! Вы только что создали свой первый WebGL program. Это как preparing eine空白 canvas для шедевра.

Vertex Shader: Формирование вашего мира

Теперь, когда у нас готов canvas, давайте поговорим о vertex shaders. Представьте vertex shaders как скульпторов вашего 3D мира. Они работают с сырыми данными ваших объектов - вершинами.

Простой Vertex Shader

Вот пример базового vertex shader:

attribute vec4 a_position;

void main() {
gl_Position = a_position;
}

Этот шейдер делает что-то простое, но важное - он принимает положение каждой вершины и присваивает его gl_Position. Это как decir каждой точке вашего 3D объекта: "Иди сюда!"

Primitive Assembly: Соединение точек

После того как vertex shader выполнил свою работу, WebGL переходит к primitive assembly. Этот этап похож на "Соединение точек" - он принимает отдельные вершины и определяет, как они должны быть соединены для образования фигур.

Например, если вы рисуете треугольник, primitive assembly возьмет три вершины и поймет, что они образуют один треугольник.

Rasterization: Пиксели повсюду

Теперь наступает магия rasterization. Этот этап преобразует наши 3D фигуры в 2D пиксели, которые вы видите на экране. Это как transform eine 3D скульптуру в подробное фото.

Fragment Shader: Окрашивание вашего мира

Fragment shader - это где happens настоящее искусство. В то время как vertex shader занимался структурой ваших объектов, fragment shader их красит.

Простой Fragment Shader

Вот пример базового fragment shader, который окрашивает все в красный цвет:

precision mediump float;

void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

Этот шейдер устанавливает gl_FragColor в вектор, представляющий красный цвет (полностью красный, без зелени, без синего, полная непрозрачность). Это как макать весь ваш 3D мир в красную краску!

Fragment Operations: Последние штрихи

После fragment shader, WebGL выполняет различные операции с фрагментами. Это включает тестирование глубины (определение, какие объекты находятся впереди других), смешивание (как прозрачные объекты взаимодействуют) и многое другое.

Frame Buffer: Grande Finale

Наконец, мы достигаем frame buffer. Это где ваш отрендеренный изображение хранится перед тем, как быть отображенным на экране. Это как backstage зона, где的最后 штрихи применяются перед поднятием занавеса.

Вszystkie вместе

Теперь, когда мы прошли через каждый этап, давайте посмотрим, как они все работают вместе в complete WebGL program:

// Источник кода vertex shader
const vsSource = `
attribute vec4 aVertexPosition;

void main() {
gl_Position = aVertexPosition;
}
`;

// Источник кода fragment shader
const fsSource = `
precision mediump float;

void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

// Инициализация шейдеров
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vsSource);
gl.compileShader(vertexShader);

const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fsSource);
gl.compileShader(fragmentShader);

// Создание шейдерной программы
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);

// Использование программы
gl.useProgram(shaderProgram);

// Создание буфера и передача данных
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const positions = [
1.0,  1.0,
-1.0,  1.0,
1.0, -1.0,
-1.0, -1.0,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

// Говорим WebGL, как извлечь позиции из буфера в атрибут vertexPosition
const numComponents = 2;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.vertexAttribPointer(
gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
numComponents,
type,
normalize,
stride,
offset);
gl.enableVertexAttribArray(gl.getAttribLocation(shaderProgram, 'aVertexPosition'));

// Рисуем сцену
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

Этот program создает простой красный квадрат на черном фоне. Давайте разберем его:

  1. Мы определяем наши vertex и fragment шейдеры.
  2. Мы компилируем эти шейдеры и связываем их в программу.
  3. Мы создаем буфер с положениями вершин нашего квадрата.
  4. Мы говорим WebGL, как интерпретировать эту буферную информацию.
  5. Наконец, мы очищаем экран и рисуем наш квадрат.

Каждый шаг соответствует этапу в графическом конвейере, о котором мы говорили. Это как наблюдать за производственной линией, где сырые материалы (vertex данные) transform в finished продукт (пиксели на вашем экране).

Methods Table

Вот таблица ключевых методов WebGL, которые мы использовали:

Метод Описание
gl.createShader() Создает объект шейдера
gl.shaderSource() Устанавливает исходный код шейдера
gl.compileShader() Компилирует шейдер
gl.createProgram() Создает объект программы
gl.attachShader() Прикрепляет шейдер к программе
gl.linkProgram() Связывает объект программы
gl.useProgram() Устанавливает указанную программу как часть текущего состояния рендеринга
gl.createBuffer() Создает объект буфера
gl.bindBuffer() Привязывает объект буфера к цели
gl.bufferData() Создает и инициализирует хранилище данных буфера
gl.vertexAttribPointer() Указывает, как извлечь позиции из буфера в атрибут vertexPosition
gl.enableVertexAttribArray() Включает массив атрибутов
gl.clearColor() Указывает цвет для clearing color buffers
gl.clear() Очищает буферы до preset значений
gl.drawArrays() Рисует примитивы из массива данных

И вот оно! Мы прошли через Графический конвейер WebGL, от JavaScript до final frame buffer. Помните, как и любая skill, овладение WebGL требует практики. Но с каждой строкой кода, которую вы пишете, вы делаете один шаг ближе к созданию потрясающей 3D графики в вашем веб-браузере. Продолжайте экспериментировать, продолжайте учиться и, что самое главное, получайте удовольствие!

Credits: Image by storyset