Закраска объекта
В предыдущих статьях мы рисовали объект, который закрашивался только шейдером. Но в большинстве случаев нам необходимо во время выполнения программы определить, в какой цвет закрасить объект. Для этого изменим наши шейдеры.
<script id="shader-fs" type="x-shader/x-fragment"> varying lowp vec4 v_color; void main(void) { gl_FragColor = v_color; } </script> <script id="shader-vs" type="x-shader/x-vertex"> attribute vec3 a_vertexPosition; attribute vec3 a_vertexColor; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; varying lowp vec4 v_color; void main(void) { gl_Position = uPMatrix * uMVMatrix * vec4(a_vertexPosition, 1.0); v_color = vec4(a_vertexColor, 1.0); } </script>
В вершинный шейдер мы добавили атрибут a_vertexColor, который будет хранить цвет вершины. Вершинный шейдер будет передавать цвет вершины переменной v_color, которая определена в фрагментном шейдере. Во время закраски треугольника фрагментный шейдер для каждого фрагмента интерполирует цвет между тремя вершинами и выполняет закраску получившимся цветом. Передача значения переменной из вершинного шейдера во фрагментный осуществляется с помощью описателя varying. А описатель lowp сообщает о точности вычисления для типа vec3
Так же изменились функции initShader(), drawScene() и initBuffers().
function initShader() { var fragmentShader = getShader(gl, "shader-fs"); var vertexShader = getShader(gl, "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); vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "a_vertexPosition"); gl.enableVertexAttribArray(vertexPositionAttribute); vertexColorAttribute = gl.getAttribLocation(shaderProgram, "a_vertexColor"); gl.enableVertexAttribArray(vertexColorAttribute); }
Мы извлекли номер атрибута a_vertexColor и сохранили его, чтобы вытаскивать данные о цвете из буфера в этот атрибут.
function initBuffers() { vertices_buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertices_buffer); var vertices = [ 1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 1.0, -1.0, 0.0, -1.0, -1.0, 0.0 ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); color_buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer); var colors = [ 0.5, 0.0, 0.5, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0 ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); }
Затем создаём новый буфер и сохраняем в нём данные о цвете для каждой вершины.
function drawScene(delta) { gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); perspectiveMatrix = makePerspective(45, 600.0/400.0, 0.1, 100.0); loadIdentity(); mvPushMatrix(); mvTranslate([-0.0, 0.0, -6.0]); mvRotate(sqrRot, [0, 0, 1]); gl.bindBuffer(gl.ARRAY_BUFFER, vertices_buffer); gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(vertexPositionAttribute); gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer); gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(vertexColorAttribute); setMatrixUniforms(); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); mvPopMatrix(); sqrRot -= delta * 10; }
И наконец, указываем, как извлечь данные о цвете и использовать их.