Перспективные языки веб-разработки

Знакомство с технологией WebGL

Показывать лекцию целиком

Примеры

WebGL, позволяет реализовывать на web-страницах очень зрелищные эффекты трехмерной графики.Технология WebGL, или WebGraphicsLibrary, основанная на стандарте OpenGLES 2.0, является интерфейсом прикладного программирования для языка JavaScript. В поддерживающих эту технологию браузерах трехмерная графика реализуется без использования дополнительных плагинов. В этом заключается ее отличие от MSSilverlight (Silverlight - это плагин, работающий поверх браузера). WebGL-программы состоят из управляющего кода, написанного на JavaScript и так называемого шейдерного кода, запускаемого на графическом процессоре. Для рендеринга трехмерных сцен используется элемент управления HTML5 Canvas. Доступ к элементу управления Canvas осуществляется через интерфейсы объектной модели документа.

Работы в данном направлении были начаты Владимиром Вукучевичем, представившем прототип Canvas 3D в 2006 году. К концу 2007-го года собственные реализации этой концепции появились в браузерах MozillaиOpera. Вначале 2009-го работы по WebGLначал независимый консорциум KhronosGroup.В работе консорциума приняли участие такие компании, как Apple, Google, Mozilla иOpera. Ранее компания Google начала использовать WebGL в своих продуктах Google Maps и Google Body. (http://en.wikipedia.org/wiki/WebGL)

Нужно сказать, что новую технологию поддерживают далеко не все браузеры. Вернее сказать, что из проверенных мною пяти браузеров под MSWindows 8 ConsumerPreview, таких как MSInternetExplorer, GoogleChrome, MozillaFireFox, AppleSafariиOpera, примеры работали только на MozillaFireFox.

Проверить поддерживает ли браузер WebGL, можно следующим образом:

Пример 1 (sample_1) Проверка совместимости с WebGL

Откройте блокнот и наберите следующий код:

<!DOCTYPEhtml>
<htmlxmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Проверка совместимости с WebGL</title>
<scripttype="text/javascript">
varstr;
str = "";
if (window.WebGLRenderingContext) {
str = "Поздравляю! Ваш браузер поддерживает технологию WebGL";
    }
else {
str = "К сожалению ваш браузер не поддерживает технологию WebGL";
    }
document.write(str);
</script>
</head>
<body>
</body>
</html>
    

Пример 2. Сравнение WebGL с MSSilverlight

Если не использовать специальных библиотек, программирование WebGL может показаться довольно утомительным делом. Сравните примеры с треугольниками, написанные с помощью WebGL и MSSilverlight:

)

<!DOCTYPEhtml>
<html>
<head>
<title>WebGL Basics part 2</title>

<scripttype='text/javascript'>

vargl; // GL context
//http://blogoben.googlecode.com/svn/trunk/webgl-basics/part-2-white-triangle.html
// Function called by onload handler
function start() {
// Gets canvas from the HTML page
var canvas = document.getElementById('glcanvas');

// Creates GL context
gl = null;
try { gl = canvas.getContext('experimental-webgl'); }
catch (e) { alert('Exception catched in getContext: ' + e.toString()); return; }

// If no exception but context creation failed, alerts user
if (!gl) { alert('Unable to create Web GL context'); return; }

// Sets clear color to non-transparent dark blue and clears context
gl.clearColor(0.0, 0.0, 0.5, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);

//---------------- end of part 1 -----------------

// Creates fragment shader (returns white color for any position)
varfshader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fshader, 'void main(void) {gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);}');
gl.compileShader(fshader);
if (!gl.getShaderParameter(fshader, gl.COMPILE_STATUS))
            { alert('Error during fragment shader compilation:\n' + gl.getShaderInfoLog(fshader)); return; }

// Creates vertex shader (converts 2D point position to coordinates)
varvshader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vshader, 'attribute vec2 ppos; void main(void) { gl_Position = vec4(ppos.x, ppos.y, 0.0, 1.0);}');
gl.compileShader(vshader);
if (!gl.getShaderParameter(vshader, gl.COMPILE_STATUS))
            { alert('Error during vertex shader compilation:\n' + gl.getShaderInfoLog(vshader)); return; }

// Creates program and links shaders to it
var program = gl.createProgram();
gl.attachShader(program, fshader);
gl.attachShader(program, vshader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS))
            { alert('Error during program linking:\n' + gl.getProgramInfoLog(program)); return; }

