aframe-extras
Version:
Add-ons and examples for A-Frame VR.
134 lines (108 loc) • 3.84 kB
JavaScript
/**
* @param {Array<THREE.Material>|THREE.Material} material
* @return {Array<THREE.Material>}
*/
function ensureMaterialArray (material) {
if (!material) {
return [];
} else if (Array.isArray(material)) {
return material;
} else if (material.materials) {
return material.materials;
} else {
return [material];
}
}
/**
* @param {THREE.Object3D} mesh
* @param {Array<string>} materialNames
* @param {THREE.Texture} envMap
* @param {number} reflectivity [description]
*/
function applyEnvMap (mesh, materialNames, envMap, reflectivity) {
if (!mesh) return;
materialNames = materialNames || [];
mesh.traverse((node) => {
if (!node.isMesh) return;
const meshMaterials = ensureMaterialArray(node.material);
meshMaterials.forEach((material) => {
if (material && !('envMap' in material)) return;
if (materialNames.length && materialNames.indexOf(material.name) === -1) return;
material.envMap = envMap;
material.reflectivity = reflectivity;
material.needsUpdate = true;
});
});
}
/**
* Specifies an envMap on an entity, without replacing any existing material
* properties.
*/
AFRAME.registerComponent('cube-env-map', {
multiple: true,
schema: {
path: {default: ''},
extension: {default: 'jpg', oneOf: ['jpg', 'png']},
enableBackground: {default: false},
reflectivity: {default: 1, min: 0, max: 1},
materials: {default: []}
},
init: function () {
const data = this.data;
this.texture = new THREE.CubeTextureLoader().load([
data.path + 'posx.' + data.extension, data.path + 'negx.' + data.extension,
data.path + 'posy.' + data.extension, data.path + 'negy.' + data.extension,
data.path + 'posz.' + data.extension, data.path + 'negz.' + data.extension
]);
this.texture.format = THREE.RGBAFormat;
this.object3dsetHandler = () => {
const mesh = this.el.getObject3D('mesh');
const data = this.data;
applyEnvMap(mesh, data.materials, this.texture, data.reflectivity);
};
this.object3dsetHandler();
this.el.addEventListener('object3dset', this.object3dsetHandler);
},
update: function (oldData) {
const data = this.data;
const mesh = this.el.getObject3D('mesh');
let addedMaterialNames = [];
let removedMaterialNames = [];
if (data.materials.length) {
if (oldData.materials) {
addedMaterialNames = data.materials.filter((name) => !oldData.materials.includes(name));
removedMaterialNames = oldData.materials.filter((name) => !data.materials.includes(name));
} else {
addedMaterialNames = data.materials;
}
}
if (addedMaterialNames.length) {
applyEnvMap(mesh, addedMaterialNames, this.texture, data.reflectivity);
}
if (removedMaterialNames.length) {
applyEnvMap(mesh, removedMaterialNames, null, 1);
}
if (oldData.materials && data.reflectivity !== oldData.reflectivity) {
const maintainedMaterialNames = data.materials
.filter((name) => oldData.materials.includes(name));
if (maintainedMaterialNames.length) {
applyEnvMap(mesh, maintainedMaterialNames, this.texture, data.reflectivity);
}
}
if (this.data.enableBackground && !oldData.enableBackground) {
this.setBackground(this.texture);
} else if (!this.data.enableBackground && oldData.enableBackground) {
this.setBackground(null);
}
},
remove: function () {
this.el.removeEventListener('object3dset', this.object3dsetHandler);
const mesh = this.el.getObject3D('mesh');
const data = this.data;
applyEnvMap(mesh, data.materials, null, 1);
if (data.enableBackground) this.setBackground(null);
},
setBackground: function (texture) {
this.el.sceneEl.object3D.background = texture;
}
});