A-Frame предоставляет удобный способ работы с 3D-моделями, используя
сущность <a-entity> с компонентом
gltf-model. Модели могут быть загружены в формате GLTF или
GLB и содержать сложные структуры, включая иерархию объектов, материалы
и текстуры.
Пример базовой загрузки модели:
<a-scene>
<a-entity gltf-model="#myModel" position="0 1.5 -3"></a-entity>
</a-scene>
Здесь #myModel — идентификатор ресурса, определённого
через <a-assets>.
<a-assets>
<a-asset-item id="myModel" src="models/car.glb"></a-asset-item>
</a-assets>
После загрузки модели, все её материалы доступны через объект
mesh Three.js, на котором основан A-Frame. Замена
материалов требует работы с этим объектом.
Когда модель загружается, событие model-loaded
сигнализирует о готовности всех ресурсов. Для замены материала
необходимо обработать это событие:
const entity = document.querySelector('[gltf-model="#myModel"]');
entity.addEventListener('model-loaded', () => {
const model = entity.getObject3D('mesh');
if (!model) return;
model.traverse((node) => {
if (node.isMesh) {
// Здесь node.material содержит текущий материал
}
});
});
Метод traverse рекурсивно проходит по всем узлам модели.
node.isMesh позволяет отличать меши от групп или пустых
узлов. Каждый node имеет свойство material,
которое может быть объектом THREE.Material или массивом
материалов, если на меш наложено несколько.
Для простой замены материала создаётся новый объект
THREE.MeshStandardMaterial или другой подходящий тип
материала. Например:
import * as THREE from 'three';
entity.addEventListener('model-loaded', () => {
const model = entity.getObject3D('mesh');
model.traverse((node) => {
if (node.isMesh) {
node.material = new THREE.MeshStandardMaterial({
color: 0xff0000,
metalness: 0.5,
roughness: 0.5
});
}
});
});
Этот подход заменяет материал для всех мешей модели на единый. Для более сложных моделей, где требуется заменить материалы выборочно, можно проверять имя меша:
if (node.name === 'Wheel') {
node.material = new THREE.MeshStandardMaterial({ color: 0x000000 });
}
Если модель содержит несколько материалов на одном меше,
node.material может быть массивом. Для замены всех
материалов используется итерация:
if (Array.isArray(node.material)) {
node.material.forEach((mat, index, arr) => {
arr[index] = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
});
} else {
node.material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
}
Таким образом можно точно контролировать, какие материалы заменять и на какие значения.
Для реалистичных эффектов применяется текстура. Текстуры загружаются
через THREE.TextureLoader:
const loader = new THREE.TextureLoader();
const texture = loader.load('textures/metal.jpg');
entity.addEventListener('model-loaded', () => {
const model = entity.getObject3D('mesh');
model.traverse((node) => {
if (node.isMesh) {
node.material = new THREE.MeshStandardMaterial({
map: texture,
metalness: 1,
roughness: 0.4
});
}
});
});
Использование карт (map, normalMap,
roughnessMap) позволяет достигнуть визуальной
реалистичности при минимальных усилиях.
Для интерактивных приложений часто требуется менять материалы в процессе работы. Например, при нажатии на кнопку:
document.querySelector('#changeColor').addEventListener('click', () => {
const model = entity.getObject3D('mesh');
model.traverse((node) => {
if (node.isMesh) {
node.material.color.set(0x0000ff);
}
});
});
Важно: при динамическом изменении материалов следует учитывать, что текстуры и физические свойства сохраняются, если не создаётся новый объект материала.
node.isMesh перед заменой материала
предотвращает ошибки при обходе групповых узлов.model-loaded перед доступом к
объекту mesh.traverse для обхода всех узлов.Эти подходы позволяют полностью контролировать внешний вид моделей в A-Frame, создавая визуально насыщенные и интерактивные 3D-сцены.