Текущая версия |
Ваш текст |
Строка 1: |
Строка 1: |
| [[Виртуальная лаборатория]] > [[Простейшая 3D программа]] <HR> | | [[Виртуальная лаборатория]] > [[Простейшая 3D программа]] <HR> |
− | Здесь расположена простейшая 3D программа, написанная на чистом WebGL. | + | Здесь расположена простейшая 3D программа, написанная на чистом WebGL |
− | | |
| | | |
| '''Чтобы работало управление, нужно щелкнуть окно программы.''' | | '''Чтобы работало управление, нужно щелкнуть окно программы.''' |
Строка 10: |
Строка 9: |
| Скачать [[Медиа:WebGL_Example_v4.zip|WebGL_Example_v4.zip]] | | Скачать [[Медиа:WebGL_Example_v4.zip|WebGL_Example_v4.zip]] |
| | | |
− | <div class="mw-collapsible mw-collapsed" style="width:100%" >
| + | Текст программы на языке JavaScript (разработчик [[Цветков Денис]]): <toggledisplay status=hide showtext="Показать↓" hidetext="Скрыть↑" linkstyle="font-size:default"> |
− | '''Текст программы на языке JavaScript (разработчик [[Цветков Денис]]):''' <div class="mw-collapsible-content">
| |
| Файл '''"WebGL_Example_v4.js"''' | | Файл '''"WebGL_Example_v4.js"''' |
− | <syntaxhighlight lang="javascript" line start="1" enclose="div"> | + | <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));
| + | </source> |
− | 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"> | + | <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> |
− | </syntaxhighlight> | + | </toggledisplay> |
− | </div>
| |
− | </div>
| |
| | | |
| | | |