Обработка пользовательского ввода предполагает обработку событий клавиатуры и мыши и не сильно отличается от общей модели, что используется в javascript, например, при создании игр с использованием элемента canvas.
Создадим программу, которая будет по нажатию клавиатуры перемещать куб вперед, назад, а также вращать его:
<script type="text/javascript"> var gl; var shaderProgram; var vertexBuffer; var indexBuffer; var angle = 2.0;//угол вращения в радианах var zTranslation = -2.0; // смещение по оси Z var mvMatrix = mat4.create(); var pMatrix = mat4.create(); 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); shaderProgram.MVMatrix = gl.getUniformLocation(shaderProgram, "uMVMatrix"); shaderProgram.ProjMatrix = gl.getUniformLocation(shaderProgram, "uPMatrix"); } function setMatrixUniforms(){ gl.uniformMatrix4fv(shaderProgram.ProjMatrix,false, pMatrix); gl.uniformMatrix4fv(shaderProgram.MVMatrix, false, mvMatrix); } 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.vertexAttribPointer(shaderProgram.vertexPositionAttribute, vertexBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.drawElements(gl.LINES, indexBuffer.numberOfItems, gl.UNSIGNED_SHORT,0); } function setupWebGL() { gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); mat4.perspective(pMatrix, 1.04, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0); mat4.identity(mvMatrix); mat4.translate(mvMatrix,mvMatrix,[0, 0, zTranslation]); mat4.rotate(mvMatrix,mvMatrix, angle, [0, 1, 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){ document.addEventListener('keydown', handleKeyDown, false); gl.viewportWidth = canvas.width; gl.viewportHeight = canvas.height; initShaders(); initBuffers(); // функция анимации (function animloop(){ setupWebGL(); setMatrixUniforms(); draw(); requestAnimFrame(animloop, canvas); })(); } } function handleKeyDown(e){ switch(e.keyCode) { case 39: // стрелка вправо angle+=0.1; break; case 37: // стрелка влево angle-=0.1; break; case 40: // стрелка вниз zTranslation+=0.1; break; case 38: // стрелка вверх zTranslation-=0.1; break; } } // настройка анимации window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback, element) { return window.setTimeout(callback, 1000/60); }; })(); </script>
Вначале для фиксации перемещения задаем две переменных:
var angle = 2.0;// угол поворота в радианах var zTranslation = -2.0; // смещение по оси Z
Дальше если у нас задан контекст WebGL, мы регистрируем обработчик события нажатия клавиши: document.addEventListener('keydown', handleKeyDown, false);
.
Соответственно добавляем в конце функцию обработчика:
function handleKeyDown(e){ switch(e.keyCode) { // изменяем угол поворота case 39: // стрелка вправо angle+=0.1; break; case 37: // стрелка влево angle-=0.1; break; // изменяем смещение по оси Z case 40: // стрелка вниз zTranslation+=0.1; break; case 38: // стрелка вверх zTranslation-=0.1; break; } }
С помощью свойства e.keyCode
мы можем узнать код нажатой клавиши и в зависимости от этого выполнить определенные действия.
А так как у нас задействована функция анимации requestAnimFrame, то в цикле функции для установки матриц получают новые значения и, таким образом,
изменяют положение объекта.