<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-784388971348462050</id><updated>2024-10-01T23:31:49.147-07:00</updated><title type='text'>Уроки WebGL</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ruwebgl.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/784388971348462050/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://ruwebgl.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Катя</name><uri>http://www.blogger.com/profile/01514348270451602520</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>3</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-784388971348462050.post-3119611092717215056</id><published>2012-01-11T22:32:00.000-08:00</published><updated>2012-02-06T02:31:34.909-08:00</updated><title type='text'>WebGL Урок 6. Ввод с клавиатуры и текстурные фильтры</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;&lt;div id=&quot;content&quot;&gt;&lt;div class=&quot;postdate&quot;&gt;&lt;a href=&quot;http://learningwebgl.com/blog/?p=571&quot;&gt;Прочитать данный урок в оригинале&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;entry&quot;&gt;&lt;span style=&quot;float: left; padding-bottom: 0px; padding-left: 0px; padding-right: 20px; padding-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;a href=&quot;http://ruwebgl.blogspot.com/2011/01/webgl-5.html&quot;&gt;&lt;&lt; Урок5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;span style=&quot;float: right; padding-bottom: 0px; padding-left: 0px; padding-right: 20px; padding-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;a href=&quot;http://ruwebgl.blogspot.com/2012/02/webgl-7.html&quot;&gt;Урок7 &gt;&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
Добро пожаловать в мой урок номер шесть в серии WebGL, основанный на &lt;a href=&quot;http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=07&quot;&gt;уроке номер 7&lt;/a&gt; в учебнике OpenGL от NeHe. Речь пойдёт о том, как вы можете реализовать обработку ввода с клавиатуры в своих WebGL страницах. Это потребуется нам для изменения скорости и направления вращения текстурированного куба, а также для изменения вида фильтрации, применяемого к текстуре, для получения низкого качества, но более быстрого, или более качественного, но медленного рендеринга. (Урок NeHe № 7 охватывает ещё и освещение. Так как освещение в WebGL более трудоёмко, чем в OpenGL, я не включил его в этот урок - мы рассмотрим его в следующий раз.)&lt;br /&gt;
&lt;br /&gt;
Здесь вы можете посмотреть, как выглядит этот урок при работе в браузере, который поддерживает WebGL, лучше всего просматривать его на сайте YouTube, чтобы можно было увидеть аннотации в которых рассказывается о том, что я делаю, для того, чтобы изменить сцену:&lt;br /&gt;
&lt;object width=&quot;640&quot; height=&quot;390&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/FKtbpLdlpf8&amp;hl=en_US&amp;feature=player_embedded&amp;version=3&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;http://www.youtube.com/v/FKtbpLdlpf8&amp;hl=en_US&amp;feature=player_embedded&amp;version=3&quot; type=&quot;application/x-shockwave-flash&quot; allowfullscreen=&quot;true&quot; allowScriptAccess=&quot;always&quot; width=&quot;640&quot; height=&quot;390&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;
Нажмите &lt;a href=&quot;http://learningwebgl.com/lessons/lesson06/index.html&quot;&gt;здесь&lt;/a&gt; для просмотра этого урока  WebGL &quot;вживую&quot;, если ваш браузер поддерживает WebGL. &lt;br /&gt;
В ином случае вы можете прочитать как получить браузер с поддержкой WebGL &lt;a href=&quot;http://learningwebgl.com/blog/?p=11&quot;&gt;здесь&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
После того как вы загрузили урок в браузер, вы можете использовать клавиши Page Up и Page Down для изменения zoom&#39;а, и использовать клавиши перемещения курсора, чтобы вращать куб (чем дольше вы удерживаете нажатыми клавиши перемещения курсора, тем больше становится скорость вращения). Вы можете также использовать клавишу F для переключения между тремя различными видами текстурных фильтров, в зависимости от того, как вам лучше рассматривать полученный эффект, когда вы находитесь совсем близко по отношению к кубу или когда вы довольно далеко от него.&lt;br /&gt;
&lt;br /&gt;
Подробнее о том, как все это работает ниже ...&lt;br /&gt;
&lt;br /&gt;
Примечание : эти уроки ориентированы на людей с достаточным количеством знаний в области программирования, но не имеющих реального опыта работы с 3D-графикой. Цель уроков состоит в том, чтобы вы начали производить свои собственные 3D веб-страницы как можно быстрее,имея хорошее представление о том, как работает данный код. Если вы ещё не ознакомились с предыдущими уроками, рекомендую сделать вам это до прочтения данного урока - здесь я буду только объяснять различия между кодом для &lt;a href=&quot;http://ruwebgl.blogspot.com/2011/01/webgl-5.html&quot;&gt;Урок 5&lt;/a&gt; и новым кодом.&lt;br /&gt;
&lt;br /&gt;
В тексте могут быть ошибки и неточности. Если вы заметили ошибку, дайте мне знать в комментариях и я исправлю это как можно скорее.&lt;br /&gt;
&lt;br /&gt;
Есть 2 способа получить код примера из этого урока: используйте &quot;View Source&quot;, если вы просматриваете урок в браузере с поддержкой WebGL &quot;вживую&quot;, или вы можете загрузить его отсюда &lt;a href=&quot;http://github.com/gpjt/webgl-lessons&quot;&gt;GitHub&lt;/a&gt;. &lt;br /&gt;
В любом случае, когда вы получите код, загрузите его в ваш любимый текстовый редактор и просмотрите.&lt;br /&gt;
&lt;br /&gt;
Самым значительным изменением между этим и предыдущим уроком является то, что теперь мы реагируем на нажатия пользователя на клавиатуре. Легче всего объяснить как это работает, это показать вам те части кода, которые отвечают за приём нажатий на клавиатуре.&lt;br /&gt;
Если вы начнёте просматривать код и промотаете до середины, то вы увидите, какое количество глобальных переменных определено:&lt;br /&gt;
&lt;br /&gt;
var xRot = 0;&lt;br /&gt;
var xSpeed = 0;&lt;br /&gt;
var yRot = 0;&lt;br /&gt;
var ySpeed = 0;&lt;br /&gt;
var Z = -5,0;&lt;br /&gt;
var filter = 0;&lt;br /&gt;
&lt;br /&gt;
xRot и yRot знакомы вам с Урока 5 - они представляют текущее вращение куба вокруг осей х и у. Теперь, когда мы, позволяем пользователю изменять скорость вращения куба при помощи клавиш управления курсором, xSpeed и ySpeed содержат скорости изменения xRot и yRot .&lt;br /&gt;
Z - конечно-же Z-координата куба - то есть то, как близко или далеко он находится по отношению к наблюдателю, она будет контролироваться клавишами Page Up и Page Down. И, наконец, фильтр, он является целым числом от 0 до 2, и означает, какой из трех фильтров используется для текстуры, которую мы накладываем на куб, и, таким образом, определяет насколько хорошо она выглядит.&lt;br /&gt;
&lt;br /&gt;
Давайте теперь взглянем на код, в котором устанавливается фильтр. Первые изменения мы видим в коде, который отвечает за загрузку текстуры, немного выше и примерно после трети кода сверху. Код настолько сильно изменился, что даже нет смысла выделять изменения маркером. Тем не менее он выглядит довольно знакомо, если не присматриваться к деталям:&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
function handleLoadedTexture(textures) {&lt;br /&gt;
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);&lt;br /&gt;
&lt;br /&gt;
gl.bindTexture(gl.TEXTURE_2D, textures[0]);&lt;br /&gt;
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textures[0].image);&lt;br /&gt;
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);&lt;br /&gt;
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);&lt;br /&gt;
&lt;br /&gt;
gl.bindTexture(gl.TEXTURE_2D, textures[1]);&lt;br /&gt;
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textures[1].image);&lt;br /&gt;
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);&lt;br /&gt;
&lt;br /&gt;
gl.bindTexture(gl.TEXTURE_2D, textures[2]);&lt;br /&gt;
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textures[2].image);&lt;br /&gt;
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);&lt;br /&gt;
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);&lt;br /&gt;
gl.generateMipmap(gl.TEXTURE_2D);&lt;br /&gt;
&lt;br /&gt;
gl.bindTexture(gl.TEXTURE_2D, null);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var crateTextures = Array();&lt;br /&gt;
&lt;br /&gt;
function initTexture() {&lt;br /&gt;
var crateImage = new Image();&lt;br /&gt;
&lt;br /&gt;
for (var i=0; i &lt; 3; i++) {
      var texture = gl.createTexture();
      texture.image = crateImage;
      crateTextures.push(texture);
    }

    crateImage.onload = function() {
      handleLoadedTexture(crateTextures)
    }
    crateImage.src = &quot;crate.gif&quot;;
  }
