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

Пример блока на сайте с 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 объектов, в которых материалов намного меньше числа мешей, то такой способ может существенно ускорить отклик интерфейса на действия пользователя.

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

Комментарии (0)