I am using Three.js, version 71. I'm using Blender, version 2.73.
I created a textured collada object (.dae file) using Blender, and now I want to load it into my three.js scene. So far, I can only load models that get exported from blender that have no textures on them.
Here is how I create the textured collada object:
In blender, I simply use the default cube. Using the settings on the right, I add a texture to the cube. Here is the texture I am putting onto the cube (NOTE: it is 2048 X 2048, so it's a power of 2):
Here is an image of the cube in render mode to prove that the texture is on it:
Here are the export settings I used when I exported the cube as a collada from Blender:
Here is some code I used to try to load the textured collada:
var loader = new THREE.ColladaLoader();
var localObject;
loader.options.convertUpAxis = true;
loader.load( './models/test_texture.dae', function ( collada ) {
localObject = collada.scene;
localObject.scale.x = localObject.scale.y = localObject.scale.z = 32;
localObject.updateMatrix();
game.scene.add(localObject);
} );
Here is the error I got:
[.WebGLRenderingContext]GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 2
I then googled that error message and someone said the I need to compute tangents. Here are my attempts at that and the errors I got:
var loader = new THREE.ColladaLoader();
var localObject;
loader.options.convertUpAxis = true;
loader.load( './models/test_texture.dae', function ( collada ) {
localObject = collada.scene;
localObject.scale.x = localObject.scale.y = localObject.scale.z = 32;
localObject.updateMatrix();
for (var i = collada.scene.children.length - 1; i >= 0; i--) {
var child = collada.scene.children[i];
// child.children[0] will give us the THREE.Mesh of the collada
if ( child.colladaId == "Cube" ) {
// ATTEMPT 1: Just tried computing tangets based on answer from neoRiley here: http://stackoverflow.com/questions/21200386/webgl-gl-error-gl-invalid-operation-gldrawelements-attempt-to-access-out-of
// child.children[0].geometry.computeTangents();
// ATTEMPT 2: Got this suggestion from Popov here: http://stackoverflow.com/questions/15717468/three-lod-and-normalmap-shader-fail
// child.children[0].geometry[ 0 ][ 0 ].computeTangents();
// child.children[0].geometry[ 1 ][ 0 ].computeTangents();
// ATTEMPT 3: Tried setting some update flags based on answer from Sayris here: http://stackoverflow.com/questions/13988615/webglrenderingcontext-error-loading-texture-maps
// child.children[0].geometry.buffersNeedUpdate = true;
// child.children[0].geometry.uvsNeedUpdate = true;
// child.children[0].material.needsUpdate = true;
// child.children[0].geometry.computeTangents();
}
};
game.scene.add(localObject);
} );
ATTEMPT 1 ERROR:
Uncaught TypeError: Cannot read property '0' of undefined
// Stack trace
three.js:9935 handleTriangle
three.js:9974 THREE.Geometry.computeTangents
myCode.js:116 (anonymous function)
ColladaLoader.js:204 parse
ColladaLoader.js:84 request.onreadystatechange
ATTEMPT 2 ERROR:
Uncaught TypeError: Cannot read property '0' of undefined
This came from own code. I didn't think geometry of THREE.Mesh is two dimensional, but I tried it anyway.
ATTEMPT 3 ERROR: (same as ATTEMPT 1 ERROR)
Uncaught TypeError: Cannot read property '0' of undefined
// Stack trace
three.js:9935 handleTriangle
three.js:9974 THREE.Geometry.computeTangents
myCode.js:116 (anonymous function)
ColladaLoader.js:204 parse
ColladaLoader.js:84 request.onreadystatechange
I decided to use the JSON loader instead because I couldn't get the collada one to work. The first thing I did was install the JSON exporter addon into Blender. I got the addon from the .zip file from my three.js download. It's in
three.js-r71/utils/exporters/blender/addons and it's called io_three. You just need to copy that folder and paste it in your Blender installation directory in Blender Foundation/Blender/2.73/scripts/addons.
You then have to enable it in Blender. To do that:
Click to File->User Preferences...
Click Add-ons
Type three in the search field
All the way to the right, click the check box to enable it
At the bottom left, click Save User Settings so you don't need to do this again. You'll know it's working if you see Three.js (.json) when you click File->Export.
I followed most of the instructions from this site to help me create and export a model: http://graphic-sim.com/B_basic_export.html
Here are the steps I used to create and export the model (I tweaked them a little bit from the site)
Start up Blender.
Look at the Properties editor (on the right).
Press the World context button. In the World panel click Ambient Color and change it from black to middle gray.
Press the Material context button. On the Diffuse panel change Intensity to 1.0. Do the same on the Specular panel. In the Shading panel put a check in the Shadeless box.
Press the Textures context button. Near the top in the Type drop down box, select Image or Movie. In the Image panel, browse to your image (make sure the image's dimensions are in a power of 2).
Choose the UV Editing screen layout (drop-down box to right of help menu at top).
With mouse cursor in 3D editor, go into edit mode (Tab key).
Unwrap (Press the U key). Choose Smart UV Project. Click Ok to accept defaults.
In the UV Editing screen, select your image using the menu at the bottom left (see screenshot)
Select Image->Save As Image. This image will need to be next to your JSON file that you will export.
Click File->Export->Three.js (.json).
To the left, select a few more export options (see screenshot for the ones i used, which I found by trial and error). I think I only added Face Materials, Materials, and Textures. You can then also click Save Settings to save these settings.
Put your JSON file and your image file that you saved earlier in your project folder.
Use the following code to load it:
var object;
var loader = new THREE.JSONLoader();
loader.load( "./models/test_texture.json", function(geometry, materials) {
object = new THREE.Mesh(geometry, materials[0]);
object.scale.set(32, 32, 32);
game.scene.add(object);
});
Related
I have a glb model which I am loading into my Vue project via Three js. I have managed to import several other models for practice, but the one I actually want on my page will not load. I have tried playing around with different scaling, positions, background colors (since the object is mostly black), and camera angles but I am not able to get it in frame no matter what I do. I am able to see the model perfectly in any regular gltf view, but I cannot see it in my project, what am I doing wrong here?
Edit: As a side note, I also tried changing the scale in blender, but that did not change the result.
const loader = new GLTFLoader();
let me = this; // must refer to the instance in vue in order to be added to the scene, have tested this with other models
loader.load(
'pantalla_ball_2.glb',
function(gltf) {
gltf.scene.traverse(function( node ) {
if ( node.isMesh ) { node.castShadow = true; }
});
gltf.scene.scale.set(1,1,1) // Have tried several scales from 0.01 to 200
me.scene.add(gltf.scene);
console.log("added") // added is successfully called every time
},
function(xhr) {
console.log(xhr);
},
function(err) {
console.log(err); // no errors appear in console
}
);
The object loading perfectly in 3d viewer below
Thanks to JP4 for his helpful comments, the issue was the ambient lighting was not strong enough to illuminate the object sufficiently enough to be seen. The axis helpers showed me that the object was there thanks to the gaps in the axes.
I have a set of models in *.obj format that come without material files (*.mtl files). Some online services display these models correctly: https://3dviewer.net/, https://sketchfab.com/. But - according to the three.js documentation - in my project I only get an incorrect display of the model:
instead of:
The developer https://3dviewer.net/ said that the idea on this service is that if the *.mtl file is not found, then the script sets the default color / material - paints the entire product in one color.
How to color an object from a *.obj file to a selected color using three.js tools?
For testing, I attach a model file that comes without a material file: test sample *.obj file.
It seems the OBJ is not exported correctly. When using macOS preview, BabylonJS or the OBJLoader of three.js, the faces seem to have the wrong winding order. You should get the desired result by doing the following in your onLoad() callback:
const material = new THREE.MeshPhongMaterial( { color: 0xff0000, side: THREE.BackSide } );
obj.traverse( function( child ) {
if ( child.isMesh ) child.material = material;
} );
I am trying to load quite complex .3ds model into three.js using TDSLoader exactly the same way as in three.js/examples: https://github.com/mrdoob/three.js/blob/master/examples/webgl_loader_3ds.html
but what I get looks like this Result when it is supposed to look like this Loaded using https://3dviewer.net/. I can see that this online viewer uses three.js so it is possible. I also know that TDSLoader loads textures but does not map them for some reason (if I move texture out of the folder I get an load resource error). Code looks like this:
var loader = new THREE.TextureLoader();
var normal = loader.load('textures/normal.png');
var loader = new THREE.TDSLoader();
loader.setPath('textures/');
loader.load('textures/CAT_336D.3ds', function (object) {
object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
child.material.normalMap = normal;
}
});
scene.add(object);
});
My model has 23 types of materials but the loader loads only 2 - black and yellow, you can see that glass, metal and others are missing. How do I map all textures and materials? Maybe it does not work because the model is too big? (over 160 meshes, around 30MB)
I am trying to display a textured plane with Three.js. I'm working with Forge RCDB.
At first, I managed to display the plane, but instead of being textured, it was completely black... I made some changes and now nothing is displayed anymore...
Here is my code :
render () {
var viewer=NOP_VIEWER;
var scene=viewer.impl.scene;
var camera = viewer.autocamCamera;
var renderer = viewer.impl.renderer();
renderer.render( scene, camera );
}
and in the function supposed to display the textured plane :
new THREE.TextureLoader(texture).load(texture, this.render);
tex.wrapS = THREE.RepeatWrapping //ClampToEdgeWrapping //MirroredRepeatWrapping
tex.wrapT = THREE.RepeatWrapping //ClampToEdgeWrapping //MirroredRepeatWrapping
tex.mapping = THREE.UVMapping
At the beginning I used loadTexture(). I managed to display my plane, but it was all black, and no texture was applied on it.
Then, I use THREE.TextureLoader().load(), in this case, I believe it is trying to find the image on localhost. The image is downloaded, I can see it on the console.
But now I get these errors :
Uncaught TypeError: scope.manager.itemStart is not a function
and :
Uncaught TypeError: renderer.render is not a function
Now the object is not displayed, even in black.
So I think this may be linked to render, but I don't understand how...
I found this, and it answers my question partially.
Finally, I decided to keep THREE.ImageUtils.loadTexture(), and I replaced MeshLambertMaterial by MeshBasicMaterial.
No need for render.
I know this is a well known question but I was not able to find a good answer.
My usage
I use three.js to display 3D models created through drone pictures (here an example).
The problem
I can't render heavy models (1M vertices, 2M faces) : Chrome or WebGl crashed.
What I tried
I used Threejs.org examples for all my tests to be sure that it was not my code that didn't work. I made my test on a x64 Chrome with --max_old_space_size=6144 flag.
Import model in .dae with ColladaLoader --> 2.5Go of RAM is used and Chrome crash (displaying "not enough memory")
Import model in .obj with OBJLoader + MTLLoader --> 2.8Go of RAM is used and WebGl crash
I red many posts about Three.js and memory allocation but many of them speak about remove an object from the scene
Possible solutions
I saw that .stl (binary) file are more compact, but as far as I know
there is no texture with these files, so I can't use it
Use BinaryLoader (which has GeometryBuffer output) but I need to convert .dae or .obj to binary files and I don't know how to do that
Load my model in multiple parts to not load in one shot ? But I didn't saw any example or posts with that kind of treatment
How to reproduce
For the code, I use basics examples on Threejs.org. For models :
If you want to try with .dae you can find on this folder a working example (WorkingModel.dae / .jpg) and the model who don't work (BigModel.dae / .jpg)
If you want to try with .obj you can find on this folder a working example (WorkingModel.dae / .jpg / .mtl) and the model who don't work (BigModel.dae / .jpg / .mtl)
Any ideas to load the big one ?
Thanks !
EDIT 1 :
I tried to put a breakpoint in the SuccessCallback to see if the overload of RAM is during the load or after. I was not able to hit the breakpoint, so the overload of RAM is before the SuccessCallback.
Then I went step by step in the ColladaLoader to find what is using so much RAM. Here is the "callstack" :
myCollada.load()
ColladaLoader.parse()
Geometry.parse()
Mesh.parse()
Source.parse (hit 3 times) = +400mo in RAM
Vertices.parse = +0mo in RAM
Triangles.parse = +1500mo in RAM
this.geometry3js.computeVertexNormals() = RAM go over 2600Mo and chrome crash
Could I do any other tests to find the reason of this problem ?
Thanks
Your textures are waaaay to big, and besides, you don't need them because your model has baked vertex colors, which includes baked lighting. Your model therefore does not require UVs eiher.
Use ColladaLoader2, and this pattern. It should work.
var loader = new THREE.ColladaLoader();
loader.load( 'BigModel.dae', function ( collada ) {
var dae = collada.scene;
dae.traverse( function( child ) {
if ( child instanceof THREE.Mesh ) {
child.geometry.removeAttribute( 'uv' ); // you don't need it
child.material = new THREE.MeshBasicMaterial( { // scene lights not required
vertexColors: THREE.VertexColors // you have them, use them
} );
scene.add( child );
}
} );
} );
three.js r.86