&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
При первом взгляде на функцию initTexture и глобальную переменную crateTextures становится ясно что код действительно изменился, схожесть в том, что мы создаём 3 объекта текстур WebGL в массиве и передаём этот массив в функцию обратного вызова handleLoadedTexture, когда изображение уже загружено. И, конечно, мы загружаем другое изображение crate.gif вместо nehe.gif.&lt;br /&gt;
&lt;br /&gt;
handleLoadedTexture сильно не изменилась; в прошлый раз мы устанавливали единственный текстурный объект WebGL с данными изображения, и устанавливали для него 2 параметра gl.TEXTURE_MAG_FILTER и gl.TEXTURE_MIN_FILTER, обоим присваивалось значение gl.NEAREST. Теперь мы устанавливаем все 3 текстуры в наш массив для одного и того же изображения, но для каждого устанавливаем разные параметры, и это важное отличие от кода предыдущего урока.&lt;br /&gt;
Здесь о различиях текстур в подробностях:&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Приближённая фильтрация&lt;/h3&gt;У первой текстуры оба парметра gl.TEXTURE_MAG_FILTER и gl.TEXTURE_MIN_FILTER установлены  в значение gl.NEAREST. Это наша первоначальная настройка, которая означает, что в обоих случаях, когда текстура сжимается и растягивается, WebGL будут использовать фильтр, который определяет цвет точки как цвет ближайшей к ней точки исходного изображения. Для того, чтобы куб хорошо смотрелся текстура не должна быть растянута вообще или должна быть уменьшена в масштабе ( дискуссию по поводу сглаживания см. ниже ). А вот когда она растягивается, это выглядит &quot;пиксельно&quot;, потому что алгоритм как бы растягивает пиксели оригинального изображения.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Линейная фильтрация&lt;/h3&gt;Для второй текстуры оба параметра gl.TEXTURE_MAG_FILTER и gl.TEXTURE_MIN_FILTER установлены в gl.LINEAR. Здесь мы опять используем тот же фильтр, что и для растягивания/сжимания. Однако линейный алгоритм для растянутых текстур работает лучше, он использует линейную интерполяцию между пикселами исходного изображения, грубо говоря, пиксел, который находится посередине между белым и чёрным получается серым. Это даёт эффект размытия, острые углы сглаживаются. ( Будьте уверены, что растягивание изображения никогда не улучшает его качества - вы не сможете разглядеть более мелкие детали изображения, если их нет ).&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Мип&lt;/h3&gt;Для третьей текстуры gl.TEXTURE_MAG_FILTER и gl.TEXTURE_MIN_FILTER установлены в gl.LINEAR_MIPMAP_NEAREST. Это самая сложная из всех трёх опций.&lt;br /&gt;
Линейная фильтрация оправдывает себя, когда вы растягиваете текстуру, но когда вы сжимаете текстуру она не эффективнее, чем приближённая фильтрация, по факту оба фильтра могут изуродовать картинку подобным сглаживаением. Для просмотра этого снова загрузите &lt;a href=&quot;http://learningwebgl.com/lessons/lesson06/index.html&quot;&gt;пример&lt;/a&gt;, где используется приближённая фильтрация, или нажмите кнопку обновить для получения примера в исходном состоянии. На несколько секунд зажмите кнопку Page Up для уменьшения масштаба. Когда кубик будет удаляться, вы увидите как он начнёт &quot;мерцать&quot;: кажется будто вертикальные линии то появляются, то исчезают. Как только вы это увидите, остановитесь и попробуйте сначала немного приблизить, а затем немного отодвинуть картинку. После того как увидите мерцание нажмите клавишу F 1 раз для того, чтобы переключиться на линейную фильтрацию, снова немного приблизьте и отдалите, отметьте для себя, что результат получился почти такой же. Теперь нажмите F ещё раз для применения мип-фильтрации, снова чуть-чуть приблизьте и отдалите отображение и вы увидите, что эффект мерцания исчез или стал почти незаметен.&lt;br /&gt;
Теперь, когда куб находится достаточно далеко от наблюдателя, скажем, его ширина/высота составляют 10% от размеров экрана - попробуйте попереключаться между фильтрами не перемещая куб. При приближённой или линейной фильтрации вы увидете шум : тёмные линии в некоторых местах на волокнах дерева очень заметны, в то время как в других местах их нет: куб как-бы выглядит немного испачканным. Это действительно выглядит очень плохо при приближённой фильтрации, но не сильно лучше и при линейной. Только мип-фильтрации выглядит хорошо.&lt;br /&gt;
Что же происходит с текстурами при применении приближённой или линейной фильтрации при сжимании текстуры? Фильтр использует каждый 10тый пиксел оригинального изображения для создания уменьшенной версии изображения. Текстура представляет собой образец деревянного волокна, это означает, что большая часть текстуры светло коричнего цвета  с тёмными вертикальными полосами, давайте представим, что зерно текстуры имеет толщину 10 пикселов, или другими словами, каждый 10 пиксел по горизонтали тёмно-коричневого цвета. Если изображение ужимается в 10 раз, то мы получаем шанс 1 из 10ти, что выбраный нами пиксел для сжатого изображения будет тёмно-коричневого цвета, 9 из 10 в таком случае будут светлыми. Другими словами, одна из 10ти тёмных линий исходного изображения будет выглядеть также как на полноразмерном изображении, все остальные линии будут скрыты. Этот эффект исчезновения и порождает мерцание при изменении размера текстуры, поскольку указанные тёмные линии могут быть совершенно разными для разных коэффициентов сжатия 9.9, 10.0 и 10.1.&lt;br /&gt;
Нам бы всегда хотелось оказываться в такой ситуации, когда размер тесктуры изменяется каждый раз на десятую часть её оригинального размера. Каждый пиксел, принадлежащий уменьшенной копии текстуры, отображается цветом, являюющимся средним арифметическим между значениями цветов пикселов квадрата10Х10. Делать это плавно слишком дорого по вычислениям для графики реального времени, вот тут на помощь и приходит мип-фильтрация.&lt;br /&gt;
Мип-фильтрация решает для текстуры проблему генерации некоторого количества производных изображений, называемых мип-уровнями, половина, четверть, одна восьмая оригинального изображения и т.д. вплоть до изображения в 1 пиксел. Набор этих мипов всех уровней называется мипмап. Каждый мип-уровень является плавно уменьшенной копией большего на уровень мипа, таким образом для текущего уровня сжатия всегда можно подобрать соотвествующий мип-уровень, алгоритм выбора зависит от параметра gl.TEXTURE_MIN_FILTER, тот алгоритм, который выберем мы означает &quot;найди ближайший мип-уровень и примени к нему линейную фильтрацию для получения цвета пиксела&quot;.&lt;br /&gt;
Теперь, когда всё объяснено, должно быть предельно ясно, зачем нужна следующая строка:&lt;br /&gt;
&lt;code&gt; gl.generateMipmap(gl.TEXTURE_2D);&lt;/code&gt;&lt;br /&gt;
...эта строка сообщает WebGL, что необходимо сгенерировать мипмап.&lt;br /&gt;
Получилось существенно больше, чем я планировал написать о мипмапах, но я думаю, что получилось достаточно ясно:-). Дайте мне знать в комментариях, если что-то осталось вам непонятно.&lt;br /&gt;
&lt;br /&gt;
Вернёмся к остальной части кода. До сих пор мы смотрели на глобальные переменные и наблюдали за тем, как текстуры загружаются и устанавливаются. Теперь давайте посмотрим на то, как они используются, когда дело доходит до отображения на сцене.&lt;br /&gt;
&lt;br /&gt;
drawScene находится через три четверти страницы и в неё внесено 3 изменения. Первое изменение: когда мы позиционируем наблюдателя при рисовании куба вне заивисимости от точки привязки, мы используем глобальную переменную z:&lt;br /&gt;
&lt;code&gt;mat4.translate(mvMatrix, [0.0, 0.0, z]);&lt;/code&gt;&lt;br /&gt;
Следующим важным изменением является, которую мы удалили из кода 5го урока,теперь мы вообще не будем вращать вокруг оси z, а заменим на вращения вокруг осей x и y:&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
mat4.rotate(mvMatrix, degToRad(xRot), [1, 0, 0]);&lt;br /&gt;
mat4.rotate(mvMatrix, degToRad(yRot), [0, 1, 0]);&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
И, наконец, перед отрисовкой куба мы должны указать, какую из 3-х текстур мы хотим использовать:&lt;br /&gt;
&lt;code&gt;gl.bindTexture(gl.TEXTURE_2D, &lt;span style=&quot;color:red;&quot;&gt;crateTextures[filter]&lt;/span&gt;);&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
На этом изменения в drawScene закончены. Ещё немного незначительных изменений в анимации; вместо изменения xRot и yRot на постоянную величину, мы теперь используем наши новые переменные xSpeed и ySpeed:&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
xRot += (&lt;span style=&quot;color:red;&quot;&gt;xSpeed&lt;/span&gt; * elapsed) / 1000.0;&lt;br /&gt;
yRot += (&lt;span style=&quot;color:red;&quot;&gt;ySpeed&lt;/span&gt; * elapsed) / 1000.0;&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
И на это всё об изменениях в коде за исключением обработки нажатий пользователем клавиш и изменения в глобальных переменных, привязанных к этому.&lt;br /&gt;
&lt;br /&gt;
Вот первое изменение, в webGLStart мы добавили 2 новые строки ( ниже, выделены красным)&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
function webGLStart() {&lt;br /&gt;
var canvas = document.getElementById(&quot;lesson06-canvas&quot;);&lt;br /&gt;
initGL(canvas);&lt;br /&gt;
initShaders();&lt;br /&gt;
initBuffers();&lt;br /&gt;
initTexture();&lt;br /&gt;
&lt;br /&gt;
gl.clearColor(0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
gl.enable(gl.DEPTH_TEST);&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
&lt;code css=&quot;color:red;&quot;&gt;&lt;br /&gt;
&lt;span style=&quot;color:red;&quot;&gt;document.onkeydown = handleKeyDown;&lt;br /&gt;
document.onkeyup = handleKeyUp;&lt;/span&gt;&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
tick();&lt;br /&gt;
}&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
Очевидно, что здесь мы сообщаем JavaScript время, в течении которого мы хотим, чтобы наша функция handleKeyDown( обработчик нажатий клавиш при условии нахождения фокуса на веб-странице) была вызвана, при отпускании клавиши должна быть вызвана функция handleKeyUp.&lt;br /&gt;
Давайте теперь взгялнем на эти функции. Они расположены на второй половине страницы сразу за глобальными переменными и выглядят следующим образом:&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
var currentlyPressedKeys = {};&lt;br /&gt;
&lt;br /&gt;
function handleKeyDown(event) {&lt;br /&gt;
currentlyPressedKeys[event.keyCode] = true;&lt;br /&gt;
&lt;br /&gt;
if (String.fromCharCode(event.keyCode) == &quot;F&quot;) {&lt;br /&gt;
filter += 1;&lt;br /&gt;
if (filter == 3) {&lt;br /&gt;
filter = 0;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleKeyUp(event) {&lt;br /&gt;
currentlyPressedKeys[event.keyCode] = false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
Мы занимаемся поддержанием словаря ( возможно вам знакомы названия &quot;хэштаблица&quot; и &quot;ассоциативный массив&quot;), который по передаваемому коду клавиши( см. коды клавиш в JavaScript ) может рассказать нам о том, нажимал ли пользователь уже данную клавишу или нет. Если вам не знакомы принципы работы JavaScript, вам может показаться интересным, что некоторый объект можно использовать в качестве словаря, как например этот, синтаксис, котрый мы используем для инициализации currentlyPressedKeys  похож на синтаксис создания словаря в Python, на самом деле он представляет собой &quot;пустую&quot; подстановку объекта базового типа.&lt;br /&gt;
В дополнение к поддержанию в актуальном состоянии словаря кодов уже нажатых клавиш, у нас есть дополнительный обработчик для кливиши ВНИЗ ( клавиша &quot;F&quot;). В этом примере мы меняем глобальную переменную фильтр, принимающую значения 0, 1 и 2 при всяком нажатии клавиши &quot;F&quot;. &lt;br /&gt;
Стоит объяснить зачем мы обработываем различные нажатия разными способами.&lt;br /&gt;
В компьютерной игре или в любой другой 3D-системе, нажатие клавиш может происходить 2мя спсособами:&lt;br /&gt;
1. Реакция на нажатие может возникать мгновенно - &quot;как огонь лазера&quot;. Такие нажатия могут происходить с любой или фиксированной скоростью, например 2 раза в секунду.&lt;br /&gt;
2. Скорость возникновения реакции на нажатие может зависеть от того, как долго вы удерживали данную клавишу нажатой. Например, когда вы зажимаете клавишу ВПЕРЕД, вы ожидаете, что движение вперёд будет продолжаться до тех пор, пока клавиша зажата. Важно, чтобы была возможность одновременной обработки нескольких нажатий одновременно, например вы начинаете движение ввперёд, затем поворачиваетесь и стреляете без остановки движения. Эта обработка нажатий значительно отличается от обработки нажатий клавиш при обычном режиме набора текста. Если вы зажмёте клавишу &quot;A&quot; в обработчике слов, вы получите несколько букв &quot;A&quot; в потоке, однако если вы нажмёте клавишу &quot;B&quot; во время удерживания клавиши &quot;А&quot;, то вы получите букву &quot;В&quot;, а поступление букв &quot;А&quot; в поток остановится. Эквивалентом этой ситуации в игре является отсановка движения вскяий раз при повороте, что будет очень раздражать пользователя.&lt;br /&gt;
Итак, в нашем коде нажатия клавиши &quot;F&quot; обрабатываются в первоочерёдном порядке, поддержание словаря нажатых клавиш имеет более низкий приоритет, он содержит последовательность всех уже зажатых клавиш, а не просто последней нажатой.&lt;br /&gt;
Этот словарь используется функцией handleKeys. Перед тем, как мы перейдём к ней, переместитесь ненадолго к концу кода и вы увидите, что она вызывается в функции tick, также как drawScene и animate:&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
function tick() {&lt;br /&gt;
requestAnimFrame(tick);&lt;br /&gt;
&lt;span style=&quot;color:red;&quot;&gt;handleKeys();&lt;/span&gt;&lt;br /&gt;
drawScene();&lt;br /&gt;
animate();&lt;br /&gt;
}&lt;br /&gt;
Вот что представляет из себя handleKeys:&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
function handleKeys() {&lt;br /&gt;
if (currentlyPressedKeys[33]) {&lt;br /&gt;
// Page Up&lt;br /&gt;
z -= 0.05;&lt;br /&gt;
}&lt;br /&gt;
if (currentlyPressedKeys[34]) {&lt;br /&gt;
// Page Down&lt;br /&gt;
z += 0.05;&lt;br /&gt;
}&lt;br /&gt;
if (currentlyPressedKeys[37]) {&lt;br /&gt;
// Left cursor key&lt;br /&gt;
ySpeed -= 1;&lt;br /&gt;
}&lt;br /&gt;
if (currentlyPressedKeys[39]) {&lt;br /&gt;
// Right cursor key&lt;br /&gt;
ySpeed += 1;&lt;br /&gt;
}&lt;br /&gt;
if (currentlyPressedKeys[38]) {&lt;br /&gt;
// Up cursor key&lt;br /&gt;
xSpeed -= 1;&lt;br /&gt;
}&lt;br /&gt;
if (currentlyPressedKeys[40]) {&lt;br /&gt;
// Down cursor key&lt;br /&gt;
xSpeed += 1;&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
Это ещё одна длинная, но очень простая функция; всё, чем она занимается-  это проверка какие клавиши зажаты на данный момент, и надлежащим образом обновляет значение нашей глобальной переменной. Важно отметить, что если одновременно зажаты клавиши ВВЕРХ и ВПРАВО, будут обновлены значеия обоих переменных xSpeed и ySpeed, это именно то, чего нам и хотелось.&lt;br /&gt;
И это всё на сегодня! Теперь у вас должно быть хорошее понимание того, как различные фильтры влияют на то, как будут выглядеть текстуры при различных значениях коэффициента масштабирования и того, как необходимо считывать нажатия пользователем клавиш в области 3D-анимации.&lt;br /&gt;
Если у вас имеются вопросы, комментарии или предложения, пожалуйста напишите об этом в комментарии ниже.&lt;br /&gt;
Следующий урок будет посвящён теме освещения.&lt;br /&gt;
&lt;div class=&quot;entry&quot;&gt;&lt;span style=&quot;float: left; padding-bottom: 0px; padding-left: 0px; padding-right: 20px; padding-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;a href=&quot;http://ruwebgl.blogspot.com/2011/01/webgl-5.html&quot;&gt;&lt;&lt; Урок5&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;float: right; padding-bottom: 0px; padding-left: 0px; padding-right: 20px; padding-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;a href=&quot;http://ruwebgl.blogspot.com/2012/02/webgl-7.html&quot;&gt;Урок7 &gt;&gt;&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;em&gt;&lt;br /&gt;
&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;Благодарности: Chris Marrin’s &lt;a href=&quot;http://webkit.org/blog-files/webgl/SpiritBox.html&quot;&gt;WebKit-only spinning box&lt;/a&gt; сильно помогло при написании данного материала, так же как и &lt;a href=&quot;http://www.nihilogic.dk/labs/webgl/webkit-demos/SpiritBox.html&quot;&gt;портирование Крисом демо Jacob Seidelin’s&lt;/a&gt; в Firefox.&lt;br /&gt;
Как всегда, я глубоко благодарен&amp;nbsp;&lt;a href=&quot;http://nehe.gamedev.net/&quot;&gt;NeHe&lt;/a&gt; за их &lt;a href=&quot;http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=06&quot;&gt;уроки OpenGL&lt;/a&gt; и за скрипты к этому уроку.&lt;/em&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruwebgl.blogspot.com/feeds/3119611092717215056/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://ruwebgl.blogspot.com/2012/01/webgl-6.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/784388971348462050/posts/default/3119611092717215056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/784388971348462050/posts/default/3119611092717215056'/><link rel='alternate' type='text/html' href='http://ruwebgl.blogspot.com/2012/01/webgl-6.html' title='WebGL Урок 6. Ввод с клавиатуры и текстурные фильтры'/><author><name>Катя</name><uri>http://www.blogger.com/profile/01514348270451602520</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-784388971348462050.post-5946457620431563106</id><published>2011-01-21T05:38:00.000-08:00</published><updated>2012-02-06T02:45:39.552-08:00</updated><title type='text'>WebGL урок 5. Введение в текстуры.</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;&lt;div id=&quot;content&quot;&gt;&lt;div class=&quot;postdate&quot;&gt;&lt;a href=&quot;http://learningwebgl.com/blog/?p=507&quot;&gt;Прочитать данный урок в оригинале&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;entry&quot;&gt;&lt;span style=&quot;float: left; padding-bottom: 0px; padding-left: 0px; padding-right: 20px; padding-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;a href=&quot;http://ruwebgl.blogspot.com/2011/01/webgl-4-3d.html&quot;&gt;&amp;lt;&amp;lt; Урок 4&lt;/a&gt;&lt;br /&gt;
&lt;/span&gt;&lt;span style=&quot;float: right; padding-bottom: 0px; padding-left: 0px; padding-right: 20px; padding-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;a href=&quot;http://ruwebgl.blogspot.com/2012/01/webgl-6.html&quot;&gt;Урок 6 &amp;gt;&amp;gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Добро пожаловать в мой пятый урок из серии WebGL, основанный на &lt;a href=&quot;http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=06&quot;&gt;уроке 6&lt;/a&gt; из курса OpenGL от NeHe.  Теперь перейдём к добавлению текстуры к 3D объекту, мы обтянем объект изображением, которое загрузим из указанного файла.&lt;br /&gt;
Это действительно рабочий способ для добавления деталей вашей сцене без усложения отрисовываемых объектов. &lt;br /&gt;
Представьте себе каменную стену в игре типа лабиринт. Вы, вероятно, не захотите моделировать каждый блок стены как отдельный объект.&amp;nbsp;Поэтому вместо создания образа кладки и покрытия стен с ним всю стену теперь можно создать как один целый объект.&lt;br /&gt;
Здесь можно посмотреть, как выглядит этот урок в браузере с поддержкой WebGL:&lt;br /&gt;
&lt;br /&gt;
&lt;object height=&quot;385&quot; width=&quot;480&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/s9kMjEMzF6k&amp;#038;hl=en&amp;#038;fs=1&amp;#038;hd=1&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;http://www.youtube.com/v/s9kMjEMzF6k&amp;#038;hl=en&amp;#038;fs=1&amp;#038;hd=1&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;480&quot; height=&quot;385&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.blogger.com/lessons/lesson05/index.html&quot;&gt;Нажмите здесь&lt;/a&gt;, если ваш браузер поддерживает WebGL и вы сможете увидеть этот урок &quot;вживую&quot;&lt;br /&gt;
&lt;a href=&quot;http://learningwebgl.com/blog/?p=11&quot;&gt;Здесь&lt;/a&gt; можно почитать как получить браузер с поддержкой WebGL&lt;br /&gt;
Более подробно о том, как это работает, ниже&lt;br /&gt;
&lt;br /&gt;
&lt;span id=&quot;more-507&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;i&gt;Примечание:&lt;/i&gt; этот урок рассчитан на людей с достаточным количеством знаний в области программирования,&amp;nbsp;но не имеющих реального опыта в программировании 3D графики. Цель курса состоит в том, чтобы вы как можно быстрее начали создавать собственные&amp;nbsp;3D страницы и имели хорошее представление о том, что происходит в коде. Если вы ещё не ознакомились с предыдущими уроками,&amp;nbsp;то вам сделать это до прочтения этого урока.&lt;br /&gt;
Тут я буду рассказывать о различиях кода из &lt;a href=&quot;http://learningwebgl.com/blog/?p=370&quot;&gt;урока4&lt;/a&gt; и нового кода.Тут я буду рассказывать о различиях кода из предыдущих и нового кода.&lt;br /&gt;
&lt;br /&gt;
В тексте могут встречатья ошибки и неточности. Если вы заметите, что что-то неверно,&amp;nbsp;дайте мне знать об этом в комментариях и мы исправим это как можно скорее.&lt;br /&gt;
Есть 2 способа получения исходного кода для этого примера: просмотр кода в браузере, если он поддерживает WebGL и вы просматриваете урок &quot;вживую&quot;&amp;nbsp;в своём браузере, или вы можете скопировать его и другие уроки с &lt;a href=&quot;http://github.com/gpjt/webgl-lessons&quot;&gt;GitHub&lt;/a&gt;.&lt;br /&gt;
В любом случае, после того, как получите код, загрузите его в ваш любимый текстовый редактор и просмотрите.&lt;br /&gt;
Ключом к пониманию работы с текстурами является то, что текстуры представляют собой настройки цвета для каждой точки 3D объекта.&lt;br /&gt;
Как вы помните из &lt;a href=&quot;http://learningwebgl.com/blog/?p=134&quot;&gt;урока 2&lt;/a&gt;,цвета указываются при помощи фрагментных шейдеров.&lt;br /&gt;
Всё что нам нужно сделать  - это загрузить изображение и передать его фрагментому шейдеру.&lt;br /&gt;
Фрагментному шейдеру также необходимо знать, какой бит изображения использовать для того фрагмента, с к отрым он работает,&amp;nbsp;поэтому мы также должны предоставить ему эту информацию.&lt;br /&gt;
Двайте начнём с просмотра кода, который загружает текстуру. Мы вызываем его прямо в начале выполнения JavaScript кода нашей страницы,&amp;nbsp;в функции &lt;code&gt;webGLStart&lt;/code&gt; внизу страницы (новый код выделен красным цветом):&lt;br /&gt;
&lt;pre&gt;function webGLStart() {
    var canvas = document.getElementById(&quot;lesson05-canvas&quot;);
    initGL(canvas);
    initShaders();
    &lt;span style=&quot;color: red;&quot;&gt;initTexture();&lt;/span&gt; 
 
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
&lt;/pre&gt;Давайте посмотрим на &lt;code&gt;initTexture&lt;/code&gt; —&amp;nbsp;она находится если промотать от начала вниз на треть файла, и этот код весь новый:&lt;br /&gt;
&lt;pre&gt;var neheTexture;
  function initTexture() {
    neheTexture = gl.createTexture();
    neheTexture.image = new Image();
    neheTexture.image.onload = function() {
      handleLoadedTexture(neheTexture)
    }
 
    neheTexture.image.src = &quot;nehe.gif&quot;;
  }
&lt;/pre&gt;Итак, мы создаём глобальную переменную для хранения текстуры. В реальном примере вы будете иметь множество текстур&amp;nbsp;и не будете использовать глобальные переменные,но мы сейчас нарочно всё упрощаем. Мы используем функцию &lt;code&gt;gl.createTexture&amp;nbsp;&lt;/code&gt;для создания ссылки на текстуру и помещения её в глобальную область видимости, затем мы создаём JavaScript объект &lt;code&gt;Image&amp;nbsp;&lt;/code&gt;и помещам его в новый аттрибут текстуры, вновь воспользовавшись возможностью JavaScript устанавливать любое свойство любому объекту.&lt;br /&gt;
По умолчанию объект текстура не имеет поля изображения image, но для нас это удобно, поэтому мы создали такое свойство.&lt;br /&gt;
Очевидно следующим шагом для получение объекта &lt;code&gt;Image&lt;/code&gt; является загрузка в него фактического изображения,но перед этим мы присоединим к нему функцию обратного вызова, которая будет вызываться, когда изображение полностью загружено.&lt;br /&gt;
Таким образом, нам следует в первую очередь установить эту функцию. Как только это сделано, мы устанавливаем изображению свойство&amp;nbsp;&lt;code&gt;src&lt;/code&gt;, теперь всё готово.&lt;br /&gt;
Изображение загружается асинхронно, но код, который устанавливает свойство &lt;code&gt;src&lt;/code&gt;&lt;br /&gt;
изображению немедленно возвращается, а в фоновом потоке происходит загрузка изображения с вебсервера.&lt;br /&gt;
Когда изображение загружено, вызывается наша функция обратного вызова, которя вызывает &lt;code&gt;handleLoadedTexture&lt;/code&gt;:&lt;br /&gt;
&lt;pre&gt;function handleLoadedTexture(texture) {
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.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, null);
  }
&lt;/pre&gt;Первое. что нам следует сделать, это сообщить WebGL, что наша текстура является текущей текстурой.&lt;br /&gt;
Все функции WebGL по работе с текстурой оперируют с текущей текстурой вместо того, &lt;br /&gt;
чтобы принимать указатель текстуру в качестве параметра.&lt;br /&gt;
&lt;br /&gt;
В &lt;code&gt;bindTexture&lt;/code&gt; показано как сделать текстуру текущей, это похоже на использование&amp;nbsp;&lt;code&gt;gl.bindBuffer&lt;/code&gt;,&amp;nbsp;которое мы рассматривали ранее.&lt;br /&gt;
Далее мы сообщаем WebGL, что все изображения, загруженные нами в текстуры, необходимо отразить по вертикали.&lt;br /&gt;
Мы делаем это из-за разницы в координатах. Для наших текстурных координат мы используем координаты,похожие на те,&amp;nbsp;что обычно используются в математике, их увеличение происходит по мере продвижения вверх по вертикальной оси. Эти координаты&amp;nbsp;согласуются с координатами X, Y, Z, которые мы используем для указания позиций вершин.&amp;nbsp;В отличие от многих других компьютерных систем - например формата GIF, который мы используем для изображения текстуры -&amp;nbsp;используют координаты, которые увеличиваются по мере продвижения вниз по вертикальной оси. Горизонтальная ось одна и та же&amp;nbsp;в обеих системах координат. Различие вертикальных осей означает, что GIF изображение, которое мы использем для нашей текстуры,  уже отражено по вертикали и нам необходимо&amp;nbsp;вернуть его обратно в исходное сосстояние.&lt;br /&gt;
(Спасибо Ilmari Heikkinen за разъяснение по этому вопроосу в комментариях.) &lt;br /&gt;
Следующим шагом является загрузка нашего только что полученного изображения на графическую карту при помощи &lt;code&gt;texImage2D&lt;/code&gt;.&lt;br /&gt;
Перечислим параметры в порядке их следования:используемое изображение,&amp;nbsp;уровень детализации(что это мы рассмотрим в одном из следующих уроков),&amp;nbsp;формат, в котором мы хотим, чтобы изображение было сохранено на графической карте(повторяю второй раз по причинам, которые вы узнаете позже),размер каждого “канала” изображения(зависит от типа данных, используемого для хранения красной, зелёной и синей цветовой составляющей),&lt;br /&gt;
и, наконец, само изображение.&lt;br /&gt;
В следующих двух строках указываются параметры масштабирования для текстуры. Первый говорит WebGL каким образом заполнить&amp;nbsp;большое пространство экрана текстурой, если заполняемое пространство больше размера изображения текстуры, другими словами,&lt;br /&gt;
в ней указано каким образом отмасштабировать текстуру.&lt;br /&gt;
Вторая является инструкцией как обрезать изображение.&lt;br /&gt;
Существуют различные способы наложения текстуры, которые вы можете указать, самый простой и непривлекательный из них &lt;code&gt;NEAREST&lt;/code&gt;он говорит о том, что оригинальный образ используется &quot;как есть&quot;,вследствие чего при просмотре крупным планом&amp;nbsp;она будет выглядеть очень блочно. У этого способа есть преимущество - скорость отображения достаточно хорошая даже на медленных машинах.&lt;br /&gt;
В следющем уроке мы рассмотрим использование различных способ наложения текстуры, так что у вас будет возможность сравнить&amp;nbsp;производительность и внешний вид каждого из них.&lt;br /&gt;
Как только всё это сделано, мы установим указатель на текущую структуру &lt;code&gt;null&lt;/code&gt;.&lt;br /&gt;
Это не является строго необходимым, но является хорошей привычкой -  очистка после использования.&lt;br /&gt;
Итак, это был весь код, который требуется для загрузки текстуры.&lt;br /&gt;
Теперь давайте перейдём к &lt;code&gt;initBuffers&lt;/code&gt;. Естественно отсутствует весь код, относящийся к пирамиде из урока4,&amp;nbsp;но более интересным изменением является замена буфера цветов вершин куба новым буфером текстурных координат.&lt;br /&gt;
Это выглядит следующим образом:&lt;br /&gt;
&lt;pre&gt;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;
&lt;/pre&gt;В таком виде код должен показаться вам наглядным, заметьте - всё, что мы сделали - это указали новый аттрибут для каждой вершины&amp;nbsp;в буфере массиве и этот новый аттрибут имеет 2 значения для каждой вершины.&lt;br /&gt;
Текстурыне координаты указывают положение &lt;i&gt;x, y&lt;/i&gt; для вершины на изображении текстуры. &lt;br /&gt;
Размер текстуры нормирован таким образом, что высота и широта изображения принимаются за единицу,&amp;nbsp;так что получаем (0, 0) в левом нижнем углу, (1, 1) в правом верхнем углу.&lt;br /&gt;
Это было единственное изменение в  &lt;code&gt;initBuffers&lt;/code&gt;,&amp;nbsp;двигаемся дальше к функции &lt;code&gt;drawScene&lt;/code&gt;.&lt;br /&gt;
Наиболее интересные изменения в этой функции естественно те, которые показывают использование текстуры.&lt;br /&gt;
Однако, прежде чем мы перейдем к ним, рассмотрим ряд более простых изменений изменений -  первое - удаление пирамиды и&amp;nbsp;второе - в настоящее время куб вращается в другом направлении.&lt;br /&gt;
Я не буду описывать их в деталях, тут всё довольно легко разобрать,изменения выделены красным цветом в верхней&amp;nbsp;части функции &lt;code&gt;drawScene&lt;/code&gt;:&lt;br /&gt;
&lt;pre&gt;&lt;span style=&quot;color: red;&quot;&gt;var xRot = 0;
  var yRot = 0;
  var zRot = 0;&lt;/span&gt; 
  function drawScene() {
    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
 
    perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);
    loadIdentity();
 
    &lt;span style=&quot;color: red;&quot;&gt;mvTranslate([0.0, 0.0, -5.0])
 
    mvRotate(xRot, [1, 0, 0]);
    mvRotate(yRot, [0, 1, 0]);
    mvRotate(zRot, [0, 0, 1]);&lt;/span&gt; 
 
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
&lt;/pre&gt;Есть также соответствующие изменения в функции &lt;code&gt;animate&lt;/code&gt;,&amp;nbsp;которая обновленяет &lt;code&gt;xRot&lt;/code&gt; , &lt;code&gt;yRot&lt;/code&gt; и &lt;code&gt;zRot&lt;/code&gt; , их я описывать не буду.&lt;br /&gt;
&lt;br /&gt;
Итак, минуя эту функцию, рассмотрим код по работе с текстурой.  &lt;br /&gt;
В функции &lt;code&gt;initBuffers&lt;/code&gt; мы создали буфер, содержащий текстурные координаты, здесь нам необходимо связать их с соответсвующим аттрибутом&amp;nbsp;так, чтобы шейдеры смогли их увидеть:&lt;br /&gt;
&lt;pre&gt;gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);
    gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, cubeVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
&lt;/pre&gt;…теперь когда WebGL знает, какой бит текстуры использует каждая вершина, нам необходимо указать ему использовать текстуру,&amp;nbsp;которую мы загрузили ранее и затем нарисовать куб:&lt;br /&gt;
&lt;pre&gt;&lt;span style=&quot;color: red;&quot;&gt;gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, neheTexture);
    gl.uniform1i(shaderProgram.samplerUniform, 0);&lt;/span&gt; 
 
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
    setMatrixUniforms();
    gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
&lt;/pre&gt;То, что происходит здесь имеет некоторую степень сложности. &lt;br /&gt;
WebGL может иметь дело с количеством текстур до 32 в течении любого вызова функции, такой как, например, &lt;code&gt;gl.drawElements&lt;/code&gt;,&amp;nbsp;текстуры пронумерованы от TEXTURE0 к TEXTURE31. То, что мы делаем, сказано в первых 2х строках - нулевая текстура - эта та, которая была загружена ранее,&amp;nbsp;в третьей строке мы передаём нулевое значение в шейдерную форму&amp;nbsp;(которую, как и другие формы,используемые нами для матриц, мы извлекаем из шейдерных программ в &lt;code&gt;initShaders&lt;/code&gt;).&lt;br /&gt;
Она сообщает шейдеру, что мы используем нулевую текстуру.  Давайте посмотрим каким образом она используется позднее.&lt;br /&gt;
Во всяком случае, как только эти три строки будут выполнены, мы готовы идти дальше,&amp;nbsp;итак, мы просто используем тот же код, что и прежде для рисования треугольников, составляющих куб.&lt;br /&gt;
Единственный код, который остался нераобранным  - изменения в шейдерах. Давайте сначала рассмотрим вершинный шейдер:&lt;br /&gt;
&lt;pre&gt;attribute vec3 aVertexPosition;
  &lt;span style=&quot;color: red;&quot;&gt;attribute vec2 aTextureCoord;&lt;/span&gt; 
 
  uniform mat4 uMVMatrix;
  uniform mat4 uPMatrix;
 
  &lt;span style=&quot;color: red;&quot;&gt;varying vec2 vTextureCoord;&lt;/span&gt; 
 
  void main(void) {
    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
    &lt;span style=&quot;color: red;&quot;&gt;vTextureCoord = aTextureCoord;&lt;/span&gt; 
  }
&lt;/pre&gt;Это очень похоже на вещи, связанные с цветом, которые мы передавали вершинному шейдеру в уроке2.&lt;br /&gt;
Всё, что мы делаем- это определяем текстурные координаты(снова, вместо цвета) в качестве аттрибута для каждой вершины&amp;nbsp;и передаём их в какой-либо переменной.&lt;br /&gt;
После того, как это было проделано для каждой вершины, WebGL будет работать с фрагментами(которые, напоминаю, являются просто пикселями),&amp;nbsp;которые находятся между вершинами, вычислив их при помощи линейной интерполяции аналогичному тому, как было проделано с цветами в уроке 2.&lt;br /&gt;
Итак, серединный фрагмент между вершинами с текстрными координатами (1, 0) и (0, 0) получит текстурные координаты (0.5, 0), и конечный фрагмент&amp;nbsp;между вершинами (0, 0) and (1, 1) получит текстурные координаты (0.5, 0.5).&lt;br /&gt;
Следующая остановка, фрагментный шейдер:&lt;br /&gt;
&lt;pre&gt;#ifdef GL_ES
  precision highp float;
  #endif
 
  &lt;span style=&quot;color: red;&quot;&gt;varying vec2 vTextureCoord;
 
  uniform sampler2D uSampler;&lt;/span&gt; 
 
  void main(void) {
    &lt;span style=&quot;color: red;&quot;&gt;gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));&lt;/span&gt; 
  }
&lt;/pre&gt;Таким образом, мы забрали интерполированные значения текстурных координат, и у нас есть переменная типа &lt;code&gt;sampler&lt;/code&gt;,&amp;nbsp;которая является способом представления текстур для шейдера.&lt;br /&gt;
В функции &lt;code&gt;drawScene&lt;/code&gt;, наша текстура это  &lt;code&gt;gl.TEXTURE0&lt;/code&gt;, а форма &lt;code&gt;uSampler&lt;/code&gt; установлена в значение ноль, этот образец&amp;nbsp;представляет нашу текстуру. Всё, что делает шейдер, это использование функции &lt;code&gt;texture2D&lt;/code&gt; для получения соответсвующего цвета из текстуры при помощи координат.&lt;br /&gt;
Для текстурных координат традиционно использются обозначения s и t чаще. чем x и y, и шейдерный язык поддерживает эти обозначения;&amp;nbsp;мы могли бы так же легко использовать &lt;code&gt;vTextureCoord.x&lt;/code&gt; и &lt;code&gt;vTextureCoord.y&lt;/code&gt;.&lt;br /&gt;
Теперь у нас есть цвет фрагмента! Мы видим на экране текстурированный объект.&amp;nbsp;На сегодня всё. Теперь вы имеете представление о том, как добавлять текстуры к 3D объекту при помощи загрузки изображения, указав WebGL использовать его&amp;nbsp;в качестве текстры, передав вашему объекту текстурные координаты и использование координат и текстур  шейдерах.&lt;br /&gt;
Если у вас есть вопросы, комментарии или поправки, пожалуйста оставьте комментарий ниже!&lt;br /&gt;
Иначе, &lt;a href=&quot;http://learningwebgl.com/blog/?p=571&quot;&gt;перейдите к следующему уроку&lt;/a&gt;,в котором я покажу, как можно получить простой ввод с клавиатруы в JavaScript, который анимирует вашу 3D сцену&amp;nbsp;и делает её интерактивной для человека, просматривающего страницу.&lt;br /&gt;
Мы будем использовать это для предоставления пользователю возможности изменять угол поворота куба, приближать и удалять сцену, и регулировать настройки,&amp;nbsp;переданные WebGL, отвечающие за наложение текстуры.&lt;br /&gt;
&lt;span style=&quot;float: left; padding-bottom: 0px; padding-left: 0px; padding-right: 20px; padding-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;a href=&quot;http://ruwebgl.blogspot.com/2011/01/webgl-4-3d.html&quot;&gt;&amp;lt;&amp;lt; Урок 4&lt;/a&gt;&lt;br /&gt;
&lt;/span&gt;&lt;span style=&quot;float: right; padding-bottom: 0px; padding-left: 0px; padding-right: 20px; padding-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;a href=&quot;http://ruwebgl.blogspot.com/2012/01/webgl-6.html&quot;&gt;Урок 6 &amp;gt;&amp;gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;em&gt;&lt;br /&gt;
&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;Благодарности: Chris Marrin’s &lt;a href=&quot;http://webkit.org/blog-files/webgl/SpiritBox.html&quot;&gt;WebKit-only spinning box&lt;/a&gt; сильно помогло при написании данного материала, так же как и &lt;a href=&quot;http://www.nihilogic.dk/labs/webgl/webkit-demos/SpiritBox.html&quot;&gt;портирование Крисом демо Jacob Seidelin’s&lt;/a&gt; в Firefox.&lt;br /&gt;
Как всегда, я глубоко благодарен&amp;nbsp;&lt;a href=&quot;http://nehe.gamedev.net/&quot;&gt;NeHe&lt;/a&gt; за их &lt;a href=&quot;http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=06&quot;&gt;уроки OpenGL&lt;/a&gt; и за скрипты к этому уроку.&lt;/em&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruwebgl.blogspot.com/feeds/5946457620431563106/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://ruwebgl.blogspot.com/2011/01/webgl-5.html#comment-form' title='Комментарии: 7'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/784388971348462050/posts/default/5946457620431563106'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/784388971348462050/posts/default/5946457620431563106'/><link rel='alternate' type='text/html' href='http://ruwebgl.blogspot.com/2011/01/webgl-5.html' title='WebGL урок 5. Введение в текстуры.'/><author><name>Катя</name><uri>http://www.blogger.com/profile/01514348270451602520</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-784388971348462050.post-6181002151750386778</id><published>2011-01-21T05:32:00.030-08:00</published><updated>2012-02-21T05:28:44.524-08:00</updated><title type='text'>WebGL Урок 4. Несколько реальнх 3D объектов.</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;&lt;div id=&quot;content&quot;&gt;&lt;div class=&quot;postdate&quot;&gt;&lt;a href=&quot;http://learningwebgl.com/blog/?p=370&quot;&gt;Прочитать данный урок в оригинале&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;entry&quot;&gt;&lt;br /&gt;
&lt;span style=&quot;float: left; padding-bottom: 0px; padding-left: 0px; padding-right: 20px; padding-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;a href=&quot;http://russian-webgl.blogspot.com/2010/09/webgl-3.html&quot;&gt;&amp;lt;&amp;lt; Урок 3&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;float: right; padding-bottom: 0px; padding-left: 0px; padding-right: 20px; padding-top: 0px;&quot;&gt;&lt;a href=&quot;http://ruwebgl.blogspot.com/2011/01/webgl-5.html&quot;&gt;Урок 5 &amp;gt;&amp;gt;&lt;/a&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Добро пожаловать в мой четвёртый урок из серии WebGL. На этот раз мы собираемся показать вам несколько уроков OpenGL.&lt;br /&gt;
Здесь можно посмотреть, как выглядит этот урок в браузере с поддержкой WebGL:&lt;br /&gt;
&lt;br /&gt;
&lt;object width=&quot;480&quot; height=&quot;385&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/Oa71cNJdkts&amp;#038;hl=en&amp;#038;fs=1&amp;#038;hd=1&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;http://www.youtube.com/v/Oa71cNJdkts&amp;#038;hl=en&amp;#038;fs=1&amp;#038;hd=1&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;480&quot; height=&quot;385&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.blogger.com/lessons/lesson05/index.html&quot;&gt;Нажмите здесь&lt;/a&gt;, если ваш браузер поддерживает WebGL и вы сможете увидеть этот урок &quot;вживую&quot;&lt;br /&gt;
&lt;a href=&quot;http://learningwebgl.com/blog/?p=11&quot;&gt;Здесь&lt;/a&gt; можно почитать как получить браузер с поддержкой WebGL&lt;br /&gt;
Более подробно о том, как это работает, ниже&lt;br /&gt;
&lt;span id=&quot;more-507&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;i&gt;Примечание:&lt;/i&gt; этот урок рассчитан на людей с достаточным количеством знаний в области программирования,&amp;nbsp;но не имеющих реального опыта в программировании 3D графики. Цель курса состоит в том, чтобы вы как можно быстрее начали создавать собственные&amp;nbsp;3D страницы и имели хорошее представление о том, что происходит в коде. Если вы ещё не ознакомились с предыдущими уроками,&amp;nbsp;то советую вам сделать это до прочтения этого урока.&lt;br /&gt;
В тексте могут встречатья ошибки и неточности. Если вы заметите, что что-то неверно,&amp;nbsp;дайте мне знать об этом в комментариях и мы исправим это как можно скорее.&lt;br /&gt;
Есть 2 способа получения исходного кода для этого примера: просмотр кода в браузере, если он поддерживает WebGL и вы просматриваете урок &quot;вживую&quot;&amp;nbsp;в своём браузере, или вы можете скопировать его и другие уроки с &lt;a href=&quot;http://github.com/gpjt/webgl-lessons&quot;&gt;GitHub&lt;/a&gt;.&lt;br /&gt;
В любом случае, после того, как получите код, загрузите его в ваш любимый редактор кода и просмотрите.&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;Разница между кодом этого урока и предыдущего сконцентрирована в функциях &lt;code&gt;animate&lt;/code&gt;, &lt;code&gt;initBuffers&lt;/code&gt; и &lt;code&gt;drawScene&lt;/code&gt;. Если вы промотаете вниз до функции &lt;code&gt;animate&lt;/code&gt;, то сперва увидете совсем незначительное изменение : переменные, которые хранит текущее состояние вращения 2х объектов сцены переиенованы; теперь они называются &lt;code&gt;rTri&lt;/code&gt; и &lt;code&gt;rSquare&lt;/code&gt;.  Мы изменили направление вращения куба( потому что так он смотрится лучше), теперь мы имеем:&lt;/p&gt;&lt;pre&gt;&lt;span style=&quot;color: red;&quot;&gt;rPyramid&lt;/span&gt; += (90 * elapsed) / 1000.0;
      &lt;span style=&quot;color: red;&quot;&gt;rCube&lt;/span&gt; -= (75 * elapsed) / 1000.0;
 &lt;/pre&gt;&lt;p&gt;С этой функцией всё; давайте переместимся вверх к функции &lt;code&gt;drawScene&lt;/code&gt;.  Прямо над определением функции у нас объявлены переменные:&lt;/p&gt;&lt;pre&gt;var &lt;span style=&quot;color: red;&quot;&gt;rPyramid&lt;/span&gt; = 0;
  var &lt;span style=&quot;color: red;&quot;&gt;rCube&lt;/span&gt; = 0;
&lt;/pre&gt;&lt;p&gt;Далее идёт заголовок функции, следующий за нашим кодом настроек и кодом перемещения в позицию, из которой мы будем рисовать пирамиду. После всего этого, мы вращаем её вокруг оси Y как мы уже это делали с треугольником в предыдущем уроке:&lt;/p&gt;&lt;pre&gt;mat4.rotate(mvMatrix, degToRad(&lt;span style=&quot;color: red;&quot;&gt;rPyramid&lt;/span&gt;), [0, 1, 0]);
&lt;/pre&gt;&lt;p&gt;&amp;#8230;и затем мы отрисовываем её.  Единственным различием между кодом этого и прошлого уроков является то, что&lt;br /&gt;
в предыдущем уроке мы рисовали разноцветный треугольник, а в этом  пирамиду - она имеет больше вершин, и соответственно больше цветов, все они задействованы в &lt;code&gt;initBuffers&lt;/code&gt; ( к которой мы сейчас перейдём).  Это означает, что кроме изменений в именах буферов, которые мы используем, код идентичен:&lt;/p&gt;&lt;pre&gt;gl.bindBuffer(gl.ARRAY_BUFFER, &lt;span style=&quot;color: red;&quot;&gt;pyramidVertexPositionBuffer&lt;/span&gt;);
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, &lt;span style=&quot;color: red;&quot;&gt;pyramidVertexPositionBuffer&lt;/span&gt;.itemSize, gl.FLOAT, false, 0, 0);
 
    gl.bindBuffer(gl.ARRAY_BUFFER, &lt;span style=&quot;color: red;&quot;&gt;pyramidVertexColorBuffer&lt;/span&gt;);
    gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, &lt;span style=&quot;color: red;&quot;&gt;pyramidVertexColorBuffer&lt;/span&gt;.itemSize, gl.FLOAT, false, 0, 0);
 
    setMatrixUniforms();
    gl.drawArrays(gl.TRIANGLES, 0, &lt;span style=&quot;color: red;&quot;&gt;pyramidVertexPositionBuffer&lt;/span&gt;.numItems);
&lt;/pre&gt;&lt;p&gt;Это было просто. Давайте посмотрим на код для куба.  Первый шаг - это вращение куба; на этот раз вместо вращения на оси X, мы будем вращать его вокруг оси, которая повёрнута ( с точки зрения наблюдателя ) вверх, вправо, и к вам:&lt;/p&gt;&lt;pre id=&quot;changedfromhere&quot;&gt;mat4.rotate(mvMatrix, degToRad(rCube), [&lt;span style=&quot;color: red;&quot;&gt;1, 1, 1&lt;/span&gt;]);
&lt;/pre&gt;&lt;p&gt;Теперь, рисуем куб. Это немного сложнее.  Есть 3 способа нарисовать куб:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;При помощи одной полоски треугольников( triangle strip ).  Если бы весь куб был одного цвета, было бы проще &amp;mdash; мы могли бы использовать позиции вершин, которые мы использвоали во время рисования передней грани, потом добавили бы другие 2 точки для добавления другой грани, и ещё 2 другие точки для следующей грани, и т.д.  Это было бы очень эффективно. К несчастью, мы хотим, чтобы  у каждой грани был свой цвет.  Поскольку каждая вершина принадлежит к углу куба, а каждый угол принадлжит 3м граням, нам необходимо указать каждую вершину 3 раза, и сделать это необходимо таким хитрым образом, что я даже не хочу даже &lt;i&gt;пытаться&lt;/i&gt; объяснить это&lt;/li&gt;
.
&lt;li&gt;Извратимся и нарисуем наш куб при помощи рисования 6 отдельных квадратов, по одному на каждую грань, с отдельными наборами позиций и цветов для каждой вершины.  Первая версия этого урока( примерно 30 октября 2009) именно это и делала, и всё прекрасно работало.  Однако, это не является хорошей практикой; потому что такое решение требует больших накладных расходов : вы всё время просите WebGL нарисовать другой объект в вашей сцене, было бы лучше иметь наименьшее количество обращений к &lt;code&gt;drawArrays&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Последний способ - определить куб как 6 квадратов, каждый из которых состоит из 2х треугольников, однако отправить всё это на отрисовку WebGL  разом.  Этот способ аналогичен способу с полоской тругольников( triangle strip ), но так как мы каждый раз указывали треугольники целиком вместо того, чтобы просто определить каждый труегольник при помощи добавления новой точки к предыдущим, то нам легче определить цвет для каждой стороны.  Также преимуществом является последовательность кода, что позволяет нам ввести новую функцию, &lt;code&gt;drawElements&lt;/code&gt; &amp;mdash; итак это именно наш метод:-)&lt;br /&gt;
&lt;/ol&gt;&lt;p&gt;Первым делом необходимо связать буферы, содержащие позиции и цвета вершин куба, которые мы создали в &lt;code&gt;initBuffers&lt;/code&gt; с соответствующими аттрибутами, точно также как мы сделали это для пирамиды:&lt;/p&gt;&lt;pre&gt;gl.bindBuffer(gl.ARRAY_BUFFER, &lt;span style=&quot;color: red;&quot;&gt;cubeVertexPositionBuffer&lt;/span&gt;);
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, &lt;span style=&quot;color: red;&quot;&gt;cubeVertexPositionBuffer&lt;/span&gt;.itemSize, gl.FLOAT, false, 0, 0);
 
    gl.bindBuffer(gl.ARRAY_BUFFER, &lt;span style=&quot;color: red;&quot;&gt;cubeVertexColorBuffer&lt;/span&gt;);
    gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, &lt;span style=&quot;color: red;&quot;&gt;cubeVertexColorBuffer&lt;/span&gt;.itemSize, gl.FLOAT, false, 0, 0);
