Моделирование вихревых частиц

В этой истории рассматривается реализация текстуры skybox с использованием Rust и WebGL для веб-просмотрщика для моделирования вихревых частиц, описанного в этой истории. Текстура скайбокса — это поле с текстурами на нем […], чтобы выглядеть как то, что находится очень далеко, включая горизонт (WebGl2Fundamentals WebGL2 SkyBox).

Скайбокс обеспечивает глубину и контекст сцены WebGL. Используемое изображение скайбокса называется miramar от Hipshot и опубликовано здесь.

Исходный код доступен на GitHub, а живую версию можно посмотреть на CFD-webassembly.com.

Взгляды/мнения, выраженные в этой истории, являются моими собственными. Эта история связана с моим личным опытом и выбором и снабжена информацией в надежде, что она будет полезной, но без каких-либо гарантий.

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

Реализация привела к размышлению над вопросом: должны ли изображения загружаться в JavaScript, а затем передаваться в Rust/WebAssembly или непосредственно в Rust? Я выбрал последнее, чтобы сохранить код, относящийся к скайбоксу, внутри один файл Rust — program_skybox.rs.

Предварительные

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

  • camera.rs изменен, чтобы разрешить отдельное извлечение матриц вида и проекции;
  • методы признаков View draw и redraw изменены, чтобы использовать структуру Camera вместо структуры Matrix4.

Выполнение

Отрисовка скайбокса реализована в структуре ProgramSkyBoxfile viewer/program_skybox.rs и реализует трейт View.

Программа WebGL, состоящая из вершинных и фрагментных шейдеров, почти дословно взята из шейдеров WebGL2 SkyBox и скомпилирована с использованием ранее созданных вспомогательных функций. Программа компилируется при первой необходимости, а затем повторно используется.

Рендеринг скайбокса реализован в методе redraw — метод draw просто вызывает redraw — так как рендеринг не зависит от состояния симуляции.

Реализация следует тем же шагам, что и в реализации WebGL2 SkyBox, но немного реорганизована следующим образом:

  • Установите программу WebGL в текущий контекст рендеринга:
  • Для реализации скайбокса мы не конвертируем пространственные 3D-координаты в пространство обзора, а вместо этого создаем четырехугольник, который покрывает все пространство обзора и напрямую использует координаты пространства обзора. Текстура применяется к этому четырехугольнику в зависимости от направления взгляда и проекции. Следующий фрагмент кода показывает определение и назначение этого четырехугольника, который снова очень похож на реализацию WebGL2 SkyBox.
  • Текстуры, применяемые к скайбоксу, также известные как кубическая карта, определяются и применяются следующим образом с использованием слоя текстуры 0. Дополнительная информация о реализации загрузки текстуры и методе assign_textures представлена ​​в следующем разделе. Этот шаг является последним и выполняется только во время первого вызова redraw.
  • Следующий код запускается при каждом вызове redraw, поскольку он относится к направлению камеры, которое может меняться между каждым вызовом redraw. Он использует матрицу вида для определения направления камеры и комбинирует ее с проекцией вида, чтобы определить взаимосвязь между местоположением пространства обзора и текстурой, хотя я понимаю матричные операции (например, строки с 10 по 14 меняют местами координаты y и z). ), я не до конца понимаю, как инверсия произведения матрицы проекции и вида соотносится с текстурой карты куба. Поэтому, пожалуйста, обратитесь к статье о WebGL2 SkyBox для получения более подробной информации по этой теме…
  • Наконец, функция рендеринга вызывается после настройки параметров рендеринга в соответствии с реализацией WebGL2 SkyBox.

Это касается реализации аспекта рендеринга WebGL, за исключением загрузки текстуры и метода assign_texture, вызываемого при применении текстуры.

Загрузка и назначение текстур

Ранее я упоминал, что изображения текстуры напрямую загружаются в Rust/WebAssembly. В статье Как загружать текстуры в Rust/WebGl представлен подход с использованием элемента HtmlImageElement и связанного с ним элемента обратного вызова on_load — при этом упоминается, что удаление замыкания требует тщательного рассмотрения, поскольку оно вызывает утечку памяти в ржавчине.

Я решил использовать fetchAPI для загрузки содержимого изображения, а затем преобразовать это содержимое в файл ImageBitmap. Эти функции (и другие) используют промисы вместо обратного вызова и, следовательно, облегчают требование отбрасывания закрытия. Промисы JavaScript обрабатываются как фьючерсы Rust с использованием крейта wasm-bindgen-futures — см. Работа с промисом JS и фьючерсом Rust в руководстве wasm-bindgen.

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

Загрузка текстур с помощью fetchAPI и преобразование в ImageBitmap выполняется, как показано ниже. Один вызов выборки выполняется для загрузки одного изображения, которое объединяет все 6 текстур, необходимых для применения к 6 граням кубической карты. Координаты текстур в изображении хранятся с помощью структуры CubeMapTexSxSySw.

Загруженный ImageBitmap используется вместе с параметрами x, y и w, хранящимися в объекте CubeMapTexSxSySw, для идентификации и применения соответствующей части изображения к каждой текстуре карты куба в методе assign_textures. Соответствующая часть изображения извлекается с помощью файла HtmlCanvasElement. Первоначально я пытался использовать метод texSubImage2d, но безуспешно — аналогично исходному постерному запросу на StackOverflow.

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