How to add texture to object in three.js? - javascript

I am trying to add to texture to my central sphere (the earth) but when I try the object disappears. Can I have some guide to where I am going wrong. Thanks
Here is the link to my jsbin http://jsbin.com/cabape/edit?html,output . I am going to get the moon to rotate around the earth
//earth
var loader = new THREE.TextureLoader();
loader.load( 'http://simpletruthsforhealthyliving.com/js/earth.jpg', function ( texture ) {
var center = new THREE.SphereGeometry(20,20,20);
var materialShereCenter = new THREE.MeshPhongMaterial( { ambient: 0xee0011, color:0xff0000, specular: 0xee0000, shininess: 70,wireframe: false, map: texture } );
centralSphere = new THREE.Mesh(center, materialShereCenter);
centralSphere.position.z = 0;
centralSphere.position.x = 0;
centralSphere.position.y = 0;
scene.add(centralSphere);
});

This needed to be added as well
var texture = new THREE.Texture();
var loader = new THREE.ImageLoader();
loader.addEventListener( 'load', function ( event ) {
Texture1.image = event.content;
Texture1.needsUpdate = true;
} );
loader.load( 'http://simpletruthsforhealthyliving.com/js/earth.jpg' );

Related

THREE.js : why THREE.DoubleSide not working in collada model?

I have collada model (.dae) displayed by this code, and I add THREE.DoubleSide but it dose not work how can i fix this?
var loadingManager = new THREE.LoadingManager( function() {
scene.add( car );
} );
var loader = new THREE.ColladaLoader( loadingManager );
var textureLoader = new THREE.TextureLoader();
var texture = textureLoader.load('./model/car_Red.jpg');
loader.options.convertUpAxis = true;
loader.load( './car.dae', function ( collada ) {
car = collada.scene;
car.traverse(function (node) {
if (node.isMesh)
{
node.material.map = texture;
node.material.side = THREE.DoubleSide;
}
});
console.log(car);

Use THREE.LoadingMAnager() to load the materials for a THREE.BoxGeometry?

I'm trying to update the image asset on a geometry after user interaction, basically loading low res assets to begin with and swapping to high res assets when the user interacts with it.
If I just use standard code like below:
var materials = [
new THREE.MeshPhongMaterial({ map:loader.load('assets/object/0.jpg' ) }),
new THREE.MeshPhongMaterial({ map:loader.load('assets/object/1.jpg' ) }),
new THREE.MeshPhongMaterial({ map:loader.load('assets/object/2.jpg' ) }),
new THREE.MeshPhongMaterial({ map:loader.load('assets/object/3.jpg' ) }),
new THREE.MeshPhongMaterial({ map:loader.load('assets/object/4.jpg' ) }),
new THREE.MeshPhongMaterial({ map:loader.load('assets/object/5.jpg' ) }),
];
target.material.map.needsUpdate = true;
var texture = new THREE.MeshFaceMaterial( materials );
target.material = texture;
The low res assets are cleared from the geometry showing the base colour, the high-res assets take a second to load and then appear on the geometry.
I need to load the assets and then swap them, and from some reading it seems like THREE.LoadingManager() is the way to go, however I'm a bit lost.
So far this is what I have but it's throwing errors....
var textureManager = new THREE.LoadingManager();
textureManager.onProgress = function ( item, loaded, total ) {
console.log(item+' = '+loaded / total * 100) + '%';
};
textureManager.onLoad = function () {
console.log(' loading complete');
var materials = [
new THREE.MeshPhongMaterial({ map:myTextureArray[0] }),
new THREE.MeshPhongMaterial({ map:myTextureArray[1] }),
new THREE.MeshPhongMaterial({ map:myTextureArray[2] }),
new THREE.MeshPhongMaterial({ map:myTextureArray[3] }),
new THREE.MeshPhongMaterial({ map:myTextureArray[4] }),
new THREE.MeshPhongMaterial({ map:myTextureArray[5] })
];
target.children[i].material.materials.map.needsUpdate = true;
var texture = new THREE.MeshFaceMaterial( materials );
target.children[i].material = texture;
};
var textureLoader = new THREE.ImageLoader( textureManager );
myTextureArray = [];
var myTexture = new THREE.Texture();
myTextureArray.push( textureLoader.load( 'assets/objtect1/hires/0.jpg', function ( image ) { myTexture.image = image; } ) );
myTextureArray.push( textureLoader.load( 'assets/objtect1/hires/1.jpg', function ( image ) { myTexture.image = image; } ) );
myTextureArray.push( textureLoader.load( 'assets/objtect1/hires/2.jpg', function ( image ) { myTexture.image = image; } ) );
myTextureArray.push( textureLoader.load( 'assets/objtect1/hires/3.jpg', function ( image ) { myTexture.image = image; } ) );
myTextureArray.push( textureLoader.load( 'assets/objtect1/hires/4.jpg', function ( image ) { myTexture.image = image; } ) );
myTextureArray.push( textureLoader.load( 'assets/objtect1/hires/5.jpg', function ( image ) { myTexture.image = image; } ) );
Any ideas where I might be going wrong?
For the benefit of anyone else, the problem was that I was using the ImageLoader, not TextureLoader.
Replace:
var textureLoader = new THREE.ImageLoader( textureManager );
With
var textureLoader = new THREE.TextureLoader( textureManager );

THREE.js Geometry map does not appear

Following I'm loading a image map on a custom geometry,
it represents the brown colored geometry on the picture above:
var aqua_ground_geo = new THREE.Geometry();
var top0 = new THREE.Vector3(aqua_ground_geo_x_NEG, user_data['aqua_soil_calc_b_y'], aqua_ground_geo_z_NEG);
var top1 = new THREE.Vector3(aqua_ground_geo_x_POS, user_data['aqua_soil_calc_b_y'], aqua_ground_geo_z_NEG);
var top2 = new THREE.Vector3(aqua_ground_geo_x_NEG, user_data['aqua_soil_calc_f_y'], aqua_ground_geo_z_POS);
aqua_ground_geo.vertices.push(top0);
aqua_ground_geo.vertices.push(top1);
aqua_ground_geo.vertices.push(top2);
aqua_ground_geo.faces.push( new THREE.Face3(0,1,2) );
aqua_ground_geo.computeFaceNormals();
aqua_ground_geo.computeVertexNormals();
var textureUrl = "http://www.lifeguider.de/wp-content/uploads/aquag/bodengrund/dennerle_kies_naturweiss_1-2mm.jpg";
var aqua_bodengrund_tex = new THREE.TextureLoader().load( textureUrl );
var aqua_bodengrund_mat = new THREE.MeshLambertMaterial( {
map: aqua_bodengrund_tex,
color: 0xffffff,
} );
aqua_bodengrund_mat.shading = THREE.FlatShading;
aqua_bodengrund_mat.side = THREE.DoubleSide;
var aqua_bodengrund = new THREE.Mesh( aqua_ground_geo,aqua_bodengrund_mat);
On a simple THREE.BoxGeometry all works as expected with the same material (it represents the cube in the picture above):
var lala = new THREE.BoxGeometry( 100, 100, 100 );
var lala2 = new THREE.Mesh( lala,aqua_bodengrund_mat);
I'm not an expert in 3D, what is missing in my code that the image texture will be shown correctly?
You need to apply the texture in the callback of the THREE.TextureLoader. Check also the documentation here; the second argument (onLoad) is the callback.
var textureUrl = "https://raw.githubusercontent.com/mrdoob/three.js/master/examples/textures/crate.gif";
var aqua_bodengrund_mat = new THREE.MeshLambertMaterial( {
color: 0xffffff
});
var onLoad = function( texture ){
aqua_bodengrund_mat.map = texture;
aqua_bodengrund_mat.needsUpdate = true;
}
var loader = new THREE.TextureLoader();
loader.load( textureUrl, onLoad );
See this fiddle for a demo.
UPDATE
In case you have a custom geometry you also need to calculate the UVs for showing the texture correctly. I used this answer here to calculate them in another fiddle here
Note. The UVs in my fiddle are calculated for faces in the XY plane, if your faces are in another plane you will have to update accordingly...

texture didn't load in to 3d object(mapping)

texture is not loaded in to ring 3d model.but it will work for some other objects.there is no compile errors.I set the all all light condition correctly.but 3d model color is grey/black.texture loaded for other object correctly.3d object file format is .obj,I didn't load mtl file to my code. mtlobjloader is not in threejs.org,there are someway to load mtl file and mapping the texture to object.
plz help me.
enter code here
<html>
<head>
<title> Test Three.js</title>
<style type="text/css">
BODY
{
margin: 0;
}
canvas
{
width: 100%;
height:100%;
}
</style>
</head>
<body>
<div>
<p>Color:
<button class="jscolor{onFineChange:'onClick(this)',valueElement:null,value:'66ccff'}"
style="width:50px; height:20px;"></button>
</p>
<p>Object:
<button style="width:50px; height:20px;" id="object"></button>
</p>
</div>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script src="three.min.js"></script>
<script src="TrackballControls.js"></script>
<script src="jscolor.js"></script>
<script src="AmbientLight.js"></script>
<script src="SpotLight.js"></script>">
<script src="JSONLoader.js"></script>">
<script src="ObjectLoader.js"></script>">
<script src="OBJLoader.js"></script>">
<script src="MTLLoader.js"></script>">
<script src="Material.js"></script>">
<script src="MeshPhongMaterial.js"></script>">
<script>
function onClick(jscolor) {
cube.material.color = new THREE.Color('#'+jscolor);
cube.material.needsUpdate = true;
};
var onClicked=function (){
scene.remove(cube);
var material1 = new THREE.LineBasicMaterial({
color: 'red'
});
var geometry1 = new THREE.Geometry();
geometry1.vertices.push(
new THREE.Vector3( -10, 0, 0 ),
new THREE.Vector3( 0, 10, 0 ),
new THREE.Vector3( 10, 0, 0 )
);
var cube1 = new THREE.Line( geometry1, material1 );
scene.add( cube1);
};
$('#object').click(onClicked);
var scene =new THREE.Scene();
var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);
var controls =new THREE.TrackballControls(camera);
controls.addEventListener('change',render);
var renderer = new THREE.WebGLRenderer( { alpha: true });
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);
/*var material = new THREE.MeshLambertMaterial({color:'red'});
var geometry=new THREE.CubeGeometry(100,100,100);
var cube=new THREE.Mesh(geometry,material);
scene.add(cube);*/
camera.position.z=500;
var light = new THREE.AmbientLight( 0x404040 );
light.intensity = 0;
light.position.z=10;
light.position.y=10; // soft white light
scene.add( light );
// }
//init();
/* var loader = new THREE.JSONLoader();
loader.load( 'ring.json', function ( geometry ) {
var mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial() );
mesh.position.x =500;
mesh.position.y =100;
mesh.position.z =500;
scene.add( mesh );
}); *//*
var loader = new THREE.ObjectLoader();
loader.load("ring.json",function ( obj ) {
THREE.ImageUtils.crossOrigin = '';
var texture = THREE.TextureLoader("images.jpg");
//obj.map= texture;
obj.scale.set (10,10,10);
obj.traverse( function( child ) {
if ( child instanceof THREE.Mesh ) {
child.geometry.computeVertexNormals();
child.material.map=texture;
}
} );
scene.add( obj );
});*/
var manager = new THREE.LoadingManager();
manager.onProgress = function ( item, loaded, total ) {
console.log( item, loaded, total );
};
var texture = new THREE.Texture();
var loader = new THREE.ImageLoader( manager );
// You can set the texture properties in this function.
// The string has to be the path to your texture file.
loader.load( 'brick_bump.jpg', function ( image ) {
texture.image = image;
texture.needsUpdate = true;
// I wanted a nearest neighbour filtering for my low-poly character,
// so that every pixel is crips and sharp. You can delete this lines
// if have a larger texture and want a smooth linear filter.
// texture.magFilter = THREE.NearestFilter;
//texture.minFilter = THREE.NearestMipMapLinearFilter;
} );
var loader = new THREE.OBJLoader(manager);
/*var Mloader= new THREE.MTLLoader(manager);
Mloader.load('ring.mtl',function(object){
object.traverse( function ( child ) {
if (child.material instanceof THREE.MeshPhongMaterial ) {
child.material.map = texture;
}
} );
scene.add( object );
});*/
// As soon as the OBJ has been loaded this function looks for a mesh
// inside the data and applies the texture to it.
loader.load( 'ring1.obj', function ( event ) {
var object = event;
/*for ( var i = 0, l = object.children.length; i < l; i ++ ) {
object.children[ i ].material.map = texture;
console.log("rgr"+ object);
}*/
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material.map = texture;
console.log("rgr"+ object.children);
}
} );
// My initial model was too small, so I scaled it upwards.
object.scale = new THREE.Vector3( 25, 25, 25 );
// You can change the position of the object, so that it is not
// centered in the view and leaves some space for overlay text.
object.position.y -= 2.5;
scene.add( object );
});
function render(){
renderer.render(scene,camera);
}
function animate(){
requestAnimationFrame(animate);
controls.update();
}
animate();
</script>
</body>
</html>
First I would check the ring.obj file. You'll need to verify that the ring.obj file is exporting with UV values on all vertexes. UV values assign points on the texture to specific points on the mesh. E.g. they define how the texture is draped over the surface. If you do not have control of the ring.obj export process to quality assure it, there was a conversation on stack about generating UVs at load time here:
THREE.js generate UV coordinate
But your milage may vary if the mesh author had specific texture anchors.
This may not be the issue, but since the texture is working for other meshes, I would think there is an issue with the ring mesh.

Using textures in THREE.js

I am starting with THREE.js, and I am trying to draw a rectangle with a texture on it, lit by a single source of light. I think this is as simple as it gets (HTML omitted for brevity):
function loadScene() {
var world = document.getElementById('world'),
WIDTH = 1200,
HEIGHT = 500,
VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1,
FAR = 10000,
renderer = new THREE.WebGLRenderer(),
camera = new THREE.Camera(VIEW_ANGLE, ASPECT, NEAR, FAR),
scene = new THREE.Scene(),
texture = THREE.ImageUtils.loadTexture('crate.gif'),
material = new THREE.MeshBasicMaterial({map: texture}),
// material = new THREE.MeshPhongMaterial({color: 0xCC0000});
geometry = new THREE.PlaneGeometry(100, 100),
mesh = new THREE.Mesh(geometry, material),
pointLight = new THREE.PointLight(0xFFFFFF);
camera.position.z = 200;
renderer.setSize(WIDTH, HEIGHT);
scene.addChild(mesh);
world.appendChild(renderer.domElement);
pointLight.position.x = 50;
pointLight.position.y = 50;
pointLight.position.z = 130;
scene.addLight(pointLight);
renderer.render(scene, camera);
}
The problem is, I cannot see anything. If I change the material and use the commented one, a square appears as I would expect. Note that
The texture is 256x256, so its sides are power of two
The function is actually called when the body is loaded; indeed it works with a different material.
It does not work even if I serve the file from a webserver, so it is not an issue of cross-domain policy not allowing to load the image.
What I am I doing wrong?
By the time the image is loaded, the renderer has already drawn the scene, hence it is too late. The solution is to change
texture = THREE.ImageUtils.loadTexture('crate.gif'),
into
texture = THREE.ImageUtils.loadTexture('crate.gif', {}, function() {
renderer.render(scene);
}),
Andrea solution is absolutely right, I will just write another implementation based on the same idea.
If you took a look at the THREE.ImageUtils.loadTexture() source you will find it uses the javascript Image object. The $(window).load event is fired after all Images are loaded ! so at that event we can render our scene with the textures already loaded...
CoffeeScript
$(document).ready ->
material = new THREE.MeshLambertMaterial(map: THREE.ImageUtils.loadTexture("crate.gif"))
sphere = new THREE.Mesh(new THREE.SphereGeometry(radius, segments, rings), material)
$(window).load ->
renderer.render scene, camera
JavaScript
$(document).ready(function() {
material = new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture("crate.gif") });
sphere = new THREE.Mesh(new THREE.SphereGeometry(radius, segments, rings), material);
$(window).load(function() {
renderer.render(scene, camera);
});
});
Thanks...
In version r75 of three.js, you should use:
var loader = new THREE.TextureLoader();
loader.load('texture.png', function ( texture ) {
var geometry = new THREE.SphereGeometry(1000, 20, 20);
var material = new THREE.MeshBasicMaterial({map: texture, overdraw: 0.5});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
});
In version r82 of Three.js TextureLoader is the object to use for loading a texture.
Loading one texture (source code, demo)
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);
Loading multiple textures (source code, demo)
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;
Without Error Handeling
//Load background texture
new THREE.TextureLoader();
loader.load('https://images.pexels.com/photos/1205301/pexels-photo-1205301.jpeg' , function(texture)
{
scene.background = texture;
});
With Error Handling
// 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 (error) {
console.log('An error happened'+error);
};
//Function called when load completes.
var onLoad = function (texture) {
var objGeometry = new THREE.BoxGeometry(30, 30, 30);
var objMaterial = new THREE.MeshPhongMaterial({
map: texture,
shading: THREE.FlatShading
});
var boxMesh = new THREE.Mesh(objGeometry, objMaterial);
scene.add(boxMesh);
var render = function () {
requestAnimationFrame(render);
boxMesh.rotation.x += 0.010;
boxMesh.rotation.y += 0.010;
sphereMesh.rotation.y += 0.1;
renderer.render(scene, camera);
};
render();
}
//LOAD TEXTURE and on completion apply it on box
var loader = new THREE.TextureLoader();
loader.load('https://upload.wikimedia.org/wikipedia/commons/thumb/9/97/The_Earth_seen_from_Apollo_17.jpg/1920px-The_Earth_seen_from_Apollo_17.jpg',
onLoad,
onProgress,
onError);
Result:
https://codepen.io/hiteshsahu/pen/jpGLpq/
Use TextureLoader to load a image as texture and then simply apply that texture to scene background.
new THREE.TextureLoader();
loader.load('https://images.pexels.com/photos/1205301/pexels-photo-1205301.jpeg' , function(texture)
{
scene.background = texture;
});
Result:
https://codepen.io/hiteshsahu/pen/jpGLpq?editors=0011
See the Pen Flat Earth Three.JS by Hitesh Sahu (#hiteshsahu) on CodePen.

Categories