Ускоряем рендер сцены в three.js путем объединения мешей в один

от автора

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

Пример блока на сайте с 3D моделью

Пример блока на сайте с 3D моделью

Известно, что, чем больше мешей внутри сцены, тем чаще нашему приложению требуется задействовать дорогостоящие операции по загрузке данных в видеокарту устройства пользователя (так называемые draw calls).

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

Реализация алгоритма

Напишем фрагмент кода с помощью библиотеки three.js, который будет обрабатывать меши в нашей сцене (массив meshes) путем объединения мешей с одним и тем же материалом в один.

Что мы делаем:

  • Составляем массив мешей нашего объекта, сгруппированных по материалам.

  • Для каждой группы создаем новый меш, полученный путем объединения геометрий всех мешей данной группы.

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

  • Повторяем действия для остальных групп.

const meshesByMaterial = [];  for (let i = 0; i < meshes.length; i++)  {   const mesh = meshes[i];   const findIndex = meshesByMaterial     .findIndex(item => item       .find(itemMesh => itemMesh.material === mesh.material) !== undefined);      if (findIndex === -1)   {     meshesByMaterial.push([mesh]);   }   else      {     meshesByMaterial[findIndex].push(mesh);   } }  for (let i = 0; i < meshesByMaterial.length; i++) {   const meshesCur = meshesByMaterial[i];      if (meshesCur.length < 2)   {     continue;   }      meshesMerge(meshesCur); }

Рассмотрим функцию соединения мешей между собой (результат объединения будет в первом меше):

meshesMerge(meshes) {   const meshFirst = meshes[0];      const geometries = meshes.map((mesh, index) =>   {     const geometry = mesh.geometry.clone();     mesh.updateMatrixWorld();     geometry.applyMatrix4(mesh.matrixWorld);     return geometry;   });      const mergeGeometry = geometriesMerge(geometries);      if (mergeGeometry === null)   {     return null;   }      mergeGeometry.applyMatrix4(meshFirst.matrixWorld.clone().invert());   meshFirst.geometry = mergeGeometry;      for (let i = 1; i < meshes.length; i++)   {     meshes[i].removeFromParent();   }      return meshFirst; }

На что стоит обратить внимание:

  • При подготовке списка геометрий для их последующего слияния важно произвести операцию клонирования.

  • Функция geometriesMerge – стандартная утилита внутри пакета three.js.

  • У результирующей геометрии необходимо скорректировать мировую матрицу исходя из положения итогового меша.

Заключение

Если в сцене много 3D объектов, в которых материалов намного меньше числа мешей, то такой способ может существенно ускорить отклик интерфейса на действия пользователя.

Пример применения алгоритма можно посмотреть в данном кейсе[ссылка удалена модератором].


ссылка на оригинал статьи https://habr.com/ru/articles/747200/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *