Настройка буфера вершин и буфер индексов

Последнее обновление: 1.11.2015

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

Так, в программе из прошлого параграфа создание буфера вершин происходило в следующем участке кода:

function initBuffers() {

  vertexBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  
  var triangleVertices = [
         0.0,  0.5,  0.0,
        -0.5, -0.5,  0.0,
         0.5, -0.5,  0.0
  ];
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW);
  
  vertexBuffer.itemSize = 3;
  vertexBuffer.numberOfItems = 3;
}

Итак, у нас есть глобальная переменная vertexBuffer, которая будет хранить буффер вершин. И для начала нам надо его создать: vertexBuffer = gl.createBuffer().

Затем выполняем привязку буфера к контексту WebGL: gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);. Привязка означает, что все операции с буфером будут происходить именно над буфером vertexBuffer.

В качестве первого параметра метод gl.bindBuffer принимает тип создаваемого буфера и может принимать следующие значения:

  • gl.ARRAY_BUFFER: данные вершин

  • gl.ELEMENT_ARRAY_BUFFER: данные индексов

Поскольку в нашем случае мы создаем буфер вершин, поэтому используется значение gl.ARRAY_BUFFER.

Впоследствии мы можем отвязать буфер, например, с помощью следующего выражения: gl.bindBuffer(gl.ARRAY_BUFFER, null);

Последним шагом является загрузка определенных разработчиком координат в буфер вершин и его типизациия: gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW);. В данном случае массив координат типизируется конструктором Float32Array, который создает представление массива в виде набора чисел с плавающей точкой.

При этом мы не можем передать просто переменную triangleVertices, представляющую массив координат. Нам обязательно надо ее типизировать. Но объект Float32Array не единственный, который мы можем использовать для типизации. Также мы можем использовать следующие объекты: Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float64Array. Только в отличие от Float32Array перечисленные типы будут создавать набор целых чисел соответственно занимающих 8, 16, 32 и 64 бита, как указано в их названии.

Переменная triangleVertices определяет набор координат, по которым будут создаваться вершины в буфере вершин, а затем по ним будут строиться геометрические примитивы.

Последние сроки vertexBuffer.itemSize = 3; vertexBuffer.numberOfItems = 3; не столь важны, так как используются лишь для последующего применения при отрисовке.

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

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

<!DOCTYPE html>
<html>
<head>
<title>Привет WebGL!</title>
<meta charset="utf-8" />
</head>
<body>
<canvas id="canvas3D" width="400" height="300">Ваш браузер не поддерживает элемент canvas</canvas>
<!-- фрагментный шейдер -->
<script id="shader-fs" type="x-shader/x-fragment">
  void main(void) {
    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
  }
</script>
<!-- вершинный шейдер -->
<script id="shader-vs" type="x-shader/x-vertex">
  attribute vec3 aVertexPosition;
  void main(void) {
    gl_Position = vec4(aVertexPosition, 1.0);
  }
</script>
<script type="text/javascript">
var gl;
var shaderProgram;
var vertexBuffer; // буфер вершин
var indexBuffer; //буфер индексов
// установка шейдеров
function initShaders() {
    // получаем шейдеры
	var fragmentShader = getShader(gl.FRAGMENT_SHADER, 'shader-fs');
	var vertexShader = getShader(gl.VERTEX_SHADER, 'shader-vs');
	//создаем объект программы шейдеров
	shaderProgram = gl.createProgram();
	// прикрепляем к ней шейдеры
	gl.attachShader(shaderProgram, vertexShader);
	gl.attachShader(shaderProgram, fragmentShader);
	// связываем программу с контекстом webgl
	gl.linkProgram(shaderProgram);
	 
	if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
	     alert("Не удалось установить шейдеры");
	}
	 
	gl.useProgram(shaderProgram);
	// установка атрибута программы
	shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
	gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
}
// Функция создания шейдера по типу и id источника в структуре DOM
function getShader(type,id) {
	var source = document.getElementById(id).innerHTML;
	// создаем шейдер по типу
	var shader = gl.createShader(type);
	// установка источника шейдера
	gl.shaderSource(shader, source);
	// компилируем шейдер
	gl.compileShader(shader);
  
	if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
		alert("Ошибка компиляции шейдера: " + gl.getShaderInfoLog(shader));
        gl.deleteShader(shader);   
        return null;
    }
    return shader;  
}
 
function initBuffers() {

    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];

    indices = [0, 1, 2, 0, 3, 2];
 // установка буфера вершин
  vertexBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
  // указываем размерность
  vertexBuffer.itemSize = 3;
  
  // создание буфера индексов
  indexBuffer = gl.createBuffer();
	gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
	gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
	// указываем число линий. это число равно числу индексов
	indexBuffer.numberOfItems = indices.length;
}
 
function draw() {    
	
	// установка фона
	gl.clearColor(0.0, 0.0, 0.0, 1.0);
	// установка области отрисовки
	gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);

	gl.clear(gl.COLOR_BUFFER_BIT);
  
	gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 
	            vertexBuffer.itemSize, gl.FLOAT, false, 0, 0);
    // отрисовка примитивов - линий
	gl.drawElements(gl.LINE_LOOP, indexBuffer.numberOfItems, gl.UNSIGNED_SHORT,0);
}
 
window.onload=function(){

    var canvas = document.getElementById("canvas3D");
    try {
	     gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
    }
    catch(e) {}
  
    if (!gl) {
	    alert("Ваш браузер не поддерживает WebGL");
    }
    if(gl){
	    // установка размеров области рисования
	    gl.viewportWidth = canvas.width;
	    gl.viewportHeight = canvas.height;
		
	    initShaders();
		
	    initBuffers();
		
	    draw();  
	}
}
</script>
</body>
</html>

Результатом будет квадрат из двух треугольников, а точнее из 5 линий. В данном случае нас интересует метод настройки буферов вершин и индексов - initBuffers().

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

Далее идет индекс 1, который указывает индекс новой точки, до которой будет построена линия:

Буфер вершин и индексов в WebGL

Далее идет создание буферов вершин и индексов. И если буфер вершин создается знакомым уже способом, то при создании буфера индексов указывается другой тип массива: gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);

В дальнейшем в методе отрисовки draw непосредственно отрисовка производится с помощью метода gl.drawElements(gl.LINE_LOOP, indexBuffer.numberOfItems, gl.UNSIGNED_SHORT,0);. Позже мы подробнее расcмотрим метод gl.drawElements, но в данном случае достаточно знать, что он рисует примитивы (в данном случае линии) по индексам, а не по вершинам.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850