webgl - RIP Tutorial · Атрибуты поставляют данные только в...

20
webgl #webgl

Transcript of webgl - RIP Tutorial · Атрибуты поставляют данные только в...

Page 1: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

webgl

#webgl

Page 2: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

1

1: webgl 2

2

Examples 3

3

WebGL - 6

, 7

2: 13

Examples 13

13

14

15

15

15

18

Page 3: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

ОколоYou can share this PDF with anyone you feel could benefit from it, downloaded the latest version from: webgl

It is an unofficial and free webgl ebook created for educational purposes. All the content is extracted from Stack Overflow Documentation, which is written by many hardworking individuals at Stack Overflow. It is neither affiliated with Stack Overflow nor official webgl.

The content is released under Creative Commons BY-SA, and the list of contributors to each chapter are provided in the credits section at the end of this book. Images may be copyright of their respective owners unless otherwise specified. All trademarks and registered trademarks are the property of their respective company owners.

Use the content presented in this book at your own risk; it is not guaranteed to be correct nor accurate, please send your feedback and corrections to [email protected]

https://riptutorial.com/ru/home 1

Page 4: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

глава 1: Начало работы с webgl

замечания

WebGL - это API растеризации, который обычно работает на вашем GPU, что дает вам возможность быстро рисовать 2D и 3D-графики. WebGL также может использоваться для выполнения вычислений на массивах данных.

WebGL - очень низкоуровневый API. На базовом уровне WebGL - это движок, который запускает на GPU 2 пользовательских функции. Одна функция называется вершинным шейдером . Задача вершинного шейдера заключается в вычислении вершинных позиций. На основе позиций, которые функция выводит WebGL, можно растрировать различные типы примитивов, включая точки, линии или треугольники. При растрировании этих примитивов он вызывает вторую пользовательскую функцию, называемую шейдером фрагментов . Задача фейдер-шейдера заключается в вычислении цвета для каждого пикселя примитива, который в настоящее время рисуется.

Эти функции написаны на языке GLSL, который несколько похож на C / C ++ и строго типизирован.

Программист должен предоставить эти функции, чтобы сделать WebGL рисованием 2d, 3d

или вычислить что-то. Почти каждая часть WebGL - это настройка этих двух функций, а затем предоставление данных для них.

Данные могут быть предоставлены из 4 источников.

Униформа•

Униформа - это входы в шейдерные функции, очень похожие на функциональные параметры или глобальные переменные. Они устанавливаются один раз перед выполнением шейдера и остаются неизменными во время выполнения

Атрибуты•

Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать данные из буферов. Например, вы можете поместить позиции, нормальные и текстурные координаты в буфер. Атрибуты позволяют сообщать WebGL, как вытащить эти данные из ваших буферов и предоставить их вершинному шейдеру. Вершинный шейдер называется пользователем определенное количество раз, вызывая gl.drawArrays или gl.drawElements и указывая счетчик. Каждый раз, когда вызывается текущий вершинный шейдер, следующий набор данных вытягивается из указанных пользователем буферов и помещается в атрибуты

текстуры•

https://riptutorial.com/ru/home 2

Page 5: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

Текстуры представляют собой двумерные массивы данных с 4 каналами. Чаще всего эти 4 канала представляют собой красный, зеленый, синий и альфа из изображения. WebGL все равно, что данные. В отличие от атрибутов и буферов шейдеры могут считывать значения из текстур со случайным доступом.

Varyings•

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

Examples

Установка или настройка

WebGL - это технология браузера, поэтому не нужно настраивать, кроме браузера. Вы можете начать работу с WebGL на JSFiddle или Codepen или JSBIn или на любом количестве других сайтов, которые позволяют редактировать HTML, CSS и JavaScript в Интернете, хотя будет несколько ограничений (см. Ниже). Вы также можете размещать файлы с открытым исходным кодом на страницах github или аналогичных сервисах.

С другой стороны, в какой-то момент вы, вероятно, собираетесь работать на местном уровне. Для этого рекомендуется запустить простой веб-сервер. Есть много вариантов, которые просты в использовании и требуют очень небольшой настройки.

