01:09
Урок 46: Введение в графику с WebGL

Курс по программированию на JavaScript

Урок 46: Введение в графику с WebGL

WebGL (Web Graphics Library) — это JavaScript API для рендеринга 2D и 3D графики в веб-браузере без использования плагинов. WebGL позволяет использовать аппаратное ускорение графики, предоставляя мощные возможности для создания интерактивных графических приложений. В этом уроке мы рассмотрим основы WebGL и создание простых 3D-сцен.

Основы WebGL

WebGL основан на OpenGL ES 2.0 и предоставляет программный интерфейс для работы с графическим процессором (GPU). С помощью WebGL можно создавать сложные графические сцены, манипулировать ими и отображать их в реальном времени.

Чтобы начать работу с WebGL, нам нужно создать контекст WebGL и инициализировать его. Рассмотрим пример создания контекста WebGL:

<canvas id="glcanvas" width="640" height="480"></canvas>

<script>
 const canvas = document.getElementById('glcanvas');
 const gl = canvas.getContext('webgl');

 if (!gl) {
 console.error('WebGL не поддерживается вашим браузером.');
 }
</script>
// Контекст WebGL инициализирован

Рендеринг простейшего треугольника

Давайте рассмотрим пример рендеринга простейшего треугольника с помощью WebGL:

<canvas id="glcanvas" width="640" height="480"></canvas>

<script>
 const canvas = document.getElementById('glcanvas');
 const gl = canvas.getContext('webgl');

 if (!gl) {
 console.error('WebGL не поддерживается вашим браузером.');
 }

 // Устанавливаем цвет очистки и очищаем буфер цвета
 gl.clearColor(0.0, 0.0, 0.0, 1.0);
 gl.clear(gl.COLOR_BUFFER_BIT);

 // Определяем вершины треугольника
 const vertices = new Float32Array([
 0.0, 1.0,
 -1.0, -1.0,
 1.0, -1.0,
 ]);

 // Создаем буфер и загружаем в него вершины
 const vertexBuffer = gl.createBuffer();
 gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
 gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

 // Определяем и компилируем шейдеры
 const vertexShaderSource = `
 attribute vec2 aPosition;
 void main() {
 gl_Position = vec4(aPosition, 0.0, 1.0);
 }
 `;
 const fragmentShaderSource = `
 void main() {
 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
 }
 `;
 const vertexShader = gl.createShader(gl.VERTEX_SHADER);
 gl.shaderSource(vertexShader, vertexShaderSource);
 gl.compileShader(vertexShader);

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

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

 // Привязываем буфер вершин к атрибуту шейдера
 const positionAttribLocation = gl.getAttribLocation(shaderProgram, 'aPosition');
 gl.enableVertexAttribArray(positionAttribLocation);
 gl.vertexAttribPointer(positionAttribLocation, 2, gl.FLOAT, false, 0, 0);

 // Рендерим треугольник
 gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
// Треугольник отрендерен

Создание простых 3D-сцен

Для создания 3D-сцен с помощью WebGL нужно определить вершины объектов, настроить камеры и освещение, а также создать шейдеры для рендеринга. Рассмотрим пример создания простого куба.

<canvas id="glcanvas" width="640" height="480"></canvas>

