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

Продолжим изучать основы низкоуровневого 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, а его использовать в пиксельном шейдере.
В функции 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);
}
В результате мы видим не только цвета вершин, но и градиентный переход цветов между вершинами:

Анимация объекта
Есть два варианта создания иллюзии движения – или движется объект, или движется камера вокруг объекта. Для начала попробуем двигать объект.
Переписываем главную программу с добавлением функции цикла 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

Мы можем таким образом менять координаты XY любой вершины. Осталось разобраться с осью Z, тогда мы сможем создать 3D вращение. Сейчас, если изменять Z вершин, то мы не заметим их движения, потому что прямоугольная проекция на экран не зависит от расстояния до вершин по оси Z, так как ось Z перпендикулярна нашему экрану.
//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
];

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