I'm trying to make this code works, but I'm on the rocks with the functions scopes.
This is my code so far:
var Canoe = function () {
this.mesh = new THREE.Object3D();
var loader = new THREE.JSONLoader();
loader.load( 'models/canoe.json', function ( geometry, materials ) {
var canoeMesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ));
canoeMesh.castShadow = true;
canoeMesh.receiveShadow = true;
this.mesh.add(canoeMesh);
});
}
And this is the error I'm getting:
Cannot read property 'add' of undefined
How can I assign the mesh I created in the inner function to the outer variable?
One solution is to put mesh in a variable defined in the function:
var Canoe = function () {
var mesh = new THREE.Object3D();
this.mesh = mesh;
var loader = new THREE.JSONLoader();
loader.load( 'models/canoe.json', function ( geometry, materials ) {
var canoeMesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ));
canoeMesh.castShadow = true;
canoeMesh.receiveShadow = true;
mesh.add(canoeMesh);
});
Someone could write a book on how this works in javascript. It's often not what you expect.
Before loader.load() add
var that = this;
In your load function put
that.mesh.add(canoeMesh);
Problem is that "this" inside loader.load() points to somewhere else than outside of the function.
I think you've got a couple options. One, is to assign this to another variable, like so:
var self = this;
var Canoe = function () {
self.mesh = new THREE.Object3D();
var loader = new THREE.JSONLoader();
loader.load( 'models/canoe.json', function ( geometry, materials ) {
var canoeMesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ));
canoeMesh.castShadow = true;
canoeMesh.receiveShadow = true;
self.mesh.add(canoeMesh);
});
}
Another option, if you have a transpiler, would be to use an arrow function, which retains lexical this:
var Canoe = () => {
this.mesh = new THREE.Object3D();
var loader = new THREE.JSONLoader();
loader.load( 'models/canoe.json', function ( geometry, materials ) {
var canoeMesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ));
canoeMesh.castShadow = true;
canoeMesh.receiveShadow = true;
this.mesh.add(canoeMesh);
});
}
Related
The most important part in my code is in JavaScript. I want that my objects can move when I press "down" or "right" or etc. The problem is that object from .json file is moving, but object from .obj file is not. Is it possible to fix that?
This is my code:
<script>
var container, scene, camera, renderer, controls, stats;
var keyboard = new THREEx.KeyboardState();
var keyboard = new KeyboardState();
var galva;
init();
animate();
render();
function init()
{
var spgeometry = new THREE.SphereGeometry( 30, 32, 32 );
var spmaterial = new THREE.MeshBasicMaterial( {color: 0x00000} );
galva = new THREE.Mesh( spgeometry, spmaterial );
galva.position.set(125, 150, 90);
scene.add( galva );
var jsonLoader = new THREE.JSONLoader();
jsonLoader.load( "models/android.js", addModelToScene );
var loader = new THREE.OBJLoader();
loader.load("models/teaport.obj", function ( object ) {
var material = new THREE.MeshLambertMaterial( );
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material = material;
}
} );
object.scale.set(50,50,50);
scene.add( object );
} );
}
function addModelToScene( geometry, materials )
{
var material = new THREE.MeshLambertMaterial( materials );
c = new THREE.Mesh( geometry, material );
c.scale.set(50,50,50);
scene.add( c );
}
function update()
{
keyboard.update();
if ( keyboard.down("left") ){
galva.translateX( -50 );
}
if ( keyboard.down("right") ){
c.translateX( 50 );
galva.translateX( 50 );
object.translateX( 50 );
}
controls.update();
stats.update();
}
If you put together a jsfiddle or something similar - it could be easier to figure out. I think you end up with variable shadowing, and your "object" is simply undefined. Try following change.
var loader = new THREE.OBJLoader();
loader.load("models/teaport.obj", function ( o ) {
var material = new THREE.MeshLambertMaterial( );
o.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material = material;
}
} );
o.scale.set(50,50,50);
scene.add( o );
object = o; // <-- important
How to multiple textures material use in Three.js?.Here three textures using and one 3D sofa.obj format file. I tried a lot of time. Below my code. What do I mistake in my code?
var loader = new THREE.OBJLoader();
var textureLoader = new THREE.TextureLoader();
threeDTexture = new THREE.ImageUtils.loadTexture( 'models/Sofa/Texturses/paradis_beige.jpg' );
threeDTexture2 = new THREE.ImageUtils.loadTexture( 'models/Sofa/Texturses/1.jpg' );
threeDTexture3 = new THREE.ImageUtils.loadTexture( 'models/Sofa/Texturses/2.jpg' );
loader.load('models/Sofa/sofa.obj', function (object) {
var geo = object.children[0].geometry;
var mats = [threeDTexture, threeDTexture2,threeDTexture3];
objct = new THREE.Mesh(geo, mats);
object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
child.material = objct;
}
});
object.position.x = posX;
object.position.y = 0;
object.position.z = posZ;
var size = new THREE.Box3().setFromObject(object).getSize();
object.scale.set(width/size.x, height/size.y, depth/size.z);
scene1.add(object);
console.log(object);
console.log(size);
console.log(width/size.x, height/size.y, depth/size.z);
},
function ( xhr ) {
returnValue = ( xhr.loaded / xhr.total * 100 ) + '% loaded';
console.log(returnValue);
},
function ( error ) {
console.log( 'An error happened' );
}
);
break
first, the textureLoader declared on line-2 is not in use;
second, belowing mats is not an Material Array, you should new MeshBasicMaterial(...) to wrap a texture, see the document here.
var mats = [threeDTexture, threeDTexture2,threeDTexture3];
objct = new THREE.Mesh(geo, mats); // Mesh will not accept this mats param!
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);
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' );
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...