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?
Related
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...
}
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());
}
im currently trying to update individual textures based on cursor position on imported JSON model. Below is the import code for the JSON model
var loader = new THREE.JSONLoader();
loader.load('slicedNew.json', function(geometry, materials) {
console.log(materials);
mesh = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial( materials ));
mesh.scale.x = mesh.scale.y = mesh.scale.z = 8;
mesh.translation = THREE.GeometryUtils.center(geometry);
scene.add(mesh);
console.log('IMPORTED OBJECT: ', mesh);
});
Below is raycaster code for when the cursor is over a particular material
switch(intersects[0].face.materialIndex)
{
case 0:
console.log('0 material index');
intersects[0].object.material.needsUpdate = true;
intersects[0].object.material.materials[0] = new THREE.MeshLambertMaterial({
map: crate
});
break;
Anytime I hover over a certain side of the shape the texture is loaded but it is always black, even initialise the model to use the texture it still appears as black, yet I can load in a simple cube and map the image as a texture to this shape with no issues.
Any help would be appreciated.
I want to use Three.js (OGL + JavaScript) to load an object from file. I have an working example without loading it (some basic elements rendered). But when I try to load object using JSONLoader.load(...), Firefox console shows error:
SyntaxError: missing formal parameter
The reference: http://threejs.org/docs/#Reference/Loaders/JSONLoader
The source code for my added fragment (loading object), which cause an error:
//loading an object
var loader = new THREE.JSONLoader(); //works so far
loader.load("./Project2/proj/grzyb.js",
function(geometry,
new THREE.MeshLambertMaterial( { map: texture, ambient: 0xbbbbbb } )
//for the line above, in Firefox console i get
//"SyntaxError: missing formal parameter"
){
var materials = new THREE.MeshFaceMaterial(
new THREE.MeshLambertMaterial( { map: texture, ambient: 0xbbbbbb } )
);
grzyb = new THREE.Mesh(geometry, materials);
grzyb.scale.set(5, 5, 5);
grzyb.position.set(2,2,2);
grzyb.receiveShadow = true;
grzyb.castShadow = true;
scene.add(grzyb);
}
);
You are trying to insert MeshLambertMaterial creation into a function header definition. Function header can only contain parameter names - not any actual code to create them.
Also it is not clear whether you want to use material coming from model file or your own material with texture that you loaded elsewhere (in the example there is no code that would set texture variable). Assuming you want to use materials from model, your code should look like this:
var loader = new THREE.JSONLoader(); //works so far
loader.load("./Project2/proj/grzyb.js",
function(geometry, materials) {
var material = new THREE.MeshFaceMaterial( materials );
grzyb = new THREE.Mesh(geometry, material);
grzyb.scale.set(5, 5, 5);
grzyb.position.set(2,2,2);
grzyb.receiveShadow = true;
grzyb.castShadow = true;
scene.add(grzyb);
}
);
if you want to use different material, then set material variable to anything you want. exmaple:
var texture = THREE.ImageUtils.LoadTexture( "../path/image.jpg" );
var material = new THREE.MeshBasicMaterial( { map:texture } );
var grzyb = new THREE.Mesh(geometry, material);
I'm using three.js to create a minecraft texture editor, similar to this. I'm just trying to get the basic click-and-paint functionality down, but I can't seem to figure it out. I currently have textures for each face of each cube and apply them by making shader materials with the following functions.
this.createBodyShaderTexture = function(part, update)
{
sides = ['left', 'right', 'top', 'bottom', 'front', 'back'];
images = [];
for (i = 0; i < sides.length; i++)
{
images[i] = 'img/'+part+'/'+sides[i]+'.png';
}
texCube = new THREE.ImageUtils.loadTextureCube(images);
texCube.magFilter = THREE.NearestFilter;
texCube.minFilter = THREE.LinearMipMapLinearFilter;
if (update)
{
texCube.needsUpdate = true;
console.log(texCube);
}
return texCube;
}
this.createBodyShaderMaterial = function(part, update)
{
shader = THREE.ShaderLib['cube'];
shader.uniforms['tCube'].value = this.createBodyShaderTexture(part, update);
shader.fragmentShader = document.getElementById("fshader").innerHTML;
shader.vertexShader = document.getElementById("vshader").innerHTML;
material = new THREE.ShaderMaterial({fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: shader.uniforms});
return material;
}
SkinApp.prototype.onClick =
function(event)
{
event.preventDefault();
this.change(); //makes texture file a simple red square for testing
this.avatar.remove(this.HEAD);
this.HEAD = new THREE.Mesh(new THREE.CubeGeometry(8, 8, 8), this.createBodyShaderMaterial('head', false));
this.HEAD.position.y = 10;
this.avatar.add(this.HEAD);
this.HEAD.material.needsUpdate = true;
this.HEAD.dynamic = true;
}
Then, when the user clicks any where on the mesh, the texture file itself is update using canvas. The update occurs, but the change isn't showing up in the browser unless the page is refreshed. I've found plenty of examples of how to change the texture image to a new file, but not on how to show changes in the same texture file during runtime, or even if it's possible. Is this possible, and if not what alternatives are there?
When you update a texture, whether its based on canvas, video or loaded externally, you need to set the following property on the texture to true:
If an object is created like this:
var canvas = document.createElement("canvas");
var canvasMap = new THREE.Texture(canvas)
var mat = new THREE.MeshPhongMaterial();
mat.map = canvasMap;
var mesh = new THREE.Mesh(geom,mat);
After the texture has been changed, set the following to true:
cube.material.map.needsUpdate = true;
And next time you render the scene it'll show the new texture.
Here is all the basics of what you have to know about "updating" stuff in three.js: https://threejs.org/docs/#manual/introduction/How-to-update-things