How to check item is loaded in the scene in three.js? - javascript

I use THREE.js Loading Manager to check the object or texture is loaded .
var Mesh;
var TLoader = new THREE.TextureLoader(manager);
var manager = new THREE.LoadingManager();
manager.onProgress = function ( item, loaded, total ) {
console.log( item, loaded, total );
};
manager.onLoad = function()
{
console.log(Renderer.domElement.toDataURL());
}
function renderModel(path,texture) {
var Material = new THREE.MeshPhongMaterial({shading: THREE.SmoothShading});
Material.side = THREE.DoubleSide;
var Loader = new THREE.JSONLoader(manager);
Loader.load(path,function(geometry){
geometry.mergeVertices();
geometry.computeFaceNormals();
geometry.computeVertexNormals();
TLoader.load(texture,function(texture){
Mesh = new THREE.Mesh(geometry, Material);
Mesh.material.map =texture;
Scene.add(Mesh);
});
});
}
and i just call the renderModel function in a loop .
But the console.log(Renderer.domElement.toDataURL()) output from the manager.onload function is giving only image of the some 3d models not all the ones in the scene
I just want to get 'Renderer.domElement.toDataURL()' when all the 3d models are rendered in the scene
now only the image of 2 or 3 models are getting ,but in scene all the items are loaded.

The renderer renders an image each frame. When the loading of all the objects is completed, the onLoad method of the manager is called immediately. So, the last objects were added to the scene and you retrieve the image data without giving the renderer a chance to render a new image. You need to wait for a new frame. Maybe a timeout with e.g. 200 milliseconds will help.
EDIT
You could also call the render method in your onLoad, so the renderer draws a new image before you call console.log.
manager.onLoad = function()
{
Renderer.render( Scene, camera );
console.log(Renderer.domElement.toDataURL());
}

Related

load texture in a class before proceeding

I have presented a simple example to illustrate what my problem is. in functions it's easy to use await async to make sure textures are loaded before proceeding with the program. if I want to work with classes because of the cleanliness of the program, I have no idea how I can do this so that the constructor waits until the texture is loaded before the subsequent function is called.
//in my three.js init function
var sphereObject = new Sphere(100, texture);
var sphere = this.sphereObject.sphere;
scene.add(sphere);
//------------------------
class Sphere{
constructor(radius, preloadedtex){
//this.material = this.doSomething(preloadedtex); this work fine
const loader = new THREE.TextureLoader();
loader.load("grass.png", function(texture){
this.material = this.doSomething(texture);
});
const geometry = new THREE.SphereGeometry( radius, 128, 64 );
this.sphere = new THREE.Mesh( geometry, this.material);
}
doSomething(texture){
//further operations with the texture before the function returns a material
return material;
}
}
TextureLoader has an onLoad callback as the second argument of .load(). This is taken directly from the docs:
const loader = new THREE.TextureLoader();
// load a resource
loader.load(
// resource URL
'textures/land_ocean_ice_cloud_2048.jpg',
// onLoad callback
function ( texture ) {
// in this example we create the material when the texture is loaded
const material = new THREE.MeshBasicMaterial( {
map: texture
} );
},
// onProgress callback currently not supported
undefined,
// onError callback
function ( err ) {
console.error( 'An error happened.' );
}
);

How to get the geometry of a model imported from STL in three.js

I'm using STLLoader to load STL file into three.js and I want to get the vertices (and the geometry) of the model after I call the loader for further usage. How can I do that? My current code is as below but I cannot get the geometry after calling the loader.
var loader = new THREE.STLLoader();
var myModel = new THREE.Object3D();
loader.load("myModel.stl", function (geometry) {
var mat = new THREE.MeshLambertMaterial({color: 0x7777ff});
var geo = new THREE.Geometry().fromBufferGeometry(geometry);
myModel = new THREE.Mesh(geo, mat);
scene.add(myModel);
});
console.log(myModel.geometry.vertices)
As of three.js R125, the recommended way to do this is with the loadAsync method, which is now native to three.js:
https://threejs.org/docs/#api/en/loaders/Loader.loadAsync
That method returns a promise. You couldthen use a 'then' to get the geometry of the STL and create the mesh. You could also use a traditional callback, or an async/await structure, but I think the example below using the native three.js method is the simplest way. The example shows how you can get geometry to a global variable once the promise is resolved and the STL file is loaded:
// Global variables for bounding boxes
let bbox;
const loader = new STLLoader();
const promise = loader.loadAsync('model1.stl');
promise.then(function ( geometry ) {
const material = new THREE.MeshPhongMaterial();
const mesh = new THREE.Mesh( geometry, material );
mesh.geometry.computeBoundingBox();
bbox = mesh.geometry.boundingBox;
scene.add( mesh );
buildScene();
console.log('STL file loaded!');
}).catch(failureCallback);
function failureCallback(){
console.log('Could not load STL file!');
}
function buildScene() {
console.log('STL file is loaded, so now build the scene');
// !VA bounding box of the STL mesh accessible now
console.log(bbox);
// Build the rest of your scene...
}