<script>
 const canvas = document.getElementById('glcanvas');
 const gl = canvas.getContext('webgl');

 if (!gl) {
 console.error('WebGL не поддерживается вашим браузером.');
 }

 // Устанавливаем цвет очистки и очищаем буфер цвета
 gl.clearColor(0.0, 0.0, 0.0, 1.0);
 gl.clear(gl.COLOR_BUFFER_BIT);

 // Определяем вершины куба
 const vertices = new Float32Array([
 -1.0, -1.0, -1.0,
 1.0, -1.0, -1.0,
 1.0, 1.0, -1.0,
 -1.0, 1.0, -1.0,
 -1.0, -1.0, 1.0,
 1.0, -1.0, 1.0,
 1.0, 1.0, 1.0,
 -1.0, 1.0, 1.0,
 ]);

 // Определяем индексы вершин для рендеринга куба
 const indices = new Uint16Array([
 0, 1, 2, 0, 2, 3,
 4, 5, 6, 4, 6, 7,
 0, 1, 5, 0, 5, 4,
 2, 3, 7, 2, 7, 6,
 0, 3, 7, 0, 7, 4,
 1, 2, 6, 1, 6, 5
 ]);

 // Создаем буферы и загружаем в них вершины и индексы
 const vertexBuffer = gl.createBuffer();
 const indexBuffer = gl.createBuffer();
 gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
 gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);

 // Определяем и компилируем шейдеры
 const vertexShaderSource = `
 attribute vec3 aPosition;
 uniform mat4 uModelViewMatrix;
 uniform mat4 uProjectionMatrix;
 void main() {
 gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aPosition, 1.0);
 }
 `;
 const fragmentShaderSource = `
 void main() {
 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
 }
 `;
 const vertexShader = gl.createShader(gl.VERTEX_SHADER);
 gl.shaderSource(vertexShader, vertexShaderSource);
 gl.compileShader(vertexShader);

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

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

 // Привязываем буфер вершин к атрибуту шейдера
 const positionAttribLocation = gl.getAttribLocation(shaderProgram, 'aPosition');
 gl.enableVertexAttribArray(positionAttribLocation);
 gl.vertexAttribPointer(positionAttribLocation, 3, gl.FLOAT, false, 0, 0);

 // Определяем матрицы модели-вида и проекции
 const modelViewMatrix = mat4.create();
 const projectionMatrix = mat4.create();
 mat4.perspective(projectionMatrix, 45, canvas.width / canvas.height, 0.1, 100.0);
 mat4.translate(modelViewMatrix, modelViewMatrix, [0.0, 0.0, -6.0]);

 // Передаем матрицы в шейдеры
 const modelViewMatrixLocation = gl.getUniformLocation(shaderProgram, 'uModelViewMatrix');
 const projectionMatrixLocation = gl.getUniformLocation(shaderProgram, 'uProjectionMatrix');
 gl.uniformMatrix4fv(modelViewMatrixLocation, false, modelViewMatrix);
 gl.uniformMatrix4fv(projectionMatrixLocation, false, projectionMatrix);

 // Рендеринг куба
 gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
</script>
// Куб отрендерен

Упражнения

Упражнение 1: Рендеринг квадрата

Создайте простую сцену, которая рендерит квадрат. Определите вершины квадрата и используйте шейдеры для отображения.

Решение:

<canvas id="glcanvas" width="640" height="480"></canvas>

<script>
 const canvas = document.getElementById('glcanvas');
 const gl = canvas.getContext('webgl');

 if (!gl) {
 console.error('WebGL не поддерживается вашим браузером.');
 }

 // Устанавливаем цвет очистки и очищаем буфер цвета
 gl.clearColor(0.0, 0.0, 0.0, 1.0);
 gl.clear(gl.COLOR_BUFFER_BIT);

 // Определяем вершины квадрата
 const vertices = new Float32Array([
 -1.0, -1.0,
 1.0, -1.0,
 1.0, 1.0,
 -1.0, 1.0,
 ]);

 // Определяем индексы вершин
 const indices = new Uint16Array([
 0, 1, 2,
 0, 2, 3
 ]);

 // Создаем буфер и загружаем в него вершины и индексы
 const vertexBuffer = gl.createBuffer();
 const indexBuffer = gl.createBuffer();
 gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
 gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);

 // Определяем и компилируем шейдеры
 const vertexShaderSource = `
 attribute vec2 aPosition;
 void main() {
 gl_Position = vec4(aPosition, 0.0, 1.0);
 }
 `;
 const fragmentShaderSource = `
 void main() {
 gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
 }
 `;
 const vertexShader = gl.createShader(gl.VERTEX_SHADER);
 gl.shaderSource(vertexShader, vertexShaderSource);
 gl.compileShader(vertexShader);

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

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

 // Привязываем буфер вершин к атрибуту шейдера
 const positionAttribLocation = gl.getAttribLocation(shaderProgram, 'aPosition');
 gl.enableVertexAttribArray(positionAttribLocation);
 gl.vertexAttribPointer(positionAttribLocation, 2, gl.FLOAT, false, 0, 0);

 // Рендеринг квадрата
 gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
