A-Frame строится поверх Three.js, предоставляя декларативный HTML-подход к созданию 3D-сцен, но иногда требуется непосредственное взаимодействие с объектами Three.js для более точного управления сценой, геометрией, материалами и анимацией. В таких случаях важно понимать структуру сущностей A-Frame и их связь с Three.js.
el.object3DКаждая сущность A-Frame, определяемая через тег
<a-entity>, содержит свойство object3D,
которое представляет собой экземпляр THREE.Object3D. Через
это свойство осуществляется прямой доступ ко всем возможностям
Three.js:
const boxEl = document.querySelector('#box');
const threeObject = boxEl.object3D;
threeObject.position.set(1, 2, 3);
threeObject.rotation.y = Math.PI / 4;
Ключевые моменты:
object3D автоматически синхронизируется с компонентами
A-Frame (position, rotation,
scale).object3D применяются мгновенно и могут
переопределять значения, заданные через HTML-атрибуты.Для доступа к геометрии или материалам объекта используется цепочка
mesh через дочерние объекты object3D. Обычно
сущность содержит один меш:
const mesh = boxEl.getObject3D('mesh');
if (mesh) {
mesh.material.color.set('red');
mesh.geometry.computeBoundingBox();
}
Особенности:
getObject3D('mesh') возвращает объект
THREE.Mesh.material.color,
material.opacity) и геометрии
(geometry.vertices, geometry.attributes).traverse.threeObject.traverse((node) => {
if (node.isMesh) {
node.material.wireframe = true;
}
});
A-Frame предоставляет доступ к сцене через
sceneEl.object3D, а камеры — через camera
внутри sceneEl:
const sceneEl = document.querySelector('a-scene');
const sceneThree = sceneEl.object3D;
// Камера по умолчанию
const cameraEl = sceneEl.camera.el;
cameraEl.object3D.position.set(0, 2, 5);
cameraEl.object3D.lookAt(new THREE.Vector3(0, 0, 0));
Особенности:
sceneEl.object3D.add(mesh) полностью управляются Three.js,
но их нужно синхронизировать с A-Frame, если планируется использовать
компоненты A-Frame.THREE.PerspectiveCamera и подключить её к сцене
напрямую.Three.js объекты можно анимировать напрямую, используя
requestAnimationFrame или библиотеку
tween.js:
function animate() {
requestAnimationFrame(animate);
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.02;
}
animate();
Особенности интеграции с A-Frame:
object3D не конфликтуют с компонентами
типа animation A-Frame.mouseenter, mouseleave) с прямыми изменениями
object3D.boxEl.addEventListener('mouseenter', () => {
const mesh = boxEl.getObject3D('mesh');
mesh.scale.set(1.5, 1.5, 1.5);
});
Создание кастомного компонента позволяет обернуть работу с
object3D в повторно используемый модуль:
AFRAME.registerComponent('rotate-on-frame', {
tick: function (time, timeDelta) {
const mesh = this.el.getObject3D('mesh');
if (mesh) {
mesh.rotation.y += 0.001 * timeDelta;
}
}
});
Преимущества такого подхода:
Для добавления объектов, которые не имеют декларативного аналога в
A-Frame, можно использовать object3D.add():
const customGeometry = new THREE.TorusKnotGeometry(1, 0.3, 100, 16);
const customMaterial = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const customMesh = new THREE.Mesh(customGeometry, customMaterial);
sceneEl.object3D.add(customMesh);
Особенности:
el.object3D
дочерних сущностей, чтобы сохранить иерархию.Прямой доступ к объектам Three.js через A-Frame позволяет:
Эта интеграция обеспечивает гибкость и контроль, сохраняя при этом преимущества удобного HTML-подхода A-Frame.