Как создать базовую библиотеку WebGL

JavaScript WebGL
Как создать базовую библиотеку WebGL

Если вы хотите использовать возможности рендеринга WebGL через GPU, первая реакция многих студентов — использовать готовые проекты с открытым исходным кодом, такие как знаменитый Three.js. Но является ли их непосредственное применение единственным вариантом? Если вы хотите углубиться в основы WebGL или даже создать свои собственные колеса, с чего вам начать? Эта статья надеется использовать собственный практический опыт автора в качестве примера для популяризации некоторых знаний о дизайне базовой графической библиотеки.

задний план

Не так давно мыЭскизный дизайн веб-страницыДобавлена ​​возможность редактирования 3D текста. Вы можете сделать текст, изначально ограниченный двухмерной плоскостью, трехмерным и добавить к нему насыщенную текстуру, например:

В WebGL-рендеринге 3D-текста используется наша собственная разработка.Beamбазовая библиотека. Это не форк-магическая ревизия проекта с открытым исходным кодом, а позитивная реализация с нуля. Как автор Beam, опыт запуска нового колеса в производство, несомненно, дал мне многое, чем можно поделиться. Начнем с самого простого позиционирования и поговорим о базовой библиотеке WebGL.

Механизм рендеринга и базовая библиотека WebGL

Когда дело доходит до WebGL, люди обычно думают о проектах с открытым исходным кодом, таких как Three.js, которые чем-то похожи на «представление веб-интерфейса с помощью корзины семейства React». На самом деле, Three уже является довольно высокоуровневым движком 3D-рендеринга. Грубо говоря, между ней и базовой библиотекой WebGL, такой как Beam, есть сходства и различия:

  • Механизм рендеринга должен скрывать внутренние понятия стороны рендеринга, такие как WebGL, а базовая библиотека должна раскрывать эти понятия.
  • Механизм рендеринга также может иметь несколько концов рендеринга, таких как SVG/Canvas, а базовая библиотека фокусируется на одном конце рендеринга.
  • Механизм рендеринга предназначен для конкретной сцены, такой как 3D или 2D, базовая библиотека не делает таких предположений.
  • Механизмы рендеринга обычно тяжелее по размеру, а базовые библиотеки значительно легче.

На самом деле я предпочитаю сравнивать Three и Beam как React и jQuery:Один хочет максимально защитить сложность рендеринга, а другой хочет максимально упростить API, непосредственно управляющий рендерингом.. Ввиду высокой гибкости конвейера рендеринга графики вкупе со значительной разницей в весе (размер исходного кода Three превысил 1M, а эффект Tree Shaking не очень хорош) автор считает, что любая сцена, которую захочет Преследовать контроль может быть базовой библиотекой использования WebGL.

У сообщества есть популярная базовая библиотека WebGL, такая как Regl, что доказывает, что подобное колесо не является псевдотребованием.

Концептуальная абстракция WebGL

Прежде чем разрабатывать фактический API базовой библиотеки, нам нужно хотя бы понять, как работает WebGL. В коде WebGL много тривиальностей, и погружение в код может легко привести к тому, что мы потеряем из виду лес за деревьями. По мнению автора, концепции, которыми мы оперируем во всем приложении WebGL, на самом деле не более чем следующие:

  • Shaderшейдер, даобъект для хранения графовых алгоритмов. Шейдеры выполняются параллельно на графическом процессоре, вычисляя отдельные цвета миллионов пикселей на кадр, по сравнению с кодом JS, который выполняется в однопоточном режиме на ЦП.
  • Resourceресурсы, даобъект для хранения графических данных. Точно так же, как JSON становится данными веб-приложения, ресурсы — это данные, передаваемые шейдерам, включая большие массивы вершин, изображения текстур и элементы глобальной конфигурации.
  • Drawрисовать, даЗапрос на запуск шейдера после выбора ресурса. Чтобы отобразить реальную сцену, обычно требуется несколько наборов шейдеров и несколько ресурсов, и для завершения кадра несколько раз выполняется отрисовка вперед и назад. Перед каждым отрисовкой нам нужно выбрать шейдер, связать с ним разные ресурсы и один раз запустить конвейер рендеринга графики.
  • Commandкоманда, даВыполнить настройку перед рисованием. WebGL очень чувствителен. Перед каждым розыгрышем мы должны тщательно обращаться с конечным автоматом. Эти изменения состояния реализуются с помощью команд. Beam значительно упрощает ручное управление командами на основе некоторых соглашений, и, конечно же, вы также можете настраивать свои собственные команды.

