Как установить цвет пикселя на холсте с помощью WebGL?
Я очень новичок в WebGL, но не Javascript или Canvas. По сути, мне нужен очень быстрый способ изменить цвет пикселя на холсте в любой координате. Я чувствую, что это можно сделать с помощью шейдеров фрагментов WebGL. Возможно ли это, и есть ли лучший способ? Как мне это сделать?
3 ответов
это не исчерпывающее руководство по рендерингу, потому что оно не включает биты об управлении шейдерами; вместо этого оно фокусируется на том, как фактически выполняется рисование примитивов WebGL и как использовать ортогональную проекцию для точного расположения вершин на экране.
для получения дополнительной информации, я настоятельно рекомендую эти источники:
WebGL делает весь свой чертеж с объектами буфера вершин (VBOs), поэтому вам нужно скомпилировать все ваши данные в 3D-вершины и отправить их на видеокарту как можно меньше VBOs (для максимальной производительности).
VBO может быть создан в WebGL так:
var vbo = gl.createBuffer();
затем вам нужно отправить данные в буфер, обычно в виде Float32Array
. Если у вас уже есть данные в виде обычного массива JavaScript, то вы можете использовать new Float32Array(jsArray)
инициализации Float32Array
С jsArray
'ы содержание. Старайтесь делать это редко. Типизированные массивы очень быстры, но инициализируются очень медленно. Лучше всего создавать их один раз и по возможности использовать повторно.
после Float32Array
, вы можете передать данные в буфер, как так:
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, float32Data, gl.DYNAMIC_DRAW);
вам нужно будет выполнить bufferData
или bufferSubData
звонить каждый время изменения данных.
к этому времени данные находятся на видеокарте, поэтому вам нужно только на самом деле ничья это:
// bind the VBO to be drawn if you haven't already
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
// send the vertex data to the shader program
gl.vertexAttribPointer(vertexAttributeLocation, 3, gl.FLOAT, false, 0, 0);
// draw the buffer
gl.drawArrays(gl.POINTS, 0, float32Data.length / 3);
обратите внимание, что хотя видеокарта может содержать довольно много VBOs, вы должны использовать как можно меньше из них, потому что больше drawArrays
вызовы, которые вы должны выполнить, тем медленнее вещи собираются получить. Действительно, если вы визуализируете только один пиксель за раз в данном VBO, он будет слишком медленным для запуска.
в причина длины Float32Array
делится на 3, потому что каждый отдельный элемент данных является координатой 3D (X, Y, Z), поэтому каждый элемент данных состоит из 3 компонентов float. Обратите внимание, что первый аргумент gl.drawArrays
был gl.POINTS
. Это указывает видеокарте нарисовать одну точку(по умолчанию один пиксель) для каждого элемента в массиве. Есть другие способы рисовать, и если вам нужно заполнить группа пикселей, один из других режимов рисования (например,gl.TRIANGLES
) может быть больше тебе нравится.
что касается освещения определенных пикселей, это зависит от того, как написан шейдер, но скорее всего вы используете матрицу modelview и матрицу проекции. Матрица modelview представляет ориентацию камеры относительно рисуемых точек, а матрица проекции представляет размеры камеры (ширину и высоту, поле зрения, ближайший и Дальний видимые диапазоны и т. д.). Поэтому, если вы хотите осветить определенные пиксели, ваш лучший выбор это применить орфографический матрица проекции с шириной и высотой, равными ширине и высоте холста; и матрица modelview, установленная на идентичность (без преобразования). В ортографической проекции объекты не сжимаются по мере удаления от камеры, поэтому они очень полезны для указания точных положений относительно экрана. Кроме того, если вы дадите им правильные размеры, вы можете расположить вершины очень точно -- в определенных пикселей, если хотите.
различные библиотеки матриц работают по-разному, но, например, для настройки ортогональной матрицы в gl-matrix, вы можете сделать это так:
var ortho = mat4.ortho(left, right, bottom, top, near, far);
точные числа зависят от ваших предпочтений; если вы хотите поместить начало координат (0, 0) в левом нижнем углу холста, вы сделаете так:
var ortho = mat4.ortho(0, canvas.width, 0, canvas.height, 0.01, 200);
обратите внимание, что значение Z каждой точки все еще должно лежать между near
и far
для того, чтобы быть оказано, однако, и near
значение не может быть установлено в 0
.
Дайте мне знать, если это требует уточнения.
Если вы просто хотите рисовать одиночные пиксели, вам, вероятно, лучше использовать canvas 2d.
в противном случае вы, вероятно, можете понять это из этого урока, который рисует прямоугольники в единицах пикселей, поэтому установите ширину и высоту в 1x1, и вы получите отдельные пиксели.
вы можете использовать GL_POINTS при рисовании. В основном вы передадите массив точек на GPU вместе с цветами и позициями. Затем вы вызываете drawArrays с правильными данными.
Это может быть слишком связано с другими вещами, но это может помочь ты:
https://github.com/funkaster/ChesterGL/blob/master/chesterGL/primitivesBlock.js#L126
https://github.com/funkaster/ChesterGL/blob/master/chesterGL/primitivesBlock.js#L260
вот как я визуализирую несколько точек в примитивном блоке для chesterGL.