Spec-Zone.ru › Web APIs

WebGLRenderingContext: метод vertexAttribPointer()

Базовая Широко поддерживается

Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна во всех браузерах с июля 2015 года.

  • Узнать больше
  • Полная совместимость
  • Отправить обратную связь

Примечание: Эта функция доступна в Web Workers.

Метод WebGLRenderingContext.vertexAttribPointer() API WebGL связывает буфер, в данный момент связанный с gl.ARRAY_BUFFER, с общим атрибутом вершины текущего объекта буфера вершин и определяет его структуру.

Синтаксис

vertexAttribPointer(index, size, type, normalized, stride, offset)

Параметры

index

Значение GLuint, определяющее индекс атрибута вершины, который необходимо изменить.

size

Значение GLint, определяющее количество компонентов на атрибут вершины. Должно быть 1, 2, 3 или 4.

type

Значение GLenum, определяющее тип данных каждого компонента в массиве. Возможные значения:

  • gl.BYTE: знаковое 8-битное целое число со значениями в диапазоне [-128, 127]
  • gl.SHORT: знаковое 16-битное целое число со значениями в диапазоне [-32768, 32767]
  • gl.UNSIGNED_BYTE: беззнаковое 8-битное целое число со значениями в диапазоне [0, 255]
  • gl.UNSIGNED_SHORT: беззнаковое 16-битное целое число со значениями в диапазоне [0, 65535]
  • gl.FLOAT: 32-битное число с плавающей запятой IEEE

При использовании контекста WebGL 2, доступны следующие дополнительные значения:

  • gl.HALF_FLOAT: 16-битное число с плавающей запятой IEEE
  • gl.INT: 32-битное знаковое двоичное целое число
  • gl.UNSIGNED_INT: 32-битное беззнаковое двоичное целое число
  • gl.INT_2_10_10_10_REV: 32-битное знаковое целое число со значениями в диапазоне [-512, 511]
  • gl.UNSIGNED_INT_2_10_10_10_REV: 32-битное беззнаковое целое число со значениями в диапазоне [0, 1023]
normalized

Значение GLboolean, определяющее, должны ли значения целочисленных данных быть нормализованы в определенный диапазон при преобразовании в число с плавающей запятой.

  • Для типов gl.BYTE и gl.SHORT, нормализует значения в диапазон [-1, 1], если значение true.
  • Для типов gl.UNSIGNED_BYTE и gl.UNSIGNED_SHORT, нормализует значения в диапазон [0, 1], если значение true.
  • Для типов gl.FLOAT и gl.HALF_FLOAT, этот параметр не оказывает влияния.
stride

Значение GLsizei, определяющее смещение в байтах между началом последовательных атрибутов вершины. Не может быть отрицательным или больше 255. Если stride равен 0, предполагается, что атрибуты плотно упакованы, то есть атрибуты не перекрываются, а каждый атрибут находится в отдельном блоке, и следующий атрибут вершины следует непосредственно за текущим.

offset

Значение GLintptr, определяющее смещение в байтах первого компонента в массиве атрибутов вершины. Должно быть кратно длине в байтах type.

Возвращаемое значение

None (undefined).

Исключения

  • Возникает ошибка gl.INVALID_VALUE, если stride или offset отрицательны.
  • Возникает ошибка gl.INVALID_OPERATION, если stride и offset не кратны размеру типа данных.
  • Возникает ошибка gl.INVALID_OPERATION, если к цели ARRAY_BUFFER не привязан ни один WebGLBuffer.
  • При использовании контекста WebGL 2, возникает ошибка gl.INVALID_OPERATION, если этот атрибут вершины определен как целочисленный в шейдере вершин (например, uvec4 или ivec4, а не vec4).

Описание

Предположим, нам нужно визуализировать некоторую 3D-геометрию, и для этого нам нужно передать наши вершины в шейдер вершин. У каждой вершины есть несколько атрибутов, такие как позиция, вектор нормали или координаты текстуры, которые определены в ArrayBuffer и будут переданы в объект буфера вершин (VBO). Сначала нам нужно привязать WebGLBuffer, который мы хотим использовать, к gl.ARRAY_BUFFER, а затем с помощью этого метода gl.vertexAttribPointer(), мы указываем, в каком порядке хранятся атрибуты и какой тип данных они имеют. Кроме того, нам нужно указать stride, который является общим размером в байтах всех атрибутов для одной вершины. Также нам нужно вызвать gl.enableVertexAttribArray(), чтобы сообщить WebGL, что этот атрибут должен быть заполнен данными из нашего буфера массива.

Обычно ваша 3D-геометрия уже находится в определенном двоичном формате, поэтому вам нужно прочитать спецификацию этого конкретного формата, чтобы понять расположение памяти. Однако, если вы сами проектируете формат или ваша геометрия находится в текстовых файлах (например, Wavefront .obj файлы) и должна быть преобразована в ArrayBuffer во время выполнения, у вас есть свобода выбора структуры памяти. Для максимальной производительности перемешайте атрибуты и используйте самый маленький тип данных, который все еще точно представляет вашу геометрию.

Максимальное количество атрибутов вершин зависит от графического процессора, и вы можете вызвать gl.getParameter(gl.MAX_VERTEX_ATTRIBS) для получения этого значения. На высокопроизводительных графических процессорах максимальное значение равно 16, на менее производительных — значение будет ниже.

Индекс атрибута

Для каждого атрибута вы должны указать его индекс. Это независимо от местоположения внутри буфера массива, поэтому ваши атрибуты могут быть отправлены в другом порядке, чем порядок их хранения в буфере массива. У вас есть два варианта:

  • Вы можете указать индекс самостоятельно. В этом случае вы вызываете gl.bindAttribLocation(), чтобы связать именованный атрибут из шейдера вершин с индексом, который вы хотите использовать. Это необходимо сделать перед вызовом gl.linkProgram(). Затем вы можете предоставить этот же индекс методу gl.vertexAttribPointer().
  • В качестве альтернативы, вы можете использовать индекс, назначенный графическим процессором при компиляции шейдера вершин. В зависимости от графического процессора индекс может отличаться, поэтому вы должны вызвать gl.getAttribLocation(), чтобы узнать индекс, и затем предоставить этот индекс методу gl.vertexAttribPointer(). Если вы используете WebGL 2, вы можете указать индекс самостоятельно в коде шейдера вершин и переопределить значение по умолчанию, используемое графическим процессором, например, layout(location = 3) in vec4 position; установит атрибут "position" в индекс 3.

Целочисленные атрибуты

Хотя ArrayBuffer может быть заполнен как целыми числами, так и числами с плавающей запятой, атрибуты всегда преобразуются в числа с плавающей запятой при отправке в шейдер вершин. Если вам необходимо использовать целые числа в коде шейдера вершин, вы можете либо преобразовать число с плавающей запятой обратно в целое число в шейдере вершин (например, (int) floatNumber), либо использовать gl.vertexAttribIPointer() из WebGL2.

Значения атрибутов по умолчанию

Код шейдера вершин может включать в себя несколько атрибутов, но нам не нужно указывать значения для каждого атрибута. Вместо этого мы можем предоставить значение по умолчанию, которое будет одинаковым для всех вершин. Мы можем вызвать gl.disableVertexAttribArray(), чтобы сообщить WebGL использовать значение по умолчанию, в то время как вызов gl.enableVertexAttribArray() будет считывать значения из буфера массива, как указано в gl.vertexAttribPointer().

Аналогично, если наш шейдер вершин ожидает, например, 4-компонентный атрибут с vec4, но в вызове gl.vertexAttribPointer() мы устанавливаем size в 2, то WebGL установит первые два компонента на основе буфера массива, в то время как третий и четвертый компоненты берутся из значения по умолчанию.

Значение по умолчанию равно vec4(0.0, 0.0, 0.0, 1.0) по умолчанию, но мы можем указать другое значение по умолчанию с помощью gl.vertexAttrib[1234]f[v]().

Например, ваш шейдер вершин может использовать атрибут позиции и атрибут цвета. У большинства мешей цвет задан на уровне каждой вершины, но некоторые меши имеют одинаковый оттенок. Для этих мешей нет необходимости помещать один и тот же цвет для каждой вершины в буфер массива, поэтому вы используете gl.vertexAttrib4fv() для задания постоянного цвета.

Запрос текущих настроек

Вы можете вызвать gl.getVertexAttrib() и gl.getVertexAttribOffset(), чтобы получить текущие параметры для атрибута, например, тип данных или должен ли атрибут быть нормализован. Имейте в виду, что эти функции WebGL имеют низкую производительность, и лучше хранить состояние внутри вашего приложения JavaScript. Тем не менее, эти функции отлично подходят для отладки контекста WebGL без изменения кода приложения.

Примеры

Этот пример демонстрирует, как отправлять атрибуты вершин в программу шейдера. Мы используем воображаемую структуру данных, где атрибуты каждой вершины хранятся интерлинированно, с длиной 20 байт на вершину:

  1. позиция: Нам нужно сохранить координаты X, Y и Z. Для максимальной точности мы используем 32-битные числа с плавающей точкой; в общей сложности это использует 12 байт.
  2. вектор нормали: Нам нужно сохранить компоненты X, Y и Z вектора нормали, но так как точность не так важна, мы используем 8-битные знаковые целые числа. Для лучшей производительности мы выравниваем данные до 32 бит, также сохраняя четвёртый нулевой компонент, что увеличивает общий размер до 4 байт. Кроме того, мы говорим WebGL нормализовать значения, потому что наши нормали всегда находятся в диапазоне [-1, 1].
  3. координата текстуры: Нам нужно сохранить координаты U и V; для этого 16-битные беззнаковые целые числа обеспечивают достаточную точность, общий размер составляет 4 байта. Мы также говорим WebGL нормализовать значения до [0, 1].