// Validates and uses program in the GL context
gl.validateProgram(program);
if (!gl.getProgramParameter(program, gl.VALIDATE_STATUS))
            { alert('Error during program validation:\n' + gl.getProgramInfoLog(program)); return; }
gl.useProgram(program);

// Gets address of the input 'attribute' of the vertex shader
varvattrib = gl.getAttribLocation(program, 'ppos');
if (vattrib == -1)
            { alert('Error during attribute address retrieval'); return; }
gl.enableVertexAttribArray(vattrib);

// Initializes the vertex buffer and sets it as current one
varvbuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbuffer);

// Puts vertices to buffer and links it to attribute variable 'ppos'
var vertices = new Float32Array([0.0, 0.5, -0.5, -0.5, 0.5, -0.5]);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.vertexAttribPointer(vattrib, 2, gl.FLOAT, false, 0, 0);

// Draws the object
gl.drawArrays(gl.TRIANGLES, 0, 3);
gl.flush()
        }

</script>
</head>

<bodyonload='start();'>
<canvasid='glcanvas'width=320height=240>
       It seems the browser does not support the 'canvas' tag (part of HTML5)
</canvas>
</body>
</html>
    

MS Silverlight (Автор - ЧарльзПетзольд, 2007)

<!-- ============================================
      Tiniest3D.xaml (c) 2007 by Charles Petzold
     ============================================ -->
<Viewport3Dxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3DPositions="-1 0 -8, 1 0 -8, 0 1 -8"/>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterialBrush="Red"/>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
    

Как видите, результат говорит сам за себя.

Обычно при программировании WebGL-приложений все же пользуются специальными библиотеками. В народе очень популярна библиотека Three.js. Эта библиотека, написанная на JavaScript, позволяет осуществлять визуализацию с помощью <canvas>, <svg> и WebGL.

Рассмотрим несколько примеров, визуализации объектов с помощью библиотеки Three.js.

Пример 3 (sample_3) Визуализация куба

Скачайте с сайта https://github.com/mrdoob/three.js библиотеку скачайте библиотеку Detector.js.

Откройте блокнот и наберите следующий код:

<!doctypehtml>
<htmllang="en">
  <head>
    <title>Визуализациякуба</title>
    <style>
      body {
        background: #000;
      }

    </style>

    <scriptsrc="Three.js"></script>
    <scriptsrc="Detector.js"></script>

  </head>

  <body>
<script>
var radius = 6371,
      rotationSpeed = 0.1,
      moonScale = 0.23,

      height = window.innerHeight,
      width = window.innerWidth,

      container,

      camera, controls, scene, renderer,
      geometry, meshMoon,
      dirLight, ambientLight,

      clock = newTHREE.Clock();

window.onload = function () {
if (!Detector.webgl) {
Detector.addGetWebGLMessage();
return;
                }
init();
                animate();
            }