Three js Texture stretched

I'm using THREE.OBJLoader to load my 3D objects in Three.js r100 and, at a certain moment, I need to load some dynamic textures with THREE.TextureLoader().
Then I simply create a new material with THREE.MeshBasicMaterial() and set this to my obj.
This is the code:
//this contains the texture loaded
let texture = await new Promise((resolve, rejects) => loadGeneralTexture(resolve, rejects, url));
texture.minFilter = THREE.LinearFilter;
texture.needsUpdate = true;
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
var material = new THREE.MeshBasicMaterial({
map: texture
});
//this loop set the new material with Texture
el.traverse(child => {
if (child instanceof THREE.Mesh) {
child.material = material;
}
});
The result is:
But the image loaded is:
I fix this error only with gizmo (3dMax tool) by "rotate" the texture but I can't do the same fix with Threejs.
The same problem with two other 3d objects but this time it's even worse
Edit: obj files are our client'file (so i didn't create It myself), i already checked the various "faces" and they are equal. Can i change uvmapping myself with threejs?

Not able to load Image texture in three js

This is my code -
var scene = new THREE.Scene();
// adding a camera
var camera = new THREE.PerspectiveCamera(fov,window.innerWidth/window.innerHeight, 1, 2000);
//camera.target = new THREE.Vector3(0, 0, 0);
// setting up the renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize(renderW, renderH);
document.body.appendChild(renderer.domElement);
// creating the panorama
// panoramas image
var panoramasArray = ["01.jpg"];
// creation of a big sphere geometry
// default segments of sphere w 8 h 6
var sphere = new THREE.SphereGeometry(400,100,40);
sphere.applyMatrix(new THREE.Matrix4().makeScale(-1, 1, 1));
// creation of the sphere material
//var sphereMaterial = new THREE.MeshBasicMaterial();
var sphereMaterial = new THREE.MeshBasicMaterial({color:0x0000FF});
sphereMaterial.map =THREE.ImageUtils.loadTexture(panoramasArray[1])
// geometry + material = mesh (actual object)
sphereMesh = new THREE.Mesh(sphere, sphereMaterial);
scene.add(sphereMesh);
camera.position.z = 900;
renderer.render(scene, camera);
I am running this on localhost apache server, but nothing visible in the browser. A black screen.
However, when I do this -
function render()
{
requestAnimationFrame(render);
renderer.render(scene, camera);
}
Everything works fine then ! I tried adding a callback on ImageUtils.Load but still nothing is rendered on screen until I put in an animation loop. I have been scratching my head since days now. Please explain n help. I dont want to put the animation frame just to display the image texture.
Loading a texture is done via an asynchronous XMLHTTPRequest. When the image is loaded after few hundred of milliseconds, the main script has executed the render call long time ago.
You have to move renderer.render(scene,camera) to the loader onLoad callback which is its third parameter :
THREE.ImageUtils.loadTexture( URL, mapping, function(){
renderer.render(scene,camera);
});
see the doc

Preload Textures and Images in ThreeJS?

i wanted to ask if there is a simple solution to preload Textures and Images in ThreeJs.
I load them all into an array: myTextureArray.push(new THREE.ImageUtils.loadTexture('../textures/floor_red.jpg');
How can i check if and when all Textures are loaded successfully ?
Here is an older Version Link: http://museum.baraq.de/
Thanks for help!
There is a Loading Manager in Three.js you can use to keep track of your loaded Textures or Objects.
Example implementation:
var textureManager = new THREE.LoadingManager();
textureManager.onProgress = function ( item, loaded, total ) {
// this gets called after any item has been loaded
};
textureManager.onLoad = function () {
// all textures are loaded
// ...
};
var textureLoader = new THREE.ImageLoader( textureManager );
var myTextureArray = [];
var myTexture = new THREE.Texture();
myTextureArray.push( myTexture );
textureLoader.load( 'my/texture.jpg', function ( image ) {
myTexture.image = image;
} );
Tested in Three.js r71.

Categories