Использование node.js в качестве сервера

установить node.js1.

Откройте командную строку терминала или узла и введите npm install -g http-server (в OSX поместите sudo перед этим.

2.

введите http-server чтобы начать обслуживать файлы в текущей папке или http-server path-to-folder на сервер в другой папке

3.

Направьте свой браузер на http://localhost:8080/name-of-file для просмотра веб-страницы WebGL.

4.

Использование devd в качестве сервера

Скачать devd1.

Откройте терминал и запустите devd с помощью devd . к файлам сервера из текущей папки или devd path-to-folder для обслуживания другой папки

2.

Укажите свой браузер на http://localhost:8000/name-of-file для просмотра веб-страницы WebGL.

3.

Использование Servez в качестве сервера

https://riptutorial.com/ru/home 3

Page 6: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

Загрузить Servez1.

Установите его, запустите2. Выберите папку для подачи3. Выберите «Пуск»4. Перейдите в http://localhost:8080 или выберите «Launch Browser»5.

Использование расширения « Веб-сервер для Chrome » Chrome

Установка веб-сервера из Chrome1.

Запустите его с помощью значка « Приложения» на новой вкладке.2.

https://riptutorial.com/ru/home 4

Page 7: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

Задайте папку, в которой находятся ваши файлы, затем нажмите ссылку http://127.0.0.1:8787

3.

https://riptutorial.com/ru/home 5

Page 8: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

Ограничение WebGL на онлайн-сервисах

В WebGL очень часто загружаются изображения. В WebGL существуют ограничения на использование изображений. В частности, WebGL не может использовать изображения из других доменов без разрешения сервера, на котором размещаются изображения. Услуги, которые в настоящее время дают разрешение на использование изображений, включают imgur и flickr. См. Раздел Загрузка изображений с перекрестных доменов. В противном

https://riptutorial.com/ru/home 6

Page 9: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

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

Привет, мир

Как упоминается в разделе замечаний, нам нужно предоставить две функции. Вершинный шейдер и фрагментарный шейдер

Начнем с вершинного шейдера

// an attribute will receive data from a buffer attribute vec4 position; // all shaders have a main function void main() { // gl_Position is a special variable a vertex shader // is responsible for setting gl_Position = position; }

Если бы все было написано на JavaScript вместо GLSL, вы могли бы предположить, что он будет использоваться так

// *** PSUEDO CODE!! *** var positionBuffer = [ 0, 0, 0, 0, 0, 0.5, 0, 0, 0.7, 0, 0, 0, ]; var attributes = {}; var gl_Position; drawArrays(..., offset, count) { for (var i = 0; i < count; ++i) { // copy the next 4 values from positionBuffer to the position attribute attributes.position = positionBuffer.slice((offset + i) * 4, 4); runVertexShader(); ... doSomethingWith_gl_Position(); }

Затем нам понадобится фрагментарный шейдер

// fragment shaders don't have a default precision so we need // to pick one. mediump, short for medium precision, is a good default. precision mediump float; void main() { // gl_FragColor is a special variable a fragment shader // is responsible for setting gl_FragColor = vec4(1, 0, 0.5, 1); // return redish-purple

https://riptutorial.com/ru/home 7

Page 10: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

}

Выше мы устанавливаем gl_FragColor в 1, 0, 0.5, 1 который равен 1 для красного, 0 для зеленого, 0,5 для синего, 1 для альфа. Цвета в WebGL идут от 0 до 1.

Теперь, когда мы написали две функции, давайте начнем с WebGL

Сначала нам нужен элемент холста HTML

<canvas id="c"></canvas>

Затем в JavaScript мы можем посмотреть, что

var canvas = document.getElementById("c");

Теперь мы можем создать WebGLRenderingContext