</script>
// Квадрат отрендерен

Объяснение: Мы определили вершины и индексы для квадрата, создали шейдеры и отрендерили квадрат.

Упражнение 2: Вращение куба

Создайте анимацию вращения куба. Используйте requestAnimationFrame для создания плавной анимации.

Решение:

<canvas id="glcanvas" width="640" height="480"></canvas>

<script>
 const canvas = document.getElementById('glcanvas');
 const gl = canvas.getContext('webgl');

 if (!gl) {
 console.error('WebGL не поддерживается вашим браузером.');
 }

 // Устанавливаем цвет очистки и очищаем буфер цвета
 gl.clearColor(0.0, 0.0, 0.0, 1.0);
 gl.clear(gl.COLOR_BUFFER_BIT);

 // Определяем вершины куба
 const vertices = new Float32Array([
 -1.0, -1.0, -1.0,
 1.0, -1.0, -1.0,
 1.0, 1.0, -1.0,
 -1.0, 1.0, -1.0,
 -1.0, -1.0, 1.0,
 1.0, -1.0, 1.0,
 1.0, 1.0, 1.0,
 -1.0, 1.0, 1.0,
 ]);

 // Определяем индексы вершин
 const indices = new Uint16Array([
 0, 1, 2, 0, 2, 3,
 4, 5, 6, 4, 6, 7,
 0, 1, 5, 0, 5, 4,
 2, 3, 7, 2, 7, 6,
 0, 3, 7, 0, 7, 4,
 1, 2, 6, 1, 6, 5
 ]);

 // Создаем буферы и загружаем в них вершины и индексы
 const vertexBuffer = gl.createBuffer();
 const indexBuffer = gl.createBuffer();
 gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
 gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);

 // Определяем и компилируем шейдеры
 const vertexShaderSource = `
 attribute vec3 aPosition;
 uniform mat4 uModelViewMatrix;
 uniform mat4 uProjectionMatrix;
 void main() {
 gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aPosition, 1.0);
 }
 `;
 const fragmentShaderSource = `
 void main() {
 gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
 }
 `;
 const vertexShader = gl.createShader(gl.VERTEX_SHADER);
 gl.shaderSource(vertexShader, vertexShaderSource);
 gl.compileShader(vertexShader);

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

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

 // Привязываем буфер вершин к атрибуту шейдера
 const positionAttribLocation = gl.getAttribLocation(shaderProgram, 'aPosition');
 gl.enableVertexAttribArray(positionAttribLocation);
 gl.vertexAttribPointer(positionAttribLocation, 3, gl.FLOAT, false, 0, 0);

 // Определяем матрицы модели-вида и проекции
 const modelViewMatrix = mat4.create();
 const projectionMatrix = mat4.create();
 mat4.perspective(projectionMatrix, 45, canvas.width / canvas.height, 0.1, 100.0);
 mat4.translate(modelViewMatrix, modelViewMatrix, [0.0, 0.0, -6.0]);

 // Передаем матрицы в шейдеры
 const modelViewMatrixLocation = gl.getUniformLocation(shaderProgram, 'uModelViewMatrix');
 const projectionMatrixLocation = gl.getUniformLocation(shaderProgram, 'uProjectionMatrix');
 gl.uniformMatrix4fv(projectionMatrixLocation, false, projectionMatrix);

 let angle = 0;

 function animate() {
 angle += 0.01;
 mat4.rotate(modelViewMatrix, mat4.create(), angle, [1, 1, 1]);
 gl.uniformMatrix4fv(modelViewMatrixLocation, false, modelViewMatrix);

 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
 gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);

 requestAnimationFrame(animate);
 }

 requestAnimationFrame(animate);
</script>
// Куб вращается

Объяснение: Мы добавили анимацию вращения куба с использованием requestAnimationFrame для создания плавной анимации.

Категория: JavaScript | Просмотров: 36 | Добавил: Admin | Рейтинг: 0.0/0
Всего комментариев: 0
Имя *:
Email *:
Код *: