In version r82 of Three.js TextureLoader is the object to use for loading a texture.
Extract (test.js):
var scene = new THREE.Scene();
var ratio = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight,
0.1, 50);
var renderer = ...
[...]
/**
* Will be called when load completes.
* The argument will be the loaded texture.
*/
var onLoad = function (texture) {
var objGeometry = new THREE.BoxGeometry(20, 20, 20);
var objMaterial = new THREE.MeshPhongMaterial({
map: texture,
shading: THREE.FlatShading
});
var mesh = new THREE.Mesh(objGeometry, objMaterial);
scene.add(mesh);
var render = function () {
requestAnimationFrame(render);
mesh.rotation.x += 0.010;
mesh.rotation.y += 0.010;
renderer.render(scene, camera);
};
render();
}
// Function called when download progresses
var onProgress = function (xhr) {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
};
// Function called when download errors
var onError = function (xhr) {
console.log('An error happened');
};
var loader = new THREE.TextureLoader();
loader.load('texture.jpg', onLoad, onProgress, onError);
In this example the textures are loaded inside the constructor of the mesh, multiple texture are loaded using Promises.
Extract (Globe.js):
Create a new container using Object3D
for having two meshes in the same container:
var Globe = function (radius, segments) {
THREE.Object3D.call(this);
this.name = "Globe";
var that = this;
// instantiate a loader
var loader = new THREE.TextureLoader();
A map called textures
where every object contains the url
of a texture file and val
for storing the value of a Three.js texture object.
// earth textures
var textures = {
'map': {
url: 'relief.jpg',
val: undefined
},
'bumpMap': {
url: 'elev_bump_4k.jpg',
val: undefined
},
'specularMap': {
url: 'wateretopo.png',
val: undefined
}
};
The array of promises, for each object in the map called textures
push a new Promise in the array texturePromises
, every Promise will call loader.load
. If the value of entry.val
is a valid THREE.Texture
object, then resolve the promise.
var texturePromises = [], path = './';
for (var key in textures) {
texturePromises.push(new Promise((resolve, reject) => {
var entry = textures[key]
var url = path + entry.url
loader.load(url,
texture => {
entry.val = texture;
if (entry.val instanceof THREE.Texture) resolve(entry);
},
xhr => {
console.log(url + ' ' + (xhr.loaded / xhr.total * 100) +
'% loaded');
},
xhr => {
reject(new Error(xhr +
'An error occurred loading while loading: ' +
entry.url));
}
);
}));
}
Promise.all
takes the promise array texturePromises
as argument. Doing so makes the browser wait for all the promises to resolve, when they do we can load the geometry and the material.
// load the geometry and the textures
Promise.all(texturePromises).then(loadedTextures => {
var geometry = new THREE.SphereGeometry(radius, segments, segments);
var material = new THREE.MeshPhongMaterial({
map: textures.map.val,
bumpMap: textures.bumpMap.val,
bumpScale: 0.005,
specularMap: textures.specularMap.val,
specular: new THREE.Color('grey')
});
var earth = that.earth = new THREE.Mesh(geometry, material);
that.add(earth);
});
For the cloud sphere only one texture is necessary:
// clouds
loader.load('n_amer_clouds.png', map => {
var geometry = new THREE.SphereGeometry(radius + .05, segments, segments);
var material = new THREE.MeshPhongMaterial({
map: map,
transparent: true
});
var clouds = that.clouds = new THREE.Mesh(geometry, material);
that.add(clouds);
});
}
Globe.prototype = Object.create(THREE.Object3D.prototype);
Globe.prototype.constructor = Globe;