Подумать только

logoas CogITas

Dubito - Ergo - Sum

× Error from canvas.getContext(): Maybe your browser or hardware (GPU) does not appear to support WebGL. The Canvas for WebGL below will be empty.
Mouse и Num Lock

WebGL примитив – раскрасим, раскрутим в 2D

Строим 3D проекты – Шаг 3

Angry Birds - торжество 2D
Angry Birds — торжество 2D

 

   Продолжим изучать основы низкоуровневого WebGL и совершенствовать тестовую программу. Установим цвет простейшего объекта, и зададим его движение в 2D по двум осям XY.

 

Добавляем цвет

   Примитив-треугольник на прошлом шаге был белым. Изменим шейдеры так, чтобы можно было принимать в вершинный шейдер цвета вершин, и далее из него передавать цвета в пиксельный шейдер:

<script id="shader-vs" type="x-shader/x-vertex">
	   attribute vec3 aVertexPosition;
	   attribute vec3 aVertexColor;

	   varying highp vec4 vColor;
	   void main(void)
	   {
		  gl_Position = vec4(aVertexPosition, 1.0);
		  vColor = vec4(aVertexColor, 1.0);
	   }
	</script>

	<script id="shader-fs" type="x-shader/x-fragment">
	   varying highp vec4 vColor;
	   void main(void)
	   {
		  //gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
		  gl_FragColor = vColor;
	   }
	</script>

   Цвета мы будем передавать в aVertexColor, формировать на его основе vColor, а его использовать в пиксельном шейдере.

Тип highp устанавливает высокую точность для типа floating point.

   В функции setupBuffers мы аналогично вершинам добавим цвета вершин в массив triangleVerticeColors и создадим на его основе буфер trianglesColorBuffer, который будем передавать в шейдер в переменную-атрибут aVertexColor:

var triangleVerticeColors =
[
1.0, 0.0, 0.0,	//Red
	0.0, 1.0, 0.0,	//Green
	0.0, 0.0, 1.0	//Blue
];

trianglesColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array( triangleVerticeColors), gl.STATIC_DRAW);

   Передачу цветов в шейдер пропишем в функции drawScene аналогично вершинам:

function drawScene()
{
vertexPositionAttribute = gl.getAttribLocation(glProgram, "aVertexPosition");
gl.enableVertexAttribArray( vertexPositionAttribute);
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffer);
gl.vertexAttribPointer( vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);

vertexColorAttribute = gl.getAttribLocation(glProgram, "aVertexColor");
gl.enableVertexAttribArray( vertexColorAttribute);
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesColorBuffer);
gl.vertexAttribPointer( vertexColorAttribute, 3, gl.FLOAT, false, 0, 0);

gl.drawArrays(gl.TRIANGLES, 0, 3);
}

   В результате мы видим не только цвета вершин, но и градиентный переход цветов между вершинами:

Примитив в основных RGB цветах
Примитив в основных RGB цветах

 

Анимация объекта

   Есть два варианта создания иллюзии движения – или движется объект, или движется камера вокруг объекта. Для начала попробуем двигать объект.

  1. Будем менять координаты XY объекта. Для этого нужно создать цикл. Используем для перехода в цикле команду requestAnimationFrame.
Команда window.requestAnimationFrame ставит на “паузу” выполнение программы WebGL, когда не активно окно  или вкладка с программой. Это позволяет снизить бесполезную нагрузку на CPU и GPU, а, следовательно, на батарею.

   Переписываем главную программу с добавлением функции цикла animloop ():

if(gl)
	{
		initShaders();   //[2]
		setupBuffers();  //[3].1

		(function animLoop()
		{
			setupWebGL();			 //[1]
			setupDynamicBuffers();		//[3].2

			drawScene();			 //[4]
			requestAnimFrame( animLoop, canvas);
		})();
}

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

   2 Мы вынесли установку буфера вершин в отдельную функцию setupDynamicBuffers, в которой будем изменять его содержимое в процессе работы программы.

function setupDynamicBuffers()
{
	//Limit translation amount to -0.5 to 0.5.
	var x_delta = Math.sin(angle_x) / 2.0;

//Move.
	var triangleVertices =
	[
	   //Triangle's points coodinates.
	   -0.5 + x_delta,  0.5, 0.0,
	    0.0 + x_delta,  0.0, 0.0,
	   -0.5 + x_delta, -0.5, 0.0
	];

	angle_x += 0.01;

	trianglesVerticeBuffer = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffer);
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.DYNAMIC_DRAW);
}

   Мы также поменяли STATIC_DRAW на DYNAMIC_DRAW.

   И завели глобальную переменную var angle_x = 0; в файле vars.js

Error from Html: Your browser does not support the HTML5 canvas element.
 

2D движение примитива
2D движение примитива

 

 

   Мы можем таким образом менять координаты XY любой вершины. Осталось разобраться с осью Z, тогда мы сможем создать 3D вращение. Сейчас, если изменять Z вершин, то мы не заметим их движения, потому что прямоугольная проекция на экран не зависит от расстояния до вершин по оси Z, так как ось Z перпендикулярна нашему экрану.

   Правда, мы можем сделать так, чтобы с помощью XY менялась площадь треугольника, и за счет этого создавалась иллюзия его приближения-удаления или даже вращения.  Для этого достаточно изменить всего 1 знак “+” на ”–“ :
        //Rotate.
	var triangleVertices =
	[
	  //Triangle's points coodinates.
	   -0.5 + x_delta,  0.5, 0.0,
	    0.0 - x_delta,  0.0, 0.0,
	   -0.5 + x_delta, -0.5, 0.0
	];

Error from Html: Your browser does not support the HTML5 canvas element.
 

2D вращение примитива
2D вращение примитива

 
 

Но это только кажущееся 3D вращение. Оно достигается за счет анимации проекции без изменения реального положения точек в компьютерной модели по третьей координате Z.

 

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

 

<< Предыдущий шаг

Следующий шаг >>

Все статьи


Оставить комментарий

Ваш email не будет отображаться. Обязательные поля помечены *

(Чтобы установить аватар, необходимо зарегистрировать свой e-mail на gravatar.com. Как это сделать, написано в статье http://cogitas.ru/robots-avatar-icon-wordpress.html)