&lt;/pre&gt;&lt;p&gt;Следующим шагом является рисование треугольников. Тут есть некоторая проблема. Давайте рассмотрим переднюю грань; для неё существует 4 позиции, и каждая имеет свой цвет. Однако, необходимо чтобы она была отрисована при помощи примитивных треугольников, а так как мы используем примитивные треугольники, для каждого из которых необходимо указать вершины индивидуально, в отличие от полосок треугольников( triangle strips), которые используют общие вершины, нам необходимо указать все 6 вершин.  Но в нашем массиве находятся только 4.  &lt;/p&gt;&lt;p&gt;Мы хотим сделать примерно следующее &amp;#8220; нарисовать треугольник, сделанный на основе первых 3х вершин буфера, затем нарисовать другой на основе первой, третьей и четвёртой.  Таким оброазом, мы получим переднюю грань; рисование остальной части куба аналогично. В точности так мы и делаем. &lt;/p&gt;&lt;p&gt;Для этого мы используем так называемый &lt;i&gt;буфер элементов&lt;/i&gt; и вызываем новую функцию &lt;code&gt;drawElements&lt;/code&gt;.  В точности так же как и буфер, который мы только что использовали, буфер элементов заполняется соответсвующими значениями в &lt;code&gt;initBuffers&lt;/code&gt;, и содержит список вершин. Отсчёт индексов массивов, которые мы используем для хранения значений цветов и позиций, начинается с нуля.&lt;/p&gt;&lt;p&gt;В порядке использования делаем наш буфер элементов куба текущим (WebGL различает текущий буфер и текущий буфер элментов, поэтому мы должны указать, какой из них мы подсоединяем в &lt;code&gt;gl.bindBuffer&lt;/code&gt;), затем идёт код для передачи наших матриц модель-вид и проекции на графическую карту, затем вызываем &lt;code&gt;drawElements&lt;/code&gt; для отрисовки треугольников:&lt;/p&gt;&lt;pre&gt;&lt;span style=&quot;color: red;&quot;&gt;gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);&lt;/span&gt;
    setMatrixUniforms();
    &lt;span style=&quot;color: red;&quot;&gt;gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;С кодом в &lt;code&gt;drawScene&lt;/code&gt; покончено.  Остальной код в &lt;code&gt;initBuffers&lt;/code&gt; и он достаточно очевиден.  Мы определяем буферы с новыми именами для отражения новой сути хранимых объектов, и добавляем новый для буфера индексов вершин куба:&lt;/p&gt;&lt;pre&gt;var pyramidVertexPositionBuffer;
  var pyramidVertexColorBuffer;
  var cubeVertexPositionBuffer;
  var cubeVertexColorBuffer;
  var cubeVertexIndexBuffer;