var gl = canvas.getContext("webgl"); if (!gl) { // no webgl for you! ...

Теперь нам нужно скомпилировать эти шейдеры, чтобы поместить их на графический процессор, поэтому сначала нам нужно получить их в строки. Вы можете получить свои строки так, как вы обычно получаете строки. Объединив, используя AJAX, поместив их в теги сценариев, не написанные на JavaScript, или в этом случае с использованием многострочных шаблонных литералов

var vertexShaderSource = ` // an attribute will receive data from a buffer attribute vec4 position; // all shaders have a main function void main() { // gl_Position is a special variable a vertex shader // is responsible for setting gl_Position = position; } `; var fragmentShaderSource = ` // fragment shaders don't have a default precision so we need // to pick one. mediump is a good default precision mediump float; void main() { // gl_FragColor is a special variable a fragment shader // is responsible for setting gl_FragColor = vec4(1, 0, 0.5, 1); // return redish-purple } `;

https://riptutorial.com/ru/home 8

Page 11: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

Тогда нам нужна функция, которая создаст шейдер, загрузит источник и скомпилирует шейдер

function createShader(gl, type, source) { var shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (success) { return shader; } console.log(gl.getShaderInfoLog(shader)); gl.deleteShader(shader); }

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

var vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource); var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

Затем нам нужно связать эти 2 шейдера с программой

function createProgram(gl, vertexShader, fragmentShader) { var program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); var sucesss = gl.getProgramParameter(program, gl.LINK_STATUS); if (success) { return program; } console.log(gl.getProgramInfoLog(program)); gl.deleteProgram(program); }

И назовите это

var program = createProgram(gl, vertexShader, fragmentShader);

Теперь, когда мы создали программу GLSL на графическом процессоре, нам необходимо предоставить данные. Большинство API WebGL - это настройка состояния для передачи данных в наши программы GLSL. В этом случае наш единственный вход в нашу программу GLSL - это position которая является атрибутом. Первое, что мы должны сделать, это найти местоположение атрибута для только что созданной нами программы

var positionAttributeLocation = gl.getAttribLocation(program, "position");

Атрибуты получают свои данные из буферов, поэтому нам нужно создать буфер

https://riptutorial.com/ru/home 9

Page 12: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

var positionBuffer = gl.createBuffer();

WebGL позволяет нам манипулировать многими ресурсами WebGL для глобальных точек привязки. Вы можете рассматривать точки привязки как внутренние глобальные переменные внутри WebGL. Сначала вы устанавливаете точку привязки на свой ресурс. Затем все остальные функции относятся к ресурсу через точку привязки. Итак, давайте свяжем буфер позиции.

gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

Теперь мы можем поместить данные в этот буфер, указав его через точку привязки

// three 2d points var positions = [ 0, 0, 0, 0.5, 0.7, 0, ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

Здесь многое происходит. Во-первых, у нас есть positions которые представляют собой массив JavaScript. WebGL с другой стороны требует строго типизированных данных, поэтому строка new Float32Array(positions) создает новый массив из 32- new Float32Array(positions) чисел с плавающей запятой и копирует значения из positions . gl.bufferData затем копирует эти данные в positionBuffer на GPU. Он использует буфер позиции, потому что мы привязали его к ARRAY_BUFFER привязки ARRAY_BUFFER выше.

Последний аргумент gl.STATIC_DRAW - это подсказка для WebGL о том, как мы будем использовать данные. Он может попытаться использовать эту информацию для оптимизации определенных вещей. gl.STATIC_DRAW сообщает WebGL, что мы вряд ли сильно изменим эти данные.

Теперь, когда мы поместили данные в буфер, нам нужно сообщить атрибуту, как получить данные из него. Прежде всего, нам нужно включить атрибут

gl.enableVertexAttribArray(positionAttributeLocation);

Затем нам нужно указать, как вытащить данные

var size = 2; // 2 components per iteration var type = gl.FLOAT; // the data is 32bit floats var normalize = false; // use the data as is var stride = 0; // 0 = move size * sizeof(type) each iteration var offset = 0; // start at the beginning of the buffer gl.vertexAttribPointer( positionAttributeLocation, size, type, normalize, stride, offset)

Скрытая часть gl.vertexAttribPointer заключается в том, что он привязывает текущий

https://riptutorial.com/ru/home 10

Page 13: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

ARRAY_BUFFER к атрибуту. Другими словами, теперь этот атрибут привязан к positionBuffer мы можем связать что-то еще с ARRAY_BUFFER привязки ARRAY_BUFFER .

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