Как эти понятия работают вместе? Пожалуйста, посмотрите на изображение ниже:

Буферы/текстуры/униформы на картинке — все типичные ресурсы. В кадре может быть несколько отрисовок, и для каждой отрисовки требуется шейдер и соответствующие ресурсы. Между отрисовками мы управляем состоянием WebGL с помощью команд. Это ментальная модель, которую я построил для WebGL, когда разрабатывал Beam.

Важно понять эту ментальную модель. Потому что дизайн Beam API полностью основан на этой модели. Рассмотрим подробнее реальный сценарий:

На картинке рисуем много сфер с разной текстурой. Рендеринг этого кадра можно разложить на приведенные выше концепции следующим образом:

  • шейдерЭто, несомненно, алгоритм рендеринга текстуры сферы. В классических 3D-играх для рендеринга объектов с разными текстурами часто необходимо переключаться между разными шейдерами. Но теперь, когда популярны алгоритмы рендеринга, основанные на физических характеристиках, эти сферы несложно визуализировать с помощью одного и того же шейдера.
  • ресурсОн включает в себя большой сегмент данных вершин сферы, данные изображений текстур материалов и элементы конфигурации, такие как параметры освещения и матрицы преобразования.
  • рисоватьЭто делается многократно. Мы выбираем каждый раз рисовать сферу, и каждое рисование также запускает конвейер рендеринга графики один раз.
  • ЗаказЭто изменения состояния, выполняемые между отрисовками соседних сфер.

Как понять изменение состояния? Думайте о WebGL как об инструменте с множеством переключателей и интерфейсов. Перед каждым нажатием клавиши «Пуск» (для выполнения рисования). Нужно настроить кучу переключателей, а потом подключить провод к шейдеру, и кучу проводов к ресурсу, вот так:

Другим важным моментом является то, что хотя мы уже знаем, что кадр может быть сгенерирован многократной отрисовкой, и каждая отрисовка соответствует выполнению конвейера рендеринга графики. Но что такое так называемый конвейер рендеринга графики? Это соответствует этому графику:

Конвейер рендеринга обычно относится к процессу от данных вершин к пикселям на таком графическом процессоре. В современных программируемых графических процессорах некоторые этапы конвейера можно программировать. В стандарте WebGL это соответствует этапам вершинного и фрагментного шейдера, выделенным синим цветом на диаграмме. Вы можете думать о них как о двух функциях, которые вам нужно написать. Как правило, они выполняют следующие работы:

  • Вершинный шейдер берет необработанные координаты вершин и выводит преобразованные координаты в соответствии с вашими потребностями.
  • Фрагментный шейдер принимает местоположение пикселя и выводит цвет пикселя, рассчитанный в соответствии с вашими потребностями.

Это базовые концепции WEBGL, которые автор начнет с точки зрения разработчика базовой библиотеки.

Базовый дизайн API

Хотя приведенные выше главы вообще не касались кода, после полного понимания концепций кодирование становится само собой разумеющимся. Поскольку команды могут быть автоматизированы, при разработке Beam я определил только три основных API, а именно

  • beam.shader
  • beam.resource
  • beam.draw

Каждый из них соответствует управлению шейдерами, ресурсами и рисованием. Давайте посмотрим, как нарисовать треугольник Hello World в WebGL на основе этого дизайна:

Пример кода для Beam выглядит следующим образом:

import { Beam, ResourceTypes } from 'beam-gl'
import { MyShader } from './my-shader.js'
const { VertexBuffers, IndexBuffer } = ResourceTypes

const canvas = document.querySelector('canvas')
const beam = new Beam(canvas)

const shader = beam.shader(MyShader)
const vertexBuffers = beam.resource(VertexBuffers, {
  position: [
    -1, -1, 0, // vertex 0, bottom left
    0, 1, 0, // vertex 1, top middle
    1, -1, 0 // vertex 2, bottom right
  ],
  color: [
    1, 0, 0, // vertex 0, red
    0, 1, 0, // vertex 1, green
    0, 0, 1 // vertex 2, blue
  ]
})
const indexBuffer = beam.resource(IndexBuffer, {
  array: [0, 1, 2]
})

beam
  .clear()
  .draw(shader, vertexBuffers, indexBuffer)

Вот несколько важных фрагментов API один за другим. Прежде всего, естественно использовать Canvas для инициализации Beam:

const canvas = document.querySelector('canvas')
const beam = new Beam(canvas)

Затем мы используемbeam.shaderдля создания экземпляра шейдера здесьMyShaderпоговорим об этом позже:

const shader = beam.shader(MyShader)

После того, как шейдер готов, пришло время подготовить ресурсы. Для этого нам нужно использоватьbeam.resourceAPI для создания данных треугольника. Эти данные загружаются в разные буферы, и Beam используетVertexBuffersтипы для их выражения. Треугольник имеет 3 вершины, и каждая вершина имеет два атрибута, а именноpositionа такжеcolor, каждое свойство соответствует отдельному буферу. Таким образом, мы можем без труда объявить эти данные вершин с помощью обычного JS-массива (или TypedArray). Beam загрузит их в GPU для вас:

Обратите внимание на различие между WebGLвершинаа такжекоординироватьконцепция. Вершина может содержать не только атрибут координаты точки, но и другие атрибуты, такие как вектор нормали, цвет и т. д. Эти атрибуты могут быть введены в вершинный шейдер для вычисления.

const vertexBuffers = beam.resource(VertexBuffers, {
  position: [
    -1, -1, 0, // vertex 0, bottom left
    0, 1, 0, // vertex 1, top middle
    1, -1, 0 // vertex 2, bottom right
  ],
  color: [
    1, 0, 0, // vertex 0, red
    0, 1, 0, // vertex 1, green
    0, 0, 1 // vertex 2, blue
  ]
})

Буферы с вершинами обычно используют очень компактные наборы данных. Мы можем определить подмножество или надмножество этих данных, которые будут использоваться для фактического рендеринга, чтобы уменьшить избыточность данных и повторно использовать больше вершин. Для этого нам необходимо ввестиIndexBufferКонцепция, которая определяет индексы вершин, используемые при рендеринге:

В этом примере каждый нижний индекс соответствует 3 позициям в массиве вершин.

const indexBuffer = beam.resource(IndexBuffer, {
  array: [0, 1, 2]
})

Наконец, мы можем перейти к этапу рендеринга. первое использованиеbeam.clearчтобы очистить текущий кадр, затемbeam.drawвходящийОбъект шейдера и любое количество объектов ресурсовТолько что:

beam
  .clear()
  .draw(shader, vertexBuffers, indexBuffer)

нашbeam.drawAPI очень гибкий. Если у вас есть несколько шейдеров и несколько ресурсов, вы можете комбинировать их по желанию, чтобы завершить рисунок в цепочке, визуализируя сложные сцены. так:

beam
  .draw(shaderX, ...resourcesA)
  .draw(shaderY, ...resourcesB)
  .draw(shaderZ, ...resourcesC)

Не забудьте еще одно упущение: как определить алгоритм рендеринга для треугольников? Это вMyShaderуказано в переменной. На самом деле это схема шейдера, например:

import { SchemaTypes } from 'beam-gl'