&lt;/pre&gt;&lt;p&gt;Мы помещаем значение буфер позиций вершин пирамид для всех граней, с соответсвующим изменением в &lt;code&gt;numItems&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;pyramidVertexPositionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexPositionBuffer);
    var vertices = [
        // Передняя грань
         0.0,  1.0,  0.0,
        -1.0, -1.0,  1.0,
         1.0, -1.0,  1.0,
        // Правая грань
         0.0,  1.0,  0.0,
         1.0, -1.0,  1.0,
         1.0, -1.0, -1.0,
        // Задняя грань
         0.0,  1.0,  0.0,
         1.0, -1.0, -1.0,
        -1.0, -1.0, -1.0,
        // Левая грань
         0.0,  1.0,  0.0,
        -1.0, -1.0, -1.0,
        -1.0, -1.0,  1.0
    ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    pyramidVertexPositionBuffer.itemSize = 3;
    pyramidVertexPositionBuffer.numItems = 12;
&lt;/pre&gt;&lt;p&gt;&amp;#8230;также для буфера цветов вершин пирамиды:&lt;/p&gt;&lt;pre&gt;pyramidVertexColorBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexColorBuffer);
    var colors = [
        // Передняя грань
        1.0, 0.0, 0.0, 1.0,
        0.0, 1.0, 0.0, 1.0,
        0.0, 0.0, 1.0, 1.0,
        // Правая грань
        1.0, 0.0, 0.0, 1.0,
        0.0, 0.0, 1.0, 1.0,
        0.0, 1.0, 0.0, 1.0,
        // Задняя грань
        1.0, 0.0, 0.0, 1.0,
        0.0, 1.0, 0.0, 1.0,
        0.0, 0.0, 1.0, 1.0,
        // Левая грань
        1.0, 0.0, 0.0, 1.0,
        0.0, 0.0, 1.0, 1.0,
        0.0, 1.0, 0.0, 1.0
    ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
    pyramidVertexColorBuffer.itemSize = 4;
    pyramidVertexColorBuffer.numItems = 12;
&lt;/pre&gt;&lt;p&gt;&amp;#8230;и для буфера позиций вершин куба:&lt;/p&gt;&lt;pre&gt;cubeVertexPositionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
    vertices = [
      // Передняя грань
      -1.0, -1.0,  1.0,
       1.0, -1.0,  1.0,
       1.0,  1.0,  1.0,
      -1.0,  1.0,  1.0,
 
      // Задняя грань
      -1.0, -1.0, -1.0,
      -1.0,  1.0, -1.0,
       1.0,  1.0, -1.0,
       1.0, -1.0, -1.0,
 
      // Верхняя грань
      -1.0,  1.0, -1.0,
      -1.0,  1.0,  1.0,
       1.0,  1.0,  1.0,
       1.0,  1.0, -1.0,
 
      // Нижняя грань
      -1.0, -1.0, -1.0,
       1.0, -1.0, -1.0,
       1.0, -1.0,  1.0,
      -1.0, -1.0,  1.0,
 
      // Правая грань
       1.0, -1.0, -1.0,
       1.0,  1.0, -1.0,
       1.0,  1.0,  1.0,
       1.0, -1.0,  1.0,
 
      // Левая грань
      -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;
&lt;/pre&gt;&lt;p&gt;Буфер цвета немного более сложный, поэтому мы используем цикл для создания списка цветов вершин. Таким образом, нет необходимости указывать один и тот же цвет 4 раза, по одному для каждой вершины:&lt;/p&gt;&lt;pre&gt;cubeVertexColorBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
    colors = [
      [1.0, 0.0, 0.0, 1.0],     // Front face
      [1.0, 1.0, 0.0, 1.0],     // Back face
      [0.0, 1.0, 0.0, 1.0],     // Top face
      [1.0, 0.5, 0.5, 1.0],     // Bottom face
      [1.0, 0.0, 1.0, 1.0],     // Right face
      [0.0, 0.0, 1.0, 1.0],     // Left face
    ];
    var unpackedColors = [];
    for (var i in colors) {
      var color = colors[i];
      for (var j=0; j &lt; 4; j++) {
        unpackedColors = unpackedColors.concat(color);
      }
    }
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(unpackedColors), gl.STATIC_DRAW);
    cubeVertexColorBuffer.itemSize = 4;
    cubeVertexColorBuffer.numItems = 24;
&lt;/pre&gt;
&lt;p&gt;Наконец, мы определяем буфер элементов ( отметьте для себя разницу между первым параметром в &lt;code&gt;gl.bindBuffer&lt;/code&gt; и &lt;code&gt;gl.bufferData&lt;/code&gt;):&lt;/p&gt;&lt;pre&gt;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;
&lt;/pre&gt;&lt;p&gt;Запомните, каждое число в этом буфере является индексом в буфере вершин и цветов вершин.  Итак, инструкция в первой строке для рисования треугольника в &lt;code&gt;drawScene&lt;/code&gt; означает, что мы получаем треугольник с вершинами 0, 1, и 2, а затем другой треугольник с вершинами 0, 2 и 3.  Так как оба треуголника одного и того же цвета и они смежные, в результате мы получим квадрат с вершинами 0, 1, 2 и 3.  Повторите всё то же самое для всех граней куба!&lt;/p&gt;&lt;p&gt;Теперь вам известно, как создавать WebGL сцены с использованием 3D объектов, и вы знаете, что при помощи буфера элементов и &lt;code&gt;drawElements&lt;/code&gt; можно повторно использовать вершины, которые вы задали в буфере.  Если у вас появились какие-либо вопросы, комментарии или уточнения, пожалуйста, оставьте их ниже. &lt;/p&gt;&lt;p&gt;В следующий раз мы поговорим о &lt;a href=&quot;http://learningwebgl.com/blog/?p=507&quot;&gt;наложении текстуры&lt;/a&gt;.  &lt;/p&gt;&lt;p&gt;&lt;span style=&quot;float: left; padding-bottom: 0px; padding-left: 0px; padding-right: 20px; padding-top: 0px;&quot;&gt;
&lt;a href=&quot;http://russian-webgl.blogspot.com/2010/09/webgl-3.html&quot;&gt;&amp;lt;&amp;lt; Урок 3&lt;/a&gt;
&lt;/span&gt;&lt;span style=&quot;float: right; padding-bottom: 0px; padding-left: 0px; padding-right: 20px; padding-top: 0px;&quot;&gt;&lt;a href=&quot;http://ruwebgl.blogspot.com/2011/01/webgl-5.html&quot;&gt;Урок 5 &amp;gt;&amp;gt;&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;&lt;em&gt;Благодарности: Как всегда я глубоко благодарен &lt;a href=&quot;http://nehe.gamedev.net/&quot;&gt;NeHe&lt;/a&gt; за скрипт для этого урока в &lt;a href=&quot;http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=05&quot;&gt;Урок по OpenGL&lt;/a&gt;.  Chris Marrin&#39;s &lt;a href=&quot;http://webkit.org/blog-files/webgl/SpinningBox.html&quot;&gt;WebKit spinning box&lt;/a&gt; вдохновило меня на адаптирование этого урока для введения в массивы элементов.&lt;/em&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruwebgl.blogspot.com/feeds/6181002151750386778/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://ruwebgl.blogspot.com/2011/01/webgl-4-3d.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/784388971348462050/posts/default/6181002151750386778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/784388971348462050/posts/default/6181002151750386778'/><link rel='alternate' type='text/html' href='http://ruwebgl.blogspot.com/2011/01/webgl-4-3d.html' title='WebGL Урок 4. Несколько реальнх 3D объектов.'/><author><name>Катя</name><uri>http://www.blogger.com/profile/01514348270451602520</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>