Первая программа на WebGL

Последнее обновление: 1.11.2015

Сейчас мы напишем первую программу с использованием технологии WebGL. Фактически это будет не одна программа, а два примера, которые покажут в действии механизм WebGL.

Первый пример

Создадим какую-нибудь веб-страничку со следующим содержимым:

<!DOCTYPE html>
<html>
<head>
<title>Привет WebGL!</title>
</head>
<body>
<canvas id="canvas3D" width="400" height="300">Ваш браузер не поддерживает элемент canvas</canvas>
<!-- фрагментный шейдер -->
<script id="shader-fs" type="x-shader/x-fragment">
  void main(void) {
    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
  }
</script>
<!-- вершинный шейдер -->
<script id="shader-vs" type="x-shader/x-vertex">
  attribute vec3 aVertexPosition;
  void main(void) {
    gl_Position = vec4(aVertexPosition, 1.0);
  }
</script>
<script type="text/javascript">
var gl;
var shaderProgram;
var vertexBuffer;
// установка шейдеров
function initShaders() {
	// получаем шейдеры
	var fragmentShader = getShader(gl.FRAGMENT_SHADER, 'shader-fs');
	var vertexShader = getShader(gl.VERTEX_SHADER, 'shader-vs');
	//создаем объект программы шейдеров
	shaderProgram = gl.createProgram();
	// прикрепляем к ней шейдеры
	gl.attachShader(shaderProgram, vertexShader);
	gl.attachShader(shaderProgram, fragmentShader);
	// связываем программу с контекстом webgl
	gl.linkProgram(shaderProgram);
	 
	if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
		alert("Не удалсь установить шейдеры");
	}
	 
	gl.useProgram(shaderProgram);
	// установка атрибута программы
	shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
    // делаем доступным атрибут для использования
	gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
}
// Функция создания шейдера по типу и id источника в структуре DOM
function getShader(type,id) {
	var source = document.getElementById(id).innerHTML;
	// создаем шейдер по типу
	var shader = gl.createShader(type);
	// установка источника шейдера
	gl.shaderSource(shader, source);
	// компилируем шейдер
	gl.compileShader(shader);
  
	if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
		alert("Ошибка компиляции шейдера: " + gl.getShaderInfoLog(shader));
		gl.deleteShader(shader);   
		return null;
	}
	return shader;  
}
// установка буфера вершин 
function initBuffers() {
 // установка буфера вершин
  vertexBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  // массив координат вершин объекта
  var triangleVertices = [
         0.0,  0.5,  0.0,
        -0.5, -0.5,  0.0,
         0.5, -0.5,  0.0
  ];
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW);
  // указываем кол-во точек
  vertexBuffer.itemSize = 3;
  vertexBuffer.numberOfItems = 3;
}
// отрисовка 
function draw() {    
	// установка области отрисовки
	gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);

	gl.clear(gl.COLOR_BUFFER_BIT);
  
	// указываем, что каждая вершина имеет по три координаты (x, y, z)
	gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 
                         vertexBuffer.itemSize, gl.FLOAT, false, 0, 0);
    // отрисовка примитивов - треугольников          
	gl.drawArrays(gl.TRIANGLES, 0, vertexBuffer.numberOfItems);
}
 
window.onload=function(){
	// получаем элемент canvas
	var canvas = document.getElementById("canvas3D");
	try {
		// Сначала пытаемся получить стандартный контекст WegGL
		// Если не получится, обращаемся к экспериментальному контексту
		gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
	}
	catch(e) {}
  
	// Если контекст не удалось получить, выводим сообщение
	  if (!gl) {
		alert("Ваш браузер не поддерживает WebGL");
	  }
	if(gl){
		// установка размеров области рисования
		gl.viewportWidth = canvas.width;
		gl.viewportHeight = canvas.height;
		// установка шейдеров 
		initShaders();
		// установка буфера вершин
		initBuffers();
		// покрасим фон в бледно-розовый цвет
		gl.clearColor(1.0, 0.0, 0.0, 0.5);
		// отрисовка сцены
		draw();  
	}
}
</script>
</body>
</html>

Я не буду останавливаться на этом коде - основные моменты подробнее мы рассмотрим детально позднее, но, я думаю, комментарии помогут разобраться. Но если вкратце: у нас есть элемент canvas, который представляет полотно для отрисовки сцены WebGL. Далее в виде скриптов javascript объявляются две мини-программы - фрагментный и вершинный шейдер.

Весь код программы находится в обработчике функции window.onload. Вначале нам надо получить контекст gl, через который и буду вестись все основные действия. Далее программа содержит три основные части: установка шейдеров, установка буфера вершин и сама отрисовка.

А пока можно запустить веб-страничку в браузере. И браузер явит нам белый треугольник на красном фоне.

Всего лишь? Это только начало. Позже мы подробнее поговорим о шейдерах, вершинах, геометрических примитивах и т.д. А теперь перейдем ко второму примеру.

Пример 2

Второй пример представляет собой хрестоматийный пример вращающегося куба. Вначале загрузим специальную библиотеку Three.js. Ее минимизированную версию можно найти по адресу Three.js. Перейдем по этому адресу и сохраним весь код на жесткий диск в файл под названием three.min.js. Эта библиотека не является необходимой для работы с WebGL, однако она упрощает работу.

В одном каталоге с загруженной библиотекой создадим файл index.html со следующим содержанием:

<DOCTYPE html>
<html>
<head>
<title>Привет WebGL!</title>
<script src="three.min.js"></script>
<script type='text/javascript'>
window.onload=function(){
	var camera, scene, renderer;
	var geometry, material, mesh;

	init();
	animate();
	// инициализация начальных значений
	function init() {
		// создаем камеру - перспективная проекция
		camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000);
		// установка z-координаты камеры
		camera.position.z = 600;
		// настройка сцены
		scene = new THREE.Scene();
		// настройка геометрии - в качестве геометрии будет куб
		// настроим его ширину, высоту и длину по оси z
		geometry = new THREE.CubeGeometry(200, 200, 200);
		// настройка материала - установка цвета
		material = new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true});
		// настраиваем меш, который будет отображать куб
		mesh = new THREE.Mesh(geometry, material);
		scene.add(mesh);
		// создаем объект для рендеринга сцены
		renderer = new THREE.WebGLRenderer();
		// установка размеров
		renderer.setSize(window.innerWidth, window.innerHeight);
		// встраиваем в DOM-структуру страницы
		document.body.appendChild(renderer.domElement);
	}
	// функция анимации
	function animate() {

		requestAnimationFrame(animate);
		// вращение меша вокруг осей
		mesh.rotation.x += 0.01;
		mesh.rotation.y += 0.02;
		// рендеринг сцены - метод, производящий по сути отрисовку
		renderer.render(scene, camera);
	}
}
</script>
</head>
<body>
</body>
</html>

Все уже выглядит гораздо круче, а кода гораздо меньше. Да, Three.js, а также другие библиотеки и фреймворки по работе с WebGL значительно упрощают работу с графикой. Но в то же время даже минимизированнные их версии весят очень не мало. Какой способ стоит выбрать - это дело разработчика. В дальнейшем мы будем рассматривать преимущественно работу с чистым WebGL, но также и затронем работу с библиотеками, например, с той же Three.js. А теперь можно переходить уже непосредственно к особенностям технологии.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850