const vertexShader = `
attribute vec4 position;
attribute vec4 color;
varying highp vec4 vColor;
void main() {
  vColor = color;
  gl_Position = position;
}
`
const fragmentShader = `
varying highp vec4 vColor;
void main() {
  gl_FragColor = vColor;
}
`

const { vec4 } = SchemaTypes
export const MyShader = {
  vs: vertexShader,
  fs: fragmentShader,
  buffers: {
    position: { type: vec4, n: 3 },
    color: { type: vec4, n: 3 }
  }
}

Схема шейдера в этом луче состоит из строк вершинного шейдера, строк фрагментного шейдера и других полей схемы. Грубо говоря, шейдер выполняется один раз для каждой вершины, а фрагментный шейдер — один раз для пикселя. Эти шейдеры написаны на языке GLSL из стандарта WebGL. В WebGL вершинные шейдеры будутgl_Positionвыводить как координатную позицию, в то время как фрагментный шейдер будетgl_FragColorВывод в виде цвета пикселей. Также называетсяvColorИзменяющаяся переменная, которая передается от вершинного шейдера к фрагментному шейдеру и автоматически интерполируется. Наконец, вотpositionа такжеcolorЭти две атрибутивные переменные и предыдущаяvertexBuffersсоответствует ключу в . Это соглашение Beam для автоматизации команд.

Расширенное использование API

Я полагаю, что у многих студентов все еще будут сомнения в удобстве использования этого дизайна, ведь даже если треугольники можно отрисовать по этому набору правил, это может не доказать, что он подходит для более сложных приложений. На самом деле, Beam действительно использовался в разных сценариях внутри нас, вот еще несколько примеров. Подробное введение в эти примеры можно найти в документации Beam, написанной автором.

Рендеринг 3D-объектов

Треугольники, которые мы только что визуализировали, — это всего лишь 2D-графика. Как визуализировать кубы, сферы и более сложные 3D-модели? На самом деле это не сложно, лишь бы было больше конфигураций вершин и шейдеров. Давайте используем Beam для рендеринга этой 3D-сферы в качестве примера:

Трехмерная графика также состоит из треугольников, а треугольники по-прежнему состоят из вершин. Ранее наши вершины содержалиpositionа такжеcolorАтрибуты. А для 3D-сфер нам нужно использоватьpositionа такжеnormalАтрибуты. Эта нормаль является вектором нормали, который содержит ориентацию поверхности сферы в положении вершины, что очень важно для расчетов освещения.

Не только это, но и для преобразования вершин из 3D-пространства в 2D-пространство нам нужна «камера», состоящая из матриц. Для каждой вершины, переданной в вершинный шейдер, нам нужно применить к ней эти матрицы преобразования. Эти матрицы глобально уникальны для шейдеров, работающих параллельно. Это то, что есть в WebGLuniformsконцепция.UniformsТакже тип ресурса в Beam, который содержит различные глобальные конфигурации в шейдерах, такие как положение камеры, цвет линии, сила эффекта и т. д.

Итак, для рендеринга самого простого шара мы можем повторно использовать фрагментный шейдер из приведенного выше примера, просто обновив вершинный шейдер, чтобы он выглядел так:

attribute vec4 position;
attribute vec4 normal;

// 变换矩阵
uniform mat4 modelMat;
uniform mat4 viewMat;
uniform mat4 projectionMat;

varying highp vec4 vColor;

void main() {
  gl_Position = projectionMat * viewMat * modelMat * position;
  vColor = normal; // 将法向量可视化
}

Поскольку мы добавили юниформ-переменные в шейдер, в Схему нужно добавить соответствующийuniformsПоле:

const identityMat = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
const { vec4, mat4 } = SchemaTypes

export const MyShader = {
  vs: vertexShader,
  fs: fragmentShader,
  buffers: {
    position: { type: vec4, n: 3 },
    normal: { type: vec4, n: 3 }
  },
  uniforms: {
    // The default field is handy for reducing boilerplate
    modelMat: { type: mat4, default: identityMat },
    viewMat: { type: mat4 },
    projectionMat: { type: mat4 }
  }
}

