Матрицы и создание 3D

Первый 3D-объект

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

Прошло несколько глав с самого начала, и возможно, у кого-то появятся вполне справедливые вопросы: а где же 3D? Все предыдущие примеры фактически рисовались на плоскости, не принимая в учет z-координаты. Теперь же мы готовы двинуться дальше и перейти уже непосредственно к созданию 3d-объектов. Поэтому наконец создадим куб.

По сути куб формируют 8 точек, связанных между собою линиями. А с линиями мы уже познакомились в предыдущих главах. Итак, полный код будет следующим:

<!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(0.0, 1.0, 0.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);

	gl.linkProgram(shaderProgram);
	 
	if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
		alert("Не удалось установить шейдеры");
	}
	 
	gl.useProgram(shaderProgram);

	shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
	gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
}
// Функция создания шейдера
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() {
	var	vertices =[
				// лицевая часть
				-0.5, -0.5, 0.5,
				-0.5, 0.5, 0.5,
				 0.5, 0.5, 0.5,
				 0.5, -0.5, 0.5,
				// задняя часть	
				-0.5, -0.5, -0.5,
				-0.5, 0.5, -0.5,
				 0.5, 0.5, -0.5,
				 0.5, -0.5, -0.5
				 ];

    var indices = [0, 1, 1, 2, 2, 3, 3, 0, 0, 4, 4, 5, 5, 6, 6,7, 7,4, 1, 5, 2, 6, 3, 7];
 // установка буфера вершин
  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.LINES, 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>

Итак, у нас есть 8 точек, которые соединены между собой линиями. Теперь мы можем запустить и увидим наш куб:

Куб в WebGL

Возможно, вы спросите меня, разве это куб? Да, это куб. Но так как мы смотрим прямо на него, то визуально мы будем видеть обычный прямоугольник. Однако повернув или изменив точку обзора, мы можем уже увидеть трехмерную проекцию куба. И для этого нам понадобятся матрицы.

Введение в матрицы

Model-View Matrix

Данная матрица, которую условно можно назвать матрицей модели, объединяет мировую матрицу и матрицу вида. Мировая матрица переводит локальные координаты объекта в глобальную систему координат с учетом различных преобразований, а матрица вида переводит глобальное пространство, в котором находятся объекты, в видимое пространство камеры.

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

Projection Matrix

Матрица проекции преобразует трехмерную систему координат объекта в двухмерные для отображения их на экране. Матрица проекции бывает двух типов: ортогональная и перспективная.

При ортогональной проекции вне зависимости от значения координаты Z все объекты будут отрисовываться как есть с их текущими шириной и высотой. А при перспективной проекции будет создаваться видимость глубины или отдаления: близлежащие объекты будут казаться больше, а те, которые находятся дальше, будут меньше. Что будет создавать некоторую иллюзию реалистичности сцены.

Познакомившись с матрицами, теперь мы можем переходить к их применению в приложении.

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