Например, следующая вершина:

{
  "position": [1.0, 2.0, 1.5],
  "normal": [1.0, 0.0, 0.0],
  "texCoord": [0.5, 0.25]
}

Будет храниться в буфере массива следующим образом:

WebGL array buffer contents

Создание буфера массива

Сначала мы динамически создаём буфер массива из данных JSON, используя DataView. Обратите внимание на использование true , поскольку WebGL ожидает, что наши данные будут в формате little-endian.

// Load geometry with fetch() and Response.json()
const response = await fetch("assets/geometry.json");
const vertices = await response.json();

// Create array buffer
const buffer = new ArrayBuffer(20 * vertices.length);
// Fill array buffer
const dv = new DataView(buffer);
vertices.forEach((vertex, i) => {
  dv.setFloat32(20 * i, vertex.position[0], true);
  dv.setFloat32(20 * i + 4, vertex.position[1], true);
  dv.setFloat32(20 * i + 8, vertex.position[2], true);
  dv.setInt8(20 * i + 12, vertex.normal[0] * 0x7f);
  dv.setInt8(20 * i + 13, vertex.normal[1] * 0x7f);
  dv.setInt8(20 * i + 14, vertex.normal[2] * 0x7f);
  dv.setInt8(20 * i + 15, 0);
  dv.setUint16(20 * i + 16, vertex.texCoord[0] * 0xffff, true);
  dv.setUint16(20 * i + 18, vertex.texCoord[1] * 0xffff, true);
});

Для повышения производительности мы также могли бы выполнить преобразование JSON в ArrayBuffer на стороне сервера, например, с помощью Node.js. Затем мы могли бы загрузить двоичный файл и интерпретировать его как буфер массива:

const response = await fetch("assets/geometry.bin");
const buffer = await response.arrayBuffer();

Использование буфера массива с WebGL

Сначала мы создаём новый объект буфера вершин (VBO) и предоставляем ему наш буфер массива:

//Bind array buffer to a Vertex Buffer Object
const vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, buffer, gl.STATIC_DRAW);

Затем мы задаём макет памяти буфера массива, либо сами устанавливая индекс:

//Describe the layout of the buffer:
//1. position, not normalized
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 20, 0);
gl.enableVertexAttribArray(0);
//2. normal vector, normalized to [-1, 1]
gl.vertexAttribPointer(1, 4, gl.BYTE, true, 20, 12);
gl.enableVertexAttribArray(1);
//3. texture coordinates, normalized to [0, 1]
gl.vertexAttribPointer(2, 2, gl.UNSIGNED_SHORT, true, 20, 16);
gl.enableVertexAttribArray(2);

//Set the attributes in the vertex shader to the same indices
gl.bindAttribLocation(shaderProgram, 0, "position");
gl.bindAttribLocation(shaderProgram, 1, "normal");
gl.bindAttribLocation(shaderProgram, 2, "texUV");
//Since the attribute indices have changed, we must re-link the shader
//Note that this will reset all uniforms that were previously set.
gl.linkProgram(shaderProgram);

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

const locPosition = gl.getAttribLocation(shaderProgram, "position");
gl.vertexAttribPointer(locPosition, 3, gl.FLOAT, false, 20, 0);
gl.enableVertexAttribArray(locPosition);

const locNormal = gl.getAttribLocation(shaderProgram, "normal");
gl.vertexAttribPointer(locNormal, 4, gl.BYTE, true, 20, 12);
gl.enableVertexAttribArray(locNormal);

const locTexUV = gl.getAttribLocation(shaderProgram, "texUV");
gl.vertexAttribPointer(locTexUV, 2, gl.UNSIGNED_SHORT, true, 20, 16);
gl.enableVertexAttribArray(locTexUV);

Спецификации

Спецификация
Спецификация WebGL
# 5.14.10

Совместимость с браузерами

Рабочие столы Мобильные устройства
Chrome Edge Firefox Opera Safari Chrome Android Firefox для Android Opera Android Safari на iOS Samsung Internet WebView Android
vertexAttribPointer 9 12 4 12 5.1 25 4 12 8 1.5 4.4.3

См. также

  • Спецификация вершин на сайте OpenGL wiki
  • WebGL2RenderingContext.vertexAttribIPointer()

© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/vertexAttribPointer

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API