Затем мы можем перейти к аккуратному API в Beam:

const beam = new Beam(canvas)

const shader = beam.shader(NormalColor)
const cameraMats = createCamera({ eye: [0, 10, 10] })
const ball = createBall()

beam.clear().draw(
  shader,
  beam.resource(VertexBuffers, ball.data),
  beam.resource(IndexBuffer, ball.index),
  beam.resource(Uniforms, cameraMats)
)

Код для этого примера можно найти по адресуBasic Ballнайти в.

Beam — это библиотека WebGL, не предназначенная для 3D, поэтому такие понятия, как геометрические объекты, матрицы преобразования, камеры и т. д., не являются ее частью. Для простоты использования примеры Beam включают соответствующий код Utils, но не требуйте от них слишком многого.

Добавить анимацию

Как перемещать объекты в WebGL? Можно, конечно, рассчитать новую позицию после движения и обновить буфер, но это может быть медленно. Другой способ — напрямую обновить упомянутую выше матрицу преобразования. Эти матрицы являются короткими, компактными и легко обновляемыми ресурсами униформы.

пройти черезrequestAnimationFrameAPI, мы можем легко заставить эту сферу двигаться:

const beam = new Beam(canvas)

const shader = beam.shader(NormalColor)
const ball = createBall()
const buffers = [
  beam.resource(VertexBuffers, ball.data),
  beam.resource(IndexBuffer, ball.index)
]
let i = 0; let d = 10
const cameraMats = createCamera({ eye: [0, d, d] })
const camera = beam.resource(Uniforms, cameraMats)

const tick = () => {
  i += 0.02
  d = 10 + Math.sin(i) * 5
  const { viewMat } = createCamera({ eye: [0, d, d] })

  // 更新 uniform 资源
  camera.set('viewMat', viewMat)

  beam.clear().draw(shader, ...buffers, camera)
  requestAnimationFrame(tick)
}
tick() // 开始 Render Loop

здесьcameraПеременная — это лучUniformsЭкземпляр ресурса, данные которого хранятся в форме "ключ-значение". Вы можете добавлять разные универсальные ключи или выше. когдаbeam.drawПри срабатывании в GPU будут загружены только юниформ-данные, соответствующие шейдеру.

Код для этого примера можно найти по адресуZooming Ballнайти в.

Доступ к буферным ресурсам также можно получить через аналогичныйset()метод обновления, хотя для более тяжелых нагрузок в WebGL это может быть медленнее.

визуализировать изображение

мы виделиVertexBuffers / IndexBuffer / UniformsСуществует три типа ресурсов. Если мы хотим визуализировать изображения, нам также понадобится последний ключевой тип ресурса, а именноTextures. Простейшим примером этого является 3D-бокс с такой текстурой:

Для графики, требующей текстур, вpositionа такжеnormalКроме того, нам также потребуется дополнительныйtexCoordАтрибут для выравнивания изображения по соответствующему положению графики, это значение также интерполируется и передается во фрагментный шейдер. Взгляните на вершинный шейдер на этом этапе:

attribute vec4 position;
attribute vec4 normal;
attribute vec2 texCoord;

uniform mat4 modelMat;
uniform mat4 viewMat;
uniform mat4 projectionMat;

varying highp vec2 vTexCoord;

void main() {
  vTexCoord = texCoord;
  gl_Position = projectionMat * viewMat * modelMat * position;
}

и новый фрагментный шейдер:

uniform sampler2D img;
uniform highp float strength;

varying highp vec2 vTexCoord;

void main() {
  gl_FragColor = texture2D(img, vTexCoord);
}

Теперь нам нужно добавить в схемуtexturesПоле:

