@@ -197,4 +197,197 @@ v_color, который мы объявили.
197197
198198 // ищем, куда должны идти данные вершин.
199199 var positionLocation = gl.getAttribLocation(program, "a_position");
200- + var colorLocation = gl.getAttribLocation(program, "a_color");
200+ + var colorLocation = gl.getAttribLocation(program, "a_color");
201+ ...
202+ + // Создаем буфер для цветов.
203+ + var buffer = gl.createBuffer();
204+ + gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
205+ +
206+ + // Устанавливаем цвета.
207+ + setColors(gl);
208+
209+ // настраиваем атрибуты
210+ ...
211+ + // говорим атрибуту цвета, как извлекать данные из текущего ARRAY_BUFFER
212+ + gl.enableVertexAttribArray(colorLocation);
213+ + var size = 4;
214+ + var type = gl.FLOAT;
215+ + var normalize = false;
216+ + var stride = 0;
217+ + var offset = 0;
218+ + gl.vertexAttribPointer(colorLocation, size, type, normalize, stride, offset);
219+
220+ ...
221+
222+ +// Заполняем буфер цветами для 2 треугольников
223+ +// которые составляют прямоугольник.
224+ +function setColors(gl) {
225+ + // Выбираем 2 случайных цвета.
226+ + var r1 = Math.random();
227+ + var b1 = Math.random();
228+ + var g1 = Math.random();
229+ +
230+ + var r2 = Math.random();
231+ + var b2 = Math.random();
232+ + var g2 = Math.random();
233+ +
234+ + gl.bufferData(
235+ + gl.ARRAY_BUFFER,
236+ + new Float32Array(
237+ + [ r1, b1, g1, 1,
238+ + r1, b1, g1, 1,
239+ + r1, b1, g1, 1,
240+ + r2, b2, g2, 1,
241+ + r2, b2, g2, 1,
242+ + r2, b2, g2, 1]),
243+ + gl.STATIC_DRAW);
244+ +}
245+
246+ И вот результат.
247+
248+ {{{example url="../webgl-2d-rectangle-with-2-colors.html" }}}
249+
250+ Обратите внимание, что у нас есть 2 треугольника сплошного цвета. Тем не менее, мы передаем значения
251+ в * varying* , поэтому они варьируются или интерполируются по
252+ треугольнику. Просто мы использовали тот же цвет на каждой из 3 вершин
253+ каждого треугольника. Если мы сделаем каждый цвет разным, мы увидим
254+ интерполяцию.
255+
256+ // Заполняем буфер цветами для 2 треугольников
257+ // которые составляют прямоугольник.
258+ function setColors(gl) {
259+ // Делаем каждую вершину разным цветом.
260+ gl.bufferData(
261+ gl.ARRAY_BUFFER,
262+ new Float32Array(
263+ * [ Math.random(), Math.random(), Math.random(), 1,
264+ * Math.random(), Math.random(), Math.random(), 1,
265+ * Math.random(), Math.random(), Math.random(), 1,
266+ * Math.random(), Math.random(), Math.random(), 1,
267+ * Math.random(), Math.random(), Math.random(), 1,
268+ * Math.random(), Math.random(), Math.random(), 1]),
269+ gl.STATIC_DRAW);
270+ }
271+
272+ И теперь мы видим интерполированный * varying* .
273+
274+ {{{example url="../webgl-2d-rectangle-with-random-colors.html" }}}
275+
276+ Не очень захватывающе, я полагаю, но это демонстрирует использование более чем одного
277+ атрибута и передачу данных от вершинного шейдера к фрагментному шейдеру. Если
278+ вы посмотрите на [ примеры обработки изображений] ( webgl-image-processing.html ) ,
279+ вы увидите, что они также используют дополнительный атрибут для передачи координат текстуры.
280+
281+ ## Что делают эти команды буфера и атрибута?
282+
283+ Буферы - это способ получения данных вершин и других данных на вершину на
284+ GPU. ` gl.createBuffer ` создает буфер.
285+ ` gl.bindBuffer ` устанавливает этот буфер как буфер для работы.
286+ ` gl.bufferData ` копирует данные в текущий буфер.
287+
288+ Как только данные находятся в буфере, нам нужно сказать WebGL, как извлекать данные из
289+ него и предоставлять их атрибутам вершинного шейдера.
290+
291+ Для этого сначала мы спрашиваем WebGL, какие локации он назначил
292+ атрибутам. Например, в коде выше у нас есть
293+
294+ // ищем, куда должны идти данные вершин.
295+ var positionLocation = gl.getAttribLocation(program, "a_position");
296+ var colorLocation = gl.getAttribLocation(program, "a_color");
297+
298+ Как только мы знаем локацию атрибута, мы выдаем 2 команды.
299+
300+ gl.enableVertexAttribArray(location);
301+
302+ Эта команда говорит WebGL, что мы хотим предоставить данные из буфера.
303+
304+ gl.vertexAttribPointer(
305+ location,
306+ numComponents,
307+ typeOfData,
308+ normalizeFlag,
309+ strideToNextPieceOfData,
310+ offsetIntoBuffer);
311+
312+ И эта команда говорит WebGL получать данные из буфера, который был последним
313+ привязан с gl.bindBuffer, сколько компонентов на вершину (1 - 4), какой
314+ тип данных (` BYTE ` , ` FLOAT ` , ` INT ` , ` UNSIGNED_SHORT ` , и т.д.), шаг
315+ который означает, сколько байт пропустить, чтобы получить от одного куска данных к
316+ следующему куску данных, и смещение для того, как далеко в буфере находятся наши данные.
317+
318+ Количество компонентов всегда от 1 до 4.
319+
320+ Если вы используете 1 буфер на тип данных, то и шаг, и смещение могут
321+ всегда быть 0. 0 для шага означает "использовать шаг, который соответствует типу и
322+ размеру". 0 для смещения означает начать с начала буфера. Установка
323+ их в значения, отличные от 0, более сложна, и хотя это может иметь некоторые
324+ преимущества с точки зрения производительности, это не стоит усложнения, если только
325+ вы не пытаетесь довести WebGL до его абсолютных пределов.
326+
327+ Я надеюсь, что это проясняет буферы и атрибуты.
328+
329+ Вы можете взглянуть на эту
330+ [ интерактивную диаграмму состояния] ( /webgl/lessons/resources/webgl-state-diagram.html )
331+ для другого способа понимания того, как работает WebGL.
332+
333+ Далее давайте пройдемся по [ шейдерам и GLSL] ( webgl-shaders-and-glsl.html ) .
334+
335+ <div class =" webgl_bottombar " ><h3 >Для чего нужен normalizeFlag в vertexAttribPointer?</h3 >
336+ <p >
337+ Флаг нормализации предназначен для всех не-плавающих типов. Если вы передаете
338+ false, то значения будут интерпретироваться как тип, которым они являются. BYTE идет
339+ от -128 до 127, UNSIGNED_BYTE идет от 0 до 255, SHORT идет от -32768 до 32767 и т.д...
340+ </p >
341+ <p >
342+ Если вы устанавливаете флаг нормализации в true, то значения BYTE (-128 до 127)
343+ представляют значения -1.0 до +1.0, UNSIGNED_BYTE (0 до 255) становятся 0.0 до +1.0.
344+ Нормализованный SHORT также идет от -1.0 до +1.0, просто у него больше разрешения, чем у BYTE.
345+ </p >
346+ <p >
347+ Самое распространенное использование нормализованных данных - для цветов. Большую часть времени цвета
348+ идут только от 0.0 до 1.0. Использование полного float для каждого красного, зеленого, синего и альфа
349+ использовало бы 16 байт на вершину на цвет. Если у вас сложная геометрия, это
350+ может сложиться в много байт. Вместо этого вы могли бы конвертировать ваши цвета в UNSIGNED_BYTE,
351+ где 0 представляет 0.0, а 255 представляет 1.0. Теперь вам понадобилось бы только 4 байта на цвет
352+ на вершину, экономия 75%.
353+ </p >
354+ <p >Давайте изменим наш код, чтобы делать это. Когда мы говорим WebGL, как извлекать наши цвета, мы бы использовали</p >
355+ <pre class =" prettyprint showlinemods " >
356+ var size = 4;
357+ * var type = gl.UNSIGNED_BYTE;
358+ * var normalize = true;
359+ var stride = 0;
360+ var offset = 0;
361+ gl.vertexAttribPointer(colorLocation, size, type, normalize, stride, offset);
362+ </pre >
363+ <p >И когда мы заполняем наш буфер цветами, мы бы использовали</p >
364+ <pre class =" prettyprint showlinemods " >
365+ // Заполняем буфер цветами для 2 треугольников
366+ // которые составляют прямоугольник.
367+ function setColors(gl) {
368+ // Выбираем 2 случайных цвета.
369+ var r1 = Math.random() * 256; // 0 до 255.99999
370+ var b1 = Math.random() * 256; // эти значения
371+ var g1 = Math.random() * 256; // будут обрезаны
372+ var r2 = Math.random() * 256; // когда сохранены в
373+ var b2 = Math.random() * 256; // Uint8Array
374+ var g2 = Math.random() * 256;
375+
376+ gl.bufferData(
377+ gl.ARRAY_BUFFER,
378+ new Uint8Array( // Uint8Array
379+ [ r1, b1, g1, 255,
380+ r1, b1, g1, 255,
381+ r1, b1, g1, 255,
382+ r2, b2, g2, 255,
383+ r2, b2, g2, 255,
384+ r2, b2, g2, 255]),
385+ gl.STATIC_DRAW);
386+ }
387+ </pre >
388+ <p >
389+ Вот этот пример.
390+ </p >
391+
392+ {{{example url="../webgl-2d-rectangle-with-2-byte-colors.html" }}}
393+ </div >
0 commit comments