Простейшая 3D программа — различия между версиями
Материал из Department of Theoretical and Applied Mechanics
Денис (обсуждение | вклад) (Новая страница: «Виртуальная лаборатория > Простейшая 3D программа <HR> Здесь расположена простейшая 3D п...») |
Денис (обсуждение | вклад) |
||
(не показано 7 промежуточных версий 2 участников) | |||
Строка 1: | Строка 1: | ||
[[Виртуальная лаборатория]] > [[Простейшая 3D программа]] <HR> | [[Виртуальная лаборатория]] > [[Простейшая 3D программа]] <HR> | ||
− | Здесь расположена простейшая 3D программа, написанная на чистом WebGL | + | Здесь расположена простейшая 3D программа, написанная на чистом WebGL. |
+ | |||
'''Чтобы работало управление, нужно щелкнуть окно программы.''' | '''Чтобы работало управление, нужно щелкнуть окно программы.''' | ||
Строка 9: | Строка 10: | ||
Скачать [[Медиа:WebGL_Example_v4.zip|WebGL_Example_v4.zip]] | Скачать [[Медиа:WebGL_Example_v4.zip|WebGL_Example_v4.zip]] | ||
− | Текст программы на языке JavaScript (разработчик [[Цветков Денис]]): < | + | <div class="mw-collapsible mw-collapsed" style="width:100%" > |
+ | '''Текст программы на языке JavaScript (разработчик [[Цветков Денис]]):''' <div class="mw-collapsible-content"> | ||
Файл '''"WebGL_Example_v4.js"''' | Файл '''"WebGL_Example_v4.js"''' | ||
− | < | + | <syntaxhighlight lang="javascript" line start="1" enclose="div"> |
+ | // Куб на чистом 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(); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
Файл '''"WebGL_Example_v4.html"''' | Файл '''"WebGL_Example_v4.html"''' | ||
− | < | + | <syntaxhighlight lang="html5" line start="1" enclose="div"> |
+ | <!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> |
− | </ | + | </syntaxhighlight> |
+ | </div> | ||
+ | </div> | ||
Текущая версия на 09:44, 11 марта 2015
Виртуальная лаборатория > Простейшая 3D программаЗдесь расположена простейшая 3D программа, написанная на чистом WebGL.
Чтобы работало управление, нужно щелкнуть окно программы.
Скачать WebGL_Example_v4.zip
Текст программы на языке JavaScript (разработчик Цветков Денис):
Файл "WebGL_Example_v4.js"
1 // Куб на чистом WebGL
2 // Версия 4.0 от 24.08.2014
3
4 function Main_WebGL_example() {
5 var gl;
6
7 function initGL(canvas) {
8 try {
9 gl = canvas.getContext("experimental-webgl");
10 gl.viewportWidth = canvas.width;
11 gl.viewportHeight = canvas.height;
12 } catch (e) {
13 }
14 if (!gl) {
15 alert("Could not initialise WebGL, sorry :-(");
16 }
17 }
18
19 function getShader(gl, id) {
20 var shaderScript = document.getElementById(id);
21 if (!shaderScript) {
22 return null;
23 }
24
25 var str = "";
26 var k = shaderScript.firstChild;
27 while (k) {
28 if (k.nodeType == 3) {
29 str += k.textContent;
30 }
31 k = k.nextSibling;
32 }
33
34 var shader;
35 if (shaderScript.type == "x-shader/x-fragment") {
36 shader = gl.createShader(gl.FRAGMENT_SHADER);
37 } else if (shaderScript.type == "x-shader/x-vertex") {
38 shader = gl.createShader(gl.VERTEX_SHADER);
39 } else {
40 return null;
41 }
42
43 gl.shaderSource(shader, str);
44 gl.compileShader(shader);
45
46 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
47 alert(gl.getShaderInfoLog(shader));
48 return null;
49 }
50
51 return shader;
52 }
53
54
55 var shaderProgram;
56
57 function initShaders() {
58 var fragmentShader = getShader(gl, "shader-fs");
59 var vertexShader = getShader(gl, "shader-vs");
60
61 shaderProgram = gl.createProgram();
62 gl.attachShader(shaderProgram, vertexShader);
63 gl.attachShader(shaderProgram, fragmentShader);
64 gl.linkProgram(shaderProgram);
65
66 if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
67 alert("Could not initialise shaders");
68 }
69
70 gl.useProgram(shaderProgram);
71
72 shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
73 gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
74
75 shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
76 gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);
77
78 shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
79 shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
80 shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
81 }
82
83
84 function handleLoadedTexture(textures) {
85 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
86
87 gl.bindTexture(gl.TEXTURE_2D, textures[0]);
88 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textures[0].image);
89 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
90 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
91
92 gl.bindTexture(gl.TEXTURE_2D, textures[1]);
93 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textures[1].image);
94 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
95 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
96
97 gl.bindTexture(gl.TEXTURE_2D, textures[2]);
98 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textures[2].image);
99 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
100 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
101 gl.generateMipmap(gl.TEXTURE_2D);
102
103 gl.bindTexture(gl.TEXTURE_2D, null);
104 }
105
106
107 var crateTextures = Array();
108
109 function initTexture() {
110 var crateImage = new Image();
111
112 for (var i=0; i < 3; i++) {
113 var texture = gl.createTexture();
114 texture.image = crateImage;
115 crateTextures.push(texture);
116 }
117
118 crateImage.onload = function () {
119 handleLoadedTexture(crateTextures)
120 }
121 crateImage.src = "teormeh.png";
122 }
123
124
125 var mvMatrix = mat4.create();
126 var mvMatrixStack = [];
127 var pMatrix = mat4.create();
128
129 //function mvPushMatrix() {
130 // var copy = mat4.create();
131 // mat4.set(mvMatrix, copy);
132 // mvMatrixStack.push(copy);
133 //}
134 //
135 //function mvPopMatrix() {
136 // if (mvMatrixStack.length == 0) {
137 // throw "Invalid popMatrix!";
138 // }
139 // mvMatrix = mvMatrixStack.pop();
140 //}
141
142
143 function setMatrixUniforms() {
144 gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
145 gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
146 }
147
148
149 function degToRad(degrees) {
150 return degrees * Math.PI / 180;
151 }
152
153
154 var xRot = 0;
155 var xSpeed = 0;
156
157 var yRot = 0;
158 var ySpeed = 0;
159
160 var z = -4.0;
161
162 var filter = 1;
163
164
165 var currentlyPressedKeys = {};
166
167 function handleKeyDown(event) {
168 currentlyPressedKeys[event.keyCode] = true;
169
170 if (String.fromCharCode(event.keyCode) == "F") {
171 filter += 1;
172 if (filter == 3) {
173 filter = 0;
174 }
175 }
176 if (event.keyCode == "36") { // TODO удалить
177 mat4.identity(rotate_buf);
178 }
179 }
180
181
182 function handleKeyUp(event) {
183 currentlyPressedKeys[event.keyCode] = false;
184 }
185
186
187 function handleKeys() {
188 if (currentlyPressedKeys[33]) {z += 0.05;} // Page Up
189 if (currentlyPressedKeys[34]) {z -= 0.05;} // Page Down
190 if (currentlyPressedKeys[37]) {ySpeed -= 2;} // Влево
191 if (currentlyPressedKeys[39]) {ySpeed += 2;} // Вправо
192 if (currentlyPressedKeys[38]) {xSpeed -= 2;} // Вверх
193 if (currentlyPressedKeys[40]) {xSpeed += 2;} // Вниз
194 }
195
196
197 var cubeVertexPositionBuffer;
198 var cubeVertexTextureCoordBuffer;
199 var cubeVertexIndexBuffer;
200 function initBuffers() {
201 cubeVertexPositionBuffer = gl.createBuffer();
202 gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
203 vertices = [
204 // Front face
205 -1.0, -1.0, 1.0,
206 1.0, -1.0, 1.0,
207 1.0, 1.0, 1.0,
208 -1.0, 1.0, 1.0,
209
210 // Back face
211 -1.0, -1.0, -1.0,
212 -1.0, 1.0, -1.0,
213 1.0, 1.0, -1.0,
214 1.0, -1.0, -1.0,
215
216 // Top face
217 -1.0, 1.0, -1.0,
218 -1.0, 1.0, 1.0,
219 1.0, 1.0, 1.0,
220 1.0, 1.0, -1.0,
221
222 // Bottom face
223 -1.0, -1.0, -1.0,
224 1.0, -1.0, -1.0,
225 1.0, -1.0, 1.0,
226 -1.0, -1.0, 1.0,
227
228 // Right face
229 1.0, -1.0, -1.0,
230 1.0, 1.0, -1.0,
231 1.0, 1.0, 1.0,
232 1.0, -1.0, 1.0,
233
234 // Left face
235 -1.0, -1.0, -1.0,
236 -1.0, -1.0, 1.0,
237 -1.0, 1.0, 1.0,
238 -1.0, 1.0, -1.0,
239 ];
240 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
241 cubeVertexPositionBuffer.itemSize = 3;
242 cubeVertexPositionBuffer.numItems = 24;
243
244 cubeVertexTextureCoordBuffer = gl.createBuffer();
245 gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);
246 var textureCoords = [
247 // Front face
248 0.0, 0.0,
249 1.0, 0.0,
250 1.0, 1.0,
251 0.0, 1.0,
252
253 // Back face
254 1.0, 0.0,
255 1.0, 1.0,
256 0.0, 1.0,
257 0.0, 0.0,
258
259 // Top face
260 0.0, 1.0,
261 0.0, 0.0,
262 1.0, 0.0,
263 1.0, 1.0,
264
265 // Bottom face
266 1.0, 1.0,
267 0.0, 1.0,
268 0.0, 0.0,
269 1.0, 0.0,
270
271 // Right face
272 1.0, 0.0,
273 1.0, 1.0,
274 0.0, 1.0,
275 0.0, 0.0,
276
277 // Left face
278 0.0, 0.0,
279 1.0, 0.0,
280 1.0, 1.0,
281 0.0, 1.0,
282 ];
283 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);
284 cubeVertexTextureCoordBuffer.itemSize = 2;
285 cubeVertexTextureCoordBuffer.numItems = 24;
286
287 cubeVertexIndexBuffer = gl.createBuffer();
288 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
289 var cubeVertexIndices = [
290 0, 1, 2, 0, 2, 3, // Front face
291 4, 5, 6, 4, 6, 7, // Back face
292 8, 9, 10, 8, 10, 11, // Top face
293 12, 13, 14, 12, 14, 15, // Bottom face
294 16, 17, 18, 16, 18, 19, // Right face
295 20, 21, 22, 20, 22, 23 // Left face
296 ]
297 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);
298 cubeVertexIndexBuffer.itemSize = 1;
299 cubeVertexIndexBuffer.numItems = 36;
300 }
301
302 var rotate_buf = mat4.create();
303 function drawScene() {
304 gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
305 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
306
307 mat4.perspective(pMatrix, 45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);
308
309 mat4.identity(mvMatrix);
310
311
312 mat4.translate(mvMatrix, mvMatrix, [0, 0, z]);
313
314 var new_rotate = mat4.create();
315
316 mat4.rotateX(new_rotate, new_rotate, degToRad(xRot));
317 mat4.rotateY(new_rotate, new_rotate, degToRad(yRot));
318
319
320 mat4.multiply(rotate_buf, new_rotate, rotate_buf);
321 mat4.multiply(mvMatrix, mvMatrix, rotate_buf);
322
323
324 gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
325 gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
326
327 gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);
328 gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, cubeVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
329
330
331 gl.activeTexture(gl.TEXTURE0);
332 gl.bindTexture(gl.TEXTURE_2D, crateTextures[filter]);
333 gl.uniform1i(shaderProgram.samplerUniform, 0);
334
335 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
336 setMatrixUniforms();
337 gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
338 }
339
340 function animate() {
341 xRot = xSpeed;
342 yRot = ySpeed;
343 xSpeed = ySpeed = 0;
344 }
345
346 function tick() {
347 requestAnimFrame(tick);
348 handleKeys();
349 drawScene();
350 animate();
351 }
352
353 function webGLStart() {
354 var canvas = document.getElementById("WebGL_canvas");
355 initGL(canvas);
356 initShaders();
357 initBuffers();
358 initTexture();
359
360 gl.clearColor(0.95, 0.95, 1.0, 1.0);
361 gl.enable(gl.DEPTH_TEST);
362
363 document.onkeydown = handleKeyDown;
364 document.onkeyup = handleKeyUp;
365
366 tick();
367 }
368
369 // Запуск программы
370 webGLStart();
371 }
Файл "WebGL_Example_v4.html"
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="UTF-8" />
5 <title>WebGL Example</title>
6
7 <!--<script type="text/javascript" src="glMatrix-0.9.5.min.js"></script>-->
8 <script type="text/javascript" src="gl-matrix.js"></script>
9 <script type="text/javascript" src="webgl-utils.js"></script>
10 <script id="shader-fs" type="x-shader/x-fragment">
11 precision mediump float;
12
13 varying vec2 vTextureCoord;
14
15 uniform sampler2D uSampler;
16
17 void main(void) {
18 gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
19 }
20 </script>
21 <script id="shader-vs" type="x-shader/x-vertex">
22 attribute vec3 aVertexPosition;
23 attribute vec2 aTextureCoord;
24
25 uniform mat4 uMVMatrix;
26 uniform mat4 uPMatrix;
27
28 varying vec2 vTextureCoord;
29
30
31 void main(void) {
32 gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
33 vTextureCoord = aTextureCoord;
34 }
35 </script>
36 <script src="WebGL_Example_v4.js"></script>
37 </head>
38
39 <body onload="Main_WebGL_example();">
40 <canvas id="WebGL_canvas" style="border: none;" width="500" height="500"></canvas>
41
42 <ul>
43 <li>Стрелочки - поворот куба
44 <li><code>[Home]</code> - вернуть куб в исходное положение
45 <li><code>[Page Up]</code>/<code>[Page Down]</code> - приближение/отдаление
46 </ul>
47 </body>
48
49 </html>