В предыдущих примерах в методе отрисовки draw
мы использовали следующее выражение:
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, vertexBuffer.itemSize, gl.FLOAT, false, 0, 0);
. С помощью данного метода
мы устанавливаем атрибут или указатель на чтение из буфера вершин. Зачем это надо?
Данный атрибут мы создаем в функции initShaders(): shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
.
Поскольку здесь мы определяем для атрибута имя "aVertexPosition", то в вершинном шейдере мы используем переменную с подобным именем:
attribute vec3 aVertexPosition; void main(void) { gl_Position = vec4(aVertexPosition, 1.0); }
Эта переменная attribute vec3 aVertexPosition
представляет собой атрибут вершинного шейдера и в программе WebGL
она передает координаты вершины в шейдер. Поскольку в методе gl.getAttribLocation()
атрибут shaderProgram.vertexPositionAttribute
связывается с именем aVertexPosition, то именно с таким именем и определяется переменная, которая будет передавать в шейдер координаты вершин.
Это не единственный атрибут. Мы можем установить различные атрибуты, например, один для вершин, другой для цветов и т.д. В данном случае
мы устанавливаем атрибут только для вершин. И чтобы эти все атрибуты должным образом установить,
мы используем метод gl.vertexAttribPointer(index, size, type, norm, stride, offset)
.
Этот метод принимает следующие параметры:
index: индекс атрибута, который мы сопоставляем с буфером вершин
size: число значений для каждой вершины, которые хранятся в буфере. Например, у нас три координаты на вершину, поэтому и число передаваемое в качестве данного параметра будет равно 3
type: тип значений, который хранятся в буфере. В качестве значения параметр может принимать следующие константы:
FIXED
, BYTE
, UNSIGNED_BYTE
, FLOAT
, SHORT
и UNSIGNED_SHORT
.
norm: представляет булевое значение. Данный параметр управляет числовыми преобразованиями.
stride: шаг. При установке в качестве значения 0 (нулевой шаг) элементы будут последовательно обрабатываться.
offset: смешение - позиция в буфере, с которой начинается обработка. Обычно устанавливается нулевое смещение, то есть все элементы обрабатываются с самого начала
Кроме установки указателя нам еще надо включить атрибут с помощью метода gl.enableVertexAttribArray()
, в который передается
ранее установленный атрибут: gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
.
После этого мы сможем передать каждую вершину в вершинный шейдер через переменную attribute vec3 aVertexPosition
.
Теперь посмотрим, что происходит в программе. Возьмем пример из прошлого параграфа. Там набор вершин задан с помощью следующего массива:
vertices =[ -0.5, -0.5, 0.0, -0.5, 0.5, 0.0, 0.5, 0.5, 0.0, 0.5, -0.5, 0.0];
Итак, сначала мы осуществляем привязку данного набора координат в качестве буфера вершин:
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
После этого нам надо установить указатель на чтение из буфера вершин:
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
Так, как у нас каждая вершина представлена тремя координатами, то в качестве второго параметра мы устанавливаем число 3. В итоге при передаче
в вершинный шейдер атрибут shaderProgram.vertexPositionAttribute
будет получать по одной вершине из трех координат.
Например, в самом начале атрибут будет передавать в вершинный шейдер первую вершину:
shaderProgram.vertexPositionAttribute =[-0.5, -0.5, 0.0]
, затем вторую и т.д. Затем в вершинном шейдере мы можем получить переданную через атрибут
вершину и провести над ней трансформации через переменную aVertexPosition
:
attribute vec3 aVertexPosition; void main(void) { gl_Position = vec4(aVertexPosition, 1.0); }
В данном случае никакой трансформации не происходит, и мы устанавливаем конечную вершину как есть.