functioninit() {
                container = document.createElement('div');
document.body.appendChild(container);
                scene = newTHREE.Scene();

                renderer = newTHREE.WebGLRenderer({ clearAlpha: 1, clearColor: 0x000000, antialias: true });
renderer.setSize(width, height);

renderer.gammaInput = true;
renderer.gammaOutput = true;

container.appendChild(renderer.domElement);

                camera = newTHREE.PerspectiveCamera(25, width / height, 50, 1e7);
camera.position.z = radius * 7;
scene.add(camera);

                controls = newTHREE.TrackballControls(camera, renderer.domElement);

controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.2;

controls.noZoom = false;
controls.noPan = false;

controls.staticMoving = false;
controls.dynamicDampingFactor = 0.3;

controls.minDistance = radius * 1.1;
controls.maxDistance = radius * 100;

controls.keys = [65, 83, 68]; // [ rotateKey, zoomKey, panKey ]

dirLight = newTHREE.DirectionalLight(0xFFFFFF);
dirLight.position.set(-1, 0, 1).normalize();

scene.add(dirLight);
scene.add(newTHREE.AmbientLight(0x404040));

varmoonTexture = THREE.ImageUtils.loadTexture("white.jpg");

varshader = THREE.ShaderUtils.lib["normal"],
        uniforms = THREE.UniformsUtils.clone(shader.uniforms);

                geometry = newTHREE.SphereGeometry(radius, 100, 50);

varmaterialMoon = newTHREE.MeshPhongMaterial({ color: 0xffffff, map: moonTexture });

                meshMoon1 = newTHREE.Mesh(geometry, materialMoon);
                meshMoon1.position.set(0, 0, 0);
                meshMoon1.scale.set(moonScale, moonScale, moonScale);
scene.add(meshMoon1);

                meshMoon2 = newTHREE.Mesh(geometry, materialMoon);
                meshMoon2.position.set(radius, 0, 0);
                meshMoon2.scale.set(moonScale, moonScale, moonScale);
scene.add(meshMoon2);

                meshMoon3 = newTHREE.Mesh(geometry, materialMoon);
                meshMoon3.position.set(0, 0, radius);
                meshMoon3.scale.set(moonScale, moonScale, moonScale);
scene.add(meshMoon3);

                meshMoon4 = newTHREE.Mesh(geometry, materialMoon);
                meshMoon4.position.set(0, radius, 0);
                meshMoon4.scale.set(moonScale, moonScale, moonScale);
scene.add(meshMoon4);

                meshMoon5 = newTHREE.Mesh(geometry, materialMoon);
                meshMoon5.position.set(0, radius, radius);
                meshMoon5.scale.set(moonScale, moonScale, moonScale);
scene.add(meshMoon5);

                meshMoon6 = newTHREE.Mesh(geometry, materialMoon);
                meshMoon6.position.set(radius, 0, radius);
                meshMoon6.scale.set(moonScale, moonScale, moonScale);
scene.add(meshMoon6);

                meshMoon7 = newTHREE.Mesh(geometry, materialMoon);
                meshMoon7.position.set(radius, radius, 0);
                meshMoon7.scale.set(moonScale, moonScale, moonScale);
scene.add(meshMoon7);

                meshMoon8 = newTHREE.Mesh(geometry, materialMoon);
                meshMoon8.position.set(radius, radius, radius);
                meshMoon8.scale.set(moonScale, moonScale, moonScale);
scene.add(meshMoon8);

window.addEventListener('resize', onWindowResize, false);
            };


functiononWindowResize(event) {
                width = window.innerWidth;
                height = window.innerHeight;

renderer.setSize(width, height);

camera.aspect = width / height;
camera.updateProjectionMatrix();

controls.screen.width = width;
controls.screen.height = height;

camera.radius = (width + height) / 4;

            };

function animate() {
requestAnimationFrame(animate);
                render();
stats.update();
            };

function render() {
controls.update();
renderer.clear();
renderer.render(scene, camera);
            };
    </script>
  </body>
</html>
    

Пример 4 (sample_4)Визуализация молекулы метана

Для нашего примера нам также понадобятся библиотеки Three.js и Detector.js. Откройте блокнот и наберите следующий код:

<!DOCTYPEhtml>
<htmllang="en">
  <head>
    <title>Метан</title>
    <metacharset="utf-8">
    <style>
      body {
        font-family: Monospace;
        background-color: #000;
        margin: 0px;
        overflow: hidden;
      }
    </style>
  </head>
  <body>

    <scriptsrc="Three.js"></script>
    <scriptsrc="Detector.js"></script>

    <script>
    if (!Detector.webgl) Detector.addGetWebGLMessage();
    var container, stats;
    var camera, scene, renderer;

    init();
        animate();

    functioninit() {

            container = document.createElement('div');
    document.body.appendChild(container);

            scene = newTHREE.Scene();

            camera = newTHREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
    camera.position.y = 400;
    scene.add(camera);

    var light, object, materials_Hydrogen, materials_Carbon;

    scene.add(newTHREE.AmbientLight(0x404040));

            light = newTHREE.DirectionalLight(0xffffff);
    light.position.set(0, 1, 0);
    scene.add(light);

    materials_Hydrogen = [
          newTHREE.MeshLambertMaterial({ ambient: 0xbbbbbb, map: THREE.ImageUtils.loadTexture('white.jpg') })

            ];

    materials_Carbon = [
          newTHREE.MeshLambertMaterial({ ambient: 0xbbbbbb, map: THREE.ImageUtils.loadTexture('red.jpg') })
            ];

    var a, x0, y0, z0, x1, y1, z1, x2, y2, z2;
            a = 250;
    //Координаты первого атома водорода
    x0 = 0;
    y0 = 0;
    z0 = 0;

    //Координаты второго атома водорода
    x1 = 0;
    y1 = a;
    z1 = 0;

    //Координаты третьего атома водорода
    x2 = a * Math.sqrt(3) / 2;
            y2 = a / 2;
            z2 = 0;

    //Координаты четвертого атома водорода
    x3 = a / (Math.sqrt(3) * 2);
    y3 = a / 2;
            z3 = a * Math.sqrt(2 / 3);


    //Координатыатомауглерода
            x4 = a / (Math.sqrt(3) * 2);
            y4 = a / 2;
            z4 = a * Math.sqrt(2 / 3) / 3;

    //Добавляематомводорода
            object = THREE.SceneUtils.createMultiMaterialObject(newTHREE.SphereGeometry(50, 100, 100), materials_Hydrogen);
    object.position.set(x0, y0, z0);
            scene.add(object);

    //Добавляем атом водорода
    object = THREE.SceneUtils.createMultiMaterialObject(newTHREE.SphereGeometry(50, 100, 100), materials_Hydrogen);
    object.position.set(x1, y1, z1);
            scene.add(object);

    //Добавляем атом водорода
    object = THREE.SceneUtils.createMultiMaterialObject(newTHREE.SphereGeometry(50, 100, 100), materials_Hydrogen);
    object.position.set(x2, y2, z2);
            scene.add(object);

    //Добавляем атом водорода
    object = THREE.SceneUtils.createMultiMaterialObject(newTHREE.SphereGeometry(50, 100, 100), materials_Hydrogen);
    object.position.set(x3, y3, z3);
    scene.add(object);

    //Добавляематомуглерода
            object = THREE.SceneUtils.createMultiMaterialObject(newTHREE.SphereGeometry(75, 100, 100), materials_Carbon);
    object.position.set(x4, y4, z4);
    scene.add(object);

            renderer = newTHREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);

    container.appendChild(renderer.domElement);
        }

    function animate() {
    requestAnimationFrame(animate);
            render();
        }

    function render() {
    var timer = Date.now() * 0.0001;
    camera.position.x = Math.cos(timer) * 800;
    camera.position.z = Math.sin(timer) * 800;
    camera.position.y = Math.sin(timer) * 800;
    camera.lookAt(scene.position);
    renderer.render(scene, camera);
        }
    </script>
  </body>
</html>
    

Пример 5 (sample_5)Визуализация Земли

Нам также понадобятся библиотеки Three.js и Detector.js. Найдите какую-нибудь старинную карту и назовите файл map.jpg.

Откройте блокнот и наберите следующий код:

<!DOCTYPEhtml>
<htmlxmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
    <style>
      body {
        font-family: Monospace;
        background-color: #000;
        margin: 0px;
        overflow: hidden;
      }
    </style>
  </head>
  <body>

    <scriptsrc="Three.js"></script>
    <scriptsrc="Detector.js"></script>


    <script>
    if (!Detector.webgl) Detector.addGetWebGLMessage();
    var container, stats;
    var camera, scene, renderer;

    init();
        animate();

    functioninit() {

            container = document.createElement('div');
    document.body.appendChild(container);

            scene = newTHREE.Scene();

            camera = newTHREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
    camera.position.y = 400;
    scene.add(camera);

    var light, object, materials;

    scene.add(newTHREE.AmbientLight(0x404040));

            light = newTHREE.DirectionalLight(0xffffff);
    light.position.set(0, 1, 0);
    scene.add(light);

            materials = [
          newTHREE.MeshLambertMaterial({ ambient: 0xbbbbbb, map: THREE.ImageUtils.loadTexture('map.jpg') }),
          newTHREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true, transparent: true, opacity: 0.1 })
            ];

            object = THREE.SceneUtils.createMultiMaterialObject(newTHREE.SphereGeometry(200, 100, 100), materials);
    object.position.set(0, 0, 0);
    scene.add(object);

    var points = [];

    for (vari = 0; i< 50; i++) {
    points.push(new THREE.Vector3(Math.sin(i * 0.2) * 15 + 50, 0, (i - 5) * 2));
            }

            renderer = newTHREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);

    container.appendChild(renderer.domElement);
        }

    function animate() {
    requestAnimationFrame(animate);
            render();
        }

    function render() {
    var timer = Date.now() * 0.0001;
    camera.position.x = Math.cos(timer) * 800;
    camera.position.z = Math.sin(timer) * 800;
    camera.position.y = Math.sin(timer) * 800;
    camera.lookAt(scene.position);
    for (vari = 0, l = scene.children.length; i< l; i++) {
    var object = scene.children[i];
    object.rotation.x += 0.005;
    object.rotation.y += 0.005;
    object.rotation.z += 0.005;
            }
    renderer.render(scene, camera);
        }
    </script>
  </body>
</html>
    
Вернуться к учебному плану