const { vec4, vec2, mat4, tex2D } = SchemaTypes
export const MyShader = {
  vs: vertexShader,
  fs: fragmentShader,
  buffers: {
    position: { type: vec4, n: 3 },
    texCoord: { type: vec2 }
  },
  uniforms: {
    modelMat: { type: mat4, default: identityMat },
    viewMat: { type: mat4 },
    projectionMat: { type: mat4 }
  },
  textures: {
    img: { type: tex2D }
  }
}

Наконец, логика рендеринга:

const beam = new Beam(canvas)

const shader = beam.shader(MyShader)
const cameraMats = createCamera({ eye: [10, 10, 10] })
const box = createBox()

loadImage('prague.jpg').then(image => {
  const imageState = { image, flip: true }
  beam.clear().draw(
    shader,
    beam.resource(VertexBuffers, box.data),
    beam.resource(IndexBuffer, box.index),
    beam.resource(Uniforms, cameraMats),
    // 这个 'img' 键用来与着色器相匹配
    beam.resource(Textures, { img: imageState })
  )
})

Вот как основные текстуры используются в Beam. Поскольку у нас есть прямой контроль над шейдером изображения, поверх него легко добавить эффекты обработки изображения.

Код для этого примера можно найти по адресуImage Boxнайти в.

Здесь могут пожелатьcreateBoxзаменитьcreateBallпытаться?

Рендеринг нескольких объектов

Как визуализировать несколько объектов? покажи намbeam.drawГибкость API:

Для рендеринга нескольких сфер и нескольких кубов нам нужно всего два набораVertexBuffersа такжеIndexBuffer, один набор шаров и другой набор кубиков:

const shader = beam.shader(MyShader)
const ball = createBall()
const box = createBox()
const ballBuffers = [
  beam.resource(VertexBuffers, ball.data),
  beam.resource(IndexBuffer, ball.index)
]
const boxBuffers = [
  beam.resource(VertexBuffers, box.data),
  beam.resource(IndexBuffer, box.index)
]

Затем внутри цикла for мы можем легко нарисовать их с различными универсальными конфигурациями. покаbeam.drawпредыдущее обновлениеmodelMat, мы можем обновить положение объекта в мировой системе координат, чтобы он отображался в разных позициях на экране:

const cameraMats = createCamera(
  { eye: [0, 50, 50], center: [10, 10, 0] }
)
const camera = beam.resource(Uniforms, cameraMats)
const baseMat = mat4.create()

const render = () => {
  beam.clear()
  for (let i = 1; i < 10; i++) {
    for (let j = 1; j < 10; j++) {
      const modelMat = mat4.translate(
        [], baseMat, [i * 2, j * 2, 0]
      )
      camera.set('modelMat', modelMat)
      const resources = (i + j) % 2
        ? ballBuffers
        : boxBuffers

      beam.draw(shader, ...resources, camera)
    }
  }
}

render()

здесьrenderфункционировать, чтобыbeam.clearначни, потом следуй комплексуbeam.drawЛогика рендеринга.

Код для этого примера можно найти по адресуMulti Graphicsнайти в.

закадровый рендеринг

Рендеринг вне экрана может быть достигнут в WebGL с помощью объекта буфера кадра, который визуализирует вывод в текстуру. Beam в настоящее время имеет соответствующийOffscreenTargetТип ресурса, но учтите, что этот тип нельзя добавитьbeam.drawиз.

Например, логика рендеринга по умолчанию выглядит так:

beam
  .clear()
  .draw(shaderX, ...resourcesA)
  .draw(shaderY, ...resourcesB)
  .draw(shaderZ, ...resourcesC)

через необязательныйoffscreen2Dметод, эта логика рендеринга может быть легко вложена в область действия функции следующим образом:

beam.clear()
beam.offscreen2D(offscreenTarget, () => {
  beam
    .draw(shaderX, ...resourcesA)
    .draw(shaderY, ...resourcesB)
    .draw(shaderZ, ...resourcesC)
})

Это перенаправляет вывод на закадровую текстуру.

Код для этого примера можно найти по адресуBasic Meshнайти в.

Другие методы рендеринга

Физически обоснованный рендеринг (PBR) для нормализации текстур рендеринга и картирование теней для рендеринга теней — два основных передовых метода рендеринга для рендеринга в реальном времени. Автор также реализует оба примера в Beam, например шейдер PBR, показанный выше:

В этих примерах опущены некоторые тривиальности и больше внимания уделяется удобочитаемости кода. Вы можете посмотреть здесь:

  • Material BallПоказан рендеринг базового шейдера PBR.
  • Basic ShadowПоказывает пример карты теней.

Как было сказано выше, в настоящее времяЭскизный дизайн Веб-версияФункция 3D-текста в , также реализована за счет возможности PBR Beam. Трехмерный текст, подобный этому:

или это:

Все они рендерятся с помощью Beam. Конечно, Beam отвечает только за часть рендеринга, непосредственно связанную с WebGL, а поверх него есть рендеринг 3D-текста, используемый во встроенном редакторе плоскостей после нашей настройки, и алгоритмы, связанные с геометрическим преобразованием текста. Этот код включает в себя некоторые из наших патентов и не будет открыт для Beam. На самом деле, легко реализовать свой собственный специализированный рендерер на основе Beam, чтобы добиться оптимизации для конкретных сцен. Это также является ожиданием автора для такой базовой библиотеки WebGL.

В примерах, поставляемых с Beam, также показаны эти примеры, основанные на Beam:

  • Загрузка объектной сетки
  • конфигурация текстуры
  • Классический алгоритм освещения
  • Соединяемые фильтры изображений
  • Визуализация текстуры глубины
  • Основные эффекты частиц
  • Конфигурация расширения WebGL
  • Инкапсуляция средства визуализации верхнего уровня

BeamОткрытый исходный код, приветствуем PR, чтобы предоставить новые примеры :)

Благодарности и заключение

В процессе внедрения Beam общение с представителями отрасли на уровне проектирования API вдохновило автора. Руководство многих старших сотрудников внутри и за пределами компании также очень полезно, когда автору приходится принимать ключевые решения. В конце концов, этот план можно реализовать, а самое главное — это поддержка фронтендеров в группе.Много деталей работы для всех.

На самом деле, прежде чем взяться за нужды 3D-текста, у автора не было более сложного WebGL-опыта, чем рисование множества кубов. Но пока вы начинаете учиться с азов, всего за несколько месяцев достаточно ознакомиться с WebGL на основе выполнения требований к продукту, и, кстати, вы можете осадить такое колесо. Так что на самом деле не нужно использовать «это выше моих сил» в качестве предлога, чтобы ставить себе ограничения и ограничивать себя определенной зоной комфорта. Как инженеры мы можем сделать гораздо больше!

Что же касается необходимости собственного существования Beam, то, по крайней мере, в Китае, автор не обнаружил, что есть продукт с открытым исходным кодом, более соответствующий идеальному дизайну, чем он в этом подразделе базовой библиотеки WebGL. Это не значит, что отечественная техническая мощь плохая, ClayGL и Xie Guanglei очень хороши. Отличие в том, что они решают задачи более высокого уровня и ближе к рядовым разработчикам, чем Beam. Сравнивать их с Beam — все равно, что сравнивать Vue с упрощенным React Reconciler.

Чем больше я этим занимаюсь, тем больше понимаю, что это довольно узкоспециализированная область. Это означает, что такие технические продукты могут быть трудно опробованы и признаны основными группами в сообществе.

Однако есть некоторые вещи, которых в конце концов нельзя избежать, и всегда есть люди, которым приходится это делать.

Я в первую очередь фронтенд-разработчик. Если вы заинтересованы в редактировании структурированных веб-данных, рендеринге WebGL, разработке гибридных приложений или мыслях компьютерных энтузиастов, подписывайтесь на меня или на мою официальную учетную запись.color-albumОй :)