attribute vec4 position;

vec4 - это 4 значения поплавка. В JavaScript вы можете думать о нем как о position = {x: 0, y: 0, z: 0, w: 0} . Выше мы задаем size = 2 . Атрибуты по умолчанию равны 0, 0, 0, 1 поэтому этот атрибут получит первые два значения (x и y) из нашего буфера. Значения z и w будут по умолчанию равными 0 и 1 соответственно.

В конце концов, мы можем, наконец, попросить WebGL выполнить программу GLSL.

var primitiveType = gl.TRIANGLES; var offset = 0; var count = 3; gl.drawArrays(primitiveType, offset, count);

Это выполнит наш вершинный шейдер 3 раза. Первая position.x и position.y в нашем вершинном шейдере будет установлена на первые 2 значения из positionBuffer. Второй раз position.xy будет установлен на 2-й 2. В последний раз он будет установлен на последние 2 значения.

Поскольку мы устанавливаем primitiveType в gl.TRIANGLES , каждый раз, когда наш вершинный шейдер запускается 3 раза, WebGL рисует треугольник, основанный на 3 значениях, которые мы устанавливаем gl_Position . Независимо от размера нашего холста эти значения находятся в координатах пространства клипов, которые идут от -1 до 1 в каждом направлении.

Поскольку наш вершинный шейдер просто копирует наши значения positionBuffer в gl_Position треугольник будет нарисован в координатах пространства клипа

0, 0, 0, 0.5, 0.7, 0,

Как эти значения преобразуются в пиксели, зависит от параметра gl.viewport . gl.viewport умолчанию gl.viewport соответствует размеру холста. Поскольку мы не задавали размер для нашего холста, размер по умолчанию составляет 300x150. Преобразование из пространства клипа в пиксели (часто называемое пространством экрана в публикациях WebGL и OpenGL). WebGL собирается нарисовать треугольник в

clip space screen space 0, 0 -> 150, 75 0, 0.5 -> 150, 112.5

https://riptutorial.com/ru/home 11

Page 14: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

0.7, 0 -> 255, 75

Теперь WebGL отобразит этот треугольник. Для каждого пикселя, который он собирается нарисовать, он вызовет наш шейдер фрагмента. Наш фрагментарный шейдер просто устанавливает gl_FragColor в 1, 0, 0.5, 1 . Поскольку Canvas представляет собой холст на 8 бит на канал, это означает, что WebGL будет записывать значения [255, 0, 127, 255] в холст.

Есть 3 основные вещи, которые мы еще не рассмотрели из замечаний . Текстуры, изменения и униформа. Каждый из них требует своей собственной темы.

Прочитайте Начало работы с webgl онлайн: https://riptutorial.com/ru/webgl/topic/2605/начало-работы-с-webgl

https://riptutorial.com/ru/home 12

Page 15: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

глава 2: государственный

Examples

Атрибуты

Атрибуты - глобальное состояние (*). Если бы они были реализованы в JavaScript, они выглядели бы примерно так

// pseudo code gl = { ARRAY_BUFFER: null, vertexArray: { attributes: [ { enable: ?, type: ?, size: ?, normalize: ?, stride: ?, offset: ?, buffer: ? }, { enable: ?, type: ?, size: ?, normalize: ?, stride: ?, offset: ?, buffer: ? }, { enable: ?, type: ?, size: ?, normalize: ?, stride: ?, offset: ?, buffer: ? }, { enable: ?, type: ?, size: ?, normalize: ?, stride: ?, offset: ?, buffer: ? }, { enable: ?, type: ?, size: ?, normalize: ?, stride: ?, offset: ?, buffer: ? }, { enable: ?, type: ?, size: ?, normalize: ?, stride: ?, offset: ?, buffer: ? }, { enable: ?, type: ?, size: ?, normalize: ?, stride: ?, offset: ?, buffer: ? }, { enable: ?, type: ?, size: ?, normalize: ?, stride: ?, offset: ?, buffer: ? }, ], ELEMENT_ARRAY_BUFFER: null, }, }

