WebGL: руковод BEGINNER'С Guide to 3D Graphics in the Browser

Привет, будущие маги 3D-графики! Я рад быть вашим проводником в этом захватывающем путешествии в мир WebGL. Как кто-то, кто преподавал компьютерную графику на протяжении многих лет, я могу告诉你, что WebGL resembles a magic wand for your web browser. Он позволяет создавать потрясающие 3D-графики и анимации прямо на ваших веб-страницах. Это классно, да? Давайте окунемся в это!

WebGL - Home

Что такое WebGL?

WebGL, сокращение от Web Graphics Library, является API на JavaScript, который позволяет рендерить интерактивные 2D и 3D графики в любом compatible веб-браузере без необходимости использования плагинов. Это как дать вашему веб-браузеру суперсилы для создания потрясающих визуальных переживаний!

Краткая история

WebGL был впервые представлен в 2011 году, и с тех пор он изменил наше представление о graphике в Интернете. До WebGL, если вы хотели создать 3D-графику в браузере, вам приходилось полагаться на плагины, такие как Flash или Java applets. Теперь, с WebGL, мы можем делать все это nativement в браузере. Это как если бы мы перешли от велосипеда к спортивному автомобилю!

Предпосылки

Before мы начнем наше приключение с WebGL, давайте убедимся, что у нас есть правильные инструменты в нашем рюкзаке:

  1. Современный веб-браузер (Chrome, Firefox, Safari или Edge)
  2. Текстовый редактор (я recommend Visual Studio Code, но любой подойдет)
  3. Основные знания HTML и JavaScript (не волнуйтесь, если вы немного подзабыли, мы revisited по мере необходимости)

Начало работы с WebGL

Давайте создадим наш первый WebGL program! Мы начнем с простого примера "Hello, WebGL!", который отображает окрашенный треугольник на экране.

Шаг 1: Настройка HTML

Сначала нам нужно создать HTML-файл с элементом canvas. Это место, где будет происходить наша WebGL магия.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Hello, WebGL!</title>
<style>
canvas { border: 1px solid black; }
</style>
</head>
<body>
<canvas id="glCanvas" width="640" height="480"></canvas>
<script src="webgl-demo.js"></script>
</body>
</html>

В этом HTML мы создали элемент canvas с ID "glCanvas" и установили его размеры 640x480 пикселей. Мы также сослались на JavaScript-файл под названием "webgl-demo.js", где мы напишем наш код WebGL.

Шаг 2: Инициализация WebGL

Теперь создадим файл "webgl-demo.js" и начнем писать JavaScript для инициализации WebGL:

function main() {
const canvas = document.getElementById("glCanvas");
const gl = canvas.getContext("webgl");

if (!gl) {
alert("Unable to initialize WebGL. Your browser or machine may not support it.");
return;
}

// Set clear color to black, fully opaque
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// Clear the color buffer with specified clear color
gl.clear(gl.COLOR_BUFFER_BIT);
}

window.onload = main;

Давайте разберем это:

  1. Мы получаем ссылку на наш элемент canvas.
  2. Мы пытаемся получить контекст WebGL из canvas. Если это не удается, это означает, что WebGL не поддерживается, и мы показываем сообщение об ошибке.
  3. Если успешно, мы устанавливаем цвет стирания (цвет фона) на черный и стираем canvas.

Шаг 3: Создание шейдеров

Шейдеры - это специальные программы, которые работают на GPU. Они написаны на языке GLSL (OpenGL Shading Language). Нам нужны два типа шейдеров: вершины и фрагменты.

// Vertex shader program
const vsSource = `
attribute vec4 aVertexPosition;

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

// Fragment shader program
const fsSource = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

Вершины шейдера задают положение наших вершин, а фрагменты шейдера красят наши пиксели (в этом случае, красные).

Шаг 4: Инициализация шейдерной программы

Теперь нам нужно скомпилировать и связать эти шейдеры в шейдерную программу:

function initShaderProgram(gl, vsSource, fsSource) {
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);

const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);

if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
return null;
}

return shaderProgram;
}

function loadShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);

if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}

return shader;
}

Этот код компилирует наши шейдеры, связывает их в программу и проверяет на наличие ошибок.

Шаг 5: Создание треугольника

Теперь давайте создадим данные для нашего треугольника:

function initBuffers(gl) {
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

const positions = [
-1.0,  1.0,
1.0,  1.0,
-1.0, -1.0,
];

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

return {
position: positionBuffer,
};
}

Это создает буфер и заполняет его положениями наших вершинного треугольника.

Шаг 6: Отрисовка сцены

Теперь давайте соберем все вместе и отрисуем наш треугольник:

function drawScene(gl, programInfo, buffers) {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);

gl.useProgram(programInfo.program);

gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
gl.vertexAttribPointer(
programInfo.attribLocations.vertexPosition,
2,        // 2 components per iteration
gl.FLOAT, // the data is 32bit floats
false,    // don't normalize
0,        // stride (0 = auto)
0         // offset into the buffer
);

gl.drawArrays(gl.TRIANGLES, 0, 3);
}

Эта функция стирает canvas, устанавливает шейдерную программу, подключает данные буфера и finally рисует наш треугольник.

Собираем все вместе

Теперь обновим нашу функцию main, чтобы использовать все эти фрагменты:

function main() {
const canvas = document.getElementById("glCanvas");
const gl = canvas.getContext("webgl");

if (!gl) {
alert("Unable to initialize WebGL. Your browser or machine may not support it.");
return;
}

const shaderProgram = initShaderProgram(gl, vsSource, fsSource);

const programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
},
};

const buffers = initBuffers(gl);

drawScene(gl, programInfo, buffers);
}

window.onload = main;

И вот оно! Ваш первый program WebGL. Когда вы откроете ваш HTML-файл в браузере, вы должны увидеть красный треугольник на черном фоне. Поздравляю!

Общие методы WebGL

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

Метод Цель
gl.createBuffer() Создает новый буферный объект
gl.bindBuffer() Привязывает буферный объект к цели
gl.bufferData() Инициализирует и создает хранилище данных буферного объекта
gl.createShader() Создает объект шейдера
gl.shaderSource() Устанавливает исходный код объекта шейдера
gl.compileShader() Компилирует объект шейдера
gl.createProgram() Создает объект программы
gl.attachShader() Привязывает объект шейдера к объекту программы
gl.linkProgram() Связывает объект программы
gl.useProgram() Устанавливает указанную программу как часть текущего состояния рендеринга
gl.getAttribLocation() Возвращает местоположение переменной атрибута
gl.enableVertexAttribArray() Включает массив атрибутов
gl.vertexAttribPointer() Указывает布局 данных атрибута вершины
gl.drawArrays() Рендерит примитивы из массивных данных

Заключение

Ух, мы covered много сегодня! Мы узнали, что такое WebGL, настроили нашу среду разработки и создали наш первый program WebGL. Помните, учиться WebGL resembles учиться ездить на велосипеде - сначала это может показаться неустойчивым, но с практикой вы быстро начнете ездить!

В будущих уроках мы explored более сложные формы, добавим интерактивность и даже погрузимся в 3D графику. Мир WebGL обширен и захватывающ, и я не могу дождаться, чтобы исследовать его с вами. До свидания, счастливого кодирования!

Credits: Image by storyset