Эта статья является частью серии статей о three.js. Первая была об основах. Если вы её еще не читали, советую вам сделать это.
Three.js имеет большое количество примитивов. Примитивы, как правило, представляют собой трехмерные фигуры, которые генерируются во время выполнения с помощью набора параметров.
Примитивы используются для таких вещей, как сфера для глобуса или куча прямоугольников для рисования трехмерного графика. Особенно часто используются примитивы для экспериментов и начала работы с 3D. Для большинства 3D-приложений художник чаще всего создает 3D-модели в программе 3D-моделирования. Позже в этой серии мы рассмотрим создание и загрузку данных из нескольких программ 3D-моделирования. А сейчас давайте рассмотрим некоторые из доступных примитивов.
TextGeometry
и TextGeometry
соответственно.wireframe: true
вы получите только одну линию. А передача этой triangle geometry в WireframeGeometry
создаст новую геометрию, которая имеет 3 отрезка линий, используя 6 точек..Мы рассмотрим создание пользовательской геометрии в другой статье. А пока давайте создадим пример создания каждого типа примитива. Начнем с примеров из предыдущей статьи.
Близ вершины давайте установим цвет фона в светло-серый
const scene = new THREE.Scene(); +scene.background = new THREE.Color(0xAAAAAA);
Камера должна изменить положение, чтобы мы могли видеть все объекты.
-const fov = 75; +const fov = 40; const aspect = 2; // the canvas default const near = 0.1; -const far = 5; +const far = 1000; const camera = new THREE.PerspectiveCamera(fov, aspect, near, far); -camera.position.z = 2; +camera.position.z = 120;
Давайте добавим функцию, addObject
, которая добавляет
объект Object3D
на сцену в позицию x, y.
const objects = []; const spread = 15; function addObject(x, y, obj) { obj.position.x = x * spread; obj.position.y = y * spread; scene.add(obj); objects.push(obj); }
Давайте также сделаем функцию для создания случайно раскрашенного материала.
Мы будем использовать особенность Color
которая позволяет вам установить цвет
на основе оттенка, насыщенности и яркости (hue, saturation, luminance).
hue
идет от 0 до 1 вокруг цветового круга с красным на 0,
зеленым на .33 и синим на .66. saturation
изменяется от 0 до 1, где 0 не имеет цвета, а 1 наиболее насыщен.
luminance
изменяется от 0 до 1, где 0 - черный, 1 - белый,
а 0.5 максимальное количество цвета. Другими словами,
luminance
от 0,0 до 0,5 цвет будет изменяться с черного на hue
.
От 0,5 до 1,0 цвет изменится hue
на белый.
function createMaterial() { const material = new THREE.MeshPhongMaterial({ side: THREE.DoubleSide, }); const hue = Math.random(); const saturation = 1; const luminance = .5; material.color.setHSL(hue, saturation, luminance); return material; }
Мы также передаем материалу side: THREE.DoubleSide
.
Это говорит three нарисовать обе стороны треугольников,
которые составляют форму. Для сплошной (solid) формы,
такой как сфера или куб, обычно нет причин рисовать
задние стороны треугольников, поскольку все они обращены
внутрь фигуры. В нашем случае мы рисуем несколько вещей,
таких как PlaneGeometry
и ShapeGeometry
которые являются двухмерными и поэтому не имеют внутренней
части. Без установки side: THREE.DoubleSide
они исчезнут,
при взгляде на их задние стороны.
Я должен отметить, что отрисовка быстрее, когда не установлено
side: THREE.DoubleSide
в реальной работе, мы бы устанавливали
его только для материалов, которые действительно в этом нуждаются,
но в этом случае мы не рисуем слишком много, поэтому нет
причин для беспокойства.
Давайте создадим функцию addSolidGeometry
, которой мы передадим
геометрию, и она создаст случайно раскрашенный материал
createMaterial
и addObject
добавит его в сцену.
function addSolidGeometry(x, y, geometry) { const mesh = new THREE.Mesh(geometry, createMaterial()); addObject(x, y, mesh); }
Теперь мы можем использовать это для большинства примитивов, которые мы создаем. Например, создание прямоугольного параллелепипеда
{ const width = 8; const height = 8; const depth = 8; addSolidGeometry(-2, -2, new THREE.BoxGeometry(width, height, depth)); }
Если вы посмотрите на код ниже, вы увидите похожую часть для каждого типа геометрии.
Вот результат:
Есть несколько заметных исключений из шаблона выше.
Самым большим, вероятно, является TextGeometry
. Он должен
загрузить данные 3D шрифта, прежде чем он сможет сгенерировать
сетку для текста. Эти данные загружаются асинхронно, поэтому
нам нужно дождаться их загрузки, прежде чем пытаться создать
геометрию. Вы можете увидеть ниже, мы создаем FontLoader
и передаем его URL нашему шрифту и обратному вызову (callback).
Обратный вызов срабатывает после загрузки шрифта.
В обратном вызове мы создаем геометрию и вызываем addObject
,
чтобы добавить к ней сцену.
{ const loader = new FontLoader(); loader.load('../resources/threejs/fonts/helvetiker_regular.typeface.json', (font) => { const geometry = new TextGeometry('three.js', { font: font, size: 3.0, height: .2, curveSegments: 12, bevelEnabled: true, bevelThickness: 0.15, bevelSize: .3, bevelSegments: 5, }); const mesh = new THREE.Mesh(geometry, createMaterial()); geometry.computeBoundingBox(); geometry.boundingBox.getCenter(mesh.position).multiplyScalar(-1); const parent = new THREE.Object3D(); parent.add(mesh); addObject(-1, 1, parent); }); }
Есть еще одно отличие. Мы хотим вращать текст вокруг его центра,
но по умолчанию three.js создает текст таким образом, чтобы его
центр вращения находился на левом краю. Чтобы обойти это, мы
можем попросить three.js вычислить ограничивающую
рамку (bounding box) геометрии. Затем мы можем вызвать getCenter
метод bounding box и передать ему объект позиции нашей полигональной
сетки (mesh). getCenter
копирует центр коробки в указанное положение.
Он также возвращает объект position, поэтому мы можем вызвать
multiplyScaler(-1)
для позиционирования всего объекта таким образом,
чтобы его центр вращения находился в центре объекта.
Если бы мы тогда просто вызвали addSolidGeometry
как в предыдущих
примерах, это снова установило бы позицию, что не годится.
Итак, в этом случае мы создаем Object3D
стандартный узел для графа
сцены three.js. Mesh
так же наследуется от Object3D
. Мы рассмотрим,
как работает график сцены, в другой статье.
На данный момент достаточно знать, что, как и DOM-узлы, дети рисуются
относительно своего родителя. Сделав Object3D
и сделав нашу сетку
дочерней по отношению к этому, мы можем расположить Object3D
в то
место, где мы хотим, и при этом сохранить смещение центра,
которое мы установили раньше.
Если бы мы этого не делали, текст был бы оторван от центра.
Обратите внимание, что то что слева не вращается вокруг своего центра, как то, что справа.
Другие исключения - это 2-строчные примеры для EdgesGeometry
и WireframeGeometry
. Вместо того, чтобы вызвать addSolidGeometry
они вызвают addLineGeomtry
который выглядит так
function addLineGeometry(x, y, geometry) { const material = new THREE.LineBasicMaterial({color: 0x000000}); const mesh = new THREE.LineSegments(geometry, material); addObject(x, y, mesh); }
Он создает черный цвет LineBasicMaterial
, а затем создает LineSegments
,
который является оберткой Mesh
, который помогает three знать, что вы
отрисовываете отрезки линии (2 точки на отрезок).
Каждый из примитивов имеет несколько параметров, которые вы можете передать при создании, и лучше всего посмотреть в документации по всем из них, а не повторять их здесь. Вы также можете нажать на ссылку выше рядом с каждой фигурой, чтобы перейти непосредственно к документам для этой фигурой.
Еще одна важная вещь - это то, что почти все фигуры имеют различные настройки того, как их разделить на полигоны. Хорошим примером может служить геометрия сферы. Сферы берут параметры для количества делений вокруг и количества делений сверху вниз. Например
Первая сфера имеет 5 сегментов вокруг и 3 высоты, что составляет 15 сегментов или 30 треугольников. Вторая сфера имеет 24 сегмента на 10. Это 240 сегментов или 480 треугольников. Последний имеет 50 на 50, что составляет 2500 сегментов или 5000 треугольников.
Вам решать, сколько сегментов вам нужно. Может показаться, что вам нужно большое количество сегментов, но удалите линии и плоскую штриховку, и мы получим это
Сейчас не очень понятно, что тот, который справа с 5000 треугольниками, полностью лучше, чем тот, что в середине с 480. Если вы рисуете только несколько сфер, как, например, один глобус для карты земли, то одна сфера из 10000 треугольников - неплохой выбор. Если, с другой стороны, вы пытаетесь нарисовать 1000 сфер, то 1000 сфер на 10000 треугольников каждый - это 10 миллионов треугольников. Для плавной анимации вам нужно, чтобы браузер рисовал со скоростью 60 кадров в секунду, поэтому вы должны просить браузер рисовать 600 миллионов треугольников в секунду. Это много вычислений.
Иногда выбрать легко. Например, вы можете выбрать разделение для плоскости.
Плоскость слева - это 2 треугольника. Плоскость справа - это 200 треугольников. В отличие от сферы, в большинстве случаев использования плоскости действительно нет компромисса в качестве. Скорее всего, вы подразделяете плоскость только в том случае, если вы хотите изменить или деформировать её каким-либо образом. Для Box аналогично.
Итак, выберите то, что подходит для вашей ситуации. Чем меньше разбиений вы выберете, тем более вероятно, что все будет работать гладко и тем меньше памяти они будут занимать. Вы должны решить для себя, каков правильный компромисс для вашей конкретной ситуации.
Далее давайте рассмотрим как работает граф сцены и как его использовать.