Как вы можете видеть выше, существует 8 атрибутов, и они являются глобальными.

Когда вы вызываете gl.enableVertexAttribArray(location) или gl.disableVertexAttribArray вы можете думать об этом так:

// pseudo code gl.enableVertexAttribArray = function(location) { gl.vertexArray.attributes[location].enable = true; }; gl.disableVertexAttribArray = function(location) { gl.vertexArray.attributes[location].enable = false; };

Другими словами, location напрямую относится к индексу атрибута.

Аналогично gl.vertexAttribPointer будет реализован что-то вроде этого

// pseudo code gl.vertexAttribPointer = function(location, size, type, normalize, stride, offset) { var attrib = gl.vertexArray.attributes[location]; attrib.size = size; attrib.type = type; attrib.normalize = normalize;

https://riptutorial.com/ru/home 13

Page 16: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

attrib.stride = stride ? stride : sizeof(type) * size; attrib.offset = offset; attrib.buffer = gl.ARRAY_BUFFER; // !!!! <----- };

Обратите внимание, что attrib.buffer установлен на то, что установлено для текущего gl.ARRAY_BUFFER . gl.ARRAY_BUFFER задается вызовом gl.bindBuffer(gl.ARRAY_BUFFER, someBuffer) .

Итак, у нас есть вершинные шейдеры. В вершинном шейдере вы объявляете атрибуты. пример

attribute vec4 position; attribute vec2 texcoord; attribute vec3 normal; ... void main() { ... }

Когда вы связываете вершинный шейдер с шейдером фрагмента, вызывая gl.linkProgram(someProgram) WebGL (драйвер / графический процессор / браузер) сами определяют, какой индекс / местоположение использовать для каждого атрибута. Вы не представляете, какие из них они собираются выбрать. Это браузер / драйвер / графический процессор. Итак, вы должны спросить, какой атрибут вы использовали для position , texcoord и normal ? , Вы делаете это, вызывая gl.getAttribLocation

var positionLoc = gl.getAttribLocation(program, "position"); var texcoordLoc = gl.getAttribLocation(program, "texcoord"); var normalLoc = gl.getAttribLocation(program, "normal");

Скажем, positionLoc = 5 . Это означает, что при выполнении вершинного шейдера (когда вы вызываете gl.drawArrays или gl.drawElements ) вершинный шейдер ожидает, что у вас есть атрибут настройки 5 с правильным type , size , offset , stride , buffer и т. Д.

Обратите внимание, что перед подключением программы вы можете выбирать места, вызывая gl.bindAttribLoction(program, location, nameOfAttribute) . Пример:

// Tell `gl.linkProgram` to assign `position` to use attribute #7 gl.bindAttribLocation(program, 7, "position");

полное состояние атрибута

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

attributes: [ { enable: ?, type: ?, size: ?, normalize: ?, stride: ?, offset: ?, buffer: ?

https://riptutorial.com/ru/home 14

Page 17: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

value: [0, 0, 0, 1], }, { enable: ?, type: ?, size: ?, normalize: ?, stride: ?, offset: ?, buffer: ? value: [0, 0, 0, 1], }, ..

Вы можете установить значение с помощью различных функций gl.vertexAttribXXX . value используется, когда enable false . Когда enable - истинные данные для атрибута вытягиваются из назначенного buffer .

Объекты вершинного массиваWebGL имеет расширение, OES_vertex_array_object

На диаграмме выше OES_vertex_array_object позволяет создавать и заменять vertexArray . Другими словами

var vao = ext.createVertexArrayOES();

создает объект, который вы видите прикрепленным к gl.vertexArray в псевдо-коде выше. Вызов ext.bindVertexArrayOES(vao) назначает ваш созданный объект массива вершин как текущий массив вершин.

// pseudo code ext.bindVertexArrayOES = function(vao) { gl.vertexArray = vao; }

Это позволяет установить все атрибуты и ELEMENT_ARRAY_BUFFER в текущем VAO, так что, когда вы хотите нарисовать, это один вызов ext.bindVertexArrayOES где, как и без расширения, это будет до одного вызова как gl.bindBuffer gl.vertexAttribPointer (и возможно gl.enableVertexAttribArray ) за атрибут.

Униформа

Униформа зависит от состояния программы . Каждая программа шейдеров имеет свое единообразное состояние и свои собственные местоположения.

текстуры

Единицы текстуры являются глобальными. Если бы они были реализованы в JavaScript, они выглядели бы примерно так

// pseudo code gl = { activeTextureUnit: 0, textureUnits: [

https://riptutorial.com/ru/home 15

Page 18: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

{ TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? }, { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? }, { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? }, { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? }, { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? }, { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? }, { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? }, { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? }, { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? }, ], };

Вы можете выбрать, какой блок индексировать с помощью gl.activeTexture .

// pseudo code gl.activeTexture = function(textureUnit) { gl.activeTextureUnit = textureUnit - gl.TEXTURE0; };

Вызов gl.bindTexture связывает текстуру с активной текстурной единицей, подобной этой

// pseudo code gl.bindTexture = function(target, texture) { var textureUnit = gl.textureUnits[gl.activeTextureUnit]; textureUnit[target] = texture; }

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

uniform sampler2D diffuse; uniform sampler2D normalMap; uniform samplerCube environmentMap; ...

Для вас нужно запросить однородные местоположения

var diffuseUniformLocation = gl.getUniformLocation(someProgram, "diffuse"); var normalMapUniformLocation = gl.getUniformLocation(someProgram, "normalMap"); var environmmentMapUniformLocation = gl.getUniformLocation(someProgram, "environmentMap");

Затем, после того, как вы сделали свою программу шейдеров текущей программой

gl.useProgram(someProgram);

Затем вам нужно указать шейдеру, какие текстурные единицы вы сделали / включите текстуры. Например

https://riptutorial.com/ru/home 16

Page 19: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

var diffuseTextureUnit = 3; var normalMapTextureUnit = 5; var environmentMapTextureUnit = 2; gl.uniform1i(diffuseUniformLocation, diffuseTextureUnit); gl.uniform1i(normalMapUniformLocation, normalMapTextureUnit); gl.uniform1i(environmentMapUniformLocation, environmentMapTextureUnit);

Теперь вы сказали шейдеру, какие единицы вы использовали / будете использовать. Какие текстурные единицы, которые вы решили использовать, полностью зависит от вас.

Чтобы фактически привязать текстуры к текстурным единицам, вы сделаете что-то вроде этого

gl.activeTexture(gl.TEXTURE0 + diffuseTextureUnit); gl.bindTexture(gl.TEXTURE_2D, diffuseTexture); gl.activeTexture(gl.TEXTURE0 + normalMapTextureUnit); gl.bindTexture(gl.TEXTURE_2D, normalMapTexture); gl.activeTexture(gl.TEXTURE0 + environmentMapTextureUnit); gl.bindTexture(gl.TEXTURE_CUBE_MAP, environmentMapTexture);

Для очень простых примеров WebGL, в которых используется только одна текстура, обычно никогда не вызывать gl.activeTexture так как по умолчанию используется блок текстур № 0. Также распространено не вызывать gl.uniform1i потому что по умолчанию используется значение по умолчанию 0, поэтому программа шейдеров будет по умолчанию использовать текстурный блок # 0 для всех текстур.

Все остальные функции текстуры также работают с активными объектами текстурной и текстурной единицы. Например, gl.texImage2D может выглядеть примерно так

gl.texImage2D = function(target, level, internalFormat, width, height, border, format, type, data) { var textureUnit = gl.textureUnits[gl.activeTextureUnit]; var texture = textureUnit[target]; // Now that we've looked up the texture form the activeTextureUnit and // the target we can effect a specific texture ... };

Прочитайте государственный онлайн: https://riptutorial.com/ru/webgl/topic/4818/

государственный

https://riptutorial.com/ru/home 17

Page 20: webgl - RIP Tutorial · Атрибуты поставляют данные только в вершинные шейдеры. Атрибуты определяют, как извлекать

кредиты

S. No

Главы Contributors

1Начало работы с webgl

Community, gman

2 государственный gman, Nikola Lukic

https://riptutorial.com/ru/home 18