Простейшая 3D программа — различия между версиями
Материал из Department of Theoretical and Applied Mechanics
Денис (обсуждение | вклад) (Новая страница: «Виртуальная лаборатория > Простейшая 3D программа <HR> Здесь расположена простейшая 3D п...») |
Денис (обсуждение | вклад) |
||
Строка 12: | Строка 12: | ||
Файл '''"WebGL_Example_v4.js"''' | Файл '''"WebGL_Example_v4.js"''' | ||
<source lang="javascript" first-line="1"> | <source lang="javascript" first-line="1"> | ||
+ | // Куб на чистом WebGL | ||
+ | // Версия 4.0 от 24.08.2014 | ||
+ | function Main_WebGL_example() { | ||
+ | var gl; | ||
+ | |||
+ | function initGL(canvas) { | ||
+ | try { | ||
+ | gl = canvas.getContext("experimental-webgl"); | ||
+ | gl.viewportWidth = canvas.width; | ||
+ | gl.viewportHeight = canvas.height; | ||
+ | } catch (e) { | ||
+ | } | ||
+ | if (!gl) { | ||
+ | alert("Could not initialise WebGL, sorry :-("); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function getShader(gl, id) { | ||
+ | var shaderScript = document.getElementById(id); | ||
+ | if (!shaderScript) { | ||
+ | return null; | ||
+ | } | ||
+ | |||
+ | var str = ""; | ||
+ | var k = shaderScript.firstChild; | ||
+ | while (k) { | ||
+ | if (k.nodeType == 3) { | ||
+ | str += k.textContent; | ||
+ | } | ||
+ | k = k.nextSibling; | ||
+ | } | ||
+ | |||
+ | var shader; | ||
+ | if (shaderScript.type == "x-shader/x-fragment") { | ||
+ | shader = gl.createShader(gl.FRAGMENT_SHADER); | ||
+ | } else if (shaderScript.type == "x-shader/x-vertex") { | ||
+ | shader = gl.createShader(gl.VERTEX_SHADER); | ||
+ | } else { | ||
+ | return null; | ||
+ | } | ||
+ | |||
+ | gl.shaderSource(shader, str); | ||
+ | gl.compileShader(shader); | ||
+ | |||
+ | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { | ||
+ | alert(gl.getShaderInfoLog(shader)); | ||
+ | return null; | ||
+ | } | ||
+ | |||
+ | return shader; | ||
+ | } | ||
+ | |||
+ | |||
+ | var shaderProgram; | ||
+ | |||
+ | function initShaders() { | ||
+ | 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("Could not initialise shaders"); | ||
+ | } | ||
+ | |||
+ | gl.useProgram(shaderProgram); | ||
+ | |||
+ | shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); | ||
+ | gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); | ||
+ | |||
+ | shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); | ||
+ | gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); | ||
+ | |||
+ | shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix"); | ||
+ | shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); | ||
+ | shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); | ||
+ | } | ||
+ | |||
+ | |||
+ | function handleLoadedTexture(textures) { | ||
+ | gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); | ||
+ | |||
+ | gl.bindTexture(gl.TEXTURE_2D, textures[0]); | ||
+ | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textures[0].image); | ||
+ | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | ||
+ | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | ||
+ | |||
+ | gl.bindTexture(gl.TEXTURE_2D, textures[1]); | ||
+ | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textures[1].image); | ||
+ | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); | ||
+ | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); | ||
+ | |||
+ | gl.bindTexture(gl.TEXTURE_2D, textures[2]); | ||
+ | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textures[2].image); | ||
+ | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); | ||
+ | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); | ||
+ | gl.generateMipmap(gl.TEXTURE_2D); | ||
+ | |||
+ | gl.bindTexture(gl.TEXTURE_2D, null); | ||
+ | } | ||
+ | |||
+ | |||
+ | var crateTextures = Array(); | ||
+ | |||
+ | function initTexture() { | ||
+ | var crateImage = new Image(); | ||
+ | |||
+ | for (var i=0; i < 3; i++) { | ||
+ | var texture = gl.createTexture(); | ||
+ | texture.image = crateImage; | ||
+ | crateTextures.push(texture); | ||
+ | } | ||
+ | |||
+ | crateImage.onload = function () { | ||
+ | handleLoadedTexture(crateTextures) | ||
+ | } | ||
+ | crateImage.src = "teormeh.png"; | ||
+ | } | ||
+ | |||
+ | |||
+ | var mvMatrix = mat4.create(); | ||
+ | var mvMatrixStack = []; | ||
+ | var pMatrix = mat4.create(); | ||
+ | |||
+ | //function mvPushMatrix() { | ||
+ | // var copy = mat4.create(); | ||
+ | // mat4.set(mvMatrix, copy); | ||
+ | // mvMatrixStack.push(copy); | ||
+ | //} | ||
+ | // | ||
+ | //function mvPopMatrix() { | ||
+ | // if (mvMatrixStack.length == 0) { | ||
+ | // throw "Invalid popMatrix!"; | ||
+ | // } | ||
+ | // mvMatrix = mvMatrixStack.pop(); | ||
+ | //} | ||
+ | |||
+ | |||
+ | function setMatrixUniforms() { | ||
+ | gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix); | ||
+ | gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix); | ||
+ | } | ||
+ | |||
+ | |||
+ | function degToRad(degrees) { | ||
+ | return degrees * Math.PI / 180; | ||
+ | } | ||
+ | |||
+ | |||
+ | var xRot = 0; | ||
+ | var xSpeed = 0; | ||
+ | |||
+ | var yRot = 0; | ||
+ | var ySpeed = 0; | ||
+ | |||
+ | var z = -4.0; | ||
+ | |||
+ | var filter = 1; | ||
+ | |||
+ | |||
+ | var currentlyPressedKeys = {}; | ||
+ | |||
+ | function handleKeyDown(event) { | ||
+ | currentlyPressedKeys[event.keyCode] = true; | ||
+ | |||
+ | if (String.fromCharCode(event.keyCode) == "F") { | ||
+ | filter += 1; | ||
+ | if (filter == 3) { | ||
+ | filter = 0; | ||
+ | } | ||
+ | } | ||
+ | if (event.keyCode == "36") { // TODO удалить | ||
+ | mat4.identity(rotate_buf); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | function handleKeyUp(event) { | ||
+ | currentlyPressedKeys[event.keyCode] = false; | ||
+ | } | ||
+ | |||
+ | |||
+ | function handleKeys() { | ||
+ | if (currentlyPressedKeys[33]) {z += 0.05;} // Page Up | ||
+ | if (currentlyPressedKeys[34]) {z -= 0.05;} // Page Down | ||
+ | if (currentlyPressedKeys[37]) {ySpeed -= 2;} // Влево | ||
+ | if (currentlyPressedKeys[39]) {ySpeed += 2;} // Вправо | ||
+ | if (currentlyPressedKeys[38]) {xSpeed -= 2;} // Вверх | ||
+ | if (currentlyPressedKeys[40]) {xSpeed += 2;} // Вниз | ||
+ | } | ||
+ | |||
+ | |||
+ | var cubeVertexPositionBuffer; | ||
+ | var cubeVertexTextureCoordBuffer; | ||
+ | var cubeVertexIndexBuffer; | ||
+ | function initBuffers() { | ||
+ | cubeVertexPositionBuffer = gl.createBuffer(); | ||
+ | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer); | ||
+ | vertices = [ | ||
+ | // Front face | ||
+ | -1.0, -1.0, 1.0, | ||
+ | 1.0, -1.0, 1.0, | ||
+ | 1.0, 1.0, 1.0, | ||
+ | -1.0, 1.0, 1.0, | ||
+ | |||
+ | // Back face | ||
+ | -1.0, -1.0, -1.0, | ||
+ | -1.0, 1.0, -1.0, | ||
+ | 1.0, 1.0, -1.0, | ||
+ | 1.0, -1.0, -1.0, | ||
+ | |||
+ | // Top face | ||
+ | -1.0, 1.0, -1.0, | ||
+ | -1.0, 1.0, 1.0, | ||
+ | 1.0, 1.0, 1.0, | ||
+ | 1.0, 1.0, -1.0, | ||
+ | |||
+ | // Bottom face | ||
+ | -1.0, -1.0, -1.0, | ||
+ | 1.0, -1.0, -1.0, | ||
+ | 1.0, -1.0, 1.0, | ||
+ | -1.0, -1.0, 1.0, | ||
+ | |||
+ | // Right face | ||
+ | 1.0, -1.0, -1.0, | ||
+ | 1.0, 1.0, -1.0, | ||
+ | 1.0, 1.0, 1.0, | ||
+ | 1.0, -1.0, 1.0, | ||
+ | |||
+ | // Left face | ||
+ | -1.0, -1.0, -1.0, | ||
+ | -1.0, -1.0, 1.0, | ||
+ | -1.0, 1.0, 1.0, | ||
+ | -1.0, 1.0, -1.0, | ||
+ | ]; | ||
+ | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); | ||
+ | cubeVertexPositionBuffer.itemSize = 3; | ||
+ | cubeVertexPositionBuffer.numItems = 24; | ||
+ | |||
+ | cubeVertexTextureCoordBuffer = gl.createBuffer(); | ||
+ | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer); | ||
+ | var textureCoords = [ | ||
+ | // Front face | ||
+ | 0.0, 0.0, | ||
+ | 1.0, 0.0, | ||
+ | 1.0, 1.0, | ||
+ | 0.0, 1.0, | ||
+ | |||
+ | // Back face | ||
+ | 1.0, 0.0, | ||
+ | 1.0, 1.0, | ||
+ | 0.0, 1.0, | ||
+ | 0.0, 0.0, | ||
+ | |||
+ | // Top face | ||
+ | 0.0, 1.0, | ||
+ | 0.0, 0.0, | ||
+ | 1.0, 0.0, | ||
+ | 1.0, 1.0, | ||
+ | |||
+ | // Bottom face | ||
+ | 1.0, 1.0, | ||
+ | 0.0, 1.0, | ||
+ | 0.0, 0.0, | ||
+ | 1.0, 0.0, | ||
+ | |||
+ | // Right face | ||
+ | 1.0, 0.0, | ||
+ | 1.0, 1.0, | ||
+ | 0.0, 1.0, | ||
+ | 0.0, 0.0, | ||
+ | |||
+ | // Left face | ||
+ | 0.0, 0.0, | ||
+ | 1.0, 0.0, | ||
+ | 1.0, 1.0, | ||
+ | 0.0, 1.0, | ||
+ | ]; | ||
+ | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW); | ||
+ | cubeVertexTextureCoordBuffer.itemSize = 2; | ||
+ | cubeVertexTextureCoordBuffer.numItems = 24; | ||
+ | |||
+ | cubeVertexIndexBuffer = gl.createBuffer(); | ||
+ | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer); | ||
+ | var cubeVertexIndices = [ | ||
+ | 0, 1, 2, 0, 2, 3, // Front face | ||
+ | 4, 5, 6, 4, 6, 7, // Back face | ||
+ | 8, 9, 10, 8, 10, 11, // Top face | ||
+ | 12, 13, 14, 12, 14, 15, // Bottom face | ||
+ | 16, 17, 18, 16, 18, 19, // Right face | ||
+ | 20, 21, 22, 20, 22, 23 // Left face | ||
+ | ] | ||
+ | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW); | ||
+ | cubeVertexIndexBuffer.itemSize = 1; | ||
+ | cubeVertexIndexBuffer.numItems = 36; | ||
+ | } | ||
+ | |||
+ | var rotate_buf = mat4.create(); | ||
+ | function drawScene() { | ||
+ | gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); | ||
+ | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); | ||
+ | |||
+ | mat4.perspective(pMatrix, 45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0); | ||
+ | |||
+ | mat4.identity(mvMatrix); | ||
+ | |||
+ | |||
+ | mat4.translate(mvMatrix, mvMatrix, [0, 0, z]); | ||
+ | |||
+ | var new_rotate = mat4.create(); | ||
+ | |||
+ | mat4.rotateX(new_rotate, new_rotate, degToRad(xRot)); | ||
+ | mat4.rotateY(new_rotate, new_rotate, degToRad(yRot)); | ||
+ | |||
+ | |||
+ | mat4.multiply(rotate_buf, new_rotate, rotate_buf); | ||
+ | mat4.multiply(mvMatrix, mvMatrix, rotate_buf); | ||
+ | |||
+ | |||
+ | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer); | ||
+ | gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0); | ||
+ | |||
+ | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer); | ||
+ | gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, cubeVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0); | ||
+ | |||
+ | |||
+ | gl.activeTexture(gl.TEXTURE0); | ||
+ | gl.bindTexture(gl.TEXTURE_2D, crateTextures[filter]); | ||
+ | gl.uniform1i(shaderProgram.samplerUniform, 0); | ||
+ | |||
+ | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer); | ||
+ | setMatrixUniforms(); | ||
+ | gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0); | ||
+ | } | ||
+ | |||
+ | function animate() { | ||
+ | xRot = xSpeed; | ||
+ | yRot = ySpeed; | ||
+ | xSpeed = ySpeed = 0; | ||
+ | } | ||
+ | |||
+ | function tick() { | ||
+ | requestAnimFrame(tick); | ||
+ | handleKeys(); | ||
+ | drawScene(); | ||
+ | animate(); | ||
+ | } | ||
+ | |||
+ | function webGLStart() { | ||
+ | var canvas = document.getElementById("WebGL_canvas"); | ||
+ | initGL(canvas); | ||
+ | initShaders(); | ||
+ | initBuffers(); | ||
+ | initTexture(); | ||
+ | |||
+ | gl.clearColor(0.95, 0.95, 1.0, 1.0); | ||
+ | gl.enable(gl.DEPTH_TEST); | ||
+ | |||
+ | document.onkeydown = handleKeyDown; | ||
+ | document.onkeyup = handleKeyUp; | ||
+ | |||
+ | tick(); | ||
+ | } | ||
+ | |||
+ | // Запуск программы | ||
+ | webGLStart(); | ||
+ | } | ||
</source> | </source> | ||
Файл '''"WebGL_Example_v4.html"''' | Файл '''"WebGL_Example_v4.html"''' | ||
<source lang="html" first-line="1"> | <source lang="html" first-line="1"> | ||
+ | <!DOCTYPE html> | ||
+ | <html> | ||
+ | <head> | ||
+ | <meta charset="UTF-8" /> | ||
+ | <title>WebGL Example</title> | ||
+ | |||
+ | <!--<script type="text/javascript" src="glMatrix-0.9.5.min.js"></script>--> | ||
+ | <script type="text/javascript" src="gl-matrix.js"></script> | ||
+ | <script type="text/javascript" src="webgl-utils.js"></script> | ||
+ | <script id="shader-fs" type="x-shader/x-fragment"> | ||
+ | precision mediump float; | ||
+ | |||
+ | varying vec2 vTextureCoord; | ||
+ | |||
+ | uniform sampler2D uSampler; | ||
+ | |||
+ | void main(void) { | ||
+ | gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)); | ||
+ | } | ||
+ | </script> | ||
+ | <script id="shader-vs" type="x-shader/x-vertex"> | ||
+ | attribute vec3 aVertexPosition; | ||
+ | attribute vec2 aTextureCoord; | ||
+ | |||
+ | uniform mat4 uMVMatrix; | ||
+ | uniform mat4 uPMatrix; | ||
+ | |||
+ | varying vec2 vTextureCoord; | ||
+ | |||
+ | |||
+ | void main(void) { | ||
+ | gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); | ||
+ | vTextureCoord = aTextureCoord; | ||
+ | } | ||
+ | </script> | ||
+ | <script src="WebGL_Example_v4.js"></script> | ||
+ | </head> | ||
+ | |||
+ | <body onload="Main_WebGL_example();"> | ||
+ | <canvas id="WebGL_canvas" style="border: none;" width="500" height="500"></canvas> | ||
+ | |||
+ | <ul> | ||
+ | <li>Стрелочки - поворот куба | ||
+ | <li><code>[Home]</code> - вернуть куб в исходное положение | ||
+ | <li><code>[Page Up]</code>/<code>[Page Down]</code> - приближение/отдаление | ||
+ | </ul> | ||
+ | </body> | ||
+ | </html> | ||
</source> | </source> | ||
</toggledisplay> | </toggledisplay> |
Версия 23:33, 25 августа 2014
Виртуальная лаборатория > Простейшая 3D программаЗдесь расположена простейшая 3D программа, написанная на чистом WebGL
Чтобы работало управление, нужно щелкнуть окно программы.
Скачать WebGL_Example_v4.zip
Текст программы на языке JavaScript (разработчик Цветков Денис): <toggledisplay status=hide showtext="Показать↓" hidetext="Скрыть↑" linkstyle="font-size:default"> Файл "WebGL_Example_v4.js"
// Куб на чистом WebGL
// Версия 4.0 от 24.08.2014
function Main_WebGL_example() {
var gl;
function initGL(canvas) {
try {
gl = canvas.getContext("experimental-webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
} catch (e) {
}
if (!gl) {
alert("Could not initialise WebGL, sorry :-(");
}
}
function getShader(gl, id) {
var shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
var str = "";
var k = shaderScript.firstChild;
while (k) {
if (k.nodeType == 3) {
str += k.textContent;
}
k = k.nextSibling;
}
var shader;
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
gl.shaderSource(shader, str);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
var shaderProgram;
function initShaders() {
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("Could not initialise shaders");
}
gl.useProgram(shaderProgram);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
}
function handleLoadedTexture(textures) {
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.bindTexture(gl.TEXTURE_2D, textures[0]);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textures[0].image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.bindTexture(gl.TEXTURE_2D, textures[1]);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textures[1].image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.bindTexture(gl.TEXTURE_2D, textures[2]);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textures[2].image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
gl.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null);
}
var crateTextures = Array();
function initTexture() {
var crateImage = new Image();
for (var i=0; i < 3; i++) {
var texture = gl.createTexture();
texture.image = crateImage;
crateTextures.push(texture);
}
crateImage.onload = function () {
handleLoadedTexture(crateTextures)
}
crateImage.src = "teormeh.png";
}
var mvMatrix = mat4.create();
var mvMatrixStack = [];
var pMatrix = mat4.create();
//function mvPushMatrix() {
// var copy = mat4.create();
// mat4.set(mvMatrix, copy);
// mvMatrixStack.push(copy);
//}
//
//function mvPopMatrix() {
// if (mvMatrixStack.length == 0) {
// throw "Invalid popMatrix!";
// }
// mvMatrix = mvMatrixStack.pop();
//}
function setMatrixUniforms() {
gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
}
function degToRad(degrees) {
return degrees * Math.PI / 180;
}
var xRot = 0;
var xSpeed = 0;
var yRot = 0;
var ySpeed = 0;
var z = -4.0;
var filter = 1;
var currentlyPressedKeys = {};
function handleKeyDown(event) {
currentlyPressedKeys[event.keyCode] = true;
if (String.fromCharCode(event.keyCode) == "F") {
filter += 1;
if (filter == 3) {
filter = 0;
}
}
if (event.keyCode == "36") { // TODO удалить
mat4.identity(rotate_buf);
}
}
function handleKeyUp(event) {
currentlyPressedKeys[event.keyCode] = false;
}
function handleKeys() {
if (currentlyPressedKeys[33]) {z += 0.05;} // Page Up
if (currentlyPressedKeys[34]) {z -= 0.05;} // Page Down
if (currentlyPressedKeys[37]) {ySpeed -= 2;} // Влево
if (currentlyPressedKeys[39]) {ySpeed += 2;} // Вправо
if (currentlyPressedKeys[38]) {xSpeed -= 2;} // Вверх
if (currentlyPressedKeys[40]) {xSpeed += 2;} // Вниз
}
var cubeVertexPositionBuffer;
var cubeVertexTextureCoordBuffer;
var cubeVertexIndexBuffer;
function initBuffers() {
cubeVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
vertices = [
// Front face
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
// Back face
-1.0, -1.0, -1.0,
-1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0,
// Top face
-1.0, 1.0, -1.0,
-1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0,
// Bottom face
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0,
-1.0, -1.0, 1.0,
// Right face
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
1.0, -1.0, 1.0,
// Left face
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0, -1.0,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
cubeVertexPositionBuffer.itemSize = 3;
cubeVertexPositionBuffer.numItems = 24;
cubeVertexTextureCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);
var textureCoords = [
// Front face
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// Back face
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
0.0, 0.0,
// Top face
0.0, 1.0,
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
// Bottom face
1.0, 1.0,
0.0, 1.0,
0.0, 0.0,
1.0, 0.0,
// Right face
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
0.0, 0.0,
// Left face
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);
cubeVertexTextureCoordBuffer.itemSize = 2;
cubeVertexTextureCoordBuffer.numItems = 24;
cubeVertexIndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
var cubeVertexIndices = [
0, 1, 2, 0, 2, 3, // Front face
4, 5, 6, 4, 6, 7, // Back face
8, 9, 10, 8, 10, 11, // Top face
12, 13, 14, 12, 14, 15, // Bottom face
16, 17, 18, 16, 18, 19, // Right face
20, 21, 22, 20, 22, 23 // Left face
]
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);
cubeVertexIndexBuffer.itemSize = 1;
cubeVertexIndexBuffer.numItems = 36;
}
var rotate_buf = mat4.create();
function drawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(pMatrix, 45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, mvMatrix, [0, 0, z]);
var new_rotate = mat4.create();
mat4.rotateX(new_rotate, new_rotate, degToRad(xRot));
mat4.rotateY(new_rotate, new_rotate, degToRad(yRot));
mat4.multiply(rotate_buf, new_rotate, rotate_buf);
mat4.multiply(mvMatrix, mvMatrix, rotate_buf);
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);
gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, cubeVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, crateTextures[filter]);
gl.uniform1i(shaderProgram.samplerUniform, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
setMatrixUniforms();
gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
}
function animate() {
xRot = xSpeed;
yRot = ySpeed;
xSpeed = ySpeed = 0;
}
function tick() {
requestAnimFrame(tick);
handleKeys();
drawScene();
animate();
}
function webGLStart() {
var canvas = document.getElementById("WebGL_canvas");
initGL(canvas);
initShaders();
initBuffers();
initTexture();
gl.clearColor(0.95, 0.95, 1.0, 1.0);
gl.enable(gl.DEPTH_TEST);
document.onkeydown = handleKeyDown;
document.onkeyup = handleKeyUp;
tick();
}
// Запуск программы
webGLStart();
}
Файл "WebGL_Example_v4.html"
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>WebGL Example</title>
<!--<script type="text/javascript" src="glMatrix-0.9.5.min.js"></script>-->
<script type="text/javascript" src="gl-matrix.js"></script>
<script type="text/javascript" src="webgl-utils.js"></script>
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
void main(void) {
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
}
</script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec2 vTextureCoord;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vTextureCoord = aTextureCoord;
}
</script>
<script src="WebGL_Example_v4.js"></script>
</head>
<body onload="Main_WebGL_example();">
<canvas id="WebGL_canvas" style="border: none;" width="500" height="500"></canvas>
<ul>
<li>Стрелочки - поворот куба
<li><code>[Home]</code> - вернуть куб в исходное положение
<li><code>[Page Up]</code>/<code>[Page Down]</code> - приближение/отдаление
</ul>
</body>
</html>
</toggledisplay>