Пример рисования квадрата ( WebGL и ThreeJS )

Автор: Евгений Рыжков Дата публикации: 04.03.2013

Используем WebGL

<html>
  <head>
    <script id="vertex" type="x-shader">
      /*
      * attribute - масив данных, каждый из элементов которого будет обработан в функции main
      * чаше всего в нем хранятся позиции вершин, их цвета или координаты текстуры
      */
      attribute vec2 aVertexPosition;

      /*
      * main - функция которая вызывается для каждого шейдера при рендеринге
      */
      void main() {
        /*
        * gl_Position параметр который возвращает функция main
        */
        /*
        * vec4(aVertexPosition, глубина( zIndex ), однородная координата)
        */
        gl_Position = vec4(aVertexPosition, 0, 1);
      }
    </script>
    <script id="fragment" type="x-shader">
      /*
      * первые три сторочки это шаблонный код
      *
      * они определяют точность при использовании чисел с плавающей запятой
      *
      * эти строчки обязательны
      */
      #ifdef GL_ES
      precision highp float;
      #endif

      /*
      * uniform константа
      */
      uniform vec4 uColor;

      /*
      * main - функция которая вызывается для каждого шейдера при рендеринге
      */
      void main() {
        gl_FragColor = uColor;
      }
    </script>
  </head>
  <body>
    <canvas id="mycanvas" width="800" height="500"> </canvas>
  </body>
</html>
<script type="text/javascript">
window.onload = function(){
    init();
};

function init(){

    var canvas = document.getElementById("mycanvas"), /* получаем канву */
        gl = canvas.getContext("experimental-webgl"); /* получаем Web GL контекст */

    /* определяем прямоугольную рабочую область на канве
    *
    *   отсчет ведется с нижнего левого угла
    *
    *   gl.viewport(x, y, width, height);
    * */
    gl.viewport(0, 0, canvas.width, canvas.height);

    /*
    * gl.COLOR_BUFFER_BIT буфер который хранит значение цвета для вывода
    *
    * gl.clearColor(r, g, b, a) записывает новый цвет в буфер ( параметры цветов меняются от 0 до 1 )
    *
    * gl.clear выводит значения буфера цвета на канву
    * */
    gl.clearColor(0, 0.5, 0, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);

    /* эти 2 строки забирают код вертексов из html как строки */
    var v = document.getElementById("vertex").firstChild.nodeValue;
    var f = document.getElementById("fragment").firstChild.nodeValue;

    /* инициализируем вертексный шейдер */
    var vs = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vs, v);
    gl.compileShader(vs);

    /* инициализируем пиксельный шейдер */
    var fs = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fs, f);
    gl.compileShader(fs);

    /* обьединение шейдеров в программу */
    program = gl.createProgram();
    gl.attachShader(program, vs);
    gl.attachShader(program, fs);
    gl.linkProgram(program);

    /*
    * следущие три условия необходимы для отладки в случае ошибки в шейдерах
    *
    * они всегда прописываются после обьеденения шейдеров в программу
    *
    * */
    if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS))
        console.log(gl.getShaderInfoLog(vs));
    if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS))
        console.log(gl.getShaderInfoLog(fs));
    if (!gl.getProgramParameter(program, gl.LINK_STATUS))
        console.log(gl.getProgramInfoLog(program));

    /* выщитываем соотношение сторон для правильного отображения обьектов на канве */
    var aspect = canvas.width / canvas.height;

    /*
    * создаем масив вершин в двумерном пространсве
    * */
    var vertices = new Float32Array([
        -0.5, 0.5*aspect, 0.5, 0.5*aspect,  0.5,-0.5*aspect,
        -0.5, 0.5*aspect, 0.5,-0.5*aspect, -0.5,-0.5*aspect
    ]);

    /*
    * здесь мы создаем буфер и передаем в него масив вершин
    * */
    vbuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vbuffer);
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

    /* определяем количество осей */
    itemSize = 2;
    /* определяем количество вершин в масиве*/
    numItems = vertices.length / itemSize;

    /* строка указывает WebGL использовать эту программу для последущих вызовов */
    gl.useProgram(program);

    /* получаем ссылку на униформу определенную в пиксельном шейдере */
    program.uColor = gl.getUniformLocation(program, "uColor");
    /* записываем в uColor новое значение цвета*/
    gl.uniform4fv(program.uColor, [0.0, 1.0, 0.0, 1.0]);

    /* получаем ссылку на атрибут определенный в вершинном шейдере */
    program.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition");
    gl.enableVertexAttribArray(program.aVertexPosition);

    /*
    * Parameters:
    *
    *   - ссылка на атрибут ( куда будем записывать параметры )
    *   - количество значений формирующих вершину ( от 1 до 4 )
    *   - тип передаваемых данных
    *
     normalized нужно ли нормализовать точки
     For glVertexAttribPointer, specifies whether fixed-point data values should be normalized (GL_TRUE) or converted
     directly as fixed-point values (GL_FALSE) when they are accessed.

     stride
     Specifies the byte offset between consecutive generic vertex attributes. If stride is 0, the generic vertex
     attributes are understood to be tightly packed in the array. The initial value is 0.

     pointer
     Specifies a offset of the first component of the first generic vertex attribute in the array in the data store of
     the buffer currently bound to the GL_ARRAY_BUFFER target. The initial value is 0.
    * */
    gl.vertexAttribPointer(program.aVertexPosition, itemSize, gl.FLOAT, false, 0, 0);

    gl.drawArrays(gl.TRIANGLES, 0, numItems);
}
</script>

демо-пример

Используем ThreeJS

<html>
<head>
    <link rel="stylesheet" href="css/main.css" />

    <script src="js/three.min.js"></script>
    <script src="js/three.main.js"></script>

</head>
<body>
</body>
</html>
<script type="text/javascript">
window.onload = function(){
    var camera, scene, renderer;
    var aspect = 800 / 500;
    var mesh;

    init();
    animate();

    function init() {


        //создание камеры
        camera = new THREE.PerspectiveCamera( 70, aspect, 1, 1000 );

        //установка позиции камеры по оси z
        camera.position.z = 400;

        //создание сцены
        scene = new THREE.Scene();

        //create geometry
        geometry = new THREE.Geometry();

        //добовляем вершины в геометрию
        geometry.vertices = [
            new THREE.Vector3( 150, 150, 0),
            new THREE.Vector3( 150, 0, 0),
            new THREE.Vector3( 0, 0, 0),
            new THREE.Vector3( 0, 150, 0)
        ];

        //добовляем грани в геометрию
        geometry.faces = [
            new THREE.Face3( 2, 1, 0 ),
            new THREE.Face3( 3, 2, 0 )
        ];

        //?
        geometry.computeBoundingSphere();

       //создаем материал ( нужно расписать все материалы )
        material = new THREE.MeshBasicMaterial( { color: 0xffff00 });

        // создаем фигуру из геометрии и материала
        mesh = new THREE.Mesh( geometry, material);
        scene.add( mesh );

        //создаем рендер
        renderer = new THREE.WebGLRenderer();

        //устанавливаем размер рендера
        renderer.setSize( 800, 500 );

        //добавляем канву в body
        document.body.appendChild( renderer.domElement );

        //отрисовываем сцену
        renderer.render( scene, camera );

    }

    function animate() {

        requestAnimationFrame( animate );

        renderer.render( scene, camera );

    }
};